zu viele Punkte in plot

Plattformunabhängige GUIs mit wxWidgets.
Antworten
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Hallo Leute,

ich hoffe von Euch kann mir Jemand einen guten Tipp geben. Also ich plotte mit meinem Programm Daten, dazu nutze ich matplotlib. Das ploten funktioniert auch wie erwünscht nur hat matplotlib Probleme mit c.a. 50 Millionen Punkten. :-) Mein Arbeitsspeicher wird so gut wie gar nicht genutzt. Ich habe 2 GByte Ram und ein Dual Core 2GHz Prozessor.

Hier noch der Code mit dem ich plotte,

Code: Alles auswählen

    def drawtransientall(self,min):
        self.subplot = self.figure.add_subplot(111)
        self.subplot.grid(True)   
        list_t1,list_peaks,t2,list_samples = self.computetransientall(min,min+self.maxitems)
        offset = 0
        color = ['green','red','blue','magenta','cyan']
        markerPeaks = ['v','<','1','3','s']
        markerSamples = ['^','>','2','4','p']
        self.plots=[[],[]]
        for i in range(len(self.showBands)):
            self.plots[0] += self.subplot.plot(list_t1[i],list_peaks[i],color=color[i],marker=markerPeaks[i],
                                            linestyle='None')
            self.plots[1] += self.subplot.plot(t2,list_samples[i]+offset,color=color[i],
                                                marker=markerSamples[i],linestyle='None')           
            offset +=1
        self.subplot.set_xlim(t2[0]-np.abs(t2[-1]-t2[0])/100,t2[-1]+np.abs(t2[-1]-t2[0])/100)
        ymax = np.amax(list_samples)
        ymin = np.amin(list_samples)
        self.subplot.set_ylim([ymin-np.abs(ymin)*0.1, ymax*1.2 + 2])
        self.subplot.set_ylabel("abs(Sample(t)) und  abs(Peak(t)+Offset)-->",fontsize = 12)
        self.subplot.set_xlabel("Zeit in Sek. -->",fontsize = 12)
Die Anzahl der zu plottenden Punkte wird über die Variable self.maxitems festgelegt. Wenn ich zu viele Punkte plotte, dann bleibt meine CPU nach dem abarbeiten der Befehle bei 100% CPU-Last.

Hat Jemand eine Idee wie ich das umgehen kann ?

Grüße Markus
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Bei 50 Mio. Punkten würde ich den ein oder anderen vorher rausfiltern. Ein Bildschirm wird selten über 2 Mio. Pixel kommen, es ist also nicht genügend Platz für alle Punkte vorhanden. Außer du machst ein Plakat :lol:

Kaum genutzter Arbeitsspeicher ist auch gut: wenn man pro Punkt 8 Byte rechnet, dann sind es fast schon 400 MB. Dazu kommt natürlich noch der übliche Python-Overhead. Unter einem GB wird das insgesamt sicher nicht.

- min und max sind übrigens ganz schlechte Namen
- wenn du Indizes brauchst, dann benutze die enumerate-Funktion und ggfs. zip (oder hier besser das zip aus functools)
- und ein Blick in PEP 8 sei empfohlen
- das wurde dir alles sicher schon öfter gesagt, du solltest es nur mal anwenden ;-)
Das Leben ist wie ein Tennisball.
feldmaus
User
Beiträge: 284
Registriert: Donnerstag 12. Oktober 2006, 16:48

Vielen Dank für die Antwort EyDu. Das mit der begrenzten Anzahl Bildpunkte ist auf jeden Fall eine gute Idee. Gibt es da für Python so eine Art fertige Decimation Funktion ? Am besten mit einstellbarer Bedingung ?

Das mit min und max werde ich sofort ändern. Hatte nicht dran gedacht, dass es mit der Python Funktion verwechselt werden könnte.

Grüße Markus
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

no offense, aber: Merkst Du Dir gelegentlich auch mal was Dir vorher so alles geraten wurde?

Zum eigentlichen Problem:

Code: Alles auswählen

plot(myarray[::100])
würde z. B. jeden 100. Punkt plotten. D. h. entweder filterest Du vorher die Zahl der Punkte oder Du sagst Dir "eigentlich brauche ich für die Genauigkeit alle Punkte - nur für die Darstellung nicht" - dann kannst Du obiges Konstrukt anwenden.

Im Übrigen:
- Das Plotten von Linien kann weniger CPU-Power kosten als das Plotten vieler Marker. Kann - muß nicht per se - aber bei derart vielen Punkten siehst Du sowieso keine Marker sondern Markerbrei.
- Dinge wie 'fontsize' würde ich auch nicht jedes Mal lokal neu einstellen, wenn es überall die selbe Größe sein soll. Stattdessen einmal global für das ganze Programm:

Code: Alles auswählen

from matplotlib import rc
rc('font', size=12)
Und dann, falls Abweichungen vorgesehen sind, diese händisch setzen.
- 'offset' ist völlig überflüssig, jetzt schon und erst recht, wenn enumerate ins Spiel kommt.

EyDu habe ich sonst wenig hinzuzufügen.

HTH
Christian
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

off-topic: Ach, und natürlich gibt es keine voreingestellte decimation-Funktion - woher soll die Sprache denn wissen, was Dein Problem ist?

Wenn Du Dich also entschließt mit weniger Speicher schneller zu rechnen (vorher überlegen wie groß der Genauigkeitsverlust sein darf (!)), dann kannst Du überlegen welche Daten Du wie am besten wegschmeisst. Eine Möglichkeit ist die oben erwähnte: Einfach nur jeden x-sten Datenpunkt nehmen. Ob das intelligent ist, hängt von der Natur Deiner Daten ab. Im scipy-Cookbook findest Du einen Eintrag über rebinning.

HTH
Christian
Antworten