pyForceDAQ 2.0.5.dev3__tar.gz → 2.0.6__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 (37) hide show
  1. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/PKG-INFO +1 -1
  2. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/pyproject.toml +1 -1
  3. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/__main__.py +4 -9
  4. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/settings.py +3 -2
  5. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/constants.py +3 -3
  6. pyforcedaq-2.0.6/src/pyforcedaq/gui/__init__.py +5 -0
  7. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_gui_status.py +7 -3
  8. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_layout.py +15 -10
  9. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_run.py +21 -14
  10. pyforcedaq-2.0.6/src/pyforcedaq/gui/rf_icon.png +0 -0
  11. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/launcher.py +8 -2
  12. pyforcedaq-2.0.5.dev3/src/pyforcedaq/gui/__init__.py +0 -5
  13. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/__init__.py +0 -0
  14. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/__init__.py +0 -0
  15. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/clock.py +0 -0
  16. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/data_recorder.py +0 -0
  17. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/file_writer.py +0 -0
  18. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/lsl.py +0 -0
  19. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/misc.py +0 -0
  20. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/process_priority_manager.py +0 -0
  21. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/sensor.py +0 -0
  22. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/sensor_process.py +0 -0
  23. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/types.py +0 -0
  24. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/_lib/udp_connection.py +0 -0
  25. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/__init__.py +0 -0
  26. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/_pyATIDAQ.py +0 -0
  27. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/calibration_dll.py +0 -0
  28. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/calibration_iaftt.py +0 -0
  29. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/read_daq_mock_sensor.py +0 -0
  30. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/read_daq_nidaqmx.py +0 -0
  31. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/daq/read_daq_pydaqmx.py +0 -0
  32. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/force.py +0 -0
  33. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_level_indicator.py +0 -0
  34. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_pg_surface.py +0 -0
  35. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_plotter.py +0 -0
  36. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/_scaling.py +0 -0
  37. {pyforcedaq-2.0.5.dev3 → pyforcedaq-2.0.6}/src/pyforcedaq/gui/forceDAQ_logo.png +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyForceDAQ
3
- Version: 2.0.5.dev3
3
+ Version: 2.0.6
4
4
  Summary: A Python package for data acquisition and analysis in force-based experiments.
5
5
  Author: Oliver Lindemann
6
6
  Author-email: Oliver Lindemann <lindemann@essb.eur.nl>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pyForceDAQ"
3
- version = "2.0.5-dev3"
3
+ version = "2.0.6"
4
4
  description = "A Python package for data acquisition and analysis in force-based experiments."
5
5
  authors = [
6
6
  { name = "Oliver Lindemann", email = "lindemann@essb.eur.nl" },
@@ -21,14 +21,6 @@ def cli():
21
21
 
22
22
  parser.add_argument("SETTINGS_FILE", nargs="?", default="", help="settings file")
23
23
 
24
- parser.add_argument(
25
- "-l",
26
- "--launcher",
27
- action="store_true",
28
- default=False,
29
- help="Run with launcher GUI to edit settings and start recording",
30
- )
31
-
32
24
  parser.add_argument(
33
25
  "-o",
34
26
  "--omit-launcher",
@@ -70,9 +62,12 @@ def cli():
70
62
  else:
71
63
  from .gui import run_settings_file
72
64
 
65
+ if len(args.SETTINGS_FILE) == 0:
66
+ print("No settings file provided, can't start recording")
67
+ exit()
68
+
73
69
  run_settings_file(args.SETTINGS_FILE)
74
70
 
75
71
 
76
72
  if __name__ == "__main__": # required because of threading
77
73
  cli()
78
- cli()
@@ -7,7 +7,7 @@ from typing import Any, Dict, List, Tuple
7
7
 
8
8
  import tomlkit
9
9
 
10
- from ..constants import CALIBRATION_FOLDER, DATA_FOLDER
10
+ from ..constants import CALIBRATION_FOLDER, DATA_FOLDER, SETTINGS_FILE_EXTENSION
11
11
 
12
12
 
13
13
  class DAQConfiguration(object):
@@ -185,11 +185,12 @@ class AppSettings(object):
185
185
  self.recording_section = "Recording"
186
186
 
187
187
  self.filepath = Path(filename)
188
+ self.filepath = self.filepath.with_suffix(SETTINGS_FILE_EXTENSION)
188
189
  if os.path.isfile(self.filepath):
189
190
  self.load()
190
191
  else:
191
192
  self.save() # defaults
192
-
193
+ print(f"WARNING: {self.filepath} not found, creating new settings file with defaults")
193
194
  self.output_filename = ""
194
195
 
195
196
  def _asdict(self):
@@ -5,8 +5,8 @@ MOCK_SENSOR = 9
5
5
  DAQ_TYPE = NIDAQMX # default to nidaqmx, use constants.MOCK_SENSOR for mock sensor, constants.PYDAQMX for PyDAQmx
6
6
  USE_AIFTT = True # <-- change to False to use ATI DLL for calibration conversion, otherwise use atiiaftt
7
7
 
8
- SETTINGS_FILE_EXTENSION = ".settings.toml"
9
- DEFAULT_SETTINGS_FILE = "pyForceDAQ" + SETTINGS_FILE_EXTENSION
8
+ SETTINGS_FILE_EXTENSION = ".toml"
9
+ DEFAULT_SETTINGS_FILE = "pyForceDAQ.settings" + SETTINGS_FILE_EXTENSION
10
10
  DEFAULT_OUTPUT_FILENAME = None
11
- CALIBRATION_FOLDER = "calibration"
11
+ CALIBRATION_FOLDER = "."
12
12
  DATA_FOLDER = "data"
@@ -0,0 +1,5 @@
1
+
2
+ print("\nStarting pyforceDAQ GUI...")
3
+ from .._lib import settings # # read settings
4
+ from ._run import run # for running with options from Python script
5
+ from ._run import run_settings_file
@@ -2,7 +2,7 @@ __author__ = "Oliver Lindemann"
2
2
 
3
3
 
4
4
  from time import sleep
5
- from typing import Tuple
5
+ from typing import List, Tuple
6
6
 
7
7
  from expyriment import io, misc
8
8
 
@@ -27,16 +27,19 @@ def _text2number_array(txt):
27
27
 
28
28
 
29
29
  class GUIStatus(object):
30
+
30
31
  def __init__(
31
32
  self,
32
33
  gui_settings: GUISettings,
33
34
  recorder: DataRecorder,
34
35
  screen_size: Tuple[int, int],
36
+ top_left_info:List[str] = [""]
35
37
  ):
36
38
 
37
39
  self.gs = gui_settings
38
40
  self.recorder = recorder
39
41
  self.screen_size = screen_size
42
+ self.top_left_info = top_left_info
40
43
 
41
44
  self.scaling_plotter = Scaling(
42
45
  min=gui_settings.data_min_max[0],
@@ -133,8 +136,9 @@ class GUIStatus(object):
133
136
 
134
137
  return RecordingScreen(
135
138
  window_size=self.screen_size,
136
- txt_top_center=info_file,
137
- txt_top_left=info_recording,
139
+ txt_top_left=self.top_left_info,
140
+ txt_top_right=info_file,
141
+ txt_top_center=info_recording,
138
142
  text_colour=txt_col,
139
143
  no_pause_option = not self.recorder.has_file_writer
140
144
  )
@@ -2,6 +2,7 @@ __author__ = "Oliver Lindemann"
2
2
 
3
3
  # helper functions
4
4
  import os
5
+ from typing import List
5
6
 
6
7
  import pygame
7
8
  from expyriment import stimuli
@@ -18,7 +19,6 @@ colours = [
18
19
  expy_constants.C_EXPYRIMENT_PURPLE,
19
20
  ]
20
21
 
21
-
22
22
  def get_pygame_rect(stimulus, screen_size):
23
23
  """little helper function that returns the pygame rect from stimuli"""
24
24
  half_screen_size = (screen_size[0] / 2, screen_size[1] / 2)
@@ -31,6 +31,7 @@ def get_pygame_rect(stimulus, screen_size):
31
31
  return pygame.Rect(rect_pos, stim_size)
32
32
 
33
33
 
34
+
34
35
  def logo_text_line(text):
35
36
  blank = stimuli.Canvas(size=(600, 400))
36
37
  logo = stimuli.Picture(
@@ -56,7 +57,11 @@ def make_text_line(text, position, text_size, text_colour):
56
57
 
57
58
  class RecordingScreen(object):
58
59
 
59
- def __init__(self, window_size, txt_top_center, txt_top_left, text_colour,
60
+ def __init__(self, window_size,
61
+ txt_top_left: List[str],
62
+ txt_top_center:str,
63
+ txt_top_right:str,
64
+ text_colour,
60
65
  no_pause_option:bool = False):
61
66
  # NOTE: Expyriment has to be intialized
62
67
  margin = 30
@@ -67,12 +72,12 @@ class RecordingScreen(object):
67
72
 
68
73
  self.text_colour = text_colour
69
74
  self.elements = []
70
- self.add_text_line_left(
71
- f"{forceDAQVersion}",
72
- [self.left, self.top],
73
- text_size=15,
74
- text_colour=None
75
- )
75
+
76
+ for cnt, txt in enumerate(txt_top_left):
77
+ self.add_text_line_left(
78
+ txt,
79
+ [self.left, self.top - cnt * 20],
80
+ text_size=15,text_colour=None)
76
81
  col = expy_constants.C_GREY
77
82
  if not no_pause_option:
78
83
  self.add_text_line_left("P: pause/unpause saving", [self.left, self.bottom + 20], text_colour=col)
@@ -88,8 +93,8 @@ class RecordingScreen(object):
88
93
  )
89
94
  self.add_text_line_right("Q: quit recording", [self.right, self.bottom], text_colour=col)
90
95
 
91
- self.add_text_line_right(txt_top_center, [self.right, self.top], text_size=15)
92
- self.add_text_line_centered(txt_top_left, [0, self.top], text_size=15)
96
+ self.add_text_line_right(txt_top_right, [self.right, self.top], text_size=15)
97
+ self.add_text_line_centered(txt_top_center, [0, self.top], text_size=15)
93
98
 
94
99
  def add_text_line_centered(
95
100
  self, text, position, text_size=12, text_colour=None
@@ -5,6 +5,7 @@ See COPYING file distributed along with the pyForceDAQ copyright and license ter
5
5
  __author__ = "Oliver Lindemann"
6
6
 
7
7
  import logging
8
+ import os
8
9
  from pathlib import Path
9
10
  from pickle import dumps
10
11
  from time import sleep
@@ -19,7 +20,7 @@ from .._lib.clock import wait_ms
19
20
  from .._lib.data_recorder import DataRecorder
20
21
  from .._lib.sensor_process import SensorProcess
21
22
  from .._lib.settings import AppSettings, GUISettings, SensorSettings
22
- from ..constants import DEFAULT_OUTPUT_FILENAME, DEFAULT_SETTINGS_FILE
23
+ from ..constants import DEFAULT_OUTPUT_FILENAME
23
24
  from ._gui_status import GUIStatus
24
25
  from ._layout import colours, get_pygame_rect, logo_text_line, make_text_line
25
26
  from ._level_indicator import level_indicator
@@ -32,8 +33,7 @@ RESPONSE_MINMAX2 = COMMAND_STR + b"xRM2"
32
33
  CHANGED_LEVEL = COMMAND_STR + b"xCL1"
33
34
  CHANGED_LEVEL2 = COMMAND_STR + b"xCL2"
34
35
 
35
-
36
- def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
36
+ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings, info_strings: List[str]):
37
37
  """udp command:
38
38
  "start", "pause", "stop"
39
39
  "thresholds = [x,...]" : start level detection for Fz parameter and set threshold
@@ -44,7 +44,8 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
44
44
  plotter_width = 900
45
45
  plotter_position = (0, -30)
46
46
 
47
- s = GUIStatus(gui_settings=gs, recorder=recorder, screen_size=exp.screen.size)
47
+ s = GUIStatus(gui_settings=gs, recorder=recorder, screen_size=exp.screen.size,
48
+ top_left_info=info_strings)
48
49
 
49
50
  # plotter
50
51
  plotter_thread = None
@@ -295,14 +296,15 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
295
296
  update_rects.append(get_pygame_rect(txt, exp.screen.size))
296
297
 
297
298
  # counter
298
- pos = (-230, 250)
299
+ pos = (-270, 240)
300
+
299
301
  stimuli.Canvas(
300
- position=pos, size=(400, 50), colour=misc.constants.C_BLACK
302
+ position=pos, size=(400, 20), colour=misc.constants.C_BLACK
301
303
  ).present(update=False, clear=False)
302
304
 
303
305
  txt = stimuli.TextBox(
304
306
  position=pos,
305
- size=(400, 50),
307
+ size=(400, 20),
306
308
  # background_colour=(30,30,30),
307
309
  text_size=15,
308
310
  text="n samples (total): {0}".format(
@@ -314,7 +316,9 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
314
316
  txt.present(update=False, clear=False)
315
317
  update_rects.append(get_pygame_rect(txt, exp.screen.size))
316
318
 
317
- # Infos
319
+ #FIXME Threshold levels down work
320
+
321
+ # Sensor info
318
322
  pos = (200, 250)
319
323
  tmp = stimuli.Canvas(
320
324
  position=pos, size=(400, 50), colour=misc.constants.C_BLACK
@@ -329,6 +333,7 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
329
333
  ]
330
334
  else:
331
335
  tmp = s.thresholds.get_level(s.level_detection_parameter_average(0))
336
+
332
337
  txt = stimuli.TextBox(
333
338
  position=pos,
334
339
  size=(400, 50),
@@ -387,11 +392,6 @@ def _main_loop(exp, recorder: DataRecorder, gs: GUISettings):
387
392
 
388
393
 
389
394
  def run_settings_file(settings_file: str | Path = ""):
390
-
391
- if isinstance(settings_file, str) and len(settings_file) < 2:
392
- # load default settings file if not specified
393
- settings_file = DEFAULT_SETTINGS_FILE
394
-
395
395
  return run(AppSettings(settings_file))
396
396
 
397
397
 
@@ -432,6 +432,12 @@ def run(settings: AppSettings):
432
432
 
433
433
  control.initialize(exp)
434
434
  exp.mouse.show_cursor() # type: ignore #
435
+ pygame.display.set_caption(f"pyforceDAQ {forceDAQVersion}")
436
+
437
+ icon_path = os.path.join(os.path.dirname(__file__), "rf_icon.png")
438
+ print(f"Loading icon from {icon_path}")
439
+ pygame.display.set_icon(pygame.image.load(icon_path))
440
+
435
441
  logo_text_line("Initializing Force Recording").present()
436
442
  show_logo_time = 0.5
437
443
  recorder = DataRecorder(
@@ -456,7 +462,8 @@ def run(settings: AppSettings):
456
462
 
457
463
  sleep(show_logo_time)
458
464
 
459
- _main_loop(exp, recorder=recorder, gs=settings.gui)
465
+ _main_loop(exp, recorder=recorder, gs=settings.gui,
466
+ info_strings=[f"{settings.filepath.name}"])
460
467
 
461
468
  recorder.quit()
462
469
  control.end()
@@ -1,3 +1,4 @@
1
+ import glob
1
2
  from os import path
2
3
  from pathlib import Path
3
4
  from typing import List
@@ -139,7 +140,13 @@ def load_settings_file(settings_file: str | Path) -> AppSettings:
139
140
 
140
141
  def run_launcher():
141
142
  _sg.theme("DarkBlue14") # please make your windows colorful
142
- settings = load_settings_file(constants.DEFAULT_SETTINGS_FILE)
143
+
144
+ toml_files = glob.glob("*.toml")
145
+ if len(toml_files) == 0:
146
+ settings_file = constants.DEFAULT_SETTINGS_FILE
147
+ else:
148
+ settings_file = toml_files[0]
149
+ settings = load_settings_file(settings_file)
143
150
 
144
151
  while True:
145
152
  event, values, settings = _windows_run(settings)
@@ -161,7 +168,6 @@ def run_launcher():
161
168
  if ch == "No":
162
169
  return # quit
163
170
  from . import gui
164
-
165
171
  gui.run(settings)
166
172
  else:
167
173
  pass
@@ -1,5 +0,0 @@
1
- from .._lib import settings # # read settings
2
- from ._run import (
3
- run, # for running with options from Python script
4
- run_settings_file,
5
- )