web-dev-qa-db-fra.com

Passer une figure matplotlib au HTML (flacon)

J'utilise matplotlib pour rendre une figure dans une application web. J'ai déjà utilisé fig.savefig() avant d'exécuter des scripts. Cependant, j'ai besoin d'une fonction pour retourner une image ".png" réelle afin de pouvoir l'appeler avec mon HTML.

Quelques informations supplémentaires (éventuellement inutiles): j'utilise Python Flask. Je pense que je pourrais utiliser fig.savefig() et simplement coller la figure dans mon dossier statique, puis l'appeler depuis mon HTML, mais je préfère ne pas le faire à chaque fois. Ce serait optimal si je pouvais simplement créer la figure, en faire une image, retourner cette image et l'appeler à partir de mon HTML, puis elle disparaît.

Le code qui crée la figure fonctionne. Cependant, cela renvoie un chiffre, ce qui ne fonctionne pas avec HTML, je suppose.

Voici où j'appelle le draw_polygon dans le routage, draw_polygon est la méthode qui renvoie la figure:

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

Et voici le HTML où j'essaye de générer l'image.

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

Et, comme vous pouvez probablement le deviner, lorsque je charge la page, tout ce que je reçois est Image Placeholder. Donc, ils n'ont pas aimé le format avec lequel j'ai alimenté la figure.

Quelqu'un sait quelles méthodes/solutions de contournement matplotlib transforment une figure en une image réelle? Je suis partout dans ces documents mais je ne trouve rien. Merci!

BTW: ne pensait pas qu'il était nécessaire d'inclure le code python qui fait la figure, mais je peux l'inclure si vous avez besoin de le voir (je ne voulais pas encombrer la question) )

25
Alex Chumbley

Vous devez séparer le HTML et l'image en deux itinéraires différents.

Votre itinéraire /images/<cropzonekey> Servira simplement la page, et dans le contenu HTML de cette page, il y aura une référence à la deuxième route, celle qui sert l'image.

L'image est servie dans sa propre route à partir d'un fichier mémoire que vous générez avec savefig().

Je n'ai évidemment pas testé cela, mais je pense que l'exemple suivant fonctionnera tel quel ou vous rapprochera d'une solution de travail:

@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')

Votre modèle images.html Devient:

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

Pour Python3 ....

J'ai un DataFrame, je veux montrer ce tracé en Flask ....

Créez donc une image Base64 de l'intrigue.

    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')

J'appelle maintenant mon modèle en utilisant les données encodées en base64 comme ceci ....

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

La partie pertinente du modèle (c'est-à-dire le bit d'image) ressemble à ceci ....

 {% if sunalt != None %}

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

J'espère que cela aide quelqu'un ...

5
Tim Seed
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')

Les autres réponses sont correctes, je voulais juste montrer les fichiers d'en-tête qui doivent être inclus. Ce programme crée un graphique simple et l'envoie à la page html.

1

Je travaille avec Python 3.x, j'ai changé certaines lignes du code et cela a fonctionné pour moi. J'ai eu le message d'erreur suivant: "..... object n'a pas d'attribut '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')
1
Rodolfo Alvarez