Matplotlib - markevery und gleichmäßig gestrichelte Linien

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
logo
User
Beiträge: 9
Registriert: Freitag 25. September 2015, 19:54

Hallo,

ich bin noch ziemlich neu in der Python-Welt und aktuell damit beschäftigt Messdaten mit matplotlib in Diagramme zu verwandeln. Ich habe sehr (sehr) viele Messdaten und diese sind leider nicht gleichmäßig über die x-Achse (konstantes dx) verteilt. Daraus resultieren zwei Probleme, für die ich keine Lösung finden konnte:

Problem #1:

Wenn ich eine gestrichelte Linie zur Darstellung wähle, sind die "kleinen Striche" nicht gleichmäßig sondern verteilen sich ähnlich wie die Messdaten. Das sieht ziemlich unprofessionell aus. Wie kann ich das umgehen?


Problem #2:

Damit man später mehrere Graphen auch im SW-Druck unterscheiden kann, wollte ich Marker einfügen (markevery=x). Da diese normalerweise auch nicht gleichmäßig über den Graph verteilt sind, habe ich in der Doku gefunden, dass man mit Werten < 1 eine annähernd gleichmäßige Verteilung erreichen kann. Leider werden dann bei mir gar keine Marker angezeigt. Leider tritt dies nur bei den Messwerten auf, wenn ich Testdaten verwende ich mit Numpy bastle, funktionieren die Marker. Was könnte denn da die Ursache sein?


Danke für eure Hilfe!

ps: Ich weiß, das sind bisher wenige Infos, da ich aber nicht weiß, was ihr wissen müsst fragt bitte :)
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

logo hat geschrieben:Wenn ich eine gestrichelte Linie zur Darstellung wähle, sind die "kleinen Striche" nicht gleichmäßig sondern verteilen sich ähnlich wie die Messdaten.
Die Erfahrung habe ich nicht gemacht. Im nachfolgenden Beispiel sind die x-Werte nicht äquidistant verteilt, die gestrichelte Linie sieht aber gleichmäßig aus.
logo hat geschrieben:Damit man später mehrere Graphen auch im SW-Druck unterscheiden kann, wollte ich Marker einfügen (markevery=x). Da diese normalerweise auch nicht gleichmäßig über den Graph verteilt sind, habe ich in der Doku gefunden, dass man mit Werten < 1 eine annähernd gleichmäßige Verteilung erreichen kann. Leider werden dann bei mir gar keine Marker angezeigt. Leider tritt dies nur bei den Messwerten auf, wenn ich Testdaten verwende ich mit Numpy bastle, funktionieren die Marker. Was könnte denn da die Ursache sein?
Im nachfolgenden Beispiel verwende ich markevery=0.1 (grüne Kreuze). Dabei werden nicht einfach grüne Kreuze gleichmäßig auf die Kurve verteilt, sondern es werden von den vorhandenen Datenpunkten (blaue Kreise) möglichst äquidistant welche ausgewählt, so gut das eben geht. Es werden aber keine neuen Datenpunkte eingefügt.

Code: Alles auswählen

import numpy as np
import matplotlib.pyplot as plt

x = np.logspace(0.001, 1, 50)
y = .95* np.sin(x)

plt.figure()
plt.plot(x,y,"--")
plt.savefig("dashed.jpg", bbox_inches="tight") 

plt.figure()
plt.plot(x,y,"o--")
plt.plot(x,y,"x", markevery=0.1, markersize=12, markeredgewidth=2)
plt.savefig("markevery.jpg", bbox_inches="tight") 
plt.show()
BildBild
a fool with a tool is still a fool, www.magben.de, YouTube
logo
User
Beiträge: 9
Registriert: Freitag 25. September 2015, 19:54

Hallo MagBen, danke für deine Hilfestellung!

Ich bin, durch deine Codebeispiele, ein Stück weiter gekommen:

Problem #1:

Ich muss mich korrigieren, das Problem scheint nicht von ungleichmäßig verteilten x-Werten zu stammen, sondern vom Rauschen, welches im Signal enthalten ist. Ich konnte mit folgenden Code das Verhalten reproduzieren. Nun scheint mir das Verhalten von Python auch irgendwo logisch, aber das Problem muss dennoch gelöst werden.

Code: Alles auswählen

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 1000)

y = np.sin(x)
noise = np.random.normal(0,0.01,1000)

signal = y+noise

plt.plot(x,signal,'--')
plt.show()
Problem #2:

Ich habe, mehr zufällig, herausgefunden, dass die fehlenden Marker (mit markevery=x und x<1) von einer leeren, überflüssigen Zeile (;;) in der importierten .csv-Datei stammen. Durch entfernen dieser Zeile, werden nun die Marker angezeigt. Leider sind sie dennoch nicht annähernd gleichmäßig über die Kurve verteilt. Ich vermute, dass die Ursache in der Art und Weise, wie die Daten aufgezeichnet wurden liegt: Ändert sich das Signal während der Messung schnell, wird eine höherer Samplerate verwendet, ändert sich das Signal nur langsam, werden demnach nur wenige Werte aufgezeichnet. Daher liegt der nächstmögliche, äquidistante Datenpunkt zu weit entfernt und daher sind die Marker auch nicht annähernd gleichmäßig verteilt. Gibt es eine Möglichkeit das Problem zu umschiffen?

Danke
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

Bei Deinem Beispiel sieht die gestrichelte Linie erstmal ungleichmäßig aus, wenn Du aber in den Plot reinzoomst dann sieht's OK aus. Würde Matplotlib die Kurve von Anfang an gleichmäßig gestrichelt anzeigen, dann müsste Matplotlib die Daten dafür glätten. Das soll Matplotlib aber nicht tun, denn das ist Teil der Datenanalyse. Nur geglättete Daten erzeugen eine glatte Kurve. Ich würde vorschlagen, dass Du die Daten Tiefpass filterst und dabei auch gleich zeitlich äqudistante Datenpunkte berechnest.

Fürs Filtern gibt es keine allgemeingültige Technik. Die geeignete Methode hängt von der Art des Signals ab:
  1. Ist es ein Puls der bei 0 anfängt und dann während der Messung auch wieder zu 0 abklingt? -> Fourier-Trafo und hohe Frequenzen dämpfen.
  2. Ist es ein periodisches Signal? -> Fourier-Reihe und hohe Frequenzen dämpfen.
  3. Ist es ein beliebiges verauschtes Signal? -> scipy.signal.firwin
a fool with a tool is still a fool, www.magben.de, YouTube
logo
User
Beiträge: 9
Registriert: Freitag 25. September 2015, 19:54

Ich werde das Filtern mal versuchen, danke für den Tipp.

Wie kann ich denn aus den Daten äquidistante Datenpunkte berechnen? Gibt es da eine fertige Funktion oder muss ich mir etwas basteln. Falls letzteres zutrifft, wäre ich für einen Hinweis über eine sinnvolle Vorgehensweise sehr dankbar :)
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

logo hat geschrieben:Wie kann ich denn aus den Daten äquidistante Datenpunkte berechnen? Gibt es da eine fertige Funktion oder muss ich mir etwas basteln.
numpy.interp
Das Interpolieren ist aber kein Ersatz für das Filtern und es sollte zuerst gefiltert werden und erst danach interpoliert werden.
a fool with a tool is still a fool, www.magben.de, YouTube
logo
User
Beiträge: 9
Registriert: Freitag 25. September 2015, 19:54

Bei meinen Recherchen bin ich über eine genau anders herum lautende Aussage gestolpert. Man solle erst interpolieren und dann filtern, da das Filtern von ungleichmäßig verteilten Daten sehr schwierig sei. Ich muss zugeben, dass ich noch nie wirklich mit Filtern gearbeitet habe :?
Benutzeravatar
MagBen
User
Beiträge: 799
Registriert: Freitag 6. Juni 2014, 05:56
Wohnort: Bremen
Kontaktdaten:

OK, FFT geht nur mit äquidistanten Daten. Ich habe in erster Linie an das Rauschen gedacht und weniger an die Ungleichmäßigkeit. Ich muss zugeben, dass ich bezüglich zeitlich ungleichmäßig verteilter Daten keine Erfahrungen habe. Bei mir sind die Daten immer schön zeitlich äquidistant, aber sehr wohl auch ein bisschen verrauscht.
a fool with a tool is still a fool, www.magben.de, YouTube
logo
User
Beiträge: 9
Registriert: Freitag 25. September 2015, 19:54

Ich glaube mit den Informationen komme ich nun weiter. Danke für deine Hilfe!

Sollte es dennoch Probleme geben, dann werde ich mich noch mal melden.
zarathustra
User
Beiträge: 59
Registriert: Samstag 17. April 2010, 23:02

Guten Abend,

wenn ich darf, würde ich mich an diesen Beitrag/ dieses Beispiel gerne anhängen.

Gibt es eine Möglichkeit mit "markevery" oder einem anderen Befehl einen einzelnen Datenpunkt, z.B. x[20] zu markieren? Ich weiß, dass man es mit einem zweiten Plotbefehl kann, indem man dann an der Stelle einen gefüllten Kringel oder ähnliches plottet. Das will ich gerade nicht, denn jeder plot stellt einen eigenen Funktionsgraphen dar.

Ich verschiebe mit der Maus aber meine Kurven auf der Diagrammfläche und da soll(en) sich die Markierung (oder die 3 bis 4 Markierungen) mitbewegen. Wenn der Marker ein separater "Graph" ist, dann bleibt er zurück.

Bei Matlab scheint das mit "MarkerIndices" zu funktionieren, bei Scilab habe ich es mal über Datatips gemacht, indem ich diesen entsprechende Marker zuwies.

Gibt es unter Matplotlib auch eine Möglicheit?

Viele Grüße

Zarathustra
zarathustra
User
Beiträge: 59
Registriert: Samstag 17. April 2010, 23:02

Guten Morgen,

ich greife nochmal meine Frage auf.

Das Markieren eines einzelnen Datenpunktes bzw. auch mehrerer habe ich mit "markevery" hinbekommen. Man übergibt ein Array mit den Positionen an markevery.

Jetzt möchte ich aber die Punkte unterschiedlich markieren. Ich bekomme es nicht hin an "marker" ein Array mit markerstyles zu übergeben. Also z.B. marker = [ "o", "D" ] -funktioniert nicht, auch nicht mit runden Klammern- für gefüllten Kringel bzw. Diamant.

Man kann es mittels weiterem Plotbefehl hinbekommen, aber wie oben schon erwähnt sollen die Marker zu der einen Kurve gehören, da sie verschoben werden kann und dann müssen die Marker mit.

Vielen Dank für Eure Hilfe

Zarathustra
Antworten