Finde den Fehler?! Graphen spinnen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Robbse1990
User
Beiträge: 16
Registriert: Montag 16. Oktober 2017, 10:29

Hallo Zusammen,

Ich arbeite mit jupyter notebook, ipython, matplotlib

folgendes Vorgehen:

Datei auslesen, Daten verarbeiten, Graph erstellen, Graph abspeichern als pdf

Dabei tritt folgendes Problem auf:

Wenn ich mir den Graphen mit plt.show anzeigen lasse, kann ich im Code beliebig viel ändern, und der Graph passt sich an. Nach einer undefinierbaren Anzahl von Änderungen, fängt der Graph an zu "spinnen". Plotten alle Daten auf 3 X-werte, oder er nimmt random daten dazu usw. Kein Plan warum das passiert und warum so random. Ein Neustart des PC's löst das Problem.
Wenn ich nun die Datei noch zusätzlich abspeicher, passt der erste graph, der 2. nach einer Änderung im Code schon überhaupt nicht mehr. Auch wenn ich die pdf Datei vor dem erneuten speichern lösche, kommt es zum selben Problem.

Jetzt zu meiner Frage:

Hat jemand eine Ahnung wo das Problem liegen könnte, anscheinend kommt mein PC/Programm ja mit dem Speicher durcheinander. Hat jemand Ähnliche Erfahrungen mit so was? Hat matplotlib Probleme beim wiederholen vom Erstellen von Graphen, oder eher jupyter oder ist es ungeeignet das ganze als pdf abzuspeichern? Oder, könnte es am Code liegen? Gerne posten ich den, falls jemand das sehen will.

Danke für jeden Tip im Voraus!

Gruß Robin
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Robbse1990: was passiert denn, wenn Du ohne Jupyter arbeitest? Was Du da genau machst, verstehe ich nicht, vielleicht hilft ja der Code beim Verstehen.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Moin,

ich hab’ dieses Verhalten noch nicht gesehen (aber ich benutze quasi immer das `inline`-Backend im Jupyter Notebook). Zur Fehlersuche (und insbesondere, wenn du Code zeigst): Versuche, ein Minimalbeispiel zu finden, das den Fehler zeigt. Also sukzessive Teile des Codes entfernen und gucken, ob der Fehler immer noch auftritt. Dabei findet man den Fehler sehr oft selbst, und wenn nicht, dann ist es für andere viel leichter zu helfen.
Ein Neustart des PC's löst das Problem.
Was passiert, wenn du den Kernel des Notebooks neustartest?

Tritt der Fehler auch mit einem anderen `matplotlib`-Backend auf?
Robbse1990
User
Beiträge: 16
Registriert: Montag 16. Oktober 2017, 10:29

Ich hab den Code nun auf einem anderen PC und ohne ipyhton getestet, selbes Problem. Aber ich weiß jetzt wo das eine Problem liegt:

def funk_1(a,b,c):
return a+b+c
def funk_2(a,b,c):
return 2*a+3*b+c

funk1_(1,2,3)
funk_2(1,2,3)

----> Bullshit

Wenn ich die Funktionen nicht beide aufrufe, passt es. Muss ich hier mit globalen Variablen arbeiten oder was anderem? ICh hätte gerne in einem Programm zwei, oder mehr Funktionen, die Verschiedenes mit den gleichen Parametern machen, aber sich nicht gegenseitig beeinflussen, was mach ich da?

Konkret geht es darum:
Ich habe eine Liste, in jeder Zeile steht Datum, Temperatur, Luftfeuchtigkeit, je mit tab getrennt. Jede halbe Stunde kommt eine Zeile dazu
Nun möchte ich diese Daten plotten. Einmal die letzten 30 tage mit je dem Tagesdurchschnitt von T und H, und, falls die Werte Grenzen überschreiten, ein Graph mit den letzten 300 (oder sonst eine Zahl) Einträgen. Die beiden graphen einzeln bekomme ich hin, nur hätte ich das gerne ungefähr so in einem Programm:

def funk_30_tage(datei_pfad,wie_viele_daten):

def funk_letzten_x_eintraege(datei_pfad):

Wie mach ich das, das sich die variablen und Listen nicht in die Quere kommen?


Das andere Problem, mit den random Fehlern, kann auch mit Neustart von Jupyter gelöst werden, wahrscheinlich liegt es daran.
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@Robbse1990: so wie Du Deine Funktionen hier zeigst, könne sie sich nicht in die Quere kommen. Du mußt den wirklichen Code posten, damit man sehen kann, was Du falsch machst.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Eventuell ist auch `pandas` einen Blick wert.
Robbse1990
User
Beiträge: 16
Registriert: Montag 16. Oktober 2017, 10:29

hier mal der code. das ganze soll auf dem raspi laufen. wenn ein monat rum ist, soll ich ein mail bekommen mit dem monatsreport. und falls die Werte die Grenzen überschreiten, soll ich eine "alarm"Mail bekommen mit dem zugehörigen Graph. Damit will ich meinen Keller vor Feuchtigkeit schützen.

Code: Alles auswählen

##############################################
###plot fuer monatsreprot und Alarm Graphen###
##############################################

import matplotlib.pyplot as plt
from copy import deepcopy



def graph_schnitt(grenzwert, laenge_uebergabe_liste, datei_pfad):  
    
    #############################################################################################################
    #Datei einlesen und fuer jeden tag den durschnitt berechnen

    temp_list = []
    temp_list_berech = []
    hum_list  = []
    hum_list_berech = []
    date_list = []

    with open(datei_pfad, 'rb') as fh: #ersten tag definieren
        for line in fh:   
            tag = line[0:3]
            date_list.append(line[0:14])
            break
    with open(datei_pfad, 'rb') as fh: #tag einlesen und in liste schreiben um spaeter durchschnitt zu berechnen 
        for line in fh:
            if line[0:3] == tag:
                temp_list_berech.append(float(line[24:28]))   
                hum_list_berech.append(float(line[29:34]))  
            else: 
                tag = line[0:3]  
                temp_list.append(sum(temp_list_berech)/len(temp_list_berech))
                temp_list_berech = []
                temp_list_berech.append(float(line[24:28]))
                hum_list.append(sum(hum_list_berech)/len(hum_list_berech))
                hum_list_berech = []
                hum_list_berech.append(float(line[29:34]))
                date_list.append(line[0:14])
    temp_list.append(sum(temp_list_berech)/len(temp_list_berech))
    hum_list.append(sum(hum_list_berech)/len(hum_list_berech))             
    
    
    ############################################################################################################
    #Sichergehen, damit lange der liste ausreicht
    
    if len(temp_list) < laenge_uebergabe_liste:
        laenge_uebergabe_liste = len(temp_list)
    

    ############################################################################################################
    #Welche Werte werden aus der liste genommen und listen sicher kopieren

    temp_list_plot = deepcopy(temp_list[-laenge_uebergabe_liste:])
    hum_list_plot = deepcopy(hum_list[-laenge_uebergabe_liste:])
    date_list_plot = [""]*len(date_list) #leere Liste die spaeter mit date gefuellt wird

    ############################################################################################################
    #bestimmen, wie viele werte auf x achse angezeigt werden

    if laenge_uebergabe_liste <= 10:
        date_list_plot = date_list 
    elif 10 < laenge_uebergabe_liste <= 20: 
        for i in range(1,len(date_list),2): #loeschen von jedem zweiten ,bzw. in leer machen
            date_list_plot[i] = date_list[i] 
    elif 20 < laenge_uebergabe_liste <= 50:   #und bei sehr vielen daten halt ueberall "0"
        for i in range(1,len(date_list),5):
            date_list_plot[i]=date_list[i]
    elif laenge_uebergabe_liste > 50:
        pass


    ############################################################################################################
    #Durschnitt bestimmen und max Werte 

    temp_durchschnitt = sum(temp_list_plot)/len(temp_list_plot)
    temp_durchschnitt_plot = [temp_durchschnitt]*laenge_uebergabe_liste

    hum_durchschnitt = sum(hum_list_plot)/len(hum_list_plot)
    hum_durchschnitt_plot = [hum_durchschnitt]*laenge_uebergabe_liste

    richtlinie_werte = [grenzwert]*laenge_uebergabe_liste #liste mit werten fuer die grenzlinie bei grenzwert

    ##############################################################################################################
    #der Plot selbst 

    range_list = range(1,laenge_uebergabe_liste+1)

    ax1 = plt.subplot()
    ax1.plot(range_list,temp_list_plot,'r')
    ax1.plot(range_list,temp_durchschnitt_plot,'r_')
    ax1.set_ylabel("Temperatur [$^\circ$C]",color='r')
    ax1.tick_params('y', direction='inout', color='r', labelcolor='r')
    ax1.set_ylim((min(temp_list_plot)-0.75),max(temp_list_plot)+0.75) #Lage der Fkten bestimmen


    ax1.text(1, temp_durchschnitt+temp_durchschnitt*0.001, '$T_D = {0:s}^\circ C$'.format(str(temp_durchschnitt)[:4]), color='r', fontsize=10)


    ax2 = ax1.twinx()
    ax2.set_ylabel("rel. Luftfeuchtigkeit [%]", color='b')
    ax2.tick_params('y', direction='inout', color='b', labelcolor='b')
    ax2.plot(range_list,hum_list_plot,'b')
    ax2.plot(range_list,hum_durchschnitt_plot,'b_')
    ax2.plot(range_list,richtlinie_werte, '-.',linewidth=1.0, color='dodgerblue')
    ax2.set_ylim(min(hum_list_plot)-1.5)
    ax2.text(1, hum_durchschnitt+0.1, '$H_D = {0:s}$%'.format(str(hum_durchschnitt)[:4]), color='b', fontsize=10)
    ax1.set_xticks(range_list)
    ax1.set_xticklabels(date_list_plot[-laenge_uebergabe_liste:], rotation='45', fontsize=9, ha='right')


    ##############################################################################################################
    #Title und Datei speichern


    plt.title("Messdaten vom " + date_list[-laenge_uebergabe_liste][0:20] + " bis " + date_list[-1][0:20])  
    save_name = 'Messdaten_vom_{0:s}.pdf'.format(date_list[-laenge_uebergabe_liste][4:20]) #das mag kein : im Namen 
    plt.savefig(save_name, bbox_inches='tight', format='pdf')
    #plt.show()


    ##############################################################################################################
    #funktion gibt save name aus 

    return save_name


###################################################################################################################
###################################################################################################################
###################################################################################################################
###################################################################################################################
###################################################################################################################
###################################################################################################################


def graph_alarm(grenzwert, datei_pfad):
    
    #############################################################################################################
    #Datei einlesen und letzten 7 Tage anzeigen, alle werte 

    laenge_uebergabe_liste =350  
      
    temp_list = []
    hum_list  = []
    date_list = []

    with open(datei_pfad, 'rb') as fh: #tag einlesen und in liste schreiben um spaeter durchschnitt zu berechnen 
        for line in fh:
            date_list.append(line[0:20])
            temp_list.append(float(line[24:28]))   
            hum_list.append(float(line[29:34])) 

    ############################################################################################################
    #Welche Werte werden aus der liste genommen und listen sicher kopieren

    temp_list_plot = deepcopy(temp_list[-laenge_uebergabe_liste:])
    hum_list_plot  = deepcopy(hum_list[-laenge_uebergabe_liste:])
    date_list_plot = [""]*len(date_list) 

    richtlinie_werte = [grenzwert]*laenge_uebergabe_liste #liste mit werten fuer die grenzlinie bei grenzwert

    ##############################################################################################################
    #der Plot selbst 

    range_list = range(1,laenge_uebergabe_liste+1)

    ax1 = plt.subplot()
    ax1.plot(range_list,temp_list_plot,'r')
    ax1.set_ylabel("Temperatur [$^\circ$C]",color='r')
    ax1.tick_params('y', direction='inout', color='r', labelcolor='r')
    ax1.set_ylim((min(temp_list_plot)-0.75),max(temp_list_plot)+0.75) #Lage der Fkten bestimmen


    ax2 = ax1.twinx()
    ax2.set_ylabel("rel. Luftfeuchtigkeit [%]", color='b')
    ax2.tick_params('y', direction='inout', color='b', labelcolor='b')
    ax2.plot(range_list,hum_list_plot,'b')
    ax2.plot(range_list,richtlinie_werte, '-.',linewidth=1.0, color='dodgerblue')
    ax2.set_ylim(min(hum_list_plot)-1.5)
    ax1.set_xticks(range_list)
    ax1.set_xticklabels(date_list_plot[-laenge_uebergabe_liste:], rotation='45', fontsize=9, ha='right')
    ax1.set_xlabel("Letzten {0:s} Messwerte (ca. 1 Woche), zwei pro Stunde".format(str(laenge_uebergabe_liste)))
    ax1.set_xticks([])

    plt.title("Messdaten vom " + date_list[-laenge_uebergabe_liste][0:20] + " bis " + date_list[-1][0:20])  
    save_name = 'Alarm_vom_{0:s}.pdf'.format(date_list[-1][4:14]) #das mag kein : im Namen 
    plt.savefig(save_name, bbox_inches='tight', format='pdf')
    #print save_name
    #plt.show()
 
    return save_name


    
    


Code: Alles auswählen

grenzwert = 65.0
laenge_uebergabe_liste =30    
datei_pfad = 'Messdaten.txt'

aaa = graph_schnitt(grenzwert, laenge_uebergabe_liste, datei_pfad)
print (aaa)
bbb = graph_alarm(grenzwert,datei_pfad)
print (bbb)



narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Das ist genau das, was ich mit einem Minimalbeispiel nicht meinte. :wink:

Nachdem du den Code gezeigt hast: Du möchtest definitiv `pandas` benutzen. Und den Code sinnvoll strukturieren, also auf Funktionen aufteilen, die jeweils eine Aufgabe haben. Also: Eine, die die Daten liest, eine pro Berechnung/Auswertung und eine für den Plot.

Zum Problem: Hast du mal versucht, `plt.close()` nach dem `plt.savefig` einzufügen?
Robbse1990
User
Beiträge: 16
Registriert: Montag 16. Oktober 2017, 10:29

ok, ich werde mir mal pandas anschauen. UND, plt.close() scheint das Problem gelöst zu haben - Danke!
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Zur Erklärung: `matplotlib.pyplot` hat ein globales `Figure`-Objekt, das mit den Funktionen aus `pyplot` manipuliert wird. Wenn man zwischen zwei separaten Graphen nicht `plt.close` aufruft, plottet man mit dem selben `Firgure`-Objekt, und das führt meist zu Mist.
Antworten