Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 从Flask中的JSON数据提供动态matplotlib图像_Python_Json_Image_Matplotlib_Flask - Fatal编程技术网

Python 从Flask中的JSON数据提供动态matplotlib图像

Python 从Flask中的JSON数据提供动态matplotlib图像,python,json,image,matplotlib,flask,Python,Json,Image,Matplotlib,Flask,在我的应用程序中,我想为通过POST方法发送的numpy数组生成的PNG图像提供服务,因此在我提出的应用程序中,有两种途径——一种是为HTML提供'.format(img.getvalue())的途径 @app.route('/img/gen',methods=['POST']) def img_gen(): data=np.array(json.loads(request.get_json())) 图=plt.图() plt.plot(数据[0,:],c='b') plt.plot(数据[1,

在我的应用程序中,我想为通过POST方法发送的numpy数组生成的PNG图像提供服务,因此在我提出的应用程序中,有两种途径——一种是为HTML提供
'.format(img.getvalue())的途径
@app.route('/img/gen',methods=['POST'])
def img_gen():
data=np.array(json.loads(request.get_json()))
图=plt.图()
plt.plot(数据[0,:],c='b')
plt.plot(数据[1,:]*-1,c='r')
plt.grid()
png=BytesIO()
图Canvasagg(图)。打印png(png)
plt.关闭(图)
返回响应(png.getvalue(),mimetype='image/png')
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app.run()

我检查了数组是否正确地传递给
/img/gen
路由并由其接收,但应用程序似乎卡在
返回
行或之前。Gunicorn v3不打印任何错误消息,除了
工作超时
。如果有人向我指出此问题的原因,我将不胜感激。

您的代码有几个问题:

  • 您正在使用
    .raw.read()
    直接访问字节响应,但是由于响应是mimetype“img/png”,您只需使用
    .content
    。我无法使
    .raw.read()
    正常工作,因此我建议使用`

  • 您正在混合字符串和字节类型。通常,每当将字节计算为字符串时,
    b'
    将附加在开头,而
    '
    将附加在结尾。此外,python字节类型不是base64,请使用
    base64
    模块中的
    b64encode

  • 您需要以URI类型开始
    src=
    。 基于2、3和4,您应该编写以下代码:
    b'%b64encode(img)
    ,它使用字节类型,声明数据类型,并插入base64 bytestring

  • 完整代码如下:

    from flask import Flask, request, url_for, Response
    import requests
    from matplotlib import pyplot as plt
    from matplotlib.backends.backend_agg import FigureCanvasAgg
    import numpy as np
    import json
    from io import BytesIO
    
    app = Flask(__name__)
    
    @app.route('/img/show')
    def show_html():
            data = np.random.rand(80).reshape((2, 40))
            img = BytesIO(requests.post(request.scheme + '://' + request.host + url_for('img_gen'), json=json.dumps(data.astype(float).tolist())).raw.read())
            return '<img src="{}" />'.format(img.getvalue())
    
    
    @app.route('/img/gen', methods=['POST'])
    def img_gen():
            data = np.array(json.loads(request.get_json()))
            fig = plt.figure()
            plt.plot(data[0, :], c='b')
            plt.plot(data[1, :]*-1, c='r')
            plt.grid()
            png = BytesIO()
            FigureCanvasAgg(fig).print_png(png)
            plt.close(fig)
            return Response(png.getvalue(), mimetype='image/png')
    
    if __name__ == '__main__':
            app.run()
    
    从烧瓶导入烧瓶,请求,url\u,响应
    导入请求
    从matplotlib导入pyplot作为plt
    从matplotlib.backends.backend_agg导入图Canvasagg
    将numpy作为np导入
    导入json
    从io导入字节io
    从base64导入b64encode
    app=烧瓶(名称)
    @应用程序路线(“/img/show”)
    def show_html():
    数据=np.random.rand(80).重塑((2,40))
    img=requests.post(
    request.scheme+“:/”+request.host+url\u for(“img\u gen”),
    json=json.dumps(data.astype(float.tolist()),
    ).内容
    返回b“”%B64编码(img)
    @app.route(“/img/gen”,methods=[“POST”])
    def img_gen():
    data=np.array(json.loads(request.get_json()))
    图=plt.图()
    plt.绘图(数据[0,:],c=“b”)
    plt.绘图(数据[1,:]*-1,c=“r”)
    plt.grid()
    png=BytesIO()
    图Canvasagg(图)。打印png(png)
    plt.关闭(图)
    返回响应(png.getvalue(),mimetype=“image/png”)
    如果名称=“\uuuuu main\uuuuuuuu”:
    app.run()
    

    最后,我将注意到,您不一定需要为映像使用单独的端点,因为该端点仅由服务器本身使用。假设您没有调用外部服务器,那么让一个函数返回图像会更有意义,该函数由
    show\u html
    函数调用。

    您的最后一句话表明您向
    响应发送了意外数据。您是否分别测试了img\U gen的
    功能,以查看它是否可以显示保存为静态文件的图像?这不是对你问题的回答,但你是否考虑过将图像保存到一个临时文件中,然后提供给它?@Kaan E。我测试了这段代码,类似的功能适用于GET请求生成的PNG图像。我从感谢您的回答中学到了这段代码,但是您提出的代码仍然不适用于我-每次我点击
    /img/show
    端点时,我都会收到工人超时。我使用的是
    gunicorn-3(版本19.9.0)
    @mac13k,我目前使用的是windows,因此无法测试gunicorn(我使用flask的内置服务器进行了测试)。不过,这可能会有所帮助。它猜测工作超时是因为生成图像和发送响应所花费的时间太长。我编写了另一个应用程序,在GET请求时以PNG格式生成matplotlib绘图,它工作正常-没有超时,图像也正常。在那里,我可以直接在
    中包含指向端点的URL,而无需存储或处理响应,因此我猜在这种情况下,我们试图显示
    请求的方式有问题。post().content
    在HTML中。我修改了另一个应用程序,该应用程序在直接从URL提供图像服务时运行良好-使用
    requests.get()
    它开始超时,所以这就是问题出现的地方,但我不明白为什么…@mac13k,我刚刚用gunicorn进行了测试,发现了问题。运行
    gunicorn main:app
    默认情况下只使用一个工作进程-这意味着它一次只能处理一个请求,但要使此代码正常工作,您至少需要运行两个工作进程,因为您需要同时调用两个端点。因此,
    show
    端点将永远等待
    gen
    端点。尝试运行
    gunicorn-w2 main:app,它应该可以工作。
    
    from flask import Flask, request, url_for, Response
    import requests
    from matplotlib import pyplot as plt
    from matplotlib.backends.backend_agg import FigureCanvasAgg
    import numpy as np
    import json
    from io import BytesIO
    from base64 import b64encode
    
    app = Flask(__name__)
    
    
    @app.route("/img/show")
    def show_html():
        data = np.random.rand(80).reshape((2, 40))
        img = requests.post(
            request.scheme + "://" + request.host + url_for("img_gen"),
            json=json.dumps(data.astype(float).tolist()),
        ).content
        return b'<img src="data:image/png;base64,%b" />' %b64encode(img)
    
    
    @app.route("/img/gen", methods=["POST"])
    def img_gen():
        data = np.array(json.loads(request.get_json()))
        fig = plt.figure()
        plt.plot(data[0, :], c="b")
        plt.plot(data[1, :] * -1, c="r")
        plt.grid()
        png = BytesIO()
        FigureCanvasAgg(fig).print_png(png)
        plt.close(fig)
        return Response(png.getvalue(), mimetype="image/png")
    
    
    if __name__ == "__main__":
        app.run()