www.errorediridondanzaciclicodotcom

  • HOME
  • Matplot
  • BACK P.P.

  • VISUALIZZARE GRAFICI

    Come sempre, appassionato di grafici ed analisi quantitative, ho messo in piedi un sistema di visualizzazione in tempo reale dei dati storici per mezzo di Matplot.

    Matplot è un ottimo sistema per disegnare grafici, open-source e relativamente facile da usare.
    L'unica difficoltà è la gestione delle date nelle serie, più che altro per questioni legate alla formattazione.
    Mi sono creato i seguenti grafici, che aprono una nuova schermata python mediante pressione di bottoni sullo schermo touch:

    - Temperature del boiler e della sonda esterna negli ultimi 14 giorni.
    - Temperature del boiler e della sonda esterna negli ultimi 7 giorni.
    - Minima, massima esterna negli ultimi 60 giorni.
    - Minima del boiler negli ultimi 60 giorni.
    - Temperatura esterna delle ore 5:00 AM negli ultimi 30 giorni.
    - Temperatura esterna delle ore 14:00 PM negli ultimi 30 giorni.





    Andamento dei consumi di gas rispetto ad un budget.








    Confronto tra temperatura esterna e consumi di gas per il riscaldamento.







    Il primo gruppo mostra quattro grafici ed alcuni dati:


    I primi due mostrano l'andamento orario di due temperature, il boiler (la cabina della caldaia) e la temperatura esterna, rispettivamente nell'arco degli ultimi 14 giorni e 7 giorni.
    Sotto l'ingrandimento di quello dei 14 giorni.


    Qui sotto invece l'ingrandimento del grafico che estrae i dati degli ultimi 30 giorni alle ore 14:00 (considerandola come ora tra le più calde del giorno).


    A destra ci sono poi tre dati statistici che riportano la massima e la minima esterne e la minima del boiler, negli ultimi 60 giorni (in questo caso sono in realtà meno di trenta perchè appena iniziato).

    Di seguito, il grafico che confronta Budget versus Real.


    Il grafico a "donut" a sx mostra un anello interno, viola, che è basato sui dati di budget. Questi dati vengono immessi ad ogni inizio di "anno termico" mediante uno script in python e registrati su un file txt. Per mia scelta sono i dati arrotondati dell'anno precedente.
    L'anello esterno invece si costruisce giorno dopo giorno ricevendo i dati dei consumi reali, sempre dal primo novembre dell'anno di partenza. Ogni mese si chiude con i dati di consumo effettivi e nel mese corrente si vedono i dati di consumo effettivi cumulati (in rosso) e la differenza (in verde) tra il budget totale dal 1/11 ad oggi ed i consumi dal 1/11 ad oggi.
    La parte verde è quanto è disponibile per i consumi prima che vengano a pareggiarsi con i dati previsti di budget.

    Nel grafico a destra sono i dati simili (budget=verde, consumi reali=rosso) ma con la differenza relativa al singolo mese. Dal grafico si vede che novembre ha lasciato un avanzo sul budget di poco più di 20 m3 e dicembre, non ancora concluso, di circa una 70ina di m3.

    Questi due grafici sono utili per verificare l'andamento dei consumi di mese in mese rispetto a quanto previsto (o quanto effettuato l'anno precedente).
    Nel mio caso, la differenza così elevata dovrebbe (spero) essere dovuta al cambio di caldaia da una camera aperta (Junkers del 1997) non modulante con una a condensazione, modulante ed alta efficienza (Bosch 7000i).

    Nel terzo grafico metto a confronto la temperatura esterna con i consumi del gas.

    L'immagine sotto non mostra una significativa analisi in quanto la serie storica è limitata. Inoltre è ancora da vedere che tipo di conclusioni è possibile trarre.
    Tuttavia fino a quando non vedo i dati non posso analizzarli e poichè si tratta di una mera estrapolazione di informazioni già presenti, mi costa poco mettere in piedi un reporting come questo.


    Nel caso, come il mio, di utilizzo di valvole termostatiche intelligenti non si dovrebbero evidenziare stranezze. Questo sarebbe invece utilissimo a chi ha un termostato centrale che "maneggia" continuamente. Infatti un andamento dei consumi non inversamente correlato alle temperature in maniere lineare e costante potrebbe evidenziare smanettamenti non giustificati ed errati.
    Per adesso il dato della temperatura è una media delle 24h ma forse potrei prendere come dati di riferimento solo le ore diurne o una particolare fascia.

    Per ultimo mostro il grafico che viene visualizzato nella schermata principale, insieme all'ora ed alle temperature.

    Si tratta di una "ciambella doppia" ottenuta con matplot.
    Sono due anelli, uno più interno per le ore dalla mezzanotte alle 12, ed uno esterno per le ore dalla 12 alla mezzanotte.
    Ogni 15 minuti lo script in python lancia il disegno (plotting) del grafico. Poichè ogni ora i dati di consumo vengono incrementati delle letture fatte in questo periodo, ogni ora circa si aggiunge un settore all'anello.
    Ogni settore viene colorato in base ai quantitativi di gas consumati e rilevati dalla lettura dei dati. Se non c'è stato un consmo di gas (o se è inferiore ad una soglia veramente minima) il settore rimane nero.
    In caso di consumi tra la soglia minima ed una soglia di riferimento (consumi legati all'acqua sanitaria per brevi durate o temporanei riscaldamenti con modulazione) il settore si colora di giallo.
    Oltre una certa soglia i consumi, palesemente importanti, mostrano un settore rosso.
    Ogni settore riporta poi l'ora relativa (es. settore delle 13 equivale al periodo dalle 13 alle 14)
    Come già spiegato, ad ogni mezzanotte il contatore giornaliero si azzera e, poichè questo grafico pesca i dati da questo indirizzo di memoria, ogni giorno il grafico ripartirà dalla mezzanotte.
    Questo è il grafico attualmente funzionante, a breve implementerò invece un sistema per la lettura del funzionamento della caldaia per riscaldamento, differente da quello per l'acqua sanitaria.
    Così, nero equivarrà a nessun funzionamento, giallo solo la sanitaria, rosso riscaldamento.

    Questo è il codice:
    dbname = '/home/pi/My.db'

    def get_data():
    conn=sqlite3.connect(dbname)
    cur=conn.cursor()
    cur.execute("SELECT counter_daily FROM Gas_counter WHERE date(timestamp)=date('now','localtime')")
    rows=cur.fetchall()
    conn.close()
    return rows
    chart_table=[]
    def create_table(rows):
    for row in rows:
    chart_table.append(float(row[0]))
    return chart_table
    lista=[]
    def get_increment():
    a=chart_table
    lista[:]=[round(x-y,3) for x, y in zip(a[1:],a)]
    return lista
    win=tk.Tk()
    win.withdraw()
    screen_x = win.winfo_screenwidth()
    screen_y = win.winfo_screenheight()
    y=int(screen_y/10)
    x=int(screen_x/10)

    while True:

    rows=get_data()
    chart_table=[]
    create_table(rows)
    lista=[]
    get_increment()
    plt.style.use('dark_background')
    plt.rcParams['toolbar'] = 'None'
    plt.rcParams['font.size']=8.0
    fig, ax = plt.subplots()
    fig.canvas.manager.window.overrideredirect(1)
    a=int(x*2.2)
    b=int(y*4.2)
    width=int(screen_x*0.64)
    height=int((y*5.2)-(b/2))
    screen_dim=str(str(a)+"x"+str(a)+"+"+str(width)+"+"+str(height))
    plt.get_current_fig_manager().window.wm_geometry(screen_dim)
    size = 0.3

    list=lista
    w=len(list)
    hot_water = 0.01
    heating = 0.20

    if w>12:
    AM=list[:12]
    PM=list[12:]
    inner_colors=['black' if x inner_values=[0.0834 for x in AM]
    lenghtAM=len(AM)
    lista_AM =[]
    for i in range(0, lenghtAM):
    lista_AM.append(i)

    inner_labels=lista_AM
    lenghtPM=len(PM)+12
    lista_PM =[]
    for i in range(12, lenghtPM):
    lista_PM.append(i)

    outer_labels=lista_PM
    outer_colors=['black' if x outer_values=[0.0834 for x in PM]

    else:
    AM=list[:]
    PM=list[12:]

    inner_colors=['black' if x inner_values=[0.0834 for x in AM]
    lenghtAM=len(AM)
    lista_AM =[]
    for i in range(0, lenghtAM):
    lista_AM.append(i)

    inner_labels=lista_AM
    outer_labels=[]
    outer_colors=[]
    outer_values=[]

    cmap = plt.get_cmap("CMRmap")
    time.sleep(0.01)
    ax.pie(outer_values, labels=outer_labels, labeldistance=0.83, radius=1, colors=outer_colors, startangle=90, counterclock=False, textprops = dict(rotation_mode='default', va='center', ha='center'), wedgeprops=dict(width=size))

    ax.pie(inner_values, labels=inner_labels, labeldistance=0.76, radius=1-size, colors=inner_colors, startangle=90, counterclock=False, wedgeprops=dict(width=size), textprops = dict(rotation_mode='default', va='center', ha='center'))

    ax.set(aspect="equal", title='BOILER WORK')

    plt.show(block=False)
    time.sleep(900)
    plt.close('all')