Relative Zeit: konvertieren, berechnen und anzeigen

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

Hallo,

wie ist es möglich Daten in ein relatives Zeitformat zu konvertieren und die verstrichene Zeit (seit erstem Zeitpunkt) in dem Format [hh]:mm:ss zu plotten. Mit [hh] ist ein fortlaufendes Stundenformat gemeint, also auch grösser 24. Importiert wird aus einem xls file.
Der Variable Explorer zeigt x als Typ "Array of object" an. Der Inhalt sieht so aus:
2022-07-11 18:42:47
2022-07-11 18:42:53
2022-07-11 18:43:03
.
.
.

Code: Alles auswählen

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import os
import os.path

 
data_path   = "..."
export_path = "..."
data_file = "....xlsx"

mydata = pd.read_excel(data_path + data_file, skiprows=2)

x = mydata.iloc[17:30,0].values   # timestamp
y1 = mydata.iloc[17:30,1].values  # dataset 1
y3 = mydata.iloc[17:30,4].values  # dataset 2

# x = x - x[0] # calc ralative time

fig   = plt.figure(constrained_layout=True)
gs    = GridSpec(2, 2, figure=fig)
ax    = fig.add_subplot(gs[0, :])
twin1 = ax.twinx()

p1, = ax.plot(x, y1)
p2, = twin1.plot(x, y3)

plt.show()
Bei Verwendung von x = x - x[0] ergibt es einen Fehler "TypeError: float() argument must be a string or a number, not 'datetime.timedelta'.
Viele Versuche es zu konvertieren scheiterten. Wer weiss wie das funktioniert?
Danke
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bussard: Da scheint doch schon was geklappt zu haben, denn Du hast da ja offenbar `timedelta`-Objekte. Die Frage ist wo die Ausnahme denn auftritt.

`os.path` muss man nicht importieren, das `os`-Modul importiert das für das System passende Modul schon selbst und bindet das an den Namen `path`. Und Du solltest das dann auch verwenden, statt Pfadteile per ``+`` zusammenzusetzen. Wobei man in neuem Code aber besser auf das `pathlib`-Modul setzen sollte.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

@__blackjack__
Die Ausnahme tritt beim plotten auf bei ax.plot(x, y1).

Code: Alles auswählen

runfile('yyy.py', wdir='C:/Users/xxx')
Traceback (most recent call last):

  File "C:\Users\xxx\yyy.py", line 27, in <module>
    p1, = ax.plot(x, y1)

  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\axes\_axes.py", line 1607, in plot
    self.add_line(line)
  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 2101, in add_line
    self._update_line_limits(line)
  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 2123, in _update_line_limits
    path = line.get_path()
  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\lines.py", line 1022, in get_path
    self.recache()
  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\lines.py", line 663, in recache
    x = _to_unmasked_float_array(xconv).ravel()
  File "C:\Users\...\Anaconda3\lib\site-packages\matplotlib\cbook\__init__.py", line 1333, in _to_unmasked_float_array
    return np.asarray(x, float)
  File "C:\Users\...\Anaconda3\lib\site-packages\numpy\core\_asarray.py", line 102, in asarray
    return array(a, dtype, copy=False, order=order)

TypeError: float() argument must be a string or a number, not 'datetime.timedelta'

Warning
Figures now render in the Plots pane by default. To make them also appear inline in the Console, uncheck "Mute Inline Plotting" under the Plots pane options menu.
Vielen Dank auch noch für deine weiteren Ratschläge!
`os.path` muss man nicht importieren, das `os`-Modul importiert das für das System passende Modul schon selbst
Ja stimmt, das ist logisch ist mir gar nicht aufgefallen :-)
und bindet das an den Namen `path`. Und Du solltest das dann auch verwenden, statt Pfadteile per ``+`` zusammenzusetzen.
Ok, und wie würde man dann das nutzen im code?

Das mit pathlib kenne ich noch nicht. Werde ich mich mal ansehen.
Benutzeravatar
Dennis89
User
Beiträge: 1156
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,
Bussard hat geschrieben: Mittwoch 7. September 2022, 05:47 Ok, und wie würde man dann das nutzen im code?
Das mit pathlib kenne ich noch nicht. Werde ich mich mal ansehen.
Beides zusammengefasst:

Code: Alles auswählen

from pathlib import Path

DATA_PATH = Path('...')
DATA_FILE = '...'


def main():
    print(DATA_PATH / DATA_FILE)


if __name__ == '__main__':
    main()
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bussard: Da scheint es noch nichts fertiges zu geben, also müsstest Du die `timedelta`-Werte zum Beispiel in Sekunden umwandeln und dir einen Tickformatter schreiben. Also beispielsweise einen `FuncFormatter` verwenden. Also im einfachsten Fall einfach eine Funktion als „tick formatter“ übergeben, die Sekunden in das von Dir gewünschte Anzeigeformat umwandelt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

Dennis89 hat geschrieben: Mittwoch 7. September 2022, 06:05 Hallo,
Bussard hat geschrieben: Mittwoch 7. September 2022, 05:47 Ok, und wie würde man dann das nutzen im code?
Das mit pathlib kenne ich noch nicht. Werde ich mich mal ansehen.
Beides zusammengefasst:

Code: Alles auswählen

from pathlib import Path

DATA_PATH = Path('...')
DATA_FILE = '...'


def main():
    print(DATA_PATH / DATA_FILE)


if __name__ == '__main__':
    main()
Grüße
Dennis
Besten Dank für dein Beispiel.
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

__blackjack__ hat geschrieben: Mittwoch 7. September 2022, 08:11 @Bussard: Da scheint es noch nichts fertiges zu geben, also müsstest Du die `timedelta`-Werte zum Beispiel in Sekunden umwandeln und dir einen Tickformatter schreiben. Also beispielsweise einen `FuncFormatter` verwenden. Also im einfachsten Fall einfach eine Funktion als „tick formatter“ übergeben, die Sekunden in das von Dir gewünschte Anzeigeformat umwandelt.
Das wundert mich ein wenig. Aufgezeichnete Daten über der Zeit zu plotten ist eigentlich nicht ungewöhnlich. Ok, ich versuche jetzt das in Sekunden zu wandeln. nach der Zeile x = x - x[0] habe ich die Differenz. Eigentlich sollte ich es dann mit x = x.total_seconds() wandeln können. Jedoch sagt mir die Fehlermeldung (AttributeError: 'numpy.ndarray' object has no attribute 'total_seconds') das ich anscheinend doch kein timedelta vorliegen haben...?

Im Variable Explorer zeigt es mir für x an:
0:00:00
0:00:06
0:00:16
0:00:26
0:00:36
0:00:46
Dies ist eigentlich schon das was ich will, nur sollte es eben auch so auf der x-Achse im Plot sein.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das total_seconds ist verfuegbar auf time_delta. Also einer Zelle deines Arrays. Nicht dem ganzen Sack. Und was du willst, ist klar, aber augenscheinlich eben so nicht direkt verfuegbar, sondern muss duch einen eigenen Formatter zur Verfuegung gestellt werden.
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

__deets__ hat geschrieben: Mittwoch 7. September 2022, 10:54 Das total_seconds ist verfuegbar auf time_delta. Also einer Zelle deines Arrays. Nicht dem ganzen Sack. Und was du willst, ist klar, aber augenscheinlich eben so nicht direkt verfuegbar, sondern muss duch einen eigenen Formatter zur Verfuegung gestellt werden.
Ach ja richtig. Ich denke damit komme ich nun weiter.
Super, vielen Dank!
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bussard: Ja das kommt häufiger vor, und dann ist das Problem wie genau die Zeit denn dargestellt werden soll. Da hat dann jeder wieder seine eigenen Vorstellungen und es wird kompliziert eine allgemeine, flexible Darstellung zu implementieren. Auf der anderen Seite ist es auch nicht so wirklich schwer sich das in ein paar Zeilen selbst zu schreiben.

Ein Numpy-Array hat diese Methode nicht, aber ein Pandas `Series`-Objekt hat ein `dt`-Attribut das eine `total_seconds()`-Methode hat. Du wirfst zu früh die Funktionalität von Pandas weg. Oder man könnte das Array auch einfach in `float` umwandeln (und die Werte durch den entsprechenden Faktor teilen, je nach `dtype` den das vorher hatte).

Randbemerkung: ich finde das ein bisschen ungünstig das hier zum Beispiel ``17:30`` so oft wiederholt wird:

Code: Alles auswählen

x = mydata.iloc[17:30,0].values   # timestamp
y1 = mydata.iloc[17:30,1].values  # dataset 1
y3 = mydata.iloc[17:30,4].values  # dataset 2
Ausserdem sollte man bessere Variablennamen verwenden. Wenn man einen Kommentar dran schreibt, der mit einem oder zwei Worten beschreibt was ein total kryptischer Name bedeuten soll, dann sollte der Kommentar der Name sein. Damit braucht man dann den Kommentar nicht mehr und das Programm ist gleich leichter verständlich.

Man könnte auch die Spalten schon beim einlesen selektieren, also nur einlesen was man auch braucht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bussard
User
Beiträge: 6
Registriert: Dienstag 6. September 2022, 15:13

Vieeelen Dank für deine weiteren Tipps!
Antworten