UnixTime in Animate Funktion

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Mauby
User
Beiträge: 5
Registriert: Donnerstag 27. Juli 2017, 10:06

Hallo an alle,

Ich sitze gerade an einem Projekt einen Beschleunigungssensor per I2C mit einem Raspberry auszulesen und live auf einem Graph mit Python und Matplotlib anzuzeigen.

Ich scheitere aber aktuell an der Zeitanzeige für den Graphen.

Meine Datendatei hat das Format wie 1501019372.741470;+240 als unix time mit µsec und als Daten die Beschleunigung

Ich wollte folgenden Code benutzen:
https://www.youtube.com/watch?v=ZmYPzES ... a1fPDKluPF

Und dazu die Umwandlung von Unix Time:
https://www.youtube.com/watch?v=aRQxMYo ... F&index=11

Funktioniert aber nicht so wirklich...
Meine aktuelle animate Funktion sieht so aus:

Code: Alles auswählen

def animate(i):
graph_data=open('/home/pi/pi_test/beschleunigung.txt','r').read()
lines = graph_data.split('\n')
xs=[]
ys=[]
for line in lines:
if len(line)>1:
x.y = line.split(';')
dateconv = np.vectorize(dt.datetime.fromtimestamp)
x=dateconv(x)
xs.append(x)
ys.append(y)

ax1.clear()
ax1.plot(xs,ys)

Bin neu in Python und Raspberry, deswegen stehe ich gerade bisschen auf dem Schlauch bei den Fehlern, die er mir ausspuckt.

Grüße.
Mauby
Zuletzt geändert von Anonymous am Donnerstag 27. Juli 2017, 10:38, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

Mauby: Funktioniert aber nicht so wirklich ist keine so wirklich gute Fehlerbeschreibung. Was erwartest Du denn, und warum, und was passiert denn stattdessen? Oder bekommst Du vielleicht eine Fehlermeldung? Wenn ja welche? Und wo? Dazu wäre der Traceback interessant.

Bei dem gezeigten Quelltext fehlt die Einrückung, die ist in Python wichtig. Falls dort Fehler liegen müssten wir jetzt raten wie die denn bei Dir tatsächlich aussieht.

Sonstige Anmerkungen:

Dateien die man öffnet sollte man auch wieder schliessen. In dem Zusammenhang ist die ``with``-Anweisung ganz nützlich.

`dateconv` macht hier nicht wirklich sinn, denn `x` ist ein Skalar.
Mauby
User
Beiträge: 5
Registriert: Donnerstag 27. Juli 2017, 10:06

Ok, ich logge mich gerade über den raspberry ins internet ein, jetzt kann ich den code komplett kopieren:

Code: Alles auswählen

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import matplotlib.dates as mdates
import datetime as dt
#import time
from matplotlib import style

style.use('dark_background')
#print(plt.style.available)


##def bytespdate2num(fmt, encoding='utf-8'):
##    strconverter = mdates.strpdate2num(fmt)
##    def bytesconverter(b):
##        s = b.decode(encoding)
##        return strconverter(s)
##    return bytesconverter


fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)

def animate(i):
    graph_data = open('/home/pi/pi_beschleunigung_daten','r').read()
    lines = graph_data.split('\n')
    xs = []
    ys = []
    for line in lines:
        if len(line)>1:
            x, y = line.split(';')
            xs.append(x)
            ys.append(y)
            dateconv = np.vectorize(dt.datetime.fromtimestamp)
            xs = dateconv(xs)
            
    
    ax1.clear()
    ax1.plot(xs, ys)

ani = animation.FuncAnimation(fig, animate, interval=250)



plt.xlabel('Time')
plt.ylabel('Accelleration')
plt.show()
Fehlercode kommt und zeigt an:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/pi/pi_beschleunigung.py", line 41, in <module>
    ani = animation.FuncAnimation(fig, animate, interval=250)
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 1052, in __init__
    TimedAnimation.__init__(self, fig, **kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 898, in __init__
    *args, **kwargs)
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 576, in __init__
    self._init_draw()
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 1077, in _init_draw
    self._draw_frame(next(self.new_frame_seq()))
  File "/usr/lib/python3/dist-packages/matplotlib/animation.py", line 1091, in _draw_frame
    self._drawn_artists = self._func(framedata, *self._args)
  File "/home/pi/pi_beschleunigung.py", line 35, in animate
    xs = dateconv(xs)
  File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1573, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1633, in _vectorize_call
    ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
  File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1597, in _get_ufunc_and_otypes
    outputs = func(*inputs)
TypeError: an integer is required (got type numpy.str_)
Zuletzt geändert von Anonymous am Donnerstag 27. Juli 2017, 11:22, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@Mauby: `x` und `y` sind Zeichenketten. `datetime.fromtimestamp()` und damit auch `dateconv()` erwarten aber Zahlen. Bei `ys` würde es beim Plotten dann später das gleiche Problem geben.

Da Du sowieso schon `numpy` verwendest, würde ich gleich dessen Funktionen zum Einlesen von CSV/Textdateien verwenden statt das selbst auszuprogrammieren.

Schau Dir mal `numpy.loadtxt()` an. Das `unpack`-Argument wäre hier auch nützlich.
Mauby
User
Beiträge: 5
Registriert: Donnerstag 27. Juli 2017, 10:06

Hab es jetzt soweit hinbekommen mit numpy... Folgend ist der Code

Code: Alles auswählen

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
import matplotlib.dates as mdates
import datetime as dt
#import time
from matplotlib import style

style.use('dark_background')
#print(plt.style.available)


##def bytespdate2num(fmt, encoding='utf-8'):
##    strconverter = mdates.strpdate2num(fmt)
##    def bytesconverter(b):
##        s = b.decode(encoding)
##        return strconverter(s)
##    return bytesconverter


fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)

def animate(i):
    graph_data = '/home/pi/pi_audi/audi_beschleunigung_daten'

    x, y = np.loadtxt(graph_data,
                      delimiter=';',
                      unpack=True)
    dateconv = np.vectorize(dt.datetime.fromtimestamp)
    x = dateconv(x)
    
    ax1.clear()
    for label in ax1.xaxis.get_ticklabels():
        label.set_rotation(45)
    ax1.tick_params(axis='x', width='1')
    ax1.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
    ax1.grid(True)
    ax1.plot(x, y)
    plt.subplots_adjust(bottom=0.18)
    plt.xlabel('Time')
    plt.ylabel('Accelleration')


ani = animation.FuncAnimation(fig, animate, interval=250)

plt.show()

## Zusätzlicher Code zum Merken:
##
##            dateconv = np.vectorize(dt.datetime.fromtimestamp)
##            xs = dateconv(xs)

Mauby
User
Beiträge: 5
Registriert: Donnerstag 27. Juli 2017, 10:06

Guten Morgen Allerseits

Hätte noch eine Frage dazu:

Aktuell schreibt mein C Programm vom Beschleunigungssensor alles in eine Datei untereinander. Irgendwann muss dann Python ne meeenge Daten plotten und ich sehe in meinem Graphen nichts mehr.
Daher würde ich gerne die x-Achsen skalierung verkleinern, so dass der Graph nur die letzten ca 1000 Datenpunkte anzeigt.

Kann man das mit nump.loadtxt() machen mit der Funktion
skiprows : int, optional
Skip the first skiprows lines; default: 0
In Kombination mit der Länge / Anzahl der Reihen in der Datei. Zb sowas wie :

Code: Alles auswählen

if length of Datei > 1000
    skiprows=length-1000
else
    skiprows=0
Oder gibt es dafür elegantere Methoden?

Grüße,
Mauby
BlackJack

@Mauby: Um zu wissen wie viele Zeilen eine Textdatei hat muss man sie lesen. Das heisst Du musst die sowieso einlesen. Und danach kannst Du Dir einfach per „slicing“ die letzten 1000 davon nehmen.

Falls die Datei dazu zu gross wird sie komplett in den Speicher zu laden, sollte man überlegen ob eine einfach Textdatei dafür geeignet ist. Man könnte über das regelmässige wechseln der Datei nachdenken, beispielsweise eine pro Tag oder Stunde oder … je nach dem wie hoch das Datenaufkommen ist. Oder man verwendet eine Datenbank. Eine SQL-Datenbank (SQLite, MySQL/MariaDB, PostgreSQL, …) oder vielleicht auch etwas spezielleres wie HDF5.
Mauby
User
Beiträge: 5
Registriert: Donnerstag 27. Juli 2017, 10:06

Slicing... Ok

Also würde sowas klappen:

Code: Alles auswählen

date = numpy.loadtxt(...)
date_s = date[len(date)-1000:]
soweit würde ich das verstehen von http://pythoncentral.io/cutting-and-sli ... in-python/

probiere ich gleich mal aus...
Benutzeravatar
snafu
User
Beiträge: 6736
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Den ersten Teil beim Slicing-Ausdruck kannst du weglassen, denn date[len(date)-1000:] lässt sich auch kürzer als date[-1000:] ausdrücken. Das hat beides exakt den gleichen Effekt.
Antworten