Передача фигуры Matplotlib в HTML (фляжка)

Я использую Matplotlib для визуализации фигуры в веб-приложении. Я использовал fig.savefig() до того, когда я просто запускаю сценарии. Однако мне нужна функция для возврата фактического изображения ".png", чтобы я мог вызвать его с помощью своего HTML.

Еще немного (возможно, ненужная) информация: я использую Python Flask. Я полагаю, я мог бы использовать fig.savefig() и просто вставьте фигуру в мою статическую папку, а затем вызовите ее из моего HTML, но я бы предпочел не делать это каждый раз. Было бы оптимальным, если бы я мог просто создать фигуру, сделать из нее изображение, вернуть это изображение и вызвать его из моего HTML-кода, тогда он исчезнет.

Код, который создает фигуру, работает. Однако, это возвращает число, которое не работает с HTML, я думаю.

Вот где я называю draw_polygon в маршрутизации, draw_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, который делает рисунок, но я могу включить его, если вам, ребята, нужно его увидеть (просто не хотел загромождать вопрос)

6 ответов

Решение

Вы должны разделить HTML и изображение на два разных маршрута.

Ваш /images/<cropzonekey> route будет обслуживать только страницу, а в 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>

Python 3

У меня было много проблем с такими ошибками, как - Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!

Для всех, кто хочет использовать matplotlib с колбой и отображать график на html-странице в python 3, вот и все -

в __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>

Для 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 %}

Надеюсь, что это помогает кому-то....

Я работаю с Python 3.x, я изменил некоторые строки кода, и это сработало для меня. У меня было следующее сообщение об ошибке: "..... объект не имеет атрибута" 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')
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-страницу.

У меня это работает очень хорошо, вы также можете проверить этот URLблог среднего

      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)
    
Другие вопросы по тегам