c3d-parser 1.6.0__tar.gz → 1.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {c3d_parser-1.6.0/src/c3d_parser.egg-info → c3d_parser-1.6.1}/PKG-INFO +2 -2
  2. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/requirements.txt +1 -1
  3. c3d_parser-1.6.1/src/c3d_parser/__init__.py +2 -0
  4. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/c3d_parser.py +27 -3
  5. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/main_window.py +15 -0
  6. {c3d_parser-1.6.0 → c3d_parser-1.6.1/src/c3d_parser.egg-info}/PKG-INFO +2 -2
  7. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser.egg-info/requires.txt +1 -1
  8. c3d_parser-1.6.0/src/c3d_parser/__init__.py +0 -2
  9. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/LICENSE +0 -0
  10. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/README.md +0 -0
  11. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/pyproject.toml +0 -0
  12. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/setup.cfg +0 -0
  13. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/application.py +0 -0
  14. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/c3d_patch.py +0 -0
  15. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/osim.py +0 -0
  16. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/osim_resources/external_loads_template.xml +0 -0
  17. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/osim_resources/ik_task_set.xml +0 -0
  18. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/core/utils.py +0 -0
  19. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/general.py +0 -0
  20. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/logging.py +0 -0
  21. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/AUC.json +0 -0
  22. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/FMC.json +0 -0
  23. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/MH.json +0 -0
  24. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/QCMAS.json +0 -0
  25. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/RBWH.json +0 -0
  26. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/RCH.json +0 -0
  27. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/settings/marker_maps/Sydney.json +0 -0
  28. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/splash_rc.py +0 -0
  29. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/splashscreen.py +0 -0
  30. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/dialogs/about_dialog.py +0 -0
  31. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/dialogs/delete_marker_set_dialog.py +0 -0
  32. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/dialogs/marker_set_dialog.py +0 -0
  33. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py +0 -0
  34. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/dialogs/options_dialog.py +0 -0
  35. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/resources_rc.py +0 -0
  36. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/ui_delete_marker_set_dialog.py +0 -0
  37. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/ui_main_window.py +0 -0
  38. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/ui_marker_set_dialog.py +0 -0
  39. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/ui_marker_set_import_dialog.py +0 -0
  40. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/ui/ui_options_dialog.py +0 -0
  41. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/utils.py +0 -0
  42. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser/view/widgets.py +0 -0
  43. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser.egg-info/SOURCES.txt +0 -0
  44. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser.egg-info/dependency_links.txt +0 -0
  45. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser.egg-info/entry_points.txt +0 -0
  46. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/src/c3d_parser.egg-info/top_level.txt +0 -0
  47. {c3d_parser-1.6.0 → c3d_parser-1.6.1}/tests/test_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: c3d-parser
3
- Version: 1.6.0
3
+ Version: 1.6.1
4
4
  Summary: C3D parser for gait data harmonisation.
5
5
  Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -12,7 +12,7 @@ Requires-Dist: numpy==1.26.4
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: c3d==0.5.2
14
14
  Requires-Dist: trc-data-reader>=0.4.1
15
- Requires-Dist: opensim-model-creator==0.10.0
15
+ Requires-Dist: opensim-model-creator==0.10.1
16
16
  Requires-Dist: PySide6
17
17
  Requires-Dist: matplotlib
18
18
  Requires-Dist: mplcursors
@@ -3,7 +3,7 @@ numpy==1.26.4
3
3
  pandas
4
4
  c3d==0.5.2
5
5
  trc-data-reader>=0.4.1
6
- opensim-model-creator==0.10.0
6
+ opensim-model-creator==0.10.1
7
7
  PySide6
8
8
  matplotlib
9
9
  mplcursors
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = "1.6.1"
@@ -92,7 +92,8 @@ def parse_session(static_trial, dynamic_trials, input_directory, output_director
92
92
  output_directory, left_foot_flat, right_foot_flat, toe_marker_proximal,
93
93
  optimise_knee_axis, progress_tracker)
94
94
 
95
- write_c3d_parser_history(input_directory, output_directory, static_trial, deidentified_file_names, static_data)
95
+ write_c3d_parser_history(input_directory, output_directory, lab, static_trial, deidentified_file_names, static_data,
96
+ left_foot_flat, right_foot_flat, toe_marker_proximal)
96
97
 
97
98
  if not trc_file_paths:
98
99
  raise CancelException("No dynamic trials found.")
@@ -251,15 +252,18 @@ def parse_dynamic_trial(c3d_file, lab, output_directory, trial_index, marker_dat
251
252
  return analog_data, events, s_t_data, trc_file_path, grf_file_path
252
253
 
253
254
 
254
- def write_c3d_parser_history(input_directory, output_directory, static_trial, deidentified_file_names, static_data):
255
+ def write_c3d_parser_history(input_directory, output_directory, lab, static_trial, deidentified_file_names, static_data,
256
+ left_foot_flat, right_foot_flat, toe_marker_proximal):
255
257
  log_path = os.path.join(input_directory, "c3d_parser_history.log")
256
258
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
257
259
 
258
260
  try:
259
261
  with open(log_path, "w", encoding="utf-8") as f:
260
262
  f.write("C3D-Parser History\n")
261
- f.write(f"Last Run: {timestamp}\n\n")
263
+ f.write(f"Last Run: {timestamp}\n")
264
+ f.write(f"C3D-Parser Version: {VERSION}\n\n")
262
265
 
266
+ f.write(f"Lab: {lab}\n")
263
267
  f.write(f"Static trial: {static_trial}\n\n")
264
268
 
265
269
  if deidentified_file_names:
@@ -286,6 +290,12 @@ def write_c3d_parser_history(input_directory, output_directory, static_trial, de
286
290
  unit = f" {units[key]}" if key in units else ""
287
291
  f.write(f"{label}: {value}{unit}\n")
288
292
 
293
+ f.write("\n")
294
+ f.write("Foot Settings:\n")
295
+ f.write(f"Toe Marker: {'Proximal' if toe_marker_proximal else '2nd/3rd Met'}\n")
296
+ f.write(f"Left Foot Flat: {left_foot_flat}\n")
297
+ f.write(f"Right Foot Flat: {right_foot_flat}\n")
298
+
289
299
  metrics, measurements = define_metrics_and_measurements(output_directory)
290
300
  if metrics:
291
301
  f.write("\n")
@@ -540,8 +550,10 @@ def trim_frames(frame_data):
540
550
  if not drop_frames.empty:
541
551
  frame_data.drop(drop_frames, inplace=True)
542
552
 
553
+ # TODO: If we convert this to a dictionary we can keep the markers that are missing and check if they are required.
543
554
  remaining_frames = [frame for frame in incomplete_frames.keys() if trim_start <= frame <= trim_end]
544
555
  if remaining_frames:
556
+ # TODO: We should raise a ParserError (skip this trial) if the missing markers are required...?
545
557
  logger.warn(f"Frames {remaining_frames} are incomplete.")
546
558
 
547
559
  return trim_start, trim_end
@@ -1105,6 +1117,8 @@ def scale_grf_data(analog_data):
1105
1117
  analog_data[columns] = analog_data[columns] / 1000
1106
1118
 
1107
1119
 
1120
+ # TODO: This incorrectly classifies Adelaide's static trials as dynamic.
1121
+ # Use `calculate_distance_covered` instead?
1108
1122
  def is_dynamic(file_path):
1109
1123
  with open(file_path, 'rb') as handle:
1110
1124
  try:
@@ -1280,6 +1294,11 @@ def normalise_kinetics(kinetic_data, events):
1280
1294
  normalised_data[foot][file_name] = {}
1281
1295
  data_segment = data.iloc[start:frame, 1:]
1282
1296
 
1297
+ # TODO: If the model +tve and -tve are wrong, then we can't just flip these.
1298
+ # Because the non-GRF parts of the moments would also be flipped.
1299
+ # Just visually check the results against some clinical kinetics.
1300
+ # ...
1301
+ # Looks pretty good so far.
1283
1302
  # Perform sign transformations.
1284
1303
  data_segment[f"hip_flexion_{side}_moment"] = -data_segment[f"hip_flexion_{side}_moment"]
1285
1304
  data_segment[f"hip_adduction_{side}_moment"] = -data_segment[f"hip_adduction_{side}_moment"]
@@ -1372,6 +1391,9 @@ def write_normalised_data(data, column_names, selected_trials, excluded_cycles,
1372
1391
  file.write('\n')
1373
1392
 
1374
1393
 
1394
+ # TODO: Rework this function to be less sequential.
1395
+ # It should be able to calculate metrics for walking and running gait.
1396
+ # Put this at the start of the sequential bit.
1375
1397
  def calculate_spatiotemporal_data(frame_data, events, static_data):
1376
1398
  stride_lengths = {"Left": {}, "Right": {}}
1377
1399
  step_lengths = {"Left": {}, "Right": {}}
@@ -1394,6 +1416,8 @@ def calculate_spatiotemporal_data(frame_data, events, static_data):
1394
1416
  for event_time, (event_type, event_plate) in stride_events.items():
1395
1417
  time_ordered_events[event_time][foot] = [event_type, stride_number]
1396
1418
 
1419
+ # TODO: We should be able to use this to calculate ALL measurements non-sequentially.
1420
+ # TODO: Double check that we don't have situations where the events are not ordered in increasing stride number.
1397
1421
  # Add terminal foot-strike to events for each cycle.
1398
1422
  full_cycle_events = copy.deepcopy(events)
1399
1423
  for foot, foot_events in full_cycle_events.items():
@@ -57,6 +57,7 @@ class ProgressTracker(QObject):
57
57
  progress = Signal(str, str)
58
58
 
59
59
 
60
+ # TODO: CGM2 event detector on GitHub...?
60
61
  class MainWindow(QMainWindow):
61
62
 
62
63
  def __init__(self):
@@ -256,6 +257,12 @@ class MainWindow(QMainWindow):
256
257
  table.deleteLater()
257
258
  self._spatiotemporal_tables = []
258
259
 
260
+ # TODO: The legend is not correctly displayed if the ST tab is open while processing...
261
+ # Repositioning and updating the legend do nothing.
262
+
263
+ # TODO: The border is still having issues.
264
+ # Seems to be related to the area being scrollable.
265
+ # Only happens on some PCs/monitors...
259
266
  def _visualise_spatiotemporal_data(self):
260
267
 
261
268
  # Temporarily disable spatio-temporal visualisation for running gait.
@@ -891,6 +898,8 @@ class MainWindow(QMainWindow):
891
898
  if (file_name, f"{foot}_{cycle_number}") not in excluded_cycles:
892
899
  counts[foot] += 1
893
900
 
901
+ # TODO: This is being displayed before processing has finished.
902
+ # Which should not be happening.
894
903
  self._ui.labelCount.setText(f"Cycles: L {counts['Left']} / R {counts['Right']}")
895
904
 
896
905
  tab = self._ui.tabWidget.currentWidget()
@@ -918,6 +927,7 @@ class MainWindow(QMainWindow):
918
927
  self._update_s_t_colours()
919
928
  self._update_legend()
920
929
 
930
+ # TODO: For some reason the legend doesn't get created at all if we are visualising the ST tab while processing...
921
931
  def _update_legend(self):
922
932
  if self._boxes:
923
933
  for side, boxes in self._boxes.items():
@@ -1010,6 +1020,8 @@ class MainWindow(QMainWindow):
1010
1020
  settings.beginGroup('MainWindow')
1011
1021
  settings.setValue('size', self.size())
1012
1022
  settings.setValue('pos', self.pos())
1023
+ # TODO: The taskbar icon fails if the application opens in full-screen...
1024
+ # DON'T open in full screen...?
1013
1025
  settings.setValue('is_maximized', self.isMaximized())
1014
1026
  settings.setValue('lab', self._ui.comboBoxLab.currentText())
1015
1027
  settings.setValue('marker_diameter', self._ui.doubleSpinBoxMarkerDiameter.value())
@@ -1214,6 +1226,9 @@ class GaitCurves(defaultdict):
1214
1226
  line.set_color(colour)
1215
1227
  line.set_zorder(z_order)
1216
1228
 
1229
+ # TODO: Replace all these with `draw_idle`?
1230
+ # Just the ones that handle many curves...?
1231
+ # Probably all...?
1217
1232
  self._canvas.draw()
1218
1233
 
1219
1234
  def show_curve_menu(self, event):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: c3d-parser
3
- Version: 1.6.0
3
+ Version: 1.6.1
4
4
  Summary: C3D parser for gait data harmonisation.
5
5
  Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -12,7 +12,7 @@ Requires-Dist: numpy==1.26.4
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: c3d==0.5.2
14
14
  Requires-Dist: trc-data-reader>=0.4.1
15
- Requires-Dist: opensim-model-creator==0.10.0
15
+ Requires-Dist: opensim-model-creator==0.10.1
16
16
  Requires-Dist: PySide6
17
17
  Requires-Dist: matplotlib
18
18
  Requires-Dist: mplcursors
@@ -3,7 +3,7 @@ numpy==1.26.4
3
3
  pandas
4
4
  c3d==0.5.2
5
5
  trc-data-reader>=0.4.1
6
- opensim-model-creator==0.10.0
6
+ opensim-model-creator==0.10.1
7
7
  PySide6
8
8
  matplotlib
9
9
  mplcursors
@@ -1,2 +0,0 @@
1
-
2
- __version__ = "1.6.0"
File without changes
File without changes
File without changes
File without changes