使用Flask和matplotlib动态生成图像

3

我希望能够绘制一张图片,而不必将其保存在静态文件夹中。

这里用户Messa发布的示例已经可以正常工作:

import io
import random
from flask import Response
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

@app.route('/plot.png')
def plot_png():
    fig = create_figure()
    output = io.BytesIO()
    FigureCanvas(fig).print_png(output)
    return Response(output.getvalue(), mimetype='image/png')

def create_figure():
    fig = Figure()
    axis = fig.add_subplot(1, 1, 1)
    xs = range(100)
    ys = [random.randint(1, 50) for x in xs]
    axis.plot(xs, ys)
    return fig

然后在HTML文件中:
<img src="/plot.png" alt="my plot">

结果非常完美,我可以即时获取图像。

现在我想使用一些参数,就像这样:

@app.route('/<x_values_source>/<y_values_source>/plot.png')
def plot_png(x_values_source, y_values_source):
    fig = create_figure(x_values_source, y_values_source)
    output = io.BytesIO()
    FigureCanvas(fig).print_png(output)
    return Response(output.getvalue(), mimetype='image/png')

def create_figure(x_values_source, y_values_source):
    x_values = function_that_returns_x_values_set(x_values_source)
    y_values = function_that_returns_y_values_set(y_values_source)
    fig = Figure()
    axis = fig.add_subplot(1, 1, 1)
    axis.plot(x_values, y_values)
    return fig

当然,它不起作用。我对Python还很陌生,仍在学习许多东西。

谢谢!

1个回答

5
为了传递参数,最好不要将它们作为URI的前缀,因为那可能会混淆Flask的路由解码。相反,如果您按照以下方式形成URL:
/plot.png?x=1,2,3,4&y=100,200,300,400

您可以通过request.args来获取参数。它们会以字符串的形式出现,所以您需要分离并将其转换为整数(或实数,如果您使用实数)。

from flask import request

@app.route('/plot.png')
def plot():
    try:
        x_values = [int(x) for x in request.args.get('x','').split(',')]
        y_values = [int(y) for y in request.args.get('y','').split(',')]
    except:
        # malformed 

我有一个工作示例在这里,展示了一种处理matplotlib动态的强大方法。总体思路是

from flask import send_file

@app.route('/plot.png')
def plot_png():
    fig, ax = plt.subplots()
    draw(ax)
    return fig_response(fig)

def fig_response(fig):
    """Turn a matplotlib Figure into Flask response"""
    img_bytes = BytesIO()
    fig.savefig(img_bytes)
    img_bytes.seek(0)
    return send_file(img_bytes, mimetype='image/png')

这里是您提供draw()的位置。不过,请查看我的示例,因为您需要添加一些缓存标头。


嗨!谢谢回复。我仍然不明白如何通过路由发送参数。 - Luciano
谢谢!我会尝试一下。我还修改了我的原始问题,以使其更清晰明了。 - Luciano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接