Software basato su Python > Web framework

Django e matplotlib plots

(1/1)

domi84:
Salve a tutti, avrei bisogno di un chiarimento.
Sto studiando come usare django, e per farlo provo a creare delle semplici webapp (studiando ovviamente la parte corrispondente).
L'obiettivo era creare una webapp che mostra dei plot (ho un piccolo script python che da una tabella (dato un nome scelto dall'utente) seleziona dei dati e crea un plot).

La documentazione non sembra tanta a riguardo, per esempio su matplotlib l'indice mi illude perchè è presente una voce matplotlib with django, ma dice:

--- Citazione ---Matplotlib with django
TODO;
--- Termina citazione ---
:confused:
(in "Matplotlib in a web application server" c'è questo che mi ha risolto un errore, ma nulla di più:
# do this before importing pylab or pyplot
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

--- Termina codice ---
)

Nella mia prima versione ho pensato la cosa più semplice fosse salvare il file prima di mostrarlo, quindi:

Template "inserisci nome" ->
Modulo Django: cancella se presente il vecchio plot.png, crea nuovo plot salvalo come plot.png ->
View e Template mostrano la pagina con il plot.


#forms.py
from django import forms

class ListForm(forms.Form):
    your_name = forms.CharField(label='Insert gene name', widget=forms.Textarea)
--- Termina codice ---


#models.py
import pandas as pd
import matplotlib
matplotlib.use('Agg')
import seaborn as sns  # sì, lo so, non uso matplotlib ma seaborn :)
import matplotlib.pyplot as plt
import numpy as np
import re
import io
import os

def lineplot(name):   
    try:
        os.remove("pages/static/pages/plot.png")
    except FileNotFoundError:
        pass
    df=pd.read_csv("pages/static/pages/BMDM/BMDM.csv",sep=",",index_col=0)
    sample=processing(df,name)  # Questa funzione seleziona i dati e ritorna un df.

    if sample is None:
        return "Not found"

    f, ax = plt.subplots(figsize=(15, 6))
    sns.despine(ax=ax)
    ax = sns.pointplot(x=sample["Time"], y=sample["value"], data=sample, hue=sample["gene"], estimator=np.median) 
 
    return f
--- Termina codice ---


#views.py
from django.shortcuts import render
from .forms import ListForm
from .models import lineplot

def insert_gene_name(request):
    listform_in_view = ListForm()
    return render(request, 'insert_name_plot.html', {'form_in_html': listform_in_view})

def plotView(request):
    data = ListForm(request.POST)
    if data.is_valid():
        text = data.cleaned_data['your_name']
        if "\r\n" in text:
            text=text.split("\r\n")

    f=lineplot(text)
    try:
        f.savefig("pages/static/pages/plot.png")
        return render(request, 'plot.html')
    except AttributeError:
        return render(request, 'plot.html', {"text":"Gene not found"})
--- Termina codice ---


#urls.py
from django.urls import path
from .views import insert_gene_name, plotView

urlpatterns = [
    path('insert_name_plot/', insert_gene_name, name='Insert Name'),
    path('plot/', plotView, name='Plot'),
]
--- Termina codice ---


#Template - insert_name_plot.html
{% extends "base.html" %}

{% block content %}
    <form action="/plot/" method="post">
        {% csrf_token %}
        {{ form_in_html }}
        <input type="submit" value="Submit">
    </form>
{% endblock %}
--- Termina codice ---


#Template - plot.html

{% extends "base.html" %}

{% block content %}
    <h2>{{text}}</h2>
    {% load static %}
    <img src="{% static "pages/plot.png" %}" alt="image">
{% endblock %}
--- Termina codice ---


(spero di aver inserito i codici in un ordine comprensibile)
La cosa sembra funzionare, mi starebbe pure bene.
Però mi sono chiesto: questo continuo creare/cancellare file è efficiente? Direi di no...non ho nessuna esigenza di salvare il file, mi basterebbe tenerlo in memoria e mostrarlo (Prima domanda: mi sbaglio???)

Mi pare di capire che per farlo devo caricarlo nel buffer (seconda domanda, è il modo migliore per farlo?). Funziona con HttpResponse:

#models.py
    #[...]
    ax = sns.pointplot(x=sample["Time"], y=sample["value"], data=sample, hue=sample["gene"], estimator=np.median)

    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    plt.close(f)
    data=buf.getvalue()
   
    return data
--- Termina codice ---



#views.py
def plotView(request):
    data = ListForm(request.POST)
    if data.is_valid():
        text = data.cleaned_data['your_name']
        if "\r\n" in text:
            text=text.split("\r\n")

    data=lineplot(text)
    return HttpResponse(data, content_type='image/png')
--- Termina codice ---


Se cerco di fare il render con la pagina però non ci riesco
 
#views.py
#[...]
    data=lineplot(text)
#    return HttpResponse(data, content_type='image/png')
    return render(request, 'plot.html', {"img":data})
--- Termina codice ---


#Template - plot.html
{% extends "base.html" %}

{% block content %}
    <h2>{{text}}</h2>
    <img src="{{img}}" alt="image">
{% endblock %}
--- Termina codice ---


Mi apre la pagina plot.html, ma l'immagine non c'è (nel template ho provato sia "{{img}}" che {{img}})
terza domanda: Il punto è che non riesco a capire se ho scritto male il view.py o il template plot.html. E non riesco a trovare niente nella documentazione o forums.
:confused:

Scusate il post lungo...

domi84:
Un gruppo di smanettoni dell'Univ mi ha trovato la soluzione. La posto, spero possa servire a qualcun altro...

#models.py
def lineplot(text):
    #[...]
    #Save in the Buffer
    buf = io.BytesIO()
    plt.savefig(buf, format='png')
    plt.close(f)
    data = buf.getvalue()
    data2 = base64.encodestring(data).decode('ascii')  # New
    return data2
--- Termina codice ---




#views.py
#[...]
    data=lineplot(text)
#    return HttpResponse(data, content_type='image/png')
    return render(request, 'plot.html', {"img":data})

--- Termina codice ---



#Template - plot.html
{% block content %}
    <img src="data:image/jpeg;base64, {{img|safe}}" alt="image">  # New
{% endblock %}

--- Termina codice ---

Navigazione

[0] Indice dei post

Vai alla versione completa