动态提供一个matplotlib图像的使用网络蟒蛇(Dynamically serving a ma

2019-07-19 18:17发布

这个问题已经被问以类似的方式在这里得到的答复是大大超过我的头(我是超级新的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>
"""

我认为,与其做pyplot.savefig(“test.png”),我应该创建一个cstringIO对象,然后做这样的事情:

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

但我非常从那里消失。 我见过的所有的例子(如http://lost-theory.org/python/dynamicimg.html )涉及做这样的事情

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

我不明白如何整合,与HTML我已经输出。

Answer 1:

你应该

  • 第一写入到cStringIO对象
  • 然后写入HTTP标头
  • 然后写入cStringIO的内容到标准输出

因此,如果在错误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()


Answer 2:

我的第一个问题是:像经常发生变化? 你想保留旧的? 如果它是一个实时的东西,那么你对优化的追求是合理的。 否则,产生的飞行图像的好处是不是显著。

该代码,因为它主张将需要2个请求:

  1. 让你已经有了HTML源代码和
  2. 获得实际的图像

也许最简单的方式(保持Web请求到最小)是@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

此代码可能不会开箱的,但给出了这个概念。

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

另一种方式是产生原始的HTML。 加载它将会触发“test.png”的请求。 您可以投放分开,无论是通过你已经提到了缓冲流媒体解决方案,或从一个静态文件。

就个人而言,我会用分离液棒:生成另一个进程(确保总有可用的图像)的图像,并使用一个很轻的东西,产生并服务于HTML。

HTH,



Answer 3:

以上答案是有点过时 - 在这里对我来说什么工作在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的”头“图像/ PNG”,写出来的字节。

根据您所使用的为您的Web服务器的代码可能会有所不同。 我用旋风作为我的网络服务器和代码做的是:

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


Answer 4:

什么工作对我来说与python3是:

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


Answer 5:

除非我不好就将误解你的问题,所有你需要做的是cd到图像的位置和运行:蟒蛇-m SimpleHTTPServer 8000&

然后打开浏览器,输入http://localhost:8000/在URL栏中。



Answer 6:

我知道我是一个有点晚了这里的聚会,但我有同样的问题,并结束了与下面的小脚本。

这条巨蟒3.6+代码:

  • 启动Web服务器,并告诉你在哪里查看
  • 扫描本身的类方法以“plot_”,并提供了浏览器与情节名单
  • 对于点击情节,提示所需的参数(如果有的话),包括一个自动刷新周期(秒)
  • 执行的情节和刷新

你可以通过代码知道,它是暂时的诊断和(在我的情况下机器学习进度)监测故意最小。

您可能需要安装任何依赖关系(PLAC +需要绘制比如我用熊猫任何其他库,matplotlib)

您可以通过运行双击命令行中的文件(无参数)或(有/无参数)

码:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import io
from http.server import HTTPServer,BaseHTTPRequestHandler
import urllib
import inspect


class PlotRequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        args = urllib.parse.parse_qs(self.path[2:])
        args = {i:args[i][0] for i in args}
        html = ''

        if 'mode' not in args:
            plots = ''
            for member in dir(self):
                if member[:5] == 'plot_':
                    plots += f'<a href="http://{self.server.server_name}:{self.server.server_port}/?mode=paramcheck&graph={member}">{member[5:].replace("_"," ").title()}</a><br/>\n'
            html = f'''<html><body><h1>Available Plots</h1>{plots}</body></html>'''

        elif args['mode'] == 'paramcheck':
            plotargs = inspect.getargspec(getattr(self,args['graph'])).args
            if len(plotargs) == 1 and plotargs[0].lower()=='self':
                args['mode'] = 'plotpage'
            else:
                for arg in plotargs:
                    if arg.lower() != 'self':
                        html += f"<input name='{arg}' placeholder='{arg}' value='' /><br />\n"
                html = f"<html><body><h1>Parameters:</h1><form method='GET'>{html}<input name='refresh_every' value='60' />(Refresh in sec)<br /><input type='hidden' name='mode' value='plotpage'/><input type='hidden' name='graph' value='{args['graph']}'/><input type='submit' value='Plot!'/></form></body></html>"

        if 'mode' in args and args['mode'] == 'plotpage':
            html = f'''<html><head><meta http-equiv="refresh" content="{args['refresh_every']};URL=\'http://{self.server.server_name}:{self.server.server_port}{self.path}\'" /></head>
                       <body><img src="http://{self.server.server_name}:{self.server.server_port}{self.path.replace('plotpage','plot')}" /></body>'''

        elif 'mode' in args and args['mode'] == 'plot':
            try:
                plt = getattr(self,args['graph'])(*tuple((args[arg] for arg in inspect.getargspec(getattr(self,args['graph'])).args if arg in args)))
                self.send_response(200)
                self.send_header('Content-type', 'image/png')
                self.end_headers()
                plt.savefig(self.wfile, format='png')
            except Exception as e:
                html = f"<html><body><h1>Error:</h1>{e}</body></html>"

        if html != '':
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(bytes(html,'utf-8'))

    def plot_convergence(self, file_path, sheet_name=None):
        if sheet_name == None:
            data = pd.read_csv(file_path)
        else:
            data = pd.read_excel(file_path, sheet_name)

        fig, ax1 = plt.subplots()

        ax1.set_xlabel('Iteration')
        ax1.set_ylabel('LOSS', color='tab:red')
        ax1.set_ylim([0,1000])
        ax1.plot(data.iteration, data.loss, color='tab:red')

        ax2 = ax1.twinx()

        ax2.set_ylabel('Precision, Recall, f Score')
        ax2.set_ylim([0,1])
        ax2.plot(data.iteration, data.precision, color='tab:blue')
        ax2.plot(data.iteration, data.recall, color='tab:green')
        ax2.plot(data.iteration, data['f-score'], color='tab:orange')

        fig.tight_layout()
        plt.legend(loc=6)
        return plt


def main(server_port:"Port to serve on."=9999,server_address:"Local server name."=''):
    httpd = HTTPServer((server_address, server_port), PlotRequestHandler)
    print(f'Serving on http://{httpd.server_name}:{httpd.server_port} ...')
    httpd.serve_forever()


if __name__ == '__main__':
    import plac; plac.call(main)


文章来源: Dynamically serving a matplotlib image to the web using python