使用python动态地将matplotlib图像提供给Web

Ben*_* S. 20 python cgi matplotlib

这个问题在这里以类似的方式提出,但答案是我的头脑(我是python和web开发的新手),所以我希望有一个更简单的方法或者可以用不同的方式解释.

我正在尝试使用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>
"""
Run Code Online (Sandbox Code Playgroud)

我认为不是做pyplot.savefig('test.png'),而是应该创建一个cstringIO对象,然后执行以下操作:

mybuffer=cStringIO.StringIO()
pyplot.savefig(mybuffer, format="png")
Run Code Online (Sandbox Code Playgroud)

但我很失落.我见过的所有例子(例如http://lost-theory.org/python/dynamicimg.html)都涉及到类似的事情.

print "Content-type: image/png\n"
Run Code Online (Sandbox Code Playgroud)

我不知道如何将它与我已经输出的HTML集成.

Tho*_*anz 19

你应该

  • 首先写入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())
Run Code Online (Sandbox Code Playgroud)

如果要将图像嵌入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()
Run Code Online (Sandbox Code Playgroud)


Mik*_*e N 7

上面的答案有点过时了 - 这是我在Python3 +上获取图形数据的原始字节的原因.

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

如其他答案所述,您现在需要将'Content-Type'标题设置为'image/png'并写出字节.

根据您用作网络服务器的内容,代码可能会有所不同.我使用Tornado作为我的网络服务器,这样做的代码是:

self.set_header('Content-Type', 'image/png')
self.write(figdata.getvalue())
Run Code Online (Sandbox Code Playgroud)


Lau*_*van 5

我的第一个问题是:图像经常变化吗?你想保留旧的吗?如果它是一个实时的东西,那么你对优化的追求是合理的.否则,动态生成图像的好处并不那么重要.

目前的代码需要2个请求:

  1. 获取你已经拥有的html源代码
  2. 得到实际的图像

可能最简单的方法(将网络请求保持在最低限度)是@Alex L'的评论,它允许您通过构建包含嵌入图像的HTML在单个请求中完成.

你的代码是这样的:

# Build your matplotlib image in a iostring here
# ......
#

# Initialise the base64 string
#
imgStr = "data:image/png;base64,"

imgStr += base64.b64encode(mybuffer)

print "Content-type: text/html\n"
print """<html><body>
# ...a bunch of text and html here...
    <img src="%s"></img>
#...more text and html...
    </body></html>
""" % imgStr
Run Code Online (Sandbox Code Playgroud)

这段代码可能不会开箱即用,但显示了这个想法.

请注意,这是一般一个坏主意,如果你的形象并没有真正改变过于频繁或产生需要很长的时间,因为它每次都产生.

另一种方法是生成原始的html.加载它将触发"test.png"的请求.您可以通过已提及的缓冲流式解决方案或静态文件单独提供.

就个人而言,我坚持使用一个解耦的解决方案:通过另一个进程生成图像(确保总有一个图像可用)并使用一个非常轻的东西来生成和提供HTML.

HTH,


小智 5

python3对我有用的是:

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