使用python向web动态提供matplotlib映像
这个问题也曾以类似的方式被问过,但答案太离谱了(我对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 ..
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个请求:
# 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_”开头的类方法,并向浏览器提供绘图列表
- 对于单击的绘图,提示输入所需参数(如果有),包括自动刷新周期(秒)
- 执行绘图并刷新
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)