使用Matplotlib读取URL中PNG文件报错的原因及方案咨询
问题:Matplotlib读取URL图片报错及解决原理
问题场景
尝试用Matplotlib加载URL中的PNG图片,后续叠加聚类图层,初始代码如下:
import urllib.request as urllib2 import matplotlib.pyplot as plt DIRECTORY = "http://commondatastorage.googleapis.com/codeskulptor-assets/" MAP_URL = DIRECTORY + "data_clustering/USA_Counties.png" map_file = urllib2.urlopen(MAP_URL) map_img = plt.imread(map_file) implot = plt.imshow(map_img)
报错信息
运行后抛出UnsupportedOperation: seek错误,完整回溯:
runfile('G:/My Drive/Python/Fundamentals of computing/AT/Application 3/untitled0.py', wdir='G:/My Drive/Python/Fundamentals of computing/AT/Application 3') Traceback (most recent call last): File "G:\My Drive\Python\Fundamentals of computing\AT\Application 3\untitled0.py", line 15, in <module> map_img = plt.imread(map_file) File "C:\Users\Tomas\anaconda3\lib\site-packages\matplotlib\pyplot.py", line 2160, in imread return matplotlib.image.imread(fname, format) File "C:\Users\Tomas\anaconda3\lib\site-packages\matplotlib\image.py", line 1560, in imread with img_open(fname) as image: File "C:\Users\Tomas\anaconda3\lib\site-packages\PIL\ImageFile.py", line 116, in __init__ self._open() File "C:\Users\Tomas\anaconda3\lib\site-packages\PIL\PngImagePlugin.py", line 727, in _open cid, pos, length = self.png.read() File "C:\Users\Tomas\anaconda3\lib\site-packages\PIL\PngImagePlugin.py", line 176, in read pos = self.fp.tell() UnsupportedOperation: seek
环境:Anaconda3 + Spyder 5.2.2,已更新conda、Spyder及Pillow包。
可行解决方法
直接将URL传入plt.imread,跳过urllib2.urlopen步骤:
import matplotlib.pyplot as plt DIRECTORY = "http://commondatastorage.googleapis.com/codeskulptor-assets/" MAP_URL = DIRECTORY + "data_clustering/USA_Counties.png" map_img = plt.imread(MAP_URL) implot = plt.imshow(map_img)
解决原理
1. urllib2.urlopen返回对象的局限性
urllib2.urlopen()返回的是HTTPResponse对象,属于单向流式IO对象,只能按顺序读取数据,不支持seek()(移动文件指针)和tell()(获取当前指针位置)操作。而Pillow解析PNG时,需要多次移动指针读取不同块的内容(如头信息、数据块、结束块),这就触发了UnsupportedOperation错误。
2. Matplotlib对URL的内部处理逻辑
当直接传入URL给plt.imread()时,Matplotlib会自动完成以下操作:
- 将URL对应的资源下载到一个可随机访问的临时IO对象(内存中的BytesIO或本地临时文件)
- 该临时对象支持
seek()和tell(),满足Pillow解析PNG的需求 - 解析完成后自动清理临时资源,无需手动处理
简言之,Matplotlib封装了网络资源的读取逻辑,把流式的网络响应转换成了符合解析要求的可随机访问对象,而自行用urllib打开的响应对象不具备这个能力。
内容的提问来源于stack exchange,提问作者Tomás Monicat
相关产品推荐
相关产品推荐

