ddalab 1.2.11__py3-none-win_amd64.whl

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 (116) hide show
  1. ddalab-1.2.11.dist-info/METADATA +277 -0
  2. ddalab-1.2.11.dist-info/RECORD +116 -0
  3. ddalab-1.2.11.dist-info/WHEEL +5 -0
  4. ddalab-1.2.11.dist-info/entry_points.txt +4 -0
  5. ddalab-1.2.11.dist-info/top_level.txt +1 -0
  6. ddalab_app/__init__.py +5 -0
  7. ddalab_app/__main__.py +4 -0
  8. ddalab_app/app/__init__.py +14 -0
  9. ddalab_app/app/core/__init__.py +1 -0
  10. ddalab_app/app/core/analysis_input.py +44 -0
  11. ddalab_app/app/core/snapshot_payload.py +84 -0
  12. ddalab_app/app/integrations/__init__.py +1 -0
  13. ddalab_app/app/integrations/cdr.py +297 -0
  14. ddalab_app/app/integrations/cdr_simulation.py +196 -0
  15. ddalab_app/app/integrations/dda_export_utils.py +421 -0
  16. ddalab_app/app/runtime/__init__.py +1 -0
  17. ddalab_app/app/runtime/perf_logging.py +70 -0
  18. ddalab_app/app/runtime/runtime_logging.py +230 -0
  19. ddalab_app/app/workbench/__init__.py +4 -0
  20. ddalab_app/app/workbench/controller.py +1971 -0
  21. ddalab_app/app/workbench/models.py +117 -0
  22. ddalab_app/app/workbench/runtime.py +45 -0
  23. ddalab_app/app/workbench/tasks.py +50 -0
  24. ddalab_app/assets/fonts/ibm_plex_sans_medium.ttf +0 -0
  25. ddalab_app/assets/fonts/ibm_plex_sans_regular.ttf +0 -0
  26. ddalab_app/assets/fonts/ibm_plex_sans_semibold.ttf +0 -0
  27. ddalab_app/assets/icons/icon.icns +0 -0
  28. ddalab_app/assets/icons/icon.ico +0 -0
  29. ddalab_app/assets/icons/icon.png +0 -0
  30. ddalab_app/assets/icons/icon.svg +49 -0
  31. ddalab_app/backend/__init__.py +10 -0
  32. ddalab_app/backend/contracts.py +174 -0
  33. ddalab_app/backend/dda/__init__.py +73 -0
  34. ddalab_app/backend/dda/engine.py +800 -0
  35. ddalab_app/backend/dda/motifs.py +135 -0
  36. ddalab_app/backend/dda/scalar.py +709 -0
  37. ddalab_app/backend/dda/sidecar.py +224 -0
  38. ddalab_app/backend/dda/sparse.py +960 -0
  39. ddalab_app/backend/local/__init__.py +11 -0
  40. ddalab_app/backend/local/client.py +256 -0
  41. ddalab_app/backend/local/dda.py +1034 -0
  42. ddalab_app/backend/local/filesystem.py +131 -0
  43. ddalab_app/backend/local/results.py +264 -0
  44. ddalab_app/backend/local/runtime.py +175 -0
  45. ddalab_app/backend/readers/__init__.py +13 -0
  46. ddalab_app/backend/readers/common.py +297 -0
  47. ddalab_app/backend/readers/delimited.py +300 -0
  48. ddalab_app/backend/readers/local.py +96 -0
  49. ddalab_app/backend/readers/mne.py +179 -0
  50. ddalab_app/backend/readers/nifti.py +225 -0
  51. ddalab_app/backend/readers/nwb.py +189 -0
  52. ddalab_app/backend/readers/xdf.py +221 -0
  53. ddalab_app/backend/services/__init__.py +10 -0
  54. ddalab_app/backend/services/ica.py +166 -0
  55. ddalab_app/backend/services/nsg.py +696 -0
  56. ddalab_app/backend/services/openneuro.py +150 -0
  57. ddalab_app/cli/__init__.py +1 -0
  58. ddalab_app/cli/commands.py +336 -0
  59. ddalab_app/cli/constants.py +47 -0
  60. ddalab_app/cli/parser.py +294 -0
  61. ddalab_app/cli/plot_style.py +37 -0
  62. ddalab_app/cli/runtime.py +500 -0
  63. ddalab_app/cli_main.py +25 -0
  64. ddalab_app/domain/__init__.py +1 -0
  65. ddalab_app/domain/file_types.py +246 -0
  66. ddalab_app/domain/models.py +902 -0
  67. ddalab_app/gui_main.py +77 -0
  68. ddalab_app/persistence/__init__.py +3 -0
  69. ddalab_app/persistence/state_db.py +969 -0
  70. ddalab_app/runtime/bin/ddalab-backend.exe +0 -0
  71. ddalab_app/runtime_binary_names.py +10 -0
  72. ddalab_app/runtime_paths.py +93 -0
  73. ddalab_app/ui/__init__.py +13 -0
  74. ddalab_app/ui/plot_benchmarks.py +163 -0
  75. ddalab_app/ui/plot_data.py +75 -0
  76. ddalab_app/ui/plot_data_common.py +162 -0
  77. ddalab_app/ui/plot_heatmap_data.py +71 -0
  78. ddalab_app/ui/plot_layers.py +12 -0
  79. ddalab_app/ui/plot_matrix_data.py +362 -0
  80. ddalab_app/ui/plot_waveform_data.py +628 -0
  81. ddalab_app/ui/qml/QuickPlotSurface.qml +248 -0
  82. ddalab_app/ui/qml/QuickWaveformSurface.qml +316 -0
  83. ddalab_app/ui/qml/__init__.py +1 -0
  84. ddalab_app/ui/qml/workbench/Main.qml +382 -0
  85. ddalab_app/ui/qml/workbench/__init__.py +1 -0
  86. ddalab_app/ui/qml/workbench/components/ActivitySpinner.qml +39 -0
  87. ddalab_app/ui/qml/workbench/components/AnalysisInputSummary.qml +80 -0
  88. ddalab_app/ui/qml/workbench/components/AnalysisInspector.qml +206 -0
  89. ddalab_app/ui/qml/workbench/components/CdrHeatmap.qml +82 -0
  90. ddalab_app/ui/qml/workbench/components/CdrLineChart.qml +199 -0
  91. ddalab_app/ui/qml/workbench/components/CdrResultsView.qml +89 -0
  92. ddalab_app/ui/qml/workbench/components/InspectorPanel.qml +96 -0
  93. ddalab_app/ui/qml/workbench/components/LibraryRail.qml +152 -0
  94. ddalab_app/ui/qml/workbench/components/LoadingOverlay.qml +32 -0
  95. ddalab_app/ui/qml/workbench/components/NavButton.qml +34 -0
  96. ddalab_app/ui/qml/workbench/components/ResultHistoryList.qml +74 -0
  97. ddalab_app/ui/qml/workbench/components/ResultsInspector.qml +151 -0
  98. ddalab_app/ui/qml/workbench/components/SectionLabel.qml +10 -0
  99. ddalab_app/ui/qml/workbench/components/SettingsInspector.qml +134 -0
  100. ddalab_app/ui/qml/workbench/components/Toggle.qml +43 -0
  101. ddalab_app/ui/qml/workbench/components/WorkbenchButton.qml +52 -0
  102. ddalab_app/ui/qml/workbench/components/WorkbenchField.qml +24 -0
  103. ddalab_app/ui/qml/workbench/components/WorkspaceInspector.qml +124 -0
  104. ddalab_app/ui/qml/workbench/components/__init__.py +1 -0
  105. ddalab_app/ui/qml/workbench/pages/AnalysisPage.qml +220 -0
  106. ddalab_app/ui/qml/workbench/pages/ResultsPage.qml +254 -0
  107. ddalab_app/ui/qml/workbench/pages/SettingsPage.qml +51 -0
  108. ddalab_app/ui/qml/workbench/pages/WorkspacePage.qml +229 -0
  109. ddalab_app/ui/qml/workbench/pages/__init__.py +1 -0
  110. ddalab_app/ui/qt_plot_renderer.py +216 -0
  111. ddalab_app/ui/quick_plot_surface.py +776 -0
  112. ddalab_app/ui/quick_waveform_surface.py +633 -0
  113. ddalab_app/ui/render_cache.py +32 -0
  114. ddalab_app/ui/style.py +205 -0
  115. ddalab_app/update_manager.py +439 -0
  116. ddalab_app/version.py +38 -0
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: ddalab
3
+ Version: 1.2.11
4
+ Summary: DDALAB desktop application and command-line interface
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/sdraeger/DDALAB
7
+ Project-URL: Documentation, https://github.com/sdraeger/DDALAB/tree/main/packages/ddalab
8
+ Project-URL: Repository, https://github.com/sdraeger/DDALAB
9
+ Project-URL: Issues, https://github.com/sdraeger/DDALAB/issues
10
+ Requires-Python: <3.13,>=3.11
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: PySide6==6.8.2.1
13
+ Requires-Dist: requests<3,>=2.32.0
14
+ Requires-Dist: urllib3<2
15
+ Requires-Dist: numpy==1.26.4
16
+ Requires-Dist: matplotlib==3.10.8
17
+ Requires-Dist: scipy==1.13.1
18
+ Requires-Dist: scikit-learn==1.5.2
19
+ Requires-Dist: mne==1.8.0
20
+ Requires-Dist: defusedxml<1,>=0.7
21
+ Requires-Dist: pymatreader<1,>=0.0.32
22
+ Requires-Dist: mffpy<1,>=0.10
23
+ Requires-Dist: nibabel==5.3.3
24
+ Requires-Dist: pyxdf==1.16.8
25
+ Requires-Dist: pynwb==2.8.3
26
+ Requires-Dist: packaging<25,>=24
27
+
28
+ # DDALAB
29
+
30
+ `ddalab` is the unified Python package for DDALAB.
31
+
32
+ It ships:
33
+
34
+ - the command-line interface
35
+ - the Qt desktop application
36
+ - the shared local runtime and dataset readers
37
+ - the bundled `dda-rs` backend binary used for local DDA analysis
38
+
39
+ ## Entry Points
40
+
41
+ Installing this package provides:
42
+
43
+ - `ddalab`
44
+ - `ddalab-cli`
45
+ - `ddalab-gui`
46
+
47
+ Use `ddalab open` to open the desktop application. Other `ddalab` commands use
48
+ the command-line interface. `ddalab gui` remains an alias for `ddalab open`,
49
+ and `ddalab-gui` launches the application directly.
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ python -m pip install ddalab
55
+ ddalab open
56
+ ```
57
+
58
+ For a source checkout:
59
+
60
+ ```bash
61
+ cd packages/ddalab
62
+ python -m pip install .
63
+ ```
64
+
65
+ Published wheels and desktop installers bundle the local `dda-rs` backend, so DDA works offline without a separate network service.
66
+
67
+ For editable or source installs, local DDA analysis also requires a working Rust toolchain with `cargo` so the bundled `dda-rs` binary can be built for your platform.
68
+
69
+ ## CLI Examples
70
+
71
+ ```bash
72
+ ddalab health
73
+ ddalab dataset info --file data/MG100_Seizure1.edf
74
+ ddalab dda info --json
75
+ ddalab dda validate data/MG100_Seizure1.edf --json
76
+ ddalab dda run data/MG100_Seizure1.edf --channels 0 1 2 --variants ST SY --end 30
77
+ ddalab dda run data/MG100_Seizure1.edf --channels 0 1 2 --variants ST --device cuda
78
+ ddalab dda batch --bids-dir data/ds003029 --variants ST --continue-on-error
79
+ ```
80
+
81
+ CPU execution is the default. The desktop DDA setup and CLI accept CUDA on
82
+ systems with an NVIDIA driver and cuBLAS runtime; `cuda:N` selects a specific
83
+ GPU. Analyses that use Rust-only CCD extensions continue those extension
84
+ computations on the CPU.
85
+
86
+ ## Python DDA Estimators
87
+
88
+ The bundled Python backend includes scalar estimators for derivative-form and
89
+ weak-form DDA. Derivative-form DDA builds delayed polynomial features
90
+ `Phi(t)` and regresses a numerical derivative of `x(t)` on those features.
91
+ Weak-form DDA uses the same delayed polynomial dictionary, but fits integrated
92
+ increments instead:
93
+
94
+ ```text
95
+ x(t + Delta) - x(t) ~= integral_t^{t+Delta} Phi(s) ds @ beta
96
+ ```
97
+
98
+ This avoids pointwise derivative estimation and can be preferable when
99
+ observation noise would be amplified by finite differences. Coefficients remain
100
+ on the same differential-equation scale as derivative-form DDA because both the
101
+ response and design matrix are integrated over the same window.
102
+
103
+ ```python
104
+ from ddalab_app.backend.dda import DerivativeDDA, WeakFormDDA
105
+
106
+ vanilla = DerivativeDDA(degree=3, delays=[0], derivative="finite_difference")
107
+ vanilla.fit(x, dt=0.01)
108
+
109
+ weak = WeakFormDDA(
110
+ degree=3,
111
+ delays=[0],
112
+ integration_window=9,
113
+ stride=1,
114
+ quadrature="trapezoid",
115
+ regression="ridge",
116
+ ridge_alpha=1e-6,
117
+ standardize_features=True,
118
+ )
119
+ weak.fit(x, dt=0.01)
120
+ print(weak.term_names_)
121
+ print(weak.coefficients_)
122
+ ```
123
+
124
+ `integration_window` and `stride` are specified in samples. Use
125
+ `integration_window_seconds` or `stride_seconds` with `dt`/`sample_rate` when
126
+ time-based settings are more convenient. The default weak-form window is
127
+ conservative: half of the smallest positive delay, with a lower bound of three
128
+ samples, or five samples for nondelayed scalar systems. Too-small windows behave
129
+ more like derivative DDA; too-large windows can blur fast dynamics.
130
+
131
+ The available quadrature rules are `trapezoid`, `left_rectangle`,
132
+ `right_rectangle`, `midpoint`, and `simpson` when SciPy is available.
133
+ `trapezoid` is the default because it is the natural continuous-time weak-form
134
+ choice for sampled trajectories. `left_rectangle` can match an Euler-stepped
135
+ simulator more closely and is useful as a discretization diagnostic, but it is
136
+ not the recommended default for continuous-time estimation.
137
+
138
+ Weak-form DDA does not universally dominate derivative DDA. It trades derivative
139
+ noise sensitivity for integration-window bias. In practice, choose
140
+ `integration_window` on a held-out validation interval by minimizing weak-form
141
+ interval prediction error, then report the selected-window result. Oracle-best
142
+ windows, selected using known synthetic coefficients, are useful for experiments
143
+ but should be treated only as upper bounds.
144
+
145
+ For noisy or ill-conditioned windows, the recommended weak-form setting is
146
+ `regression="ridge"` with `standardize_features=True`. Feature standardization is
147
+ used only internally for numerical conditioning; exposed coefficients are
148
+ back-transformed to the original feature scale, so they remain comparable to
149
+ ordinary derivative-form DDA coefficients.
150
+
151
+ ## Weak-Form Sparse Additive DDA
152
+
153
+ The currently supported reliable Python estimator is polynomial `WeakFormDDA`.
154
+ `SparseAdditiveWeakFormDDA` is experimental infrastructure for nonlinear
155
+ main-effect delay discovery; use it for method development and diagnostics, not
156
+ as a replacement for polynomial weak-form DDA in production analyses.
157
+
158
+ Fixed polynomial dictionaries are interpretable but can be brittle when the
159
+ true delayed response is saturating, threshold-like, or otherwise smooth but not
160
+ well approximated by low-order monomials. `SparseAdditiveWeakFormDDA` replaces
161
+ polynomial terms with cubic B-spline response functions over candidate delays:
162
+
163
+ ```text
164
+ dx/dt = c + sum_tau f_tau(x(t - tau))
165
+ ```
166
+
167
+ Each response function is fit in weak form by integrating spline basis functions
168
+ over the same interval used for the observed increment. The first implementation
169
+ is scalar and main-effect only; it does not yet fit pairwise delay surfaces.
170
+ Delay selection is statistically meaningful only with group sparsity, because
171
+ all spline basis functions for one delay must enter or leave the model together.
172
+ Neighboring candidate delays can also be nearly duplicate predictors, so delay
173
+ dictionary thinning and state-coverage diagnostics are part of the estimator.
174
+
175
+ ```python
176
+ from ddalab_app.backend.dda import (
177
+ SparseAdditiveWeakFormDDA,
178
+ stability_select_sparse_additive_weak_form,
179
+ )
180
+
181
+ model = SparseAdditiveWeakFormDDA(
182
+ candidate_delays=[0, 10, 11, 24, 25, 40],
183
+ n_knots=7,
184
+ spline_degree=3,
185
+ integration_window=9,
186
+ stride=1,
187
+ quadrature="trapezoid",
188
+ regression="group_lasso",
189
+ group_lasso_alpha=0.004,
190
+ ridge_alpha=1e-6,
191
+ standardize_features=True,
192
+ thin_delays=True,
193
+ max_delay_correlation=0.98,
194
+ )
195
+ model.fit([x_trial_1, x_trial_2, x_trial_3], dt=0.01)
196
+ print(model.selected_delays_)
197
+ print(model.group_strengths_)
198
+ print(model.delay_block_correlation_)
199
+ print(model.state_coverage_)
200
+
201
+ grid, effect = model.effect_curves_[10]
202
+ ```
203
+
204
+ `fit` accepts either one scalar trajectory or a list of scalar trajectories. For
205
+ list input, spline bases are shared across trajectories and weak-form windows
206
+ are built within each trajectory only, never across trajectory boundaries.
207
+
208
+ Delay ranking is based on the L2 norm of each delay-specific spline coefficient
209
+ block. With `regression="group_lasso"`, inactive delay blocks can be driven to
210
+ zero directly. For more conservative delay selection, use stability selection
211
+ with null calibration:
212
+
213
+ ```python
214
+ scores = stability_select_sparse_additive_weak_form(
215
+ [x_trial_1, x_trial_2, x_trial_3],
216
+ dt=0.01,
217
+ candidate_delays=model.candidate_delays_,
218
+ integration_window=9,
219
+ regression="group_lasso",
220
+ group_lasso_alpha=0.004,
221
+ n_repeats=20,
222
+ null_repeats=10,
223
+ calibrate=True,
224
+ )
225
+ print(scores.selection_frequency)
226
+ print(scores.null_selection_frequency)
227
+ print(scores.calibrated_selected_delays)
228
+ ```
229
+
230
+ Prefer polynomial weak-form DDA when a low-order dictionary is scientifically
231
+ meaningful and coefficient-level interpretation is the primary output. Prefer
232
+ sparse additive weak-form DDA only when the main question is whether a small set
233
+ of candidate delays has smooth nonlinear influence and the shape of that
234
+ influence is itself informative. Current limitations are scalar input, main
235
+ effects only, sensitivity to candidate-delay collinearity, dependence on broad
236
+ state coverage, and validation-dependent choices of spline, group penalty, and
237
+ stability thresholds.
238
+
239
+ ## Choosing Between WeakFormDDA and SparseAdditiveWeakFormDDA
240
+
241
+ Use `WeakFormDDA` as the default estimator when the goal is robust recovery of
242
+ polynomial DDA coefficients or when the analysis must be stable without
243
+ additional model-selection diagnostics. It is the reliable general-purpose
244
+ Python estimator.
245
+
246
+ Use `SparseAdditiveWeakFormDDA` only as an experimental nonlinear-delay
247
+ estimator. A defensible sparse-additive analysis should use group-lasso delay
248
+ blocks, candidate-delay thinning, stability selection, null calibration, and
249
+ state-coverage checks. Sparse-additive delay selections should not be trusted
250
+ when instantaneous null diagnostics select delayed terms, even if interval
251
+ prediction error is competitive. The current estimator also cannot represent
252
+ pairwise or interacting nonlinear delayed effects; those require a future
253
+ pairwise-surface model rather than the current main-effect spline model.
254
+
255
+ ## Desktop Development
256
+
257
+ ```bash
258
+ cd packages/ddalab
259
+ ./start.sh
260
+ ```
261
+
262
+ The script provisions a local virtual environment, installs the unified package in editable mode, and launches the Qt application.
263
+
264
+ The desktop application uses a Qt Quick/QML workbench. Waveform and DDA-result
265
+ plots use viewport-aware, cached Qt Quick scene-graph surfaces; there is no
266
+ separate QWidget rendering mode.
267
+
268
+ See [ARCHITECTURE.md](ARCHITECTURE.md) for the desktop boundaries and data flow.
269
+
270
+ If you are working from source, `./start.sh` expects `cargo` to be available so it can build or refresh the bundled `dda-rs` runtime.
271
+
272
+ ## Smoke Test
273
+
274
+ ```bash
275
+ cd packages/ddalab
276
+ ./start.sh --smoke-test
277
+ ```
@@ -0,0 +1,116 @@
1
+ ddalab_app/__init__.py,sha256=YKRhpInhcIqFLhs3fSFrUy_o9HMgwFO3lPDxXG4363k,103
2
+ ddalab_app/__main__.py,sha256=Jk9YMe4tVRadNwNcM9mxdW1_tN_pkg26sis3mkW00kk,88
3
+ ddalab_app/cli_main.py,sha256=1UlDcblfWrYsuW_CmqaiF0w0vywCkK3HdRyYvJbQPGs,695
4
+ ddalab_app/gui_main.py,sha256=_8jOoBTTh3QVRR5dSGyfdtwtuCPojDHD4ddRybJhmuQ,2496
5
+ ddalab_app/runtime_binary_names.py,sha256=WwNOibNAYTXYUfOQYX52FAtZOoQMtTHjKFCJurszXH4,232
6
+ ddalab_app/runtime_paths.py,sha256=4p3bzh_-XdFMKrU7qfJwWK58JqTJUpqmQWAIa0jZpt8,2984
7
+ ddalab_app/update_manager.py,sha256=8wk_L_XW2WZC6pC1UvGr9wvXZTAvN42cp_kJaKxy1Fo,16212
8
+ ddalab_app/version.py,sha256=wr0yVXCX4U6wjc3AcG1itFbxKxKRePJCNBF5ZYM8PjI,1156
9
+ ddalab_app/app/__init__.py,sha256=Nl-gYPu5IVo422-S41L_qbnJMXULzeUlL33E2WDy4Wo,394
10
+ ddalab_app/app/core/__init__.py,sha256=LBHvoYmCg4kz2wVRNj692IFMjqEuJ3Y-VTOdz7uBdCs,33
11
+ ddalab_app/app/core/analysis_input.py,sha256=8gyK65SARoZi48pqcNLCawzOxhULgXKQbYQZGDHtIk8,1287
12
+ ddalab_app/app/core/snapshot_payload.py,sha256=yu_QBDm_3H4gI9_qNa-UMXSivl_8RUU-uDgGCnMPFjo,2778
13
+ ddalab_app/app/integrations/__init__.py,sha256=hV2ircjsAHrXw2AKsMlFMNSq4pAP09Gn5QBkbQyNhHA,48
14
+ ddalab_app/app/integrations/cdr.py,sha256=EwQkZYBEgWo21eEgKACp44suJdWPurdBo67YYijHrQs,10406
15
+ ddalab_app/app/integrations/cdr_simulation.py,sha256=rlyMabtNOIzWvISjFSUsoZHcyipKJt1S-7TYVpKltco,6713
16
+ ddalab_app/app/integrations/dda_export_utils.py,sha256=LO22y84MibdHfwq6Pdu4pHZaXPFT5xB7gmt8A8h50BU,14706
17
+ ddalab_app/app/runtime/__init__.py,sha256=LX6v7hqHEUCcFIanbkd6faYDpHkF4sme-TFgZHFUiC4,48
18
+ ddalab_app/app/runtime/perf_logging.py,sha256=Q_OXeCqHNtCjTSAwCqK2kLMMZD0gu_AL1DwJzovFdOI,2277
19
+ ddalab_app/app/runtime/runtime_logging.py,sha256=gPrFqC1-tMLXk2pvs7oWUC3ayE5fF2FSFk4-CrYq7q8,7792
20
+ ddalab_app/app/workbench/__init__.py,sha256=yBvhosFpyzoveWVbN610c8Yb7G2hEPaWQj-5Qgz5y7A,139
21
+ ddalab_app/app/workbench/controller.py,sha256=V640Fj6P8yTxzLuZQl2TwyuiqxLNaj4Kktxf1Xn-HGk,72893
22
+ ddalab_app/app/workbench/models.py,sha256=hwcJbfSLI1ltEqIxiZOXhIY8hQyaeBGD7ksY4Yn_AR8,3985
23
+ ddalab_app/app/workbench/runtime.py,sha256=ZXn1z6DVmN1H8D2oiM6z9cFHwejNc5cEyhqq_oQ6S8s,1440
24
+ ddalab_app/app/workbench/tasks.py,sha256=O1P9IwAWo0dhBjHvhvhpWeA_rF71bOtcPdedThOtRy0,1580
25
+ ddalab_app/assets/fonts/ibm_plex_sans_medium.ttf,sha256=MxyGOddZiyzeYqkRpx2xleMMtlXNa98uMkp-mElV-Qc,202460
26
+ ddalab_app/assets/fonts/ibm_plex_sans_regular.ttf,sha256=l13No32A8Djc0UPCLjPKLZegzFqSmqzhx0kVOw_hr6U,200500
27
+ ddalab_app/assets/fonts/ibm_plex_sans_semibold.ttf,sha256=ogyvgoYCOmp6heQLHSpK6fw-Ox-e2o9MVC3UmGr2e7E,202632
28
+ ddalab_app/assets/icons/icon.icns,sha256=-jt9ZDzQJZ2lmiWe13uVbZKYxBhCWgBrBOuyb5D6x-0,719367
29
+ ddalab_app/assets/icons/icon.ico,sha256=pFdwmDiX4Y_w_F40aH5El-AWb0MdoP5fvDe54T3UA20,99678
30
+ ddalab_app/assets/icons/icon.png,sha256=gcEZiLqUi0i3xiKOOci7I2Mvx6zhxAzPivzTw7ztr0Y,32619
31
+ ddalab_app/assets/icons/icon.svg,sha256=26OUw8DJz1vrL9uTugHFztGqM8RNPEL4zHAgJPYkpcw,1867
32
+ ddalab_app/backend/__init__.py,sha256=EjzlFTQrjHgu5TxV-AZOpLNQsmvXfTvezYIg_4WMN04,254
33
+ ddalab_app/backend/contracts.py,sha256=wV1zecq0M7wP_OL0URTCIB0tPIVCJcyjN6Pc-C5xw1o,4811
34
+ ddalab_app/backend/dda/__init__.py,sha256=B9pvY05NBZEIUMg9n_-o7Gf7tOIaeJEuG3Jh8gobcuQ,2151
35
+ ddalab_app/backend/dda/engine.py,sha256=PVhgb3dHBcVA8DjabBuUdFBFEF4-I-sxLjxnKuzYE0U,28612
36
+ ddalab_app/backend/dda/motifs.py,sha256=oPq94AGZoc_5JxkpjDO400ro185FtDDYiJJAjp8Omeg,4698
37
+ ddalab_app/backend/dda/scalar.py,sha256=Iau1Ljaf2xoz1a2NwtuMDSySlN85QQC42pF2_8l66RI,24132
38
+ ddalab_app/backend/dda/sidecar.py,sha256=87BmQoBdC11yW1sRAvhGwevSXcPzrby4QC2_74vct9o,7874
39
+ ddalab_app/backend/dda/sparse.py,sha256=TKgFDRW2pX9en0K2FxXB9Js84U4z-cbj-GBK4t_HZdI,36904
40
+ ddalab_app/backend/local/__init__.py,sha256=VgaxGkVdpaktLe4mJEB_ypf6rHuR_NlUY6W3Ee3TJe0,234
41
+ ddalab_app/backend/local/client.py,sha256=_WBNcQPWbDA_bHcWfKhXDQfUio3N_aX_EPOfjm2hZc4,9102
42
+ ddalab_app/backend/local/dda.py,sha256=0TWzrt-3d_8k4QAxOYbVl6fCrcyp8J2l_A--noFNjjI,40108
43
+ ddalab_app/backend/local/filesystem.py,sha256=yS3uwmf5Aojj3HvZJ3jw0LKHbILAN3PONAGmp29oYJU,4641
44
+ ddalab_app/backend/local/results.py,sha256=pt6BlDByQhkhXXNjxzQjm9wvIFf-SK7fEb9-STrbsmY,9143
45
+ ddalab_app/backend/local/runtime.py,sha256=fvqAlB-lLtMkIQeTa13riqWvi4ylwKGoOVabFLHoyMM,5647
46
+ ddalab_app/backend/readers/__init__.py,sha256=QlnWBE98mlNzXPzA_jOLEjlZKx1wRh_BeGFh884MRiY,299
47
+ ddalab_app/backend/readers/common.py,sha256=pn3BbzsK1MwPy_RGRb-_00kfgUb49VnUWeH6RF9xy1c,8929
48
+ ddalab_app/backend/readers/delimited.py,sha256=ktEHhytsi-Ch8a_j9x2cNvGZbcottDr7zeqqDpWzwes,10728
49
+ ddalab_app/backend/readers/local.py,sha256=tQN8aN9tPZNDhkjQIsZ-xE-FljQ6ZCWZIkg1rZNhrRs,2587
50
+ ddalab_app/backend/readers/mne.py,sha256=c_BuDmhKs7_a8XX3G1zl0d8Qml_5T86_6zK5QK62_oY,6295
51
+ ddalab_app/backend/readers/nifti.py,sha256=1YfiQoRz351qF-RsUpFLE-zhzAiqywBI3j_2OmPXbGA,8173
52
+ ddalab_app/backend/readers/nwb.py,sha256=zNamTE5jDjMDGiekT7CMBNsH1NyO_ssUx7J619ZGrrA,6727
53
+ ddalab_app/backend/readers/xdf.py,sha256=PkNnad2YN1ssFX7uSPbCGS9P8i7Bap9eZQaGUHObkps,7631
54
+ ddalab_app/backend/services/__init__.py,sha256=QJv9t4bmQbSI3k4a-xPr94FLeFpTythkN-zDAyrDx8U,253
55
+ ddalab_app/backend/services/ica.py,sha256=9N0v8GvT10ZIB9KIqBrqT97qO5e-60H5voJK34NUhLk,5805
56
+ ddalab_app/backend/services/nsg.py,sha256=Z0lsFm2GjALIWq2Fky4y9pIz6DchQUYgBsBI4S0-L-0,25572
57
+ ddalab_app/backend/services/openneuro.py,sha256=xOVnMp2mOu_rKxoP_I_1QZ8ip71nqB79Sj8FQtBLWMg,4658
58
+ ddalab_app/cli/__init__.py,sha256=bFFVE9jRKczNy4HhmegWoC6KOL_Nrej-ag37DAIDzaA,36
59
+ ddalab_app/cli/commands.py,sha256=UTSzEE18mrD3AKceruxK6E_p8bbC6pLR4cSoufX5Jms,11275
60
+ ddalab_app/cli/constants.py,sha256=lvczhH-2rL-w66USvvWWqxvVk3ox4GxAFnMgPPZ46Gk,1379
61
+ ddalab_app/cli/parser.py,sha256=8UMlqk4rYIstnzCaKVS32uSLk12PE5fDF47dOtnfjEE,10279
62
+ ddalab_app/cli/plot_style.py,sha256=34hKnC4bg34r1KlKOqesP28Kv0SjFAZwmklJje9LTpQ,1168
63
+ ddalab_app/cli/runtime.py,sha256=gO-A0bFQINCc-krBjr2wmTTK0b8LAgckYcK6qPxOj6o,18200
64
+ ddalab_app/domain/__init__.py,sha256=Hi8XD2DicapE64k3jc2oAxGs3-dInkmp-f03NDKEfmk,60
65
+ ddalab_app/domain/file_types.py,sha256=pLObJBAniDijJrceXQjzX1VQ4XgUgtpQX8cvXXMlZYk,7471
66
+ ddalab_app/domain/models.py,sha256=N9xYT7z02sZiPW2oYkBb1_-6_xghjWtq2ELxVT1yqKA,31852
67
+ ddalab_app/persistence/__init__.py,sha256=DKQN6zQTekOZh8SHTKGRZ9RfvAzgk2jg3afXGmGRLNw,68
68
+ ddalab_app/persistence/state_db.py,sha256=jDFhyBI8tdxnksHAvTwpUc4UxVUr8mjfYHLHc7Abkjc,35376
69
+ ddalab_app/runtime/bin/ddalab-backend.exe,sha256=VgUkXxRHuq9Uy5EilWJtz5tiVGOJOJ8ZZ5uV7qhFGrg,2724864
70
+ ddalab_app/ui/__init__.py,sha256=Z2CetSy5ceJDCuajBd3ESYcY3Ftn6kaj0yVtTHSU0J0,245
71
+ ddalab_app/ui/plot_benchmarks.py,sha256=2SA7a28uLkFQ4ImZnz-hLLvVnNO8dT2h73e4VM24U5U,5216
72
+ ddalab_app/ui/plot_data.py,sha256=wXjI0pJS9_SFPmTRfowjJ1gZz8IrPEzn0ODljGze25Q,2072
73
+ ddalab_app/ui/plot_data_common.py,sha256=wGU7emw61eP9-VkqHA89D7JPXsim2ejMjMQtaV2rg-o,4215
74
+ ddalab_app/ui/plot_heatmap_data.py,sha256=2Lw8rOYIs32lKFfYxjuQbvpunWK3VLdWiyfJTpgnE8s,2775
75
+ ddalab_app/ui/plot_layers.py,sha256=L43iS5TpktldOKzJf9hZlViwd3d8F9vuEfLjbwUzruk,257
76
+ ddalab_app/ui/plot_matrix_data.py,sha256=RQ5YhIVQM-S3kpRVyjl52K-gdvkh1TsIwIRURxopjU0,11573
77
+ ddalab_app/ui/plot_waveform_data.py,sha256=rFo93LLL6GCsTfVFln7oLtWmQQXpuKVVqhQgCE308Mc,20940
78
+ ddalab_app/ui/qt_plot_renderer.py,sha256=RhUzNq-Ku2fa3GJCP7fOZHqvuSiJUn7Vkfe71aFC-3Y,6493
79
+ ddalab_app/ui/quick_plot_surface.py,sha256=U29C3Zq74rMVIDrGHF6AWzT-f3YcsNRllX35ZfryMMI,26015
80
+ ddalab_app/ui/quick_waveform_surface.py,sha256=CM2ho5bYdjg9wSCYg0v76pi0c7j-DgupktpxNJxDmhg,21747
81
+ ddalab_app/ui/render_cache.py,sha256=E6OZw4v5rN-bwje5PK3P3YxO0zfePytW3XjZJIMQ_Xo,903
82
+ ddalab_app/ui/style.py,sha256=dTOQL_3yVjeW2-uvSX3qfPO8d_0pZplFava_Y9F9h_s,6689
83
+ ddalab_app/ui/qml/QuickPlotSurface.qml,sha256=Y_N0abEpOeJLAIV34gv1MFdhuFfPsuyzafyiGi2aPH0,9637
84
+ ddalab_app/ui/qml/QuickWaveformSurface.qml,sha256=yQYUdVHwQ2x6xjILkiCXEXJA6pPRVGDibivuaUvq7DM,11934
85
+ ddalab_app/ui/qml/__init__.py,sha256=7aBq1lfxIG5FLTuCLWhDQIRB6Q0QiZBmc6yaH2vH9XQ,72
86
+ ddalab_app/ui/qml/workbench/Main.qml,sha256=H_gCWdtwxJSaScJdCYRxqh4DaWlJdvn3MGd8rlC5i78,13340
87
+ ddalab_app/ui/qml/workbench/__init__.py,sha256=DPkO2mOqDlO2axsS3Of4wqENeO9q6XxR6U6zmibq8Gc,37
88
+ ddalab_app/ui/qml/workbench/components/ActivitySpinner.qml,sha256=EdapSc4n3XwVbkVrm2pUEKGkopennzjw5o3Is8caCR0,785
89
+ ddalab_app/ui/qml/workbench/components/AnalysisInputSummary.qml,sha256=uKHgGVvT83ThtWFFi0biwNuzAOaYQIfnktOnvRnvCBs,2554
90
+ ddalab_app/ui/qml/workbench/components/AnalysisInspector.qml,sha256=4bEVIVX2JszT4zl9NfALl501IItaCBKsVLXAY0065_s,7616
91
+ ddalab_app/ui/qml/workbench/components/CdrHeatmap.qml,sha256=ZZReFJI3UXURKxekyv_6np57aES_Oi-9n-rBIRO8rXQ,3013
92
+ ddalab_app/ui/qml/workbench/components/CdrLineChart.qml,sha256=a2BRmfRZOfykBpdh6WBd6Hy8t9lh4KvdN-k_Wvi7apU,8200
93
+ ddalab_app/ui/qml/workbench/components/CdrResultsView.qml,sha256=SmOFDKu3NdJwfL5Fp8QAmSmGR_XvafykTU1uVT__s44,2433
94
+ ddalab_app/ui/qml/workbench/components/InspectorPanel.qml,sha256=8XCeusls7G0mQM0wSf3ykU-gkmqG02Kv07D-jmqbMiY,3260
95
+ ddalab_app/ui/qml/workbench/components/LibraryRail.qml,sha256=RhZYuPonGMdfpX-imFPglB7-aXT-YR_2x6ImazGS5Hc,5016
96
+ ddalab_app/ui/qml/workbench/components/LoadingOverlay.qml,sha256=pwu39ayNT6EiLZK5d_NtvbGMFETPbFZ8NMG4yH322rU,704
97
+ ddalab_app/ui/qml/workbench/components/NavButton.qml,sha256=ziVw23WLROYBJpVpAwoIo_llAeJfvVnyqoVNej6X6ac,886
98
+ ddalab_app/ui/qml/workbench/components/ResultHistoryList.qml,sha256=axLmWhCBuj6fxL5nmKdNX6MEQYsDnGTI9xUZ1-Kg6yY,1932
99
+ ddalab_app/ui/qml/workbench/components/ResultsInspector.qml,sha256=toKlTL7Ibpzv4OIaX3TuyCCty0t_BQJ8nqeF95MAEj8,4860
100
+ ddalab_app/ui/qml/workbench/components/SectionLabel.qml,sha256=5D78qV3yoxqpxuV1teRgAvCfMpfRmj0KzrhaTVxaZog,174
101
+ ddalab_app/ui/qml/workbench/components/SettingsInspector.qml,sha256=HkVR4c1EdaoABWN5aL8mJYErDKOGQWJKqKdhYe7Fo5o,4050
102
+ ddalab_app/ui/qml/workbench/components/Toggle.qml,sha256=jJk1kKxUsEvhtg3KSDCLAMStyXNBBO4tCv5xTPRsaJA,1144
103
+ ddalab_app/ui/qml/workbench/components/WorkbenchButton.qml,sha256=kycnNl2WyoeBP7eUJd6poM-sQeWxZsThYCsbyFvfgtQ,1606
104
+ ddalab_app/ui/qml/workbench/components/WorkbenchField.qml,sha256=fGXJpjsuNauy10DFj1w4tEhaRp0oactLnqUgy5rQyfQ,561
105
+ ddalab_app/ui/qml/workbench/components/WorkspaceInspector.qml,sha256=4w4USbJOTslm1sX_x8osuFEDmwFfBcK4dpAMa27XJ94,4035
106
+ ddalab_app/ui/qml/workbench/components/__init__.py,sha256=NgYAbZxtCPTuzNbWu6NNrYhie1c8V6LiXHhXYBfQNpc,37
107
+ ddalab_app/ui/qml/workbench/pages/AnalysisPage.qml,sha256=C2P9vBMr3xtesYYQ5u69RJ09AHk621x-DC6EJU5L3z0,9274
108
+ ddalab_app/ui/qml/workbench/pages/ResultsPage.qml,sha256=1yo3gzn0DFlpLYbbmhB0m6hmcXsuMugRtTBqv6wsRDc,10416
109
+ ddalab_app/ui/qml/workbench/pages/SettingsPage.qml,sha256=i-1CvtfftqVedu8LWEzfEpLdavdn_c-AtiIp_lwy4FY,1293
110
+ ddalab_app/ui/qml/workbench/pages/WorkspacePage.qml,sha256=XL3kaVNNrhaJjpW0Aa1olfaoKhRdstgMdCP6Ro0G8jU,9563
111
+ ddalab_app/ui/qml/workbench/pages/__init__.py,sha256=GIQ00j6UixZn_KzluWKExcWBD8NkYTFIcPEFkZTGTzY,31
112
+ ddalab-1.2.11.dist-info/METADATA,sha256=kEm1HG88h_J28P7fuNXOPX7b_l0_wQ5Qd7RtFK-wGpk,10755
113
+ ddalab-1.2.11.dist-info/WHEEL,sha256=Zx98gwb_dQKckJK3HEOVKnxxD52EfU_PXDG_usMJ2ng,98
114
+ ddalab-1.2.11.dist-info/entry_points.txt,sha256=G1j5iVXh-26MI9fcJFTIa5QTWOZeR6s-8H_UQjSUEzc,128
115
+ ddalab-1.2.11.dist-info/top_level.txt,sha256=o4GDxaoK1ej70LrJjAx2U_XqlkZkqZB2MVmq75likkw,11
116
+ ddalab-1.2.11.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.0.0)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
5
+
@@ -0,0 +1,4 @@
1
+ [console_scripts]
2
+ ddalab = ddalab_app.__main__:main
3
+ ddalab-cli = ddalab_app.__main__:main
4
+ ddalab-gui = ddalab_app.gui_main:main
@@ -0,0 +1 @@
1
+ ddalab_app
ddalab_app/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """DDALAB Qt prototype."""
2
+
3
+ from .version import get_app_version
4
+
5
+ __version__ = get_app_version()
ddalab_app/__main__.py ADDED
@@ -0,0 +1,4 @@
1
+ from .cli_main import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ __all__ = ["WorkbenchController", "build_workbench"]
4
+
5
+
6
+ def __getattr__(name: str):
7
+ if name in __all__:
8
+ from .workbench import WorkbenchController, build_workbench
9
+
10
+ return {
11
+ "WorkbenchController": WorkbenchController,
12
+ "build_workbench": build_workbench,
13
+ }[name]
14
+ raise AttributeError(name)
@@ -0,0 +1 @@
1
+ """Shared app-level helpers."""
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional
4
+
5
+
6
+ def parse_time_bounds(
7
+ start_text: str,
8
+ end_text: str,
9
+ *,
10
+ label: str,
11
+ default_start: Optional[float] = 0.0,
12
+ ) -> tuple[Optional[float], Optional[float]]:
13
+ start = _parse_optional_seconds(
14
+ start_text,
15
+ field_name=f"{label} start",
16
+ default=default_start,
17
+ )
18
+ end = _parse_optional_seconds(
19
+ end_text,
20
+ field_name=f"{label} end",
21
+ default=None,
22
+ )
23
+ if start is not None and start < 0:
24
+ raise ValueError(f"{label} start must be greater than or equal to 0.")
25
+ if end is not None and end < 0:
26
+ raise ValueError(f"{label} end must be greater than or equal to 0.")
27
+ if start is not None and end is not None and end <= start:
28
+ raise ValueError(f"{label} end must be greater than the start time.")
29
+ return start, end
30
+
31
+
32
+ def _parse_optional_seconds(
33
+ raw_text: str,
34
+ *,
35
+ field_name: str,
36
+ default: Optional[float],
37
+ ) -> Optional[float]:
38
+ text = str(raw_text or "").strip()
39
+ if not text:
40
+ return default
41
+ try:
42
+ return float(text)
43
+ except ValueError as exc:
44
+ raise ValueError(f"{field_name} must be a valid number of seconds.") from exc
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+
8
+ def relink_snapshot_payload(
9
+ payload: dict,
10
+ *,
11
+ old_path: str,
12
+ new_path: str,
13
+ ) -> dict:
14
+ rewritten = deepcopy(payload)
15
+ rewritten["activeFilePath"] = _replace_exact_path(
16
+ rewritten.get("activeFilePath"),
17
+ old_path,
18
+ new_path,
19
+ )
20
+ rewritten["openFiles"] = _replace_path_list(
21
+ rewritten.get("openFiles"),
22
+ old_path,
23
+ new_path,
24
+ )
25
+ rewritten["pinnedFiles"] = _replace_path_list(
26
+ rewritten.get("pinnedFiles"),
27
+ old_path,
28
+ new_path,
29
+ )
30
+ annotations = rewritten.get("annotationsByFile")
31
+ if isinstance(annotations, dict):
32
+ remapped: dict[str, object] = {}
33
+ for key, value in annotations.items():
34
+ remapped[new_path if key == old_path else str(key)] = value
35
+ rewritten["annotationsByFile"] = remapped
36
+ _rewrite_result_path(rewritten.get("ddaResult"), old_path, new_path)
37
+ _rewrite_result_path(rewritten.get("icaResult"), old_path, new_path)
38
+ return rewritten
39
+
40
+
41
+ def first_missing_snapshot_source(payload: dict) -> Optional[str]:
42
+ active_file = payload.get("activeFilePath")
43
+ return active_file if isinstance(active_file, str) and active_file else None
44
+
45
+
46
+ def missing_snapshot_source_name(payload: dict, missing_path: str) -> str:
47
+ active_file = payload.get("activeFilePath")
48
+ if isinstance(active_file, str) and active_file:
49
+ return Path(active_file).name
50
+ if missing_path:
51
+ return Path(missing_path).name
52
+ dda_result = payload.get("ddaResult")
53
+ if isinstance(dda_result, dict):
54
+ for key in ("fileName", "file_name"):
55
+ value = dda_result.get(key)
56
+ if isinstance(value, str) and value:
57
+ return value
58
+ return "snapshot dataset"
59
+
60
+
61
+ def _replace_exact_path(value: object, old_path: str, new_path: str) -> object:
62
+ if isinstance(value, str) and value == old_path:
63
+ return new_path
64
+ return value
65
+
66
+
67
+ def _replace_path_list(value: object, old_path: str, new_path: str) -> list[str]:
68
+ if not isinstance(value, list):
69
+ return []
70
+ rewritten: list[str] = []
71
+ for item in value:
72
+ if not isinstance(item, str) or not item:
73
+ continue
74
+ rewritten.append(new_path if item == old_path else item)
75
+ return rewritten
76
+
77
+
78
+ def _rewrite_result_path(payload: object, old_path: str, new_path: str) -> None:
79
+ if not isinstance(payload, dict):
80
+ return
81
+ for key in ("filePath", "file_path"):
82
+ value = payload.get(key)
83
+ if isinstance(value, str) and value == old_path:
84
+ payload[key] = new_path
@@ -0,0 +1 @@
1
+ """External integration and export actions."""