【问题标题】:Passing a matplotlib figure to HTML (flask)将 matplotlib 图传递给 HTML(烧瓶)
【发布时间】:2013-12-05 02:56:59
【问题描述】:

我正在使用 matplotlib 在 Web 应用程序中渲染一些图形。我之前在运行脚本时使用过fig.savefig()。但是,我需要一个函数来返回一个实际的“.png”图像,以便我可以用我的 HTML 调用它。

更多(可能是不必要的)信息:我正在使用 Python Flask。我想我可以使用 fig.savefig() 并将图形粘贴在我的静态文件夹中,然后从我的 HTML 中调用它,但我不想每次都这样做。如果我可以创建图形,从中制作图像,返回该图像,然后从我的 HTML 中调用它,那将是最佳选择,然后它就消失了。

创建图形的代码有效。但是,它返回一个数字,我猜它不适用于 HTML。

这里我在路由中调用draw_polygondraw_polygon是返回图的方法:

@app.route('/images/<cropzonekey>')
def images(cropzonekey):
    fig = draw_polygons(cropzonekey)
    return render_template("images.html", title=cropzonekey, figure = fig)

这是我尝试生成图像的 HTML。

<html>
  <head>
    <title>{{ title }} - image</title>
  </head>
  <body>
    <img src={{ figure }} alt="Image Placeholder" height="100">
  </body>
</html>

而且,正如您可能猜到的,当我加载页面时,我得到的只是Image Placeholder。所以,他们不喜欢我输入这个数字的格式。

任何人都知道 matplotlib 方法/解决方法可以将图形变成实际图像吗?我到处都是这些文档,但我找不到任何东西。谢谢!

顺便说一句:认为没有必要包含制作该图的 python 代码,但如果你们需要查看它,我可以包含它(只是不想让问题变得混乱)

【问题讨论】:

  • 最近做了一些工作以使 mpl 与 google appEnigne 配合得很好,有关此的讨论包括如何处理此类事情的示例。另一种选择是像 ipython notebook 那样做,它将 png 转换为字符串并直接嵌入。

标签: python html image matplotlib flask


【解决方案1】:

您必须将 HTML 和图像分成两个不同的路径。

您的/images/&lt;cropzonekey&gt; 路由只会为页面提供服务,并且在该页面的 HTML 内容中将引用第二个路由,即提供图像的路由。

图像从您使用savefig() 生成的内存文件以自己的路径提供。

我显然没有对此进行测试,但我相信以下示例将按原样运行,或者让您非常接近可行的解决方案:

@app.route('/images/<cropzonekey>')
def images(cropzonekey):
    return render_template("images.html", title=cropzonekey)

@app.route('/fig/<cropzonekey>')
def fig(cropzonekey):
    fig = draw_polygons(cropzonekey)
    img = StringIO()
    fig.savefig(img)
    img.seek(0)
    return send_file(img, mimetype='image/png')

您的images.html 模板变为:

<html>
  <head>
    <title>{{ title }} - image</title>
  </head>
  <body>
    <img src="{{ url_for('fig', cropzonekey = title) }}" alt="Image Placeholder" height="100">
  </body>
</html>

【讨论】:

  • Miguel,首先,只想说你的烧瓶教程太棒了。为此+1。但是,当我导航到该页面时,我仍然会收到占位符文本。是否可能是与flask无关的问题(即draw_polygons(cropzonekey)返回的格式?
  • 安装我的更改后,在浏览器中导航到http://localhost:5000/fig/cropzonekey。那你看到图片了吗?
  • 哇,是的,它奏效了。只是没有重新路由到正确的地方,但我可以解决这个问题。非常感谢,完美的答案!
  • @Miguel 您是否看到将 matplolib web_agg 后端与烧瓶集成的任何变化? Here 是一个将它集成到 Tornado 中的示例,但是我不知道如何将它集成到烧瓶中。
  • 当我将 img = StringIO() 切换到 img = BytesIO() 时为我工作
【解决方案2】:

我正在使用 Python 3.x,我更改了一些代码行,它对我有用。我收到以下错误消息:".....object has no attribute 'savefig'"

@app.route('/fig/<cropzonekey>')

def fig(cropzonekey):
    #fig = draw_polygons(cropzonekey)
    fig = plt.plot([1,2,3,4], [1,2,3,4])
    #img = StringIO()
    img = BytesIO()
    #fig.savefig(img)
    plt.savefig(img)
    img.seek(0)
    return send_file(img, mimetype='image/png')

【讨论】:

    【解决方案3】:
    from flask import Flask, send_file
    from io import StringIO
    import matplotlib.pyplot as plt
    from StringIO import StringIO
    @app.route('/fig/')
    def fig():
          plt.plot([1,2,3,4], [1,2,3,4])
          img = StringIO()
          plt.savefig(img)
          img.seek(0)
          return send_file(img, mimetype='image/png')
    

    其他答案是正确的,我只是想显示必须包含的头文件。 该程序创建一个简单的图形并将其发送到 html 页面。

    【讨论】:

      【解决方案4】:

      对于 Python3 ....

      我有一个 DataFrame,我想在 Flask 中显示这个图 ....

      所以创建一个 Base64 图像的情节。

          df_week_min_az = pd.DataFrame.from_dict(week_max_az.to_dict(),
                                                  orient='index', columns=['min_az'])
      
      
      
          sunalt = df_week_max_angle.plot().get_figure()
          buf = io.BytesIO()
          sunalt.savefig(buf, format='png')
          buf.seek(0)
          buffer = b''.join(buf)
          b2 = base64.b64encode(buffer)
          sunalt2=b2.decode('utf-8')
      

      我现在使用这样的 base64 编码数据调用我的模板......

      return render_template('where.html', form=form, sunalt=sunalt2)

      模板的相关部分(即图片位)如下所示......

       {% if sunalt != None %}
      
            <h2>Sun Altitude during the year</h2>
          <img src="data:image/png;base64,{{ sunalt }}">
      {% endif %}
      

      希望对某人有所帮助....

      【讨论】:

        【解决方案5】:

        Python 3

        我遇到了很多错误,例如 - Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!

        对于所有想要将 matplotlib 与烧瓶一起使用并在 python 3 中的 html 页面上呈现图形的人,这里是 -

        __init__.py

        import matplotlib
        matplotlib.use('Agg')
        import matplotlib.pyplot as plt
        from flask import Flask, render_template
        from io import BytesIO
        import base64
        
            @app.route('/plot')
            def plot():
                img = BytesIO()
                y = [1,2,3,4,5]
                x = [0,2,1,3,4]
        
                plt.plot(x,y)
        
                plt.savefig(img, format='png')
                plt.close()
                img.seek(0)
                plot_url = base64.b64encode(img.getvalue()).decode('utf8')
        
                return render_template('plot.html', plot_url=plot_url)
        

        flaskr/templates/plot.html

        <!doctype html>
        <title>heatmap - </title>
        <section>
          <h2>Heatmap</h2>
          <img src="data:image/png;base64, {{ plot_url }}">
        </section>
        
        

        【讨论】:

          【解决方案6】:

          这对我来说效果很好,你也可以查看这个 URL medium blog

          from flask import Flask, render_template
          from PIL import Image
          import base64
          import io
          
          app = Flask(__name__)
          
          @app.route('/')
          def show_image():
          
          
              # Your plt plots instructions here 
              # plt.save('generated_plot.png') 
          
              im = Image.open("generated_plot.png") #Open the generated image
              data = io.BytesIO() 
              im.save(data, "png")
              encoded_img_data = base64.b64encode(data.getvalue())
          
              return render_template("show_image.html", img=encoded_img_data.decode('utf-8'))
          
          
          if __name__ == '__main__':
          
          
             app.run(debug=True)
              
          

          【讨论】:

            猜你喜欢
            • 2017-10-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-21
            • 2017-11-19
            • 2015-04-22
            • 1970-01-01
            相关资源
            最近更新 更多