datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.1__py3-none-any.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 (496) hide show
  1. datalab/__init__.py +35 -2
  2. datalab/adapters_metadata/__init__.py +31 -0
  3. datalab/adapters_metadata/base_adapter.py +316 -0
  4. datalab/adapters_metadata/common.py +422 -0
  5. datalab/adapters_metadata/geometry_adapter.py +98 -0
  6. datalab/adapters_metadata/table_adapter.py +84 -0
  7. datalab/adapters_plotpy/__init__.py +54 -0
  8. datalab/adapters_plotpy/annotations.py +124 -0
  9. datalab/adapters_plotpy/base.py +110 -0
  10. datalab/adapters_plotpy/converters.py +86 -0
  11. datalab/adapters_plotpy/factories.py +80 -0
  12. datalab/adapters_plotpy/objects/__init__.py +0 -0
  13. datalab/adapters_plotpy/objects/base.py +197 -0
  14. datalab/adapters_plotpy/objects/image.py +157 -0
  15. datalab/adapters_plotpy/objects/scalar.py +565 -0
  16. datalab/adapters_plotpy/objects/signal.py +264 -0
  17. datalab/adapters_plotpy/roi/__init__.py +0 -0
  18. datalab/adapters_plotpy/roi/base.py +146 -0
  19. datalab/adapters_plotpy/roi/factory.py +93 -0
  20. datalab/adapters_plotpy/roi/image.py +207 -0
  21. datalab/adapters_plotpy/roi/signal.py +72 -0
  22. datalab/app.py +98 -0
  23. datalab/config.py +817 -0
  24. datalab/control/__init__.py +0 -0
  25. datalab/control/baseproxy.py +776 -0
  26. datalab/control/proxy.py +343 -0
  27. datalab/control/remote.py +1005 -0
  28. datalab/data/doc/DataLab_en.pdf +0 -0
  29. datalab/data/doc/DataLab_fr.pdf +0 -0
  30. datalab/data/icons/analysis/delete_results.svg +109 -0
  31. datalab/data/icons/analysis/fw1e2.svg +156 -0
  32. datalab/data/icons/analysis/fwhm.svg +156 -0
  33. datalab/data/icons/analysis/histogram.svg +49 -0
  34. datalab/data/icons/analysis/peak_detect.svg +160 -0
  35. datalab/data/icons/analysis/plot_results.svg +151 -0
  36. datalab/data/icons/analysis/show_results.svg +83 -0
  37. datalab/data/icons/analysis/stats.svg +49 -0
  38. datalab/data/icons/analysis.svg +120 -0
  39. datalab/data/icons/apply.svg +3 -0
  40. datalab/data/icons/check_all.svg +15 -0
  41. datalab/data/icons/collapse.svg +44 -0
  42. datalab/data/icons/collapse_selection.svg +63 -0
  43. datalab/data/icons/console.svg +101 -0
  44. datalab/data/icons/create/1d-normal.svg +8 -0
  45. datalab/data/icons/create/1d-poisson.svg +9 -0
  46. datalab/data/icons/create/1d-uniform.svg +8 -0
  47. datalab/data/icons/create/1d-zero.svg +57 -0
  48. datalab/data/icons/create/2d-gaussian.svg +56 -0
  49. datalab/data/icons/create/2d-normal.svg +38 -0
  50. datalab/data/icons/create/2d-poisson.svg +38 -0
  51. datalab/data/icons/create/2d-ramp.svg +90 -0
  52. datalab/data/icons/create/2d-sinc.svg +62 -0
  53. datalab/data/icons/create/2d-uniform.svg +38 -0
  54. datalab/data/icons/create/2d-zero.svg +13 -0
  55. datalab/data/icons/create/checkerboard.svg +39 -0
  56. datalab/data/icons/create/cosine.svg +12 -0
  57. datalab/data/icons/create/exponential.svg +55 -0
  58. datalab/data/icons/create/gaussian.svg +12 -0
  59. datalab/data/icons/create/grating.svg +29 -0
  60. datalab/data/icons/create/linear_chirp.svg +7 -0
  61. datalab/data/icons/create/logistic.svg +7 -0
  62. datalab/data/icons/create/lorentzian.svg +12 -0
  63. datalab/data/icons/create/planck.svg +12 -0
  64. datalab/data/icons/create/polynomial.svg +7 -0
  65. datalab/data/icons/create/pulse.svg +12 -0
  66. datalab/data/icons/create/ring.svg +18 -0
  67. datalab/data/icons/create/sawtooth.svg +7 -0
  68. datalab/data/icons/create/siemens.svg +35 -0
  69. datalab/data/icons/create/sinc.svg +12 -0
  70. datalab/data/icons/create/sine.svg +7 -0
  71. datalab/data/icons/create/square.svg +7 -0
  72. datalab/data/icons/create/square_pulse.svg +7 -0
  73. datalab/data/icons/create/step.svg +7 -0
  74. datalab/data/icons/create/step_pulse.svg +12 -0
  75. datalab/data/icons/create/triangle.svg +7 -0
  76. datalab/data/icons/create/voigt.svg +12 -0
  77. datalab/data/icons/edit/annotations.svg +72 -0
  78. datalab/data/icons/edit/annotations_copy.svg +114 -0
  79. datalab/data/icons/edit/annotations_delete.svg +83 -0
  80. datalab/data/icons/edit/annotations_edit.svg +98 -0
  81. datalab/data/icons/edit/annotations_export.svg +85 -0
  82. datalab/data/icons/edit/annotations_import.svg +85 -0
  83. datalab/data/icons/edit/annotations_paste.svg +100 -0
  84. datalab/data/icons/edit/copy_titles.svg +109 -0
  85. datalab/data/icons/edit/delete.svg +84 -0
  86. datalab/data/icons/edit/delete_all.svg +214 -0
  87. datalab/data/icons/edit/duplicate.svg +64 -0
  88. datalab/data/icons/edit/goto_source.svg +60 -0
  89. datalab/data/icons/edit/metadata.svg +60 -0
  90. datalab/data/icons/edit/metadata_add.svg +80 -0
  91. datalab/data/icons/edit/metadata_copy.svg +96 -0
  92. datalab/data/icons/edit/metadata_delete.svg +62 -0
  93. datalab/data/icons/edit/metadata_export.svg +68 -0
  94. datalab/data/icons/edit/metadata_import.svg +68 -0
  95. datalab/data/icons/edit/metadata_paste.svg +79 -0
  96. datalab/data/icons/edit/move_down.svg +55 -0
  97. datalab/data/icons/edit/move_up.svg +54 -0
  98. datalab/data/icons/edit/new_group.svg +76 -0
  99. datalab/data/icons/edit/recompute.svg +60 -0
  100. datalab/data/icons/edit/rename.svg +49 -0
  101. datalab/data/icons/edit.svg +16 -0
  102. datalab/data/icons/expand.svg +44 -0
  103. datalab/data/icons/expand_selection.svg +63 -0
  104. datalab/data/icons/fit/cdf_fit.svg +56 -0
  105. datalab/data/icons/fit/exponential_fit.svg +55 -0
  106. datalab/data/icons/fit/gaussian_fit.svg +62 -0
  107. datalab/data/icons/fit/interactive_fit.svg +101 -0
  108. datalab/data/icons/fit/linear_fit.svg +57 -0
  109. datalab/data/icons/fit/lorentzian_fit.svg +209 -0
  110. datalab/data/icons/fit/multigaussian_fit.svg +85 -0
  111. datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
  112. datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
  113. datalab/data/icons/fit/planckian_fit.svg +62 -0
  114. datalab/data/icons/fit/polynomial_fit.svg +59 -0
  115. datalab/data/icons/fit/sigmoid_fit.svg +56 -0
  116. datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
  117. datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
  118. datalab/data/icons/fit/voigt_fit.svg +57 -0
  119. datalab/data/icons/group.svg +56 -0
  120. datalab/data/icons/h5/h5array.svg +59 -0
  121. datalab/data/icons/h5/h5attrs.svg +75 -0
  122. datalab/data/icons/h5/h5browser.svg +133 -0
  123. datalab/data/icons/h5/h5file.svg +69 -0
  124. datalab/data/icons/h5/h5group.svg +49 -0
  125. datalab/data/icons/h5/h5scalar.svg +1 -0
  126. datalab/data/icons/help_pdf.svg +46 -0
  127. datalab/data/icons/history.svg +7 -0
  128. datalab/data/icons/image.svg +135 -0
  129. datalab/data/icons/io/fileopen_directory.svg +60 -0
  130. datalab/data/icons/io/fileopen_h5.svg +84 -0
  131. datalab/data/icons/io/fileopen_ima.svg +187 -0
  132. datalab/data/icons/io/fileopen_py.svg +123 -0
  133. datalab/data/icons/io/fileopen_sig.svg +138 -0
  134. datalab/data/icons/io/filesave_h5.svg +97 -0
  135. datalab/data/icons/io/filesave_ima.svg +200 -0
  136. datalab/data/icons/io/filesave_py.svg +136 -0
  137. datalab/data/icons/io/filesave_sig.svg +151 -0
  138. datalab/data/icons/io/import_text.svg +144 -0
  139. datalab/data/icons/io/save_to_directory.svg +134 -0
  140. datalab/data/icons/io.svg +84 -0
  141. datalab/data/icons/libre-camera-flash-off.svg +1 -0
  142. datalab/data/icons/libre-camera-flash-on.svg +1 -0
  143. datalab/data/icons/libre-gui-about.svg +1 -0
  144. datalab/data/icons/libre-gui-action-delete.svg +1 -0
  145. datalab/data/icons/libre-gui-add.svg +1 -0
  146. datalab/data/icons/libre-gui-arrow-down.svg +1 -0
  147. datalab/data/icons/libre-gui-arrow-left.svg +1 -0
  148. datalab/data/icons/libre-gui-arrow-right.svg +1 -0
  149. datalab/data/icons/libre-gui-arrow-up.svg +1 -0
  150. datalab/data/icons/libre-gui-close.svg +40 -0
  151. datalab/data/icons/libre-gui-cogs.svg +1 -0
  152. datalab/data/icons/libre-gui-globe.svg +1 -0
  153. datalab/data/icons/libre-gui-help.svg +1 -0
  154. datalab/data/icons/libre-gui-link.svg +1 -0
  155. datalab/data/icons/libre-gui-menu.svg +1 -0
  156. datalab/data/icons/libre-gui-pencil.svg +1 -0
  157. datalab/data/icons/libre-gui-plugin.svg +1 -0
  158. datalab/data/icons/libre-gui-questions.svg +1 -0
  159. datalab/data/icons/libre-gui-settings.svg +1 -0
  160. datalab/data/icons/libre-gui-unlink.svg +1 -0
  161. datalab/data/icons/libre-tech-ram.svg +1 -0
  162. datalab/data/icons/libre-toolbox.svg +1 -0
  163. datalab/data/icons/logs.svg +1 -0
  164. datalab/data/icons/markers.svg +74 -0
  165. datalab/data/icons/menu.svg +13 -0
  166. datalab/data/icons/new_ima.svg +148 -0
  167. datalab/data/icons/new_sig.svg +123 -0
  168. datalab/data/icons/operations/abs.svg +116 -0
  169. datalab/data/icons/operations/arithmetic.svg +123 -0
  170. datalab/data/icons/operations/average.svg +124 -0
  171. datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
  172. datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
  173. datalab/data/icons/operations/constant.svg +116 -0
  174. datalab/data/icons/operations/constant_add.svg +109 -0
  175. datalab/data/icons/operations/constant_divide.svg +109 -0
  176. datalab/data/icons/operations/constant_multiply.svg +109 -0
  177. datalab/data/icons/operations/constant_subtract.svg +109 -0
  178. datalab/data/icons/operations/convert_dtype.svg +117 -0
  179. datalab/data/icons/operations/convolution.svg +46 -0
  180. datalab/data/icons/operations/deconvolution.svg +57 -0
  181. datalab/data/icons/operations/derivative.svg +127 -0
  182. datalab/data/icons/operations/difference.svg +52 -0
  183. datalab/data/icons/operations/division.svg +139 -0
  184. datalab/data/icons/operations/exp.svg +116 -0
  185. datalab/data/icons/operations/flip_horizontally.svg +69 -0
  186. datalab/data/icons/operations/flip_vertically.svg +74 -0
  187. datalab/data/icons/operations/im.svg +124 -0
  188. datalab/data/icons/operations/integral.svg +50 -0
  189. datalab/data/icons/operations/inverse.svg +143 -0
  190. datalab/data/icons/operations/log10.svg +109 -0
  191. datalab/data/icons/operations/phase.svg +116 -0
  192. datalab/data/icons/operations/power.svg +118 -0
  193. datalab/data/icons/operations/product.svg +124 -0
  194. datalab/data/icons/operations/profile.svg +379 -0
  195. datalab/data/icons/operations/profile_average.svg +399 -0
  196. datalab/data/icons/operations/profile_radial.svg +261 -0
  197. datalab/data/icons/operations/profile_segment.svg +262 -0
  198. datalab/data/icons/operations/quadratic_difference.svg +84 -0
  199. datalab/data/icons/operations/re.svg +124 -0
  200. datalab/data/icons/operations/rotate_left.svg +72 -0
  201. datalab/data/icons/operations/rotate_right.svg +72 -0
  202. datalab/data/icons/operations/signals_to_image.svg +314 -0
  203. datalab/data/icons/operations/sqrt.svg +110 -0
  204. datalab/data/icons/operations/std.svg +124 -0
  205. datalab/data/icons/operations/sum.svg +102 -0
  206. datalab/data/icons/play_demo.svg +9 -0
  207. datalab/data/icons/processing/axis_transform.svg +62 -0
  208. datalab/data/icons/processing/bandpass.svg +79 -0
  209. datalab/data/icons/processing/bandstop.svg +71 -0
  210. datalab/data/icons/processing/binning.svg +126 -0
  211. datalab/data/icons/processing/clip.svg +119 -0
  212. datalab/data/icons/processing/detrending.svg +173 -0
  213. datalab/data/icons/processing/distribute_on_grid.svg +769 -0
  214. datalab/data/icons/processing/edge_detection.svg +46 -0
  215. datalab/data/icons/processing/erase.svg +1 -0
  216. datalab/data/icons/processing/exposure.svg +143 -0
  217. datalab/data/icons/processing/fourier.svg +104 -0
  218. datalab/data/icons/processing/highpass.svg +59 -0
  219. datalab/data/icons/processing/interpolation.svg +71 -0
  220. datalab/data/icons/processing/level_adjustment.svg +70 -0
  221. datalab/data/icons/processing/lowpass.svg +60 -0
  222. datalab/data/icons/processing/morphology.svg +49 -0
  223. datalab/data/icons/processing/noise_addition.svg +114 -0
  224. datalab/data/icons/processing/noise_reduction.svg +38 -0
  225. datalab/data/icons/processing/normalize.svg +84 -0
  226. datalab/data/icons/processing/offset_correction.svg +131 -0
  227. datalab/data/icons/processing/resampling1d.svg +101 -0
  228. datalab/data/icons/processing/resampling2d.svg +240 -0
  229. datalab/data/icons/processing/reset_positions.svg +185 -0
  230. datalab/data/icons/processing/resize.svg +9 -0
  231. datalab/data/icons/processing/reverse_signal_x.svg +171 -0
  232. datalab/data/icons/processing/stability.svg +11 -0
  233. datalab/data/icons/processing/swap_x_y.svg +65 -0
  234. datalab/data/icons/processing/thresholding.svg +63 -0
  235. datalab/data/icons/processing/windowing.svg +45 -0
  236. datalab/data/icons/properties.svg +26 -0
  237. datalab/data/icons/reset.svg +9 -0
  238. datalab/data/icons/restore.svg +40 -0
  239. datalab/data/icons/roi/roi.svg +76 -0
  240. datalab/data/icons/roi/roi_coordinate.svg +78 -0
  241. datalab/data/icons/roi/roi_copy.svg +112 -0
  242. datalab/data/icons/roi/roi_delete.svg +81 -0
  243. datalab/data/icons/roi/roi_export.svg +87 -0
  244. datalab/data/icons/roi/roi_graphical.svg +78 -0
  245. datalab/data/icons/roi/roi_grid.svg +67 -0
  246. datalab/data/icons/roi/roi_ima.svg +188 -0
  247. datalab/data/icons/roi/roi_import.svg +87 -0
  248. datalab/data/icons/roi/roi_new.svg +81 -0
  249. datalab/data/icons/roi/roi_new_circle.svg +95 -0
  250. datalab/data/icons/roi/roi_new_polygon.svg +110 -0
  251. datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
  252. datalab/data/icons/roi/roi_paste.svg +98 -0
  253. datalab/data/icons/roi/roi_sig.svg +124 -0
  254. datalab/data/icons/shapes.svg +134 -0
  255. datalab/data/icons/signal.svg +103 -0
  256. datalab/data/icons/table.svg +85 -0
  257. datalab/data/icons/table_unavailable.svg +102 -0
  258. datalab/data/icons/to_signal.svg +124 -0
  259. datalab/data/icons/tour/next.svg +44 -0
  260. datalab/data/icons/tour/previous.svg +44 -0
  261. datalab/data/icons/tour/rewind.svg +51 -0
  262. datalab/data/icons/tour/stop.svg +47 -0
  263. datalab/data/icons/tour/tour.svg +16 -0
  264. datalab/data/icons/uncheck_all.svg +78 -0
  265. datalab/data/icons/view/curve_antialiasing.svg +50 -0
  266. datalab/data/icons/view/new_window.svg +98 -0
  267. datalab/data/icons/view/refresh-auto.svg +57 -0
  268. datalab/data/icons/view/refresh-manual.svg +51 -0
  269. datalab/data/icons/view/reset_curve_styles.svg +96 -0
  270. datalab/data/icons/view/show_first.svg +55 -0
  271. datalab/data/icons/view/show_titles.svg +46 -0
  272. datalab/data/icons/visualization.svg +51 -0
  273. datalab/data/logo/DataLab-Banner-150.png +0 -0
  274. datalab/data/logo/DataLab-Banner-200.png +0 -0
  275. datalab/data/logo/DataLab-Banner2-100.png +0 -0
  276. datalab/data/logo/DataLab-Splash.png +0 -0
  277. datalab/data/logo/DataLab-watermark.png +0 -0
  278. datalab/data/logo/DataLab.svg +83 -0
  279. datalab/data/tests/reordering_test.h5 +0 -0
  280. datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
  281. datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
  282. datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
  283. datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
  284. datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
  285. datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
  286. datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
  287. datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
  288. datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
  289. datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
  290. datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
  291. datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
  292. datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
  293. datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
  294. datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
  295. datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
  296. datalab/env.py +542 -0
  297. datalab/gui/__init__.py +89 -0
  298. datalab/gui/actionhandler.py +1701 -0
  299. datalab/gui/docks.py +473 -0
  300. datalab/gui/h5io.py +150 -0
  301. datalab/gui/macroeditor.py +310 -0
  302. datalab/gui/main.py +2081 -0
  303. datalab/gui/newobject.py +217 -0
  304. datalab/gui/objectview.py +766 -0
  305. datalab/gui/panel/__init__.py +48 -0
  306. datalab/gui/panel/base.py +3254 -0
  307. datalab/gui/panel/image.py +157 -0
  308. datalab/gui/panel/macro.py +607 -0
  309. datalab/gui/panel/signal.py +164 -0
  310. datalab/gui/plothandler.py +800 -0
  311. datalab/gui/processor/__init__.py +84 -0
  312. datalab/gui/processor/base.py +2456 -0
  313. datalab/gui/processor/catcher.py +75 -0
  314. datalab/gui/processor/image.py +1214 -0
  315. datalab/gui/processor/signal.py +755 -0
  316. datalab/gui/profiledialog.py +333 -0
  317. datalab/gui/roieditor.py +633 -0
  318. datalab/gui/roigrideditor.py +208 -0
  319. datalab/gui/settings.py +612 -0
  320. datalab/gui/tour.py +908 -0
  321. datalab/h5/__init__.py +12 -0
  322. datalab/h5/common.py +314 -0
  323. datalab/h5/generic.py +580 -0
  324. datalab/h5/native.py +39 -0
  325. datalab/h5/utils.py +95 -0
  326. datalab/objectmodel.py +640 -0
  327. datalab/plugins/_readme_.txt +9 -0
  328. datalab/plugins/datalab_imageformats.py +175 -0
  329. datalab/plugins/datalab_testdata.py +190 -0
  330. datalab/plugins.py +355 -0
  331. datalab/tests/__init__.py +199 -0
  332. datalab/tests/backbone/__init__.py +1 -0
  333. datalab/tests/backbone/config_unit_test.py +170 -0
  334. datalab/tests/backbone/config_versioning_unit_test.py +34 -0
  335. datalab/tests/backbone/dictlistserial_app_test.py +38 -0
  336. datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
  337. datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
  338. datalab/tests/backbone/execenv_unit.py +262 -0
  339. datalab/tests/backbone/loadtest_gdi.py +147 -0
  340. datalab/tests/backbone/long_callback.py +96 -0
  341. datalab/tests/backbone/main_app_test.py +137 -0
  342. datalab/tests/backbone/memory_leak.py +43 -0
  343. datalab/tests/backbone/procisolation1_unit.py +128 -0
  344. datalab/tests/backbone/procisolation2_unit.py +171 -0
  345. datalab/tests/backbone/procisolation_unit_test.py +22 -0
  346. datalab/tests/backbone/profiling_app.py +27 -0
  347. datalab/tests/backbone/strings_unit_test.py +65 -0
  348. datalab/tests/backbone/title_formatting_unit_test.py +82 -0
  349. datalab/tests/conftest.py +131 -0
  350. datalab/tests/features/__init__.py +1 -0
  351. datalab/tests/features/applauncher/__init__.py +1 -0
  352. datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
  353. datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
  354. datalab/tests/features/common/__init__.py +1 -0
  355. datalab/tests/features/common/add_metadata_app_test.py +134 -0
  356. datalab/tests/features/common/add_metadata_unit_test.py +267 -0
  357. datalab/tests/features/common/annotations_management_unit_test.py +152 -0
  358. datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
  359. datalab/tests/features/common/createobject_unit_test.py +50 -0
  360. datalab/tests/features/common/geometry_results_app_test.py +135 -0
  361. datalab/tests/features/common/interactive_processing_test.py +1109 -0
  362. datalab/tests/features/common/io_app_test.py +75 -0
  363. datalab/tests/features/common/large_results_app_test.py +187 -0
  364. datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
  365. datalab/tests/features/common/metadata_app_test.py +139 -0
  366. datalab/tests/features/common/metadata_io_unit_test.py +60 -0
  367. datalab/tests/features/common/misc_app_test.py +236 -0
  368. datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
  369. datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
  370. datalab/tests/features/common/operation_modes_app_test.py +392 -0
  371. datalab/tests/features/common/plot_results_app_test.py +278 -0
  372. datalab/tests/features/common/reorder_app_test.py +75 -0
  373. datalab/tests/features/common/result_deletion_unit_test.py +96 -0
  374. datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
  375. datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
  376. datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
  377. datalab/tests/features/common/roieditor_unit_test.py +102 -0
  378. datalab/tests/features/common/save_to_dir_app_test.py +163 -0
  379. datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
  380. datalab/tests/features/common/stat_app_test.py +40 -0
  381. datalab/tests/features/common/stats_tools_unit_test.py +77 -0
  382. datalab/tests/features/common/table_results_app_test.py +52 -0
  383. datalab/tests/features/common/textimport_unit_test.py +131 -0
  384. datalab/tests/features/common/uuid_preservation_test.py +281 -0
  385. datalab/tests/features/common/worker_unit_test.py +402 -0
  386. datalab/tests/features/control/__init__.py +1 -0
  387. datalab/tests/features/control/connect_dialog.py +28 -0
  388. datalab/tests/features/control/embedded1_unit_test.py +304 -0
  389. datalab/tests/features/control/embedded2_unit_test.py +52 -0
  390. datalab/tests/features/control/remoteclient_app_test.py +219 -0
  391. datalab/tests/features/control/remoteclient_unit.py +75 -0
  392. datalab/tests/features/control/simpleclient_unit_test.py +321 -0
  393. datalab/tests/features/hdf5/__init__.py +1 -0
  394. datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
  395. datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
  396. datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
  397. datalab/tests/features/hdf5/h5import_app_test.py +25 -0
  398. datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
  399. datalab/tests/features/image/__init__.py +1 -0
  400. datalab/tests/features/image/annotations_app_test.py +28 -0
  401. datalab/tests/features/image/annotations_unit_test.py +80 -0
  402. datalab/tests/features/image/average_app_test.py +46 -0
  403. datalab/tests/features/image/background_dialog_test.py +70 -0
  404. datalab/tests/features/image/blobs_app_test.py +50 -0
  405. datalab/tests/features/image/contour_app_test.py +42 -0
  406. datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
  407. datalab/tests/features/image/denoise_app_test.py +31 -0
  408. datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
  409. datalab/tests/features/image/edges_app_test.py +31 -0
  410. datalab/tests/features/image/erase_app_test.py +21 -0
  411. datalab/tests/features/image/fft2d_app_test.py +27 -0
  412. datalab/tests/features/image/flatfield_app_test.py +40 -0
  413. datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
  414. datalab/tests/features/image/imagetools_app_test.py +51 -0
  415. datalab/tests/features/image/imagetools_unit_test.py +27 -0
  416. datalab/tests/features/image/load_app_test.py +73 -0
  417. datalab/tests/features/image/morph_app_test.py +32 -0
  418. datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
  419. datalab/tests/features/image/peak2d_app_test.py +53 -0
  420. datalab/tests/features/image/profile_app_test.py +73 -0
  421. datalab/tests/features/image/profile_dialog_test.py +56 -0
  422. datalab/tests/features/image/roi_app_test.py +98 -0
  423. datalab/tests/features/image/roi_circ_app_test.py +62 -0
  424. datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
  425. datalab/tests/features/image/roigrid_unit_test.py +60 -0
  426. datalab/tests/features/image/side_by_side_app_test.py +52 -0
  427. datalab/tests/features/macro/__init__.py +1 -0
  428. datalab/tests/features/macro/macro_app_test.py +28 -0
  429. datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
  430. datalab/tests/features/signal/__init__.py +1 -0
  431. datalab/tests/features/signal/baseline_dialog_test.py +53 -0
  432. datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
  433. datalab/tests/features/signal/fft1d_app_test.py +26 -0
  434. datalab/tests/features/signal/filter_app_test.py +44 -0
  435. datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
  436. datalab/tests/features/signal/interpolation_app_test.py +110 -0
  437. datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
  438. datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
  439. datalab/tests/features/signal/pulse_features_app_test.py +118 -0
  440. datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
  441. datalab/tests/features/signal/roi_app_test.py +78 -0
  442. datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
  443. datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
  444. datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
  445. datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
  446. datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
  447. datalab/tests/features/tour_unit_test.py +22 -0
  448. datalab/tests/features/utilities/__init__.py +1 -0
  449. datalab/tests/features/utilities/installconf_unit_test.py +21 -0
  450. datalab/tests/features/utilities/logview_app_test.py +21 -0
  451. datalab/tests/features/utilities/logview_error.py +24 -0
  452. datalab/tests/features/utilities/logview_unit_test.py +21 -0
  453. datalab/tests/features/utilities/memstatus_app_test.py +42 -0
  454. datalab/tests/features/utilities/settings_unit_test.py +88 -0
  455. datalab/tests/scenarios/__init__.py +1 -0
  456. datalab/tests/scenarios/beautiful_app.py +121 -0
  457. datalab/tests/scenarios/common.py +463 -0
  458. datalab/tests/scenarios/demo.py +212 -0
  459. datalab/tests/scenarios/example_app_test.py +47 -0
  460. datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
  461. datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
  462. datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
  463. datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
  464. datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
  465. datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
  466. datalab/utils/__init__.py +1 -0
  467. datalab/utils/conf.py +304 -0
  468. datalab/utils/dephash.py +105 -0
  469. datalab/utils/qthelpers.py +633 -0
  470. datalab/utils/strings.py +34 -0
  471. datalab/utils/tests.py +0 -0
  472. datalab/widgets/__init__.py +1 -0
  473. datalab/widgets/connection.py +138 -0
  474. datalab/widgets/filedialog.py +91 -0
  475. datalab/widgets/fileviewer.py +84 -0
  476. datalab/widgets/fitdialog.py +788 -0
  477. datalab/widgets/h5browser.py +1048 -0
  478. datalab/widgets/imagebackground.py +111 -0
  479. datalab/widgets/instconfviewer.py +175 -0
  480. datalab/widgets/logviewer.py +80 -0
  481. datalab/widgets/signalbaseline.py +90 -0
  482. datalab/widgets/signalcursor.py +208 -0
  483. datalab/widgets/signaldeltax.py +151 -0
  484. datalab/widgets/signalpeak.py +199 -0
  485. datalab/widgets/status.py +249 -0
  486. datalab/widgets/textimport.py +786 -0
  487. datalab/widgets/warningerror.py +223 -0
  488. datalab/widgets/wizard.py +286 -0
  489. datalab_platform-1.0.1.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.1.dist-info/RECORD +494 -0
  491. datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
  492. datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
  493. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,392 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Operation modes test
5
+ --------------------
6
+
7
+ DataLab has two operation modes:
8
+
9
+ - **Single operand mode**: the operation is applied to the selected objects (this
10
+ is the default mode)
11
+
12
+ - **Pairwise mode**: the operation is applied to the selected pairs of objects
13
+
14
+ This test scenario covers the pairwise mode and the operations that can be
15
+ performed in this mode: sum, difference, product, division, ...
16
+ """
17
+
18
+ # guitest: show
19
+
20
+ from __future__ import annotations
21
+
22
+ from datalab import app
23
+ from datalab.config import Conf
24
+ from datalab.env import execenv
25
+ from datalab.gui.processor.base import is_pairwise_mode
26
+ from datalab.objectmodel import get_short_id
27
+ from datalab.tests import helpers
28
+ from datalab.utils.qthelpers import datalab_app_context
29
+
30
+
31
+ def get_h5fname() -> str:
32
+ """Get the HDF5 test filename"""
33
+ fnames = helpers.get_test_fnames("reorder*")
34
+ return fnames[0]
35
+
36
+
37
+ def check_titles(title: str, titles: list[tuple[str, str]]) -> None:
38
+ """Check that the title is one of the expected titles"""
39
+ execenv.print(f"{title}:")
40
+ for actual_title, expected_title in titles:
41
+ execenv.print(f" {actual_title} == {expected_title}", end=" ")
42
+ assert actual_title == expected_title
43
+ if actual_title == expected_title:
44
+ execenv.print("✓")
45
+ else:
46
+ execenv.print("✗")
47
+
48
+
49
+ def test_single_operand_mode_compute_n_to_1() -> None:
50
+ """Run single operand mode test scenario
51
+ with `compute_n_to_1` operation (e.g. sum)"""
52
+ h5fname = get_h5fname()
53
+ original_mode = Conf.proc.operation_mode.get()
54
+ Conf.proc.operation_mode.set("single")
55
+
56
+ with datalab_app_context(exec_loop=True):
57
+ win = app.create(h5files=[h5fname], console=False)
58
+ panel = win.signalpanel
59
+ view, model = panel.objview, panel.objmodel
60
+
61
+ # Checking the operation mode:
62
+ assert not is_pairwise_mode()
63
+
64
+ # Store the number of groups before the operations
65
+ n_groups = len(model.get_groups())
66
+
67
+ # Select the two first groups
68
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
69
+ view.select_groups(groups)
70
+
71
+ # Perform a sum operation
72
+ panel.processor.run_feature("addition")
73
+
74
+ # Default operation mode is single operand mode, so the sum operation
75
+ # is applied to the selected groups, and we should have a new group
76
+ # with two signals being the sum of signals from each group:
77
+ # - signal 1: group 1 signal 1 + group 1 signal 2
78
+ # - signal 2: group 2 signal 1 + group 2 signal 2
79
+ assert len(model.get_groups()) == n_groups + 1
80
+ new_group = model.get_group_from_number(n_groups + 1)
81
+ assert len(new_group) == 2
82
+ titles = []
83
+ for idx, obj in enumerate(new_group):
84
+ pfx_orig = ", ".join(get_short_id(obj) for obj in groups[idx].get_objects())
85
+ titles.append((obj.title, f"Σ({pfx_orig})"))
86
+ check_titles(f"Single operand mode Σ[{new_group.title}]", titles)
87
+
88
+ # Remove new group
89
+ view.select_groups([new_group])
90
+ panel.remove_object(force=True)
91
+
92
+ # Store the number of groups before the operations
93
+ n_groups = len(model.get_groups())
94
+
95
+ # Select the two first signals of the first two groups
96
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
97
+ objs = groups[0][:2] + groups[1][:2]
98
+ view.select_objects(objs)
99
+
100
+ # Perform a sum operation
101
+ panel.processor.run_feature("addition")
102
+
103
+ # Default operation mode is single operand mode, so the sum operation
104
+ # is applied to the selected signals, and we should have a new resulting
105
+ # signal being the sum of the selected signals added in each group:
106
+ # - signal added to group 1: group 1 signal 1 + group 2 signal 1
107
+ # - signal added to group 2: group 1 signal 2 + group 2 signal 2
108
+ assert len(model.get_groups()) == n_groups # no new group
109
+ titles = []
110
+ for idx in range(1):
111
+ pfx_orig = ", ".join(get_short_id(obj) for obj in groups[idx][:2])
112
+ titles.append((groups[idx][-1].title, f"Σ({pfx_orig})"))
113
+ check_titles(f"Single operand mode Σ[{groups[1].title}]", titles)
114
+
115
+ Conf.proc.operation_mode.set(original_mode)
116
+
117
+
118
+ def test_pairwise_operations_mode_compute_n_to_1() -> None:
119
+ """Run pairwise operations mode test scenario
120
+ with `compute_n_to_1` operation (e.g. sum)"""
121
+ h5fname = get_h5fname()
122
+ original_mode = Conf.proc.operation_mode.get()
123
+ Conf.proc.operation_mode.set("pairwise")
124
+
125
+ with datalab_app_context(exec_loop=True):
126
+ win = app.create(h5files=[h5fname], console=False)
127
+ panel = win.signalpanel
128
+ view, model = panel.objview, panel.objmodel
129
+
130
+ # Checking the operation mode:
131
+ assert is_pairwise_mode()
132
+
133
+ # Store the number of groups before the operations
134
+ n_groups = len(model.get_groups())
135
+
136
+ # Select the two first groups
137
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
138
+ view.select_groups(groups)
139
+
140
+ # Checking that each group contains the same number of signals (this is
141
+ # required for pairwise operations - this part of the test is checking
142
+ # if the data file is the one we expect)
143
+ n_objects = len(groups[0])
144
+ assert all(len(group) == n_objects for group in groups)
145
+
146
+ # Perform a sum operation
147
+ panel.processor.run_feature("addition")
148
+
149
+ # Operation mode is now pairwise, so the sum operation is applied to the
150
+ # selected groups, and we should have a new group with as many signals as
151
+ # the original groups, each signal being the sum of the corresponding signals:
152
+ # - signal 1: group 1 signal 1 + group 2 signal 1
153
+ # - signal 2: group 1 signal 1 + group 2 signal 2
154
+ # ...
155
+ assert len(model.get_groups()) == n_groups + 1
156
+ new_group = model.get_group_from_number(n_groups + 1)
157
+ assert len(new_group.get_objects()) == n_objects
158
+ titles = []
159
+ for idx in range(len(groups[0])):
160
+ obj = new_group[idx]
161
+ pfx_orig = ", ".join(
162
+ get_short_id(obj) for obj in (grp[idx] for grp in groups)
163
+ )
164
+ titles.append((obj.title, f"Σ({pfx_orig})"))
165
+ check_titles(f"Pairwise operations mode Σ[{new_group.title}]", titles)
166
+
167
+ # Remove new group
168
+ view.select_groups([new_group])
169
+ panel.remove_object(force=True)
170
+
171
+ # Store the number of groups before the operations
172
+ n_groups = len(model.get_groups())
173
+
174
+ # Select two signals of the first two groups
175
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
176
+ objs = [groups[0][0]] + [groups[0][-1]] + groups[1][-2:]
177
+ view.select_objects(objs)
178
+
179
+ # Perform a sum operation
180
+ panel.processor.run_feature("addition")
181
+
182
+ # Operation mode is now pairwise, so the sum operation is applied to the
183
+ # selected signals, and we should have a new group with as many signals as
184
+ # the selected signals, each signal being the sum of the corresponding signals:
185
+ # - signal 1: group 1 signal 1 + group 2 signal 1
186
+ # - signal 2: group 1 signal 1 + group 2 signal 2
187
+ # ...
188
+ assert len(model.get_groups()) == n_groups + 1
189
+ new_group = model.get_group_from_number(n_groups + 1)
190
+ assert len(new_group) == 2 # 2 signals were selected
191
+ titles = []
192
+ for idx, obj in enumerate(new_group):
193
+ pfx_orig = ", ".join(get_short_id(obj) for obj in objs[idx::2])
194
+ titles.append((obj.title, f"Σ({pfx_orig})"))
195
+ check_titles(f"Pairwise operations mode Σ[{new_group.title}]", titles)
196
+
197
+ Conf.proc.operation_mode.set(original_mode)
198
+
199
+
200
+ def test_single_operand_mode_compute_2_to_1() -> None:
201
+ """Run single operand mode test scenario
202
+ with `compute_2_to_1` operation (e.g. difference)"""
203
+ h5fname = get_h5fname()
204
+ original_mode = Conf.proc.operation_mode.get()
205
+ Conf.proc.operation_mode.set("single")
206
+
207
+ with datalab_app_context(exec_loop=True):
208
+ win = app.create(h5files=[h5fname], console=False)
209
+ panel = win.signalpanel
210
+ view, model = panel.objview, panel.objmodel
211
+
212
+ # Checking the operation mode:
213
+ assert not is_pairwise_mode()
214
+
215
+ # Store the number of groups before the operations
216
+ n_groups = len(model.get_groups())
217
+
218
+ # Select the two first groups
219
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
220
+ view.select_groups(groups)
221
+ n_objects = [len(grp) for grp in groups]
222
+
223
+ # Perform a difference operation with the first signal of the third group
224
+ group3 = model.get_group_from_number(3)
225
+ panel.processor.run_feature("difference", group3[0])
226
+
227
+ # Default operation mode is single operand mode, so we should have new signals
228
+ # in each selected group being the difference between the original signals and
229
+ # the selected signal:
230
+ # - in group 1:
231
+ # - signal 1: group 1 signal 1 - group 3 signal 1
232
+ # - signal 2: group 1 signal 2 - group 3 signal 1
233
+ # - in group 2:
234
+ # - signal 1: group 2 signal 1 - group 3 signal 1
235
+ # - signal 2: group 2 signal 2 - group 3 signal 1
236
+ assert len(model.get_groups()) == n_groups
237
+ new_objs = []
238
+ for i_group, group in enumerate(groups):
239
+ titles = []
240
+ for i_obj in range(n_objects[i_group]):
241
+ obj = group[i_obj + n_objects[i_group]]
242
+ titles.append(
243
+ (
244
+ obj.title,
245
+ f"{get_short_id(group[i_obj])}-{get_short_id(group3[0])}",
246
+ )
247
+ )
248
+ new_objs.append(obj)
249
+ check_titles(f"Single operand mode Δ[{group.title}]", titles)
250
+
251
+ # Remove new signals
252
+ view.select_objects(new_objs)
253
+ panel.remove_object(force=True)
254
+
255
+ # Store the number of groups before the operations
256
+ n_groups = len(model.get_groups())
257
+
258
+ # Select the two first signals of the first two groups
259
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
260
+ objs = groups[0][:2] + groups[1][:2]
261
+ view.select_objects(objs)
262
+ n_objects = [2, 2]
263
+
264
+ # Perform a difference operation with the first signal of the third group
265
+ panel.processor.run_feature("difference", group3[0])
266
+
267
+ # Default operation mode is single operand mode, so we should have new signals
268
+ # being the difference between the original signals and the selected signal:
269
+ # - in group 1:
270
+ # - signal 1: group 1 signal 1 - group 3 signal 1
271
+ # - signal 2: group 1 signal 2 - group 3 signal 1
272
+ # - in group 2:
273
+ # - signal 1: group 2 signal 1 - group 3 signal 1
274
+ # - signal 2: group 2 signal 2 - group 3 signal 1
275
+ assert len(model.get_groups()) == n_groups # no new group
276
+ for i_group, group in enumerate(groups):
277
+ titles = []
278
+ for i_obj in range(n_objects[i_group]):
279
+ obj = group[len(group) - n_objects[i_group] + i_obj]
280
+ titles.append(
281
+ (
282
+ obj.title,
283
+ f"{get_short_id(group[i_obj])}-{get_short_id(group3[0])}",
284
+ )
285
+ )
286
+ check_titles(f"Single operand mode Δ[{group.title}]", titles)
287
+
288
+ Conf.proc.operation_mode.set(original_mode)
289
+
290
+
291
+ def test_pairwise_operations_mode_compute_2_to_1() -> None:
292
+ """Run pairwise operations mode test scenario
293
+ with `compute_2_to_1` operation (e.g. difference)"""
294
+ h5fname = get_h5fname()
295
+ original_mode = Conf.proc.operation_mode.get()
296
+ Conf.proc.operation_mode.set("pairwise")
297
+
298
+ with datalab_app_context(exec_loop=True):
299
+ win = app.create(h5files=[h5fname], console=False)
300
+ panel = win.signalpanel
301
+ view, model = panel.objview, panel.objmodel
302
+
303
+ # Checking the operation mode:
304
+ assert is_pairwise_mode()
305
+
306
+ # Store the number of groups before the operations
307
+ n_groups = len(model.get_groups())
308
+
309
+ # Select the two first groups
310
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
311
+ view.select_groups(groups)
312
+
313
+ # Checking that each group contains the same number of signals (this is
314
+ # required for pairwise operations - this part of the test is checking
315
+ # if the data file is the one we expect)
316
+ n_objects = len(groups[0])
317
+ assert all(len(group) == n_objects for group in groups)
318
+
319
+ # Perform a difference operation with the third group
320
+ group3 = model.get_group_from_number(3)
321
+ assert len(group3) == n_objects
322
+ panel.processor.run_feature("difference", group3.get_objects())
323
+
324
+ # Operation mode is now pairwise, so the difference operation is applied to the
325
+ # selected groups, and we should have a new group with as many signals as the
326
+ # original groups, each signal being the difference of the corresponding
327
+ # signals:
328
+ # - signal 1: group 1 signal 1 - group 2 signal 1
329
+ # - signal 2: group 1 signal 1 - group 2 signal 2
330
+ # ...
331
+ assert len(model.get_groups()) == n_groups + 2
332
+ new_groups = [
333
+ model.get_group_from_number(idx) for idx in (n_groups + 1, n_groups + 2)
334
+ ]
335
+ execenv.print("Δ|pairwise")
336
+ for i_new_grp, new_grp in enumerate(new_groups):
337
+ assert len(new_grp.get_objects()) == n_objects
338
+ titles = []
339
+ for idx in range(n_objects):
340
+ obj = new_grp[idx]
341
+ obj1, obj2 = groups[i_new_grp][idx], group3[idx]
342
+ titles.append((obj.title, f"{get_short_id(obj1)}-{get_short_id(obj2)}"))
343
+ check_titles(f"Pairwise operations mode Δ[{new_grp.title}]", titles)
344
+
345
+ # Remove new groups
346
+ view.select_groups(new_groups)
347
+ panel.remove_object(force=True)
348
+
349
+ # Store the number of groups before the operations
350
+ n_groups = len(model.get_groups())
351
+
352
+ # Select two signals of the first two groups
353
+ groups = [model.get_group_from_number(idx) for idx in (1, 2)]
354
+ objs = [groups[0][0]] + [groups[0][-1]] + groups[1][-2:]
355
+ view.select_objects(objs)
356
+ n_objects = 2
357
+
358
+ # Perform a difference operation with two signals from the third group
359
+ objs2 = group3[:2]
360
+ panel.processor.run_feature("difference", objs2)
361
+
362
+ # Operation mode is now pairwise, so the difference operation is applied to the
363
+ # selected signals, and we should have a new group with as many signals as the
364
+ # selected signals, each signal being the difference of the corresponding
365
+ # signals:
366
+ # - signal 1: group 1 signal 1 - group 3 signal 1
367
+ # - signal 2: group 1 signal 1 - group 3 signal 2
368
+ # ...
369
+ assert len(model.get_groups()) == n_groups + 2
370
+ new_groups = [
371
+ model.get_group_from_number(idx) for idx in (n_groups + 1, n_groups + 2)
372
+ ]
373
+ i_obj1 = 0
374
+ execenv.print("Δ|pairwise")
375
+ for i_new_grp, new_grp in enumerate(new_groups):
376
+ assert len(new_grp.get_objects()) == n_objects
377
+ titles = []
378
+ for idx in range(n_objects):
379
+ obj = new_grp[idx]
380
+ obj1, obj2 = objs[i_obj1], objs2[idx]
381
+ i_obj1 += 1
382
+ titles.append((obj.title, f"{get_short_id(obj1)}-{get_short_id(obj2)}"))
383
+ check_titles(f"Pairwise operations mode Δ[{new_grp.title}]", titles)
384
+
385
+ Conf.proc.operation_mode.set(original_mode)
386
+
387
+
388
+ if __name__ == "__main__":
389
+ test_single_operand_mode_compute_n_to_1()
390
+ test_pairwise_operations_mode_compute_n_to_1()
391
+ test_single_operand_mode_compute_2_to_1()
392
+ test_pairwise_operations_mode_compute_2_to_1()
@@ -0,0 +1,278 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Plot results application test:
5
+
6
+ Testing the "Plot results" feature with different options:
7
+ - Different plot kinds (one curve per object vs. one curve per title)
8
+ - Different X/Y axis selections
9
+ - Results with and without ROIs
10
+ - Both signal and image panels
11
+ - Multiple result types (scalar and geometry results)
12
+ - Group selection creates a new result group
13
+ """
14
+
15
+ # guitest: show
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Generator
20
+
21
+ import sigima.objects
22
+ import sigima.params
23
+ from sigima.tests import data as test_data
24
+
25
+ from datalab.config import _
26
+ from datalab.env import execenv
27
+ from datalab.objectmodel import get_uuid
28
+ from datalab.tests import datalab_test_app_context
29
+
30
+
31
+ def iterate_noisy_signals(
32
+ count: int,
33
+ a: float,
34
+ sigma: float,
35
+ ) -> Generator[tuple[sigima.objects.SignalObj, float], None, None]:
36
+ """Generate noisy signals for testing."""
37
+ noiseparam = sigima.objects.NormalDistribution1DParam.create(sigma=sigma, mu=0.0)
38
+ param = sigima.objects.GaussParam.create(a=a)
39
+ for i in range(count):
40
+ param.sigma = 1.0 + (i * 0.1) ** 2
41
+ theoretical_fwhm = param.get_expected_features().fwhm
42
+ sig = test_data.create_noisy_signal(
43
+ noiseparam, param, f"Signal|fwhm_th={theoretical_fwhm:.2f}"
44
+ )
45
+ yield sig, theoretical_fwhm
46
+
47
+
48
+ def test_plot_results_signals_one_curve_per_title():
49
+ """Test plot results feature with signals, one curve per title.
50
+
51
+ Create signals with single-value results (e.g., FWHM) and plot them.
52
+ Verify that results are created in the "Results" group.
53
+ """
54
+ with datalab_test_app_context() as win:
55
+ panel = win.signalpanel
56
+
57
+ with execenv.context(unattended=True):
58
+ x_th = []
59
+ y_th = []
60
+ for i, (sig, theoretical_fwhm) in enumerate(
61
+ iterate_noisy_signals(5, a=10.0, sigma=0.01)
62
+ ):
63
+ x_th.append(i)
64
+ y_th.append(theoretical_fwhm)
65
+ panel.add_object(sig)
66
+ # Compute FWHM using the default method (zero-crossing) which introduces
67
+ # a systematic ~2% error compared to the theoretical value
68
+ # (trade-off for noise robustness)
69
+ panel.processor.run_feature("fwhm", sigima.params.FWHMParam())
70
+
71
+ # Get number of groups before plotting
72
+ groups_before = len(panel.objmodel.get_groups())
73
+
74
+ panel.objview.selectAll()
75
+ panel.show_results()
76
+ panel.plot_results(kind="one_curve_per_title", xaxis="indices", yaxis="Δx")
77
+
78
+ # Verify a Results group was created
79
+ groups_after = panel.objmodel.get_groups()
80
+ assert len(groups_after) == groups_before + 1, (
81
+ f"Expected {groups_before + 1} groups, got {len(groups_after)}"
82
+ )
83
+
84
+ # Verify the new group is named "Results"
85
+ expected_title = _("Results")
86
+ result_group = groups_after[-1]
87
+ assert result_group.title == expected_title, (
88
+ f"Expected last group to be '{expected_title}', "
89
+ f"got '{result_group.title}'"
90
+ )
91
+
92
+ # Verify the Results group contains the result signal
93
+ assert len(result_group) > 0, (
94
+ "Results group should contain at least one result signal"
95
+ )
96
+
97
+ fwhm_var_th = sigima.objects.create_signal("FWHM_Theoretical", x_th, y_th)
98
+ panel.add_object(fwhm_var_th)
99
+ panel.objview.select_objects((6, 7))
100
+ # The observed offset should be around ~2% of the theoretical value
101
+
102
+
103
+ def test_plot_results_images_one_curve_per_object():
104
+ """Test plot results feature with images, one curve per object.
105
+
106
+ Create images with multi-value results (e.g., peak detection) and plot them.
107
+ """
108
+ with datalab_test_app_context() as win:
109
+ panel = win.imagepanel
110
+
111
+ with execenv.context(unattended=True):
112
+ for i in range(3):
113
+ img = test_data.create_peak_image()
114
+ img.title = f"Peaks_{i + 1}"
115
+ panel.add_object(img)
116
+ param = sigima.params.Peak2DDetectionParam.create(create_rois=False)
117
+ panel.processor.run_feature("peak_detection", param)
118
+
119
+ panel.objview.selectAll()
120
+ panel.show_results()
121
+ # Use programmatic parameters: plot y vs x for each peak
122
+ panel.plot_results(kind="one_curve_per_object", xaxis="x", yaxis="y")
123
+
124
+
125
+ def test_plot_results_images_with_rois():
126
+ """Test plot results feature with images containing ROIs.
127
+
128
+ Create images with ROIs and single-value results (e.g., centroid) and plot them.
129
+ """
130
+ with datalab_test_app_context() as win:
131
+ panel = win.imagepanel
132
+
133
+ with execenv.context(unattended=True):
134
+ size = 512
135
+ peak_param = test_data.PeakDataParam.create(size=size)
136
+ for i in range(3):
137
+ data, peak_coords = test_data.get_peak2d_data(peak_param)
138
+ img = sigima.objects.create_image(f"Image_ROI_{i + 1}", data)
139
+ # Add rectangular ROI to image
140
+ roi_coords = []
141
+ for xpeak, ypeak in peak_coords:
142
+ roi_coords.append([xpeak, ypeak, 20])
143
+ img.roi = sigima.objects.create_image_roi("circle", roi_coords)
144
+ panel.add_object(img)
145
+ panel.processor.run_feature("centroid")
146
+
147
+ panel.objview.selectAll()
148
+ panel.show_results()
149
+ # Plot centroid x vs indices with ROIs
150
+ panel.plot_results(kind="one_curve_per_title", xaxis="indices", yaxis="x")
151
+
152
+
153
+ def test_plot_results_with_group_selection():
154
+ """Test plot results with Results group.
155
+
156
+ All plot results operations should create result signals in a reusable
157
+ "Results" group for better organization.
158
+ """
159
+ with datalab_test_app_context() as win:
160
+ panel = win.signalpanel
161
+
162
+ with execenv.context(unattended=True):
163
+ # Create a group with signals
164
+ panel.add_group("Test Group")
165
+
166
+ # Add signals and compute FWHM
167
+ for i, (sig, _fwhm) in enumerate(
168
+ iterate_noisy_signals(3, a=10.0, sigma=0.01)
169
+ ):
170
+ sig.title = f"Signal_{i + 1}"
171
+ panel.add_object(sig)
172
+ panel.processor.run_feature("fwhm", sigima.params.FWHMParam())
173
+
174
+ # Get the number of groups before plotting results
175
+ groups_before = len(panel.objmodel.get_groups())
176
+
177
+ # Select the group (not individual objects)
178
+ panel.objview.select_groups([1])
179
+
180
+ # Verify the group is selected
181
+ sel_groups = panel.objview.get_sel_groups()
182
+ assert len(sel_groups) == 1, (
183
+ f"Expected 1 selected group, got {len(sel_groups)}"
184
+ )
185
+
186
+ # Plot results - this should create or reuse a "Results" group
187
+ panel.plot_results(kind="one_curve_per_title", xaxis="indices", yaxis="Δx")
188
+
189
+ # Verify a new group was created
190
+ groups_after = panel.objmodel.get_groups()
191
+ assert len(groups_after) == groups_before + 1, (
192
+ f"Expected {groups_before + 1} groups, got {len(groups_after)}"
193
+ )
194
+
195
+ # Check that the new group is named "Results" (or its translation)
196
+ expected_title = _("Results")
197
+ result_group = groups_after[-1] # Last group should be Results
198
+ assert result_group.title == expected_title, (
199
+ f"Expected last group to be '{expected_title}', "
200
+ f"got '{result_group.title}'"
201
+ )
202
+
203
+ # Check that the Results group contains at least one result signal
204
+ assert len(result_group) > 0, (
205
+ "Results group should contain at least one result signal"
206
+ )
207
+
208
+ # Verify that the result signal title includes source object short IDs
209
+ result_signal = list(result_group)[0]
210
+ # Should contain all three source signal IDs: s001, s002, s003
211
+ # (s000 is the default group, so signals start at s001)
212
+ assert "(s001, s002, s003)" in result_signal.title, (
213
+ f"Result signal title should include source IDs (s001, s002, s003), "
214
+ f"got '{result_signal.title}'"
215
+ )
216
+
217
+ # Test that the group is reused: create another group and plot results
218
+ test_group_2 = panel.add_group("Test Group 2")
219
+ test_group_2_id = get_uuid(test_group_2)
220
+ for i, (sig, _fwhm) in enumerate(
221
+ iterate_noisy_signals(2, a=10.0, sigma=0.01)
222
+ ):
223
+ sig.title = f"Signal2_{i + 1}"
224
+ panel.add_object(sig, group_id=test_group_2_id)
225
+ panel.processor.run_feature("fwhm", sigima.params.FWHMParam())
226
+
227
+ # Select the second group and plot results again
228
+ panel.objview.select_groups([3])
229
+
230
+ # Plot results again
231
+ num_results_before = len(result_group)
232
+ panel.plot_results(kind="one_curve_per_title", xaxis="indices", yaxis="Δx")
233
+
234
+ # Verify no new group was created (reused existing Results group)
235
+ groups_final = panel.objmodel.get_groups()
236
+ assert len(groups_final) == len(groups_after), (
237
+ "Results group should be reused, no new group created"
238
+ )
239
+
240
+ # Verify more results were added to the existing Results group
241
+ assert len(result_group) > num_results_before, (
242
+ "More results should be added to the existing Results group"
243
+ )
244
+
245
+ # Test with many objects (more than 3) to verify "..." is used
246
+ test_group_3 = panel.add_group("Test Group 3")
247
+ test_group_3_id = get_uuid(test_group_3)
248
+ for i, (sig, _fwhm) in enumerate(
249
+ iterate_noisy_signals(5, a=10.0, sigma=0.01)
250
+ ):
251
+ sig.title = f"Signal3_{i + 1}"
252
+ panel.add_object(sig, group_id=test_group_3_id)
253
+ panel.processor.run_feature("fwhm", sigima.params.FWHMParam())
254
+
255
+ # Select the third group
256
+ panel.objview.select_groups([4])
257
+
258
+ # Plot results
259
+ num_results_before = len(result_group)
260
+ panel.plot_results(kind="one_curve_per_title", xaxis="indices", yaxis="Δx")
261
+
262
+ # Verify the result signal title uses "..." for many objects
263
+ new_results = list(result_group)[num_results_before:]
264
+ assert len(new_results) > 0, "Should have new results"
265
+ result_signal_many = new_results[0]
266
+ # With 5 source signals, should show first 2 IDs, "...", then last ID
267
+ # Format: "fwhm (s..., s..., ..., s...): ..."
268
+ assert ", ..., " in result_signal_many.title, (
269
+ f"Result signal title should use '...' before last ID, "
270
+ f"got '{result_signal_many.title}'"
271
+ )
272
+
273
+
274
+ if __name__ == "__main__":
275
+ test_plot_results_signals_one_curve_per_title()
276
+ test_plot_results_images_one_curve_per_object()
277
+ test_plot_results_images_with_rois()
278
+ test_plot_results_with_group_selection()