Prof. Dr. Fabian Transchel, Hochschule Harz, Oktober 2025
import pandas as pd
import plotly as px
import matplotlib
%matplotlib widget
print(matplotlib.get_backend())
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as pxgo
widget
data_file_name = 'AIEng Exo Motion Sensing\\23-07-2025Mocap2Gameplay-002.bvh'
data_file_ok = True
data_file_error = ""
data_start_line = 0
frames = 0
frame_time = 0
column_header = []
column_header_prefix = ""
# Daten in der Datei mittels Keyword "MOTION" suchen und Definitionen für die Generierung der Spaltenbezeichnungen einlesen
with open(data_file_name) as fp:
lines = fp.readlines()
i = -1
for row in lines:
'''
Ich gehe davon aus, dass die Einträge ROOT/JOINT und CHANNELS sich abwechseln.
ROOT/JOINT bildet das Präfix für alle folgenden CHANNELS bei der Spaltenbezeichnung.
Schlielich wird noch nach MOTION gesucht, um den Einstiegspunkt für die einzulesenden
Daten zu finden. Abschließend wird die Anzahl der Frames sowie die Framelänge gelesen.
Annahme: Angabe der Frame Time in [s]
'''
i+=1
if row.find("ROOT") != -1 or row.find("JOINT") != -1:
column_header_prefix = row.strip().split(" ")[1]
# print (column_header_prefix)
continue
if row.find("CHANNELS") != -1:
column_header = column_header + [ column_header_prefix +"_"+ item for item in row.strip().split(" ")[2:] ]
# print ([ column_header_prefix +"_"+ item for item in row.strip().split(" ")[2:] ])
continue
if row.find('MOTION') != -1:
data_start_line = i + 3
frames = int(lines[i+1].strip().split(" ")[1])
frame_time = float(lines[i+2].strip().split(" ")[2])
break
if data_start_line == 0:
data_file_ok = False
data_file_error += "Keyword 'Motion' nicht gefunden. Keine Daten zum einlesen vorhanden."
if data_file_ok:
# Daten einlesen
df = pd.read_csv(data_file_name, sep=" ", skiprows=data_start_line, header=None, names=column_header)
# Duplikate verwerfen
df = df.drop_duplicates()
# Index definineren
df = df.set_index( pd.date_range('1/1/2025', periods=df.shape[0], freq=str(frame_time)) )
# Daten mit neuer Zeitbasis resampeln
df = df.resample("0.1s").mean()
print("Daten eingelesen")
else:
print("FEHLER\n" + data_file_error)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) File pandas/_libs/tslibs/offsets.pyx:4855, in pandas._libs.tslibs.offsets.to_offset() ValueError: last element must be blank During handling of the above exception, another exception occurred: ValueError Traceback (most recent call last) Cell In[24], line 42 39 df = df.drop_duplicates() 41 # Index definineren ---> 42 df = df.set_index( pd.date_range('1/1/2025', periods=df.shape[0], freq=str(frame_time)) ) 44 # Daten mit neuer Zeitbasis resampeln 45 df = df.resample("0.1s").mean() File d:\Anaconda\envs\MSuT\Lib\site-packages\pandas\core\indexes\datetimes.py:1008, in date_range(start, end, periods, freq, tz, normalize, name, inclusive, unit, **kwargs) 1005 if freq is None and com.any_none(periods, start, end): 1006 freq = "D" -> 1008 dtarr = DatetimeArray._generate_range( 1009 start=start, 1010 end=end, 1011 periods=periods, 1012 freq=freq, 1013 tz=tz, 1014 normalize=normalize, 1015 inclusive=inclusive, 1016 unit=unit, 1017 **kwargs, 1018 ) 1019 return DatetimeIndex._simple_new(dtarr, name=name) File d:\Anaconda\envs\MSuT\Lib\site-packages\pandas\core\arrays\datetimes.py:423, in DatetimeArray._generate_range(cls, start, end, periods, freq, tz, normalize, ambiguous, nonexistent, inclusive, unit) 418 if com.count_not_none(start, end, periods, freq) != 3: 419 raise ValueError( 420 "Of the four parameters: start, end, periods, " 421 "and freq, exactly three must be specified" 422 ) --> 423 freq = to_offset(freq) 425 if start is not None: 426 start = Timestamp(start) File pandas/_libs/tslibs/offsets.pyx:4791, in pandas._libs.tslibs.offsets.to_offset() File pandas/_libs/tslibs/offsets.pyx:4954, in pandas._libs.tslibs.offsets.to_offset() ValueError: Invalid frequency: 0.016667, failed to parse with error message: ValueError('last element must be blank')
df.head(20)
| Hips_Xposition | Hips_Yposition | Hips_Zposition | Hips_Yrotation | Hips_Xrotation | Hips_Zrotation | Chest_Yrotation | Chest_Xrotation | Chest_Zrotation | Chest2_Yrotation | ... | LeftHip_Zrotation | LeftKnee_Yrotation | LeftKnee_Xrotation | LeftKnee_Zrotation | LeftAnkle_Yrotation | LeftAnkle_Xrotation | LeftAnkle_Zrotation | LeftToe_Yrotation | LeftToe_Xrotation | LeftToe_Zrotation | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.0 | 0.995491 | 0.0 | 0.000000 | 6.340192 | 0.000000 | 0.000000 | -6.340192 | 0.000000 | 0.000000 | ... | 0.000000 | 0.000000 | 1.905768 | 0.000000 | 0.000000 | -4.658254 | 0.000000 | 0.0 | 0.0 | 0.0 |
| 1 | 0.0 | 1.250000 | 0.0 | -129.519133 | 7.040608 | -1.145609 | 1.671974 | -5.508269 | 1.501748 | 0.689633 | ... | 1.679436 | 0.398210 | 11.530228 | -0.110554 | -2.813527 | -9.878268 | -1.547494 | 0.0 | -0.0 | 0.0 |
| 2 | 0.0 | 1.250000 | 0.0 | -129.631701 | 6.936906 | -1.120711 | 1.676278 | -5.451491 | 1.441430 | 0.693434 | ... | 1.560593 | 0.418050 | 11.311385 | -0.125586 | -2.871568 | -9.819166 | -1.408210 | -0.0 | -0.0 | 0.0 |
| 3 | 0.0 | 1.250000 | 0.0 | -129.704610 | 6.852042 | -1.094486 | 1.674093 | -5.406982 | 1.388953 | 0.694141 | ... | 1.457488 | 0.438776 | 11.122996 | -0.121332 | -2.921298 | -9.773088 | -1.298656 | 0.0 | 0.0 | -0.0 |
| 4 | 0.0 | 1.250000 | 0.0 | -129.710698 | 6.796788 | -1.063975 | 1.661378 | -5.381869 | 1.347789 | 0.689853 | ... | 1.376957 | 0.460616 | 10.982769 | -0.083128 | -2.956303 | -9.748521 | -1.239878 | 0.0 | -0.0 | 0.0 |
| 5 | 0.0 | 1.250000 | 0.0 | -129.677129 | 6.760305 | -1.032362 | 1.642162 | -5.368912 | 1.314560 | 0.682444 | ... | 1.311873 | 0.483467 | 10.872982 | -0.025577 | -2.983026 | -9.737142 | -1.210721 | -0.0 | 0.0 | -0.0 |
| 6 | 0.0 | 1.250000 | 0.0 | -129.645717 | 6.728973 | -1.007798 | 1.622036 | -5.358692 | 1.286974 | 0.674447 | ... | 1.256649 | 0.508034 | 10.770980 | 0.026858 | -3.012495 | -9.726953 | -1.177458 | 0.0 | -0.0 | -0.0 |
| 7 | 0.0 | 1.250000 | 0.0 | -129.630408 | 6.699372 | -0.994375 | 1.602600 | -5.349927 | 1.265212 | 0.666564 | ... | 1.210587 | 0.535335 | 10.669086 | 0.066194 | -3.050177 | -9.714889 | -1.126979 | -0.0 | -0.0 | 0.0 |
| 8 | 0.0 | 1.250000 | 0.0 | -129.617236 | 6.674939 | -0.987983 | 1.582250 | -5.343900 | 1.249093 | 0.658089 | ... | 1.174393 | 0.564398 | 10.574979 | 0.100416 | -3.090620 | -9.704001 | -1.072404 | 0.0 | -0.0 | -0.0 |
| 9 | 0.0 | 1.250000 | 0.0 | -129.606157 | 6.652380 | -0.984450 | 1.561764 | -5.335073 | 1.235769 | 0.649454 | ... | 1.144637 | 0.592919 | 10.489046 | 0.129005 | -3.128498 | -9.691433 | -1.019375 | -0.0 | 0.0 | -0.0 |
| 10 | 0.0 | 1.250000 | 0.0 | -129.597200 | 6.630917 | -0.982954 | 1.540399 | -5.321041 | 1.225236 | 0.640325 | ... | 1.120946 | 0.621741 | 10.410841 | 0.151669 | -3.162967 | -9.675991 | -0.967511 | -0.0 | -0.0 | -0.0 |
| 11 | 0.0 | 1.250000 | 0.0 | -129.590332 | 6.611330 | -0.984312 | 1.518894 | -5.304207 | 1.217496 | 0.631033 | ... | 1.103684 | 0.650075 | 10.340826 | 0.168741 | -3.194858 | -9.658869 | -0.917182 | 0.0 | 0.0 | 0.0 |
| 12 | 0.0 | 1.250000 | 0.0 | -129.585419 | 6.592653 | -0.986811 | 1.500244 | -5.286250 | 1.209712 | 0.623006 | ... | 1.090520 | 0.673167 | 10.280761 | 0.180656 | -3.221339 | -9.640799 | -0.875147 | -0.0 | 0.0 | 0.0 |
| 13 | 0.0 | 1.250000 | 0.0 | -129.582456 | 6.573590 | -0.990264 | 1.486002 | -5.266777 | 1.201089 | 0.616956 | ... | 1.081831 | 0.688932 | 10.233554 | 0.186428 | -3.240684 | -9.621623 | -0.846054 | -0.0 | -0.0 | 0.0 |
| 14 | 0.0 | 1.250000 | 0.0 | -129.581448 | 6.555438 | -0.994855 | 1.474615 | -5.246182 | 1.192426 | 0.612169 | ... | 1.077243 | 0.699495 | 10.196310 | 0.187080 | -3.254592 | -9.601506 | -0.825237 | 0.0 | -0.0 | 0.0 |
| 15 | 0.0 | 1.250000 | 0.0 | -129.582278 | 6.541122 | -0.999421 | 1.464417 | -5.227329 | 1.183285 | 0.607930 | ... | 1.073302 | 0.706413 | 10.162076 | 0.186063 | -3.265368 | -9.581668 | -0.805478 | -0.0 | -0.0 | -0.0 |
| 16 | 0.0 | 1.250000 | 0.0 | -129.586493 | 6.532947 | -1.003906 | 1.455376 | -5.211449 | 1.173282 | 0.604239 | ... | 1.069675 | 0.709135 | 10.131002 | 0.183341 | -3.271568 | -9.562270 | -0.785250 | 0.0 | 0.0 | 0.0 |
| 17 | 0.0 | 1.250000 | 0.0 | -129.592547 | 6.528608 | -1.008366 | 1.447521 | -5.197313 | 1.162803 | 0.601093 | ... | 1.066697 | 0.708217 | 10.102939 | 0.178955 | -3.274634 | -9.543153 | -0.766072 | 0.0 | 0.0 | -0.0 |
| 18 | 0.0 | 1.250000 | 0.0 | -129.595692 | 6.524117 | -1.011801 | 1.439288 | -5.184094 | 1.152565 | 0.597774 | ... | 1.061912 | 0.706865 | 10.070482 | 0.176456 | -3.281200 | -9.525055 | -0.745303 | -0.0 | -0.0 | -0.0 |
| 19 | 0.0 | 1.250000 | 0.0 | -129.593691 | 6.519215 | -1.013571 | 1.429914 | -5.171796 | 1.142711 | 0.593938 | ... | 1.054076 | 0.704535 | 10.029531 | 0.177350 | -3.295863 | -9.507830 | -0.720525 | -0.0 | 0.0 | -0.0 |
20 rows × 72 columns
fig = pxgo.Figure()
features = ["Chest_Xrotation","Chest_Yrotation","Hips_Xrotation","Hips_Yrotation"]
for f in features:
fig.add_trace(pxgo.Scatter(x=df.index, y=df[f],mode='lines',name=f))
fig.show()