使用python向web动态提供matplotlib映像

使用python向web动态提供matplotlib映像,python,matplotlib,cgi,Python,Matplotlib,Cgi,这个问题也曾以类似的方式被问过,但答案太离谱了(我对python和web开发非常陌生),所以我希望有一种更简单的方法,或者可以用不同的方式来解释 我正在尝试使用matplotlib生成一个图像,并在不向服务器写入文件的情况下提供它。我的代码可能有点傻,但它是这样的: import cgi import matplotlib.pyplot as pyplot import cStringIO #I think I will need this but not sure how to use ..

这个问题也曾以类似的方式被问过,但答案太离谱了(我对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>
"""
但我从那里迷路了。我看到的所有例子都涉及到

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

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

除非我严重误解了您的问题,否则您所需要做的就是将cd刻录到映像的位置并运行:python-msimplehttpserver 8000&


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

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

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

  • 获取您已有的html源代码,并
  • 要得到真实的图像
  • 可能最简单的方法(将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
    
    #在iostring中构建matplotlib映像
    # ......
    #
    #初始化base64字符串
    #
    imgStr=“data:image/png;base64,”
    imgStr+=base64.b64编码(mybuffer)
    打印“内容类型:文本/html\n”
    打印“”
    #…这里有一堆文本和html。。。
    #…更多文本和html。。。
    “”%imgStr
    
    这段代码可能不会开箱即用,但它展示了这个想法

    请注意,如果您的图像没有经常更改,或者生成它需要很长时间,这通常是一个坏主意,因为每次都会生成它

    另一种方法是生成原始html。加载它将触发对“test.png”的请求。您可以通过前面提到的缓冲区流解决方案或静态文件单独提供服务

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

    嗯,你应该

    • 首先写入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()
    
    print“内容类型:text/html\n”
    打印“”
    …这里有一堆文本和html。。。
    …更多文本和html。。。
    “%sio.getvalue().encode(“base64”).strip()
    
    上面的答案有点过时了——下面是我在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”,并写出字节

    根据您用作Web服务器的内容,代码可能会有所不同。我使用Tornado作为我的Web服务器,代码如下:

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

    使用python3对我有效的是:

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

    我知道我在这里参加聚会有点晚了,但我也遇到了同样的问题,最后还是写了下面的小脚本

    此python 3.6+代码:

    • 启动web服务器并告诉您在何处查看它
    • 扫描自身以“plot_”开头的类方法,并向浏览器提供绘图列表
    • 对于单击的绘图,提示输入所需参数(如果有),包括自动刷新周期(秒)
    • 执行绘图并刷新
    从代码中可以看出,临时诊断和监视(在我的例子中是机器学习进度)故意将其最小化

    您可能需要安装任何依赖项(plac+绘图所需的任何其他LIB,例如我使用pandas、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)
    
    将numpy导入为np
    将matplotlib.pyplot作为plt导入
    作为pd进口熊猫
    输入io
    从http.server导入HTTPServer,BaseHTTPRequestHandler
    导入URL库
    进口检验
    类PlotRequestHandler(BaseHTTPRequestHandler):
    def do_获得(自我):
    args=urllib.parse.parse_qs(self.path[2:])
    args={i:args[i][0]表示args中的i}
    html=“”
    如果参数中没有“模式”:
    绘图=“”
    对于dir(self)中的成员:
    如果成员[:5]=“绘图”:
    绘图+=f'
    \n' html=f''Available Plots{Plots}'' elif args['mode']=='paramcheck': plotargs=inspect.getargspec(getattr(self,args['graph']).args 如果len(plotargs)==1且plotargs[0]。lower()==“self”: args['mode']='plotpage' 其他: 对于绘图参数中的参数: 如果参数较低()!='自我‘: html+=f“
    \n” html=f“参数:{html}(以秒刷新)
    ” 如果args中的'mode'和args['mode']='plotpage': html=f'' ''' 参数中的elif“mode”和参数[“mode”]=“plot”: 尝试: plt=getattr(self,args['graph'])(*元组((inspect.getargspec中arg的args[arg])(getattr(self,args['graph']))。如果args中arg,则为args))) 自我发送_响应(200) self.send_头('Content-type','image/png') 自攻头
    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)