使用Python动态在网页上展示matplotlib图像

25 投票
6 回答
31678 浏览
提问于 2025-04-17 15:34

这个问题在这里以类似的方式被问过 这里,但答案对我来说太复杂了(我对python和网页开发都是新手),所以我希望能有更简单的方法,或者能用不同的方式解释一下。

我想用matplotlib生成一张图片,并且不想先把文件写到服务器上。我的代码可能有点傻,但大致是这样的:

import cgi
import matplotlib.pyplot as pyplot
import cStringIO #I think I will need this but not sure how to use

...a bunch of matplotlib stuff happens....
pyplot.savefig('test.png')

print "Content-type: text/html\n"
print """<html><body>
...a bunch of text and html here...
<img src="test.png"></img>
...more text and html...
</body></html>
"""

我觉得我应该用一个叫做cstringIO的对象,而不是直接用pyplot.savefig('test.png'),然后做类似这样的事情:

mybuffer=cStringIO.StringIO()
pyplot.savefig(mybuffer, format="png")

但从那之后我就有点迷茫了。我看到的所有例子(比如 http://lost-theory.org/python/dynamicimg.html)都涉及到做一些像这样的事情:

print "Content-type: image/png\n"

而我不太明白怎么把这些和我已经输出的HTML结合起来。

6 个回答

9

我在使用Python3时,发现这个方法对我很有效:

buf = io.BytesIO()
plt.savefig(buf, format='png')
image_base64 = base64.b64encode(buf.getvalue()).decode('utf-8').replace('\n', '')
buf.close()
13

上面的回答有点过时了——这里是我在Python3+中获取图像数据原始字节的方法。

import matplotlib.pyplot as plt
from io import BytesIO
fig = plt.figure()
plt.plot(range(10))
figdata = BytesIO()
fig.savefig(figdata, format='png')

正如其他回答提到的,你现在需要设置一个'Content-Type'头为'image/png',然后输出字节。

根据你使用的网络服务器,代码可能会有所不同。我使用Tornado作为我的网络服务器,下面是实现这个功能的代码:

self.set_header('Content-Type', 'image/png')
self.write(figdata.getvalue())
21

你应该这样做:

  • 首先写入一个 cStringIO 对象
  • 然后写入 HTTP 头信息
  • 接着把 cStringIO 的内容写到标准输出(stdout)

这样,如果在 savefig 过程中出现错误,你仍然可以返回其他内容,甚至是另一个头信息。有些错误不会提前被发现,比如文本问题、图片尺寸过大等。

你需要告诉 savefig 输出应该写到哪里。你可以这样做:

format = "png"
sio = cStringIO.StringIO()
pyplot.savefig(sio, format=format)
print "Content-Type: image/%s\n" % format
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) # Needed this on windows, IIS
sys.stdout.write(sio.getvalue())

如果你想把图片嵌入到 HTML 中:

print "Content-Type: text/html\n"
print """<html><body>
...a bunch of text and html here...
<img src="data:image/png;base64,%s"/>
...more text and html...
</body></html>""" % sio.getvalue().encode("base64").strip()

撰写回答