datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.0__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.0.dist-info/METADATA +121 -0
  490. datalab_platform-1.0.0.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.0.dist-info}/WHEEL +0 -0
  494. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
  495. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
  496. {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,565 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ PlotPy Adapter Scalar Module
5
+ ----------------------------
6
+
7
+ This module contains adapters for scalar results (GeometryResult, TableResult)
8
+ to avoid circular imports with the base and factories modules.
9
+ """
10
+
11
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
12
+
13
+ from __future__ import annotations
14
+
15
+ from collections.abc import Iterable
16
+ from typing import TYPE_CHECKING, Literal
17
+
18
+ import guidata.dataset as gds
19
+ import numpy as np
20
+ from guidata.configtools import get_font
21
+ from plotpy.builder import make
22
+ from plotpy.items import (
23
+ AnnotatedCircle,
24
+ AnnotatedEllipse,
25
+ AnnotatedPoint,
26
+ AnnotatedRectangle,
27
+ AnnotatedSegment,
28
+ AnnotatedShape,
29
+ LabelItem,
30
+ Marker,
31
+ PolygonShape,
32
+ )
33
+ from sigima.objects.base import BaseObj
34
+ from sigima.objects.scalar import KindShape
35
+ from sigima.objects.signal import SignalObj
36
+ from sigima.tools import coordinates
37
+ from sigima.tools.signal import pulse
38
+
39
+ from datalab.adapters_metadata import (
40
+ GeometryAdapter,
41
+ TableAdapter,
42
+ resultadapter_to_html,
43
+ )
44
+ from datalab.adapters_plotpy.base import (
45
+ config_annotated_shape,
46
+ items_to_json,
47
+ json_to_items,
48
+ set_plot_item_editable,
49
+ )
50
+ from datalab.config import PLOTPY_CONF, Conf, _
51
+
52
+ if TYPE_CHECKING:
53
+ from plotpy.styles import ShapeParam
54
+
55
+
56
+ class ResultPlotPyAdapter:
57
+ """Adapter for converting `sigima` table or geometry adapters to PlotPy
58
+
59
+ Args:
60
+ result: Table or geometry adapter
61
+ """
62
+
63
+ def __init__(self, result_adapter: TableAdapter | GeometryAdapter) -> None:
64
+ self.result_adapter = result_adapter
65
+
66
+ def get_other_items(self, obj: BaseObj) -> list: # pylint: disable=unused-argument
67
+ """Return other items associated to this result (excluding label item)
68
+
69
+ Those items are not serialized to JSON.
70
+
71
+ Args:
72
+ obj: object (signal/image)
73
+
74
+ Returns:
75
+ List of other items
76
+ """
77
+ return []
78
+
79
+
80
+ class GeometryPlotPyAdapter(ResultPlotPyAdapter):
81
+ """Adapter for converting `sigima` geometry adapters to PlotPy
82
+
83
+ Args:
84
+ result: Geometry adapter
85
+
86
+ Raises:
87
+ AssertionError: invalid argument
88
+ """
89
+
90
+ def __init__(self, result_adapter: GeometryAdapter) -> None:
91
+ assert isinstance(result_adapter, GeometryAdapter)
92
+ super().__init__(result_adapter)
93
+
94
+ def iterate_shape_items(
95
+ self, fmt: str, lbl: bool, prefix: Literal["s", "i"]
96
+ ) -> Iterable:
97
+ """Iterate over metadata shape plot items.
98
+
99
+ Args:
100
+ fmt: numeric format (e.g. "%.3f")
101
+ lbl: if True, show shape labels
102
+ prefix: "s" for signal, "i" for image
103
+
104
+ Yields:
105
+ Plot item
106
+ """
107
+ max_shapes = Conf.view.max_shapes_to_draw.get(200)
108
+ total_coords = len(self.result_adapter.result.coords)
109
+
110
+ # Yield shapes up to the maximum limit
111
+ for idx, coords in enumerate(self.result_adapter.result.coords):
112
+ if idx >= max_shapes:
113
+ break
114
+ yield self.create_shape_item(coords, fmt, lbl, prefix)
115
+
116
+ # If shapes were truncated, create a warning label
117
+ if total_coords > max_shapes:
118
+ warning_text = "⚠ " + _("Only %d out of %d shapes are displayed") % (
119
+ max_shapes,
120
+ total_coords,
121
+ )
122
+ warning_label = make.label(warning_text, "BR", (0, 0), "BR")
123
+ warning_label.labelparam.font.bold = True
124
+ warning_label.labelparam.font.size = 10
125
+ warning_label.labelparam.bgalpha = 0.8
126
+ warning_label.labelparam.bgcolor = "#ff9800" # Orange background
127
+ warning_label.labelparam.textcolor = "#000000" # Black text
128
+ warning_label.labelparam.update_item(warning_label)
129
+ warning_label.set_readonly(True)
130
+ yield warning_label
131
+
132
+ def create_shape_item(
133
+ self, coords: np.ndarray, fmt: str, lbl: bool, prefix: Literal["s", "i"]
134
+ ) -> (
135
+ AnnotatedPoint
136
+ | Marker
137
+ | AnnotatedRectangle
138
+ | AnnotatedCircle
139
+ | AnnotatedSegment
140
+ | AnnotatedEllipse
141
+ | PolygonShape
142
+ | None
143
+ ):
144
+ """Create individual shape item from coordinates
145
+
146
+ Args:
147
+ coords: coordinate array
148
+ fmt: numeric format (e.g. "%.3f")
149
+ lbl: if True, show shape labels
150
+ prefix: "s" for signal, "i" for image
151
+
152
+ Returns:
153
+ Plot item
154
+ """
155
+ if self.result_adapter.result.kind == KindShape.POINT:
156
+ assert len(coords) == 2, "Coordinates must be a 2-element array"
157
+ x0, y0 = coords
158
+ item = AnnotatedPoint(x0, y0)
159
+ sparam: ShapeParam = item.shape.shapeparam
160
+ sparam.symbol.marker = "Ellipse"
161
+ sparam.symbol.size = 6
162
+ sparam.sel_symbol.marker = "Ellipse"
163
+ sparam.sel_symbol.size = 6
164
+ aparam = item.annotationparam
165
+ aparam.title = self.result_adapter.title
166
+ sparam.update_item(item.shape)
167
+ aparam.update_item(item)
168
+ elif self.result_adapter.result.kind == KindShape.MARKER:
169
+ assert len(coords) == 2, "Coordinates must be a 2-element array"
170
+ x0, y0 = coords
171
+ item = self.__make_marker_item(x0, y0, fmt)
172
+ elif self.result_adapter.result.kind == KindShape.RECTANGLE:
173
+ assert len(coords) == 4, "Coordinates must be a 4-element array"
174
+ x0, y0, dx, dy = coords
175
+ item = make.annotated_rectangle(
176
+ x0, y0, x0 + dx, y0 + dy, title=self.result_adapter.title
177
+ )
178
+ elif self.result_adapter.result.kind == KindShape.CIRCLE:
179
+ assert len(coords) == 3, "Coordinates must be a 3-element array"
180
+ xc, yc, r = coords
181
+ x0, y0, x1, y1 = coordinates.circle_to_diameter(xc, yc, r)
182
+ item = make.annotated_circle(
183
+ x0, y0, x1, y1, title=self.result_adapter.title
184
+ )
185
+ elif self.result_adapter.result.kind == KindShape.SEGMENT:
186
+ assert len(coords) == 4, "Coordinates must be a 4-element array"
187
+ x0, y0, x1, y1 = coords
188
+ item = make.annotated_segment(
189
+ x0, y0, x1, y1, title=self.result_adapter.title
190
+ )
191
+ elif self.result_adapter.result.kind == KindShape.ELLIPSE:
192
+ assert len(coords) == 5, "Coordinates must be a 5-element array"
193
+ xc, yc, a, b, t = coords
194
+ coords = coordinates.ellipse_to_diameters(xc, yc, a, b, t)
195
+ x0, y0, x1, y1, x2, y2, x3, y3 = coords
196
+ item = make.annotated_ellipse(
197
+ x0, y0, x1, y1, x2, y2, x3, y3, title=self.result_adapter.title
198
+ )
199
+ elif self.result_adapter.result.kind == KindShape.POLYGON:
200
+ assert len(coords) >= 6, "Coordinates must be at least 6-element array"
201
+ assert len(coords) % 2 == 0, "Coordinates must be even-length array"
202
+ x, y = coords[::2], coords[1::2]
203
+ # Filter out NaN coordinates to avoid performance issues
204
+ # Polygons are padded with NaNs to create regular arrays, but we only
205
+ # need to draw the valid coordinates
206
+ valid_mask = ~(np.isnan(x) | np.isnan(y))
207
+ x, y = x[valid_mask], y[valid_mask]
208
+ item = make.polygon(x, y, title=self.result_adapter.title, closed=False)
209
+ else:
210
+ raise NotImplementedError(
211
+ f"Unsupported shape kind: {self.result_adapter.result.kind}"
212
+ )
213
+
214
+ if isinstance(item, AnnotatedShape):
215
+ config_annotated_shape(item, fmt, lbl, "results", f"{prefix}/annotation")
216
+ # Apply settings for annotated shapes (except AnnotatedPoint)
217
+ if not isinstance(item, AnnotatedPoint):
218
+ if prefix == "s":
219
+ config_param = Conf.view.sig_shape_param.get()
220
+ else:
221
+ config_param = Conf.view.ima_shape_param.get()
222
+ shape_param: ShapeParam = item.shape.shapeparam
223
+ gds.update_dataset(shape_param, config_param)
224
+ shape_param.update_item(item.shape)
225
+
226
+ if isinstance(item, Marker):
227
+ item.set_style("results", f"{prefix}/marker")
228
+ # Apply cursor/marker settings from config
229
+ if prefix == "s":
230
+ config_param = Conf.view.sig_marker_param.get()
231
+ else:
232
+ config_param = Conf.view.ima_marker_param.get()
233
+ param = item.markerparam
234
+ gds.update_dataset(param, config_param)
235
+ param.update_item(item)
236
+
237
+ set_plot_item_editable(item, False)
238
+ return item
239
+
240
+ def __make_marker_item(self, x0: float, y0: float, fmt: str) -> Marker:
241
+ """Make marker item
242
+
243
+ Args:
244
+ x0: x coordinate
245
+ y0: y coordinate
246
+ fmt: numeric format (e.g. '%.3f')
247
+ """
248
+ if np.isnan(x0):
249
+ mstyle = "-"
250
+
251
+ def label(x, y): # pylint: disable=unused-argument
252
+ return (self.result_adapter.title + ": " + fmt) % y
253
+
254
+ elif np.isnan(y0):
255
+ mstyle = "|"
256
+
257
+ def label(x, y): # pylint: disable=unused-argument
258
+ return (self.result_adapter.title + ": " + fmt) % x
259
+
260
+ else:
261
+ mstyle = "+"
262
+ txt = self.result_adapter.title + ": (" + fmt + ", " + fmt + ")"
263
+
264
+ def label(x, y):
265
+ return txt % (x, y)
266
+
267
+ marker = make.marker(position=(x0, y0), markerstyle=mstyle, label_cb=label)
268
+ return marker
269
+
270
+
271
+ def create_pulse_segment(
272
+ x0: float, y0: float, x1: float, y1: float, label: str
273
+ ) -> AnnotatedSegment:
274
+ """Create a signal segment item for pulse visualization.
275
+
276
+ Args:
277
+ x0: X-coordinate of the start point
278
+ y0: Y-coordinate of the start point
279
+ x1: X-coordinate of the end point
280
+ y1: Y-coordinate of the end point
281
+ label: Label for the segment
282
+
283
+ Returns:
284
+ Annotated segment item styled for pulse visualization
285
+ """
286
+ item = make.annotated_segment(x0, y0, x1, y1, label, show_computations=False)
287
+
288
+ # Configure label appearance similar to Sigima's vistools
289
+ item.label.labelparam.bgalpha = 0.5
290
+ item.label.labelparam.anchor = "T"
291
+ item.label.labelparam.yc = 10
292
+ item.label.labelparam.update_item(item.label)
293
+
294
+ # Configure segment appearance
295
+ param = item.shape.shapeparam
296
+ param.line.color = "#33ff00" # Green color for baselines/plateaus
297
+ param.line.width = 5
298
+ param.symbol.facecolor = "#26be00"
299
+ param.symbol.edgecolor = "#33ff00"
300
+ param.symbol.marker = "Ellipse"
301
+ param.symbol.size = 11
302
+ param.update_item(item.shape)
303
+
304
+ # Make non-interactive
305
+ item.set_movable(False)
306
+ item.set_resizable(False)
307
+ item.set_selectable(False)
308
+
309
+ return item
310
+
311
+
312
+ def create_pulse_crossing_marker(
313
+ orientation: Literal["h", "v"], position: float, label: str
314
+ ) -> Marker:
315
+ """Create a crossing marker for pulse visualization.
316
+
317
+ Args:
318
+ orientation: 'h' for horizontal, 'v' for vertical cursor
319
+ position: Position of the cursor along the relevant axis
320
+ label: Label for the cursor
321
+
322
+ Returns:
323
+ Marker item styled for crossing visualization
324
+ """
325
+ if orientation == "h":
326
+ cursor = make.hcursor(position, label=label)
327
+ elif orientation == "v":
328
+ cursor = make.vcursor(position, label=label)
329
+ else:
330
+ raise ValueError("Orientation must be 'h' or 'v'")
331
+
332
+ # Configure appearance similar to Sigima's vistools
333
+ cursor.set_movable(False)
334
+ cursor.set_selectable(False)
335
+ cursor.markerparam.line.color = "#a7ff33" # Light green
336
+ cursor.markerparam.line.width = 3
337
+ cursor.markerparam.symbol.marker = "NoSymbol"
338
+ cursor.markerparam.text.textcolor = "#ffffff"
339
+ cursor.markerparam.text.background_color = "#000000"
340
+ cursor.markerparam.text.background_alpha = 0.5
341
+ cursor.markerparam.text.font.bold = True
342
+ cursor.markerparam.update_item(cursor)
343
+
344
+ return cursor
345
+
346
+
347
+ def are_values_valid(values: list[float | None]) -> bool:
348
+ """Check if all values are valid (not None or nan)
349
+
350
+ Args:
351
+ values: list of values
352
+
353
+ Returns:
354
+ True if all values are valid, False otherwise
355
+ """
356
+ for v in values:
357
+ if v is None or (isinstance(v, float) and np.isnan(v)):
358
+ return False
359
+ return True
360
+
361
+
362
+ class TablePlotPyAdapter(ResultPlotPyAdapter):
363
+ """Adapter for converting `sigima` table adapters to PlotPy
364
+
365
+ Args:
366
+ result: Table adapter
367
+
368
+ Raises:
369
+ AssertionError: invalid argument
370
+ """
371
+
372
+ def __init__(self, result_adapter: TableAdapter) -> None:
373
+ assert isinstance(result_adapter, TableAdapter)
374
+ super().__init__(result_adapter)
375
+
376
+ def get_other_items(self, obj: BaseObj) -> list:
377
+ """Return other items associated to this result (excluding label item)
378
+
379
+ Those items are not serialized to JSON.
380
+
381
+ Args:
382
+ obj: object (signal/image)
383
+
384
+ Returns:
385
+ List of other items
386
+ """
387
+ items = []
388
+ if self.result_adapter.result.is_pulse_features():
389
+ pulse_items = self.create_pulse_visualization_items(obj)
390
+ items.extend(pulse_items)
391
+ return items
392
+
393
+ def create_pulse_visualization_items(
394
+ self, obj: SignalObj
395
+ ) -> list[AnnotatedSegment | Marker]:
396
+ """Create pulse visualization items from table data.
397
+
398
+ Args:
399
+ obj: Signal object containing the pulse data
400
+
401
+ Returns:
402
+ List of PlotPy items for pulse visualization
403
+ """
404
+ items = []
405
+ df = self.result_adapter.to_dataframe()
406
+ for _index, row in df.iterrows():
407
+ # Start baseline
408
+ xs0, xs1 = row["xstartmin"], row["xstartmax"]
409
+ ys = pulse.get_range_mean_y(obj.x, obj.y, (xs0, xs1))
410
+ if are_values_valid([xs0, xs1, ys]):
411
+ items.append(create_pulse_segment(xs0, ys, xs1, ys, "Start baseline"))
412
+ # End baseline
413
+ xe0, xe1 = row["xendmin"], row["xendmax"]
414
+ ye = pulse.get_range_mean_y(obj.x, obj.y, (xe0, xe1))
415
+ if are_values_valid([xe0, xe1, ye]):
416
+ items.append(create_pulse_segment(xe0, ye, xe1, ye, "End baseline"))
417
+ if "xplateaumin" in row and "xplateaumax" in row:
418
+ xp0, xp1 = row["xplateaumin"], row["xplateaumax"]
419
+ yp = pulse.get_range_mean_y(obj.x, obj.y, (xp0, xp1))
420
+ if are_values_valid([xp0, xp1, yp]):
421
+ items.append(create_pulse_segment(xp0, yp, xp1, yp, "Plateau"))
422
+ for metric in ("x0", "x50", "x100"):
423
+ if metric in row:
424
+ x = row[metric]
425
+ metric_str = metric.replace("x", "x|<sub>") + "%</sub>"
426
+ if are_values_valid([x]):
427
+ items.append(create_pulse_crossing_marker("v", x, metric_str))
428
+ return items
429
+
430
+
431
+ class MergedResultPlotPyAdapter:
432
+ """Adapter for merging multiple result adapters into a single label.
433
+
434
+ This adapter manages a merged label that displays all results for a given object.
435
+ Instead of creating individual labels for each result (which causes overlapping),
436
+ it creates a single label with all results concatenated as HTML.
437
+
438
+ Args:
439
+ result_adapters: List of result adapters (GeometryAdapter or TableAdapter)
440
+ obj: Signal or image object associated with the results
441
+ """
442
+
443
+ def __init__(
444
+ self,
445
+ result_adapters: list[GeometryAdapter | TableAdapter],
446
+ obj: BaseObj,
447
+ ) -> None:
448
+ self.result_adapters = result_adapters
449
+ self.obj = obj
450
+ self._cached_label: LabelItem | None = None
451
+
452
+ def get_cached_label(self) -> LabelItem | None:
453
+ """Get the cached merged label item, if it exists.
454
+
455
+ Returns:
456
+ Merged label item, or None if not cached
457
+ """
458
+ return self._cached_label
459
+
460
+ def invalidate_cached_label(self) -> None:
461
+ """Invalidate the cached merged label item."""
462
+ self._cached_label = None
463
+
464
+ @property
465
+ def item_json(self) -> str | None:
466
+ """JSON representation of the merged label item.
467
+
468
+ The position is stored in all result adapters so they stay in sync.
469
+ """
470
+ if self.result_adapters:
471
+ return self.result_adapters[0].get_applicative_attr("item_json")
472
+ return None
473
+
474
+ @item_json.setter
475
+ def item_json(self, value: str | None) -> None:
476
+ """Set JSON representation of the merged label item.
477
+
478
+ The position is stored in all result adapters to keep them synchronized.
479
+ """
480
+ for result_adapter in self.result_adapters:
481
+ result_adapter.set_applicative_attr("item_json", value)
482
+
483
+ def create_merged_label(self) -> LabelItem | None:
484
+ """Create a single merged label from all result adapters.
485
+
486
+ Returns:
487
+ Merged label item, or None if no results
488
+ """
489
+ if not self.result_adapters:
490
+ return None
491
+
492
+ # Create the label with merged content
493
+ merged_html = resultadapter_to_html(self.result_adapters, self.obj)
494
+ item = make.label(merged_html, "TL", (0, 0), "TL", title="Results")
495
+ font = get_font(PLOTPY_CONF, "results", "label/font")
496
+ item.set_style("results", "label")
497
+ item.labelparam.font.update_param(font)
498
+ item.labelparam.update_item(item)
499
+
500
+ # Make label read-only (user cannot delete it to remove individual results)
501
+ item.set_readonly(True)
502
+
503
+ self._cached_label = item
504
+ return item
505
+
506
+ def get_merged_label(self) -> LabelItem | None:
507
+ """Get the merged label, creating it if necessary or updating if it exists.
508
+
509
+ Returns:
510
+ Merged label item, or None if no results
511
+ """
512
+ if not self.result_adapters:
513
+ self._cached_label = None
514
+ return None
515
+
516
+ # Try to restore existing label from stored JSON position
517
+ if self.item_json and self._cached_label is None:
518
+ stored_item = json_to_items(self.item_json)[0]
519
+ if isinstance(stored_item, LabelItem):
520
+ # Update the stored item with current merged content
521
+ merged_html = resultadapter_to_html(self.result_adapters, self.obj)
522
+ stored_item.set_text(merged_html)
523
+ stored_item.set_readonly(True)
524
+ self._cached_label = stored_item
525
+ return stored_item
526
+
527
+ # Update existing cached label if present
528
+ if self._cached_label is not None:
529
+ merged_html = resultadapter_to_html(self.result_adapters, self.obj)
530
+ self._cached_label.set_text(merged_html)
531
+ return self._cached_label
532
+
533
+ # Create new label
534
+ return self.create_merged_label()
535
+
536
+ def update_obj_metadata_from_item(self, item: LabelItem) -> None:
537
+ """Update all result adapters' metadata with the label item position.
538
+
539
+ Args:
540
+ item: Merged label item (after user moved it)
541
+ """
542
+ if item is not None:
543
+ self.item_json = items_to_json([item])
544
+ # Update all result adapters in the object's metadata
545
+ for result_adapter in self.result_adapters:
546
+ result_adapter.add_to(self.obj)
547
+
548
+ def get_other_items(self) -> list:
549
+ """Return other items from all result adapters (e.g., geometric shapes).
550
+
551
+ Returns:
552
+ List of all other items from all result adapters
553
+ """
554
+ items = []
555
+ for result_adapter in self.result_adapters:
556
+ if isinstance(result_adapter, GeometryAdapter):
557
+ plotpy_adapter = GeometryPlotPyAdapter(result_adapter)
558
+ elif isinstance(result_adapter, TableAdapter):
559
+ plotpy_adapter = TablePlotPyAdapter(result_adapter)
560
+ else:
561
+ raise NotImplementedError(
562
+ f"Unsupported result adapter type: {type(result_adapter)}"
563
+ )
564
+ items.extend(plotpy_adapter.get_other_items(self.obj))
565
+ return items