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,633 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ ROI editor
5
+ ==========
6
+
7
+ The :mod:`datalab.gui.roieditor` module provides the ROI editor widgets
8
+ for signals and images.
9
+
10
+ Signal ROI editor
11
+ -----------------
12
+
13
+ .. autoclass:: SignalROIEditor
14
+ :members:
15
+
16
+ Image ROI editor
17
+ ----------------
18
+
19
+ .. autoclass:: ImageROIEditor
20
+ :members:
21
+ """
22
+
23
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
24
+
25
+ from __future__ import annotations
26
+
27
+ import abc
28
+ import re
29
+ from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar, Union
30
+
31
+ from guidata.configtools import get_icon
32
+ from guidata.qthelpers import add_actions, create_action
33
+ from plotpy.items import (
34
+ AnnotatedCircle,
35
+ AnnotatedPolygon,
36
+ AnnotatedRectangle,
37
+ AnnotatedXRange,
38
+ CurveItem,
39
+ MaskedXYImageItem,
40
+ )
41
+ from plotpy.plot import PlotDialog, PlotManager, PlotOptions
42
+ from plotpy.tools import CircleTool, HRangeTool, PolygonTool, RectangleTool, SelectTool
43
+ from qtpy import QtCore as QC
44
+ from qtpy import QtWidgets as QW
45
+ from sigima.objects import (
46
+ CircularROI,
47
+ ImageObj,
48
+ ImageROI,
49
+ PolygonalROI,
50
+ RectangularROI,
51
+ ROI1DParam,
52
+ ROI2DParam,
53
+ SegmentROI,
54
+ SignalObj,
55
+ SignalROI,
56
+ TypeObj,
57
+ TypeROI,
58
+ )
59
+ from sigima.objects.base import get_generic_roi_title
60
+
61
+ from datalab.adapters_plotpy import (
62
+ TypePlotItem,
63
+ TypeROIItem,
64
+ configure_roi_item,
65
+ create_adapter_from_object,
66
+ plotitem_to_singleroi,
67
+ )
68
+ from datalab.config import Conf, _
69
+ from datalab.env import execenv
70
+
71
+ if TYPE_CHECKING:
72
+ from plotpy.plot import BasePlot
73
+ from plotpy.tools.base import InteractiveTool
74
+
75
+
76
+ def configure_roi_item_in_tool(shape, obj: SignalObj | ImageObj) -> None:
77
+ """Configure ROI item in tool"""
78
+ fmt = create_adapter_from_object(obj).get_obj_option("format")
79
+ configure_roi_item(shape, fmt, lbl=True, editable=True, option=obj.PREFIX)
80
+
81
+
82
+ def tool_deselect_items(tool: InteractiveTool) -> None:
83
+ """Deselect all items in plot associated with the tool"""
84
+ plot = tool.get_active_plot()
85
+ plot.select_some_items([]) # Deselect all items
86
+
87
+
88
+ def tool_setup_shape(
89
+ plot: BasePlot,
90
+ shape: TypeROIItem,
91
+ obj: SignalObj | ImageObj,
92
+ ) -> None:
93
+ """Tool setup shape"""
94
+ configure_roi_item_in_tool(shape, obj)
95
+ max_index = -1
96
+ for item in plot.get_items():
97
+ name = str(item.title().text())
98
+ match = re.match(r"ROI(\d+)", name)
99
+ if match is not None:
100
+ max_index = max(max_index, int(match.group(1)))
101
+ shape.setTitle(get_generic_roi_title(max_index + 1))
102
+
103
+
104
+ class ROISegmentTool(HRangeTool):
105
+ """ROI segment tool"""
106
+
107
+ TITLE = _("Range ROI")
108
+ ICON = "roi_sig.svg"
109
+
110
+ def __init__(self, manager: PlotManager, obj: SignalObj) -> None:
111
+ super().__init__(manager, switch_to_default_tool=False, toolbar_id=None)
112
+ self.roi = SegmentROI([0, 1], False)
113
+ self.obj = obj
114
+
115
+ def activate(self):
116
+ """Activate tool"""
117
+ tool_deselect_items(self)
118
+ super().activate()
119
+
120
+ def create_shape(self) -> AnnotatedXRange:
121
+ """Create shape"""
122
+ shape = create_adapter_from_object(self.roi).to_plot_item(self.obj)
123
+ tool_setup_shape(self.get_active_plot(), shape, self.obj)
124
+ return shape
125
+
126
+
127
+ class ROIRectangleTool(RectangleTool):
128
+ """ROI rectangle tool"""
129
+
130
+ TITLE = _("Rectangular ROI")
131
+ ICON = "roi_new_rectangle.svg"
132
+
133
+ def __init__(self, manager: PlotManager, obj: ImageObj) -> None:
134
+ super().__init__(manager, switch_to_default_tool=False, toolbar_id=None)
135
+ self.roi = RectangularROI([0, 0, 1, 1], False)
136
+ self.obj = obj
137
+
138
+ def activate(self):
139
+ """Activate tool"""
140
+ tool_deselect_items(self)
141
+ super().activate()
142
+
143
+ def create_shape(self) -> tuple[AnnotatedRectangle, int, int]:
144
+ """Create shape"""
145
+ item = create_adapter_from_object(self.roi).to_plot_item(self.obj)
146
+ return item, 0, 2
147
+
148
+ # Reimplement `RectangularShapeTool` method
149
+ def setup_shape(self, shape: AnnotatedRectangle) -> None:
150
+ """Setup shape"""
151
+ tool_setup_shape(self.get_active_plot(), shape, self.obj)
152
+
153
+
154
+ class ROICircleTool(CircleTool):
155
+ """ROI circle tool"""
156
+
157
+ TITLE = _("Circular ROI")
158
+ ICON = "roi_new_circle.svg"
159
+
160
+ def __init__(self, manager: PlotManager, obj: ImageObj) -> None:
161
+ super().__init__(manager, switch_to_default_tool=False, toolbar_id=None)
162
+ self.roi = CircularROI([0, 0, 1], False)
163
+ self.obj = obj
164
+
165
+ def activate(self):
166
+ """Activate tool"""
167
+ tool_deselect_items(self)
168
+ super().activate()
169
+
170
+ def create_shape(self) -> tuple[AnnotatedCircle, int, int]:
171
+ """Create shape"""
172
+ item = create_adapter_from_object(self.roi).to_plot_item(self.obj)
173
+ return item, 0, 1
174
+
175
+ # Reimplement `RectangularShapeTool` method
176
+ def setup_shape(self, shape: AnnotatedCircle) -> None:
177
+ """Setup shape"""
178
+ tool_setup_shape(self.get_active_plot(), shape, self.obj)
179
+
180
+
181
+ class ROIPolygonTool(PolygonTool):
182
+ """ROI polygon tool"""
183
+
184
+ TITLE = _("Polygonal ROI")
185
+ ICON = "roi_new_polygon.svg"
186
+
187
+ def __init__(self, manager: PlotManager, obj: ImageObj) -> None:
188
+ super().__init__(manager, switch_to_default_tool=False, toolbar_id=None)
189
+ self.roi = PolygonalROI([[0, 0], [1, 0], [1, 1], [0, 1]], False)
190
+ self.obj = obj
191
+
192
+ def activate(self):
193
+ """Activate tool"""
194
+ tool_deselect_items(self)
195
+ super().activate()
196
+
197
+ def create_shape(self) -> tuple[AnnotatedPolygon, int, int]:
198
+ """Create shape"""
199
+ return create_adapter_from_object(self.roi).to_plot_item(self.obj)
200
+
201
+ # Reimplement `RectangularShapeTool` method
202
+ def setup_shape(self, shape: AnnotatedPolygon) -> None:
203
+ """Setup shape"""
204
+ tool_setup_shape(self.get_active_plot(), shape, self.obj)
205
+
206
+
207
+ TypeROIEditor = TypeVar("TypeROIEditor", bound="BaseROIEditor")
208
+
209
+
210
+ class BaseROIEditorMeta(type(PlotDialog), abc.ABCMeta):
211
+ """Mixed metaclass to avoid conflicts"""
212
+
213
+
214
+ class BaseROIEditor(
215
+ PlotDialog,
216
+ Generic[TypeObj, TypeROI, TypePlotItem, TypeROIItem], # type: ignore
217
+ metaclass=BaseROIEditorMeta,
218
+ ):
219
+ """ROI Editor
220
+
221
+ Args:
222
+ parent: Parent plot dialog
223
+ obj: Object to edit (:class:`sigima.objects.SignalObj` or
224
+ :class:`sigima.objects.ImageObj`)
225
+ mode: Mode of operation, either "apply" (define ROI, then apply it to
226
+ selected objects), "extract" (define ROI, then extract data from it),
227
+ or "define" (define ROI without applying or extracting).
228
+ item: Optional plot item to add to the plot (if None, a new item is created
229
+ from the object)
230
+ """
231
+
232
+ ICON_NAME = None
233
+ OBJ_NAME = None
234
+ ROI_ITEM_TYPES = ()
235
+ ADDITIONAL_OPTIONS: dict[str, Any] = {}
236
+
237
+ def __init__(
238
+ self,
239
+ parent: QW.QWidget | None,
240
+ obj: SignalObj | ImageObj,
241
+ mode: Literal["apply", "extract", "define"] = "apply",
242
+ item: TypePlotItem | None = None,
243
+ options: PlotOptions | dict[str, Any] | None = None,
244
+ size: tuple[int, int] | None = None,
245
+ ) -> None:
246
+ assert mode in ("apply", "extract", "define"), (
247
+ f"Invalid mode: {mode}. Must be either 'apply', 'extract' or 'define'."
248
+ )
249
+ self.editor_layout: QW.QHBoxLayout | None = None
250
+ self.remove_all_action: QW.QAction | None = None
251
+ self.singleobj_btn: QW.QCheckBox | None = None
252
+ self.obj = obj
253
+ self.mode = mode
254
+ if item is None:
255
+ item = create_adapter_from_object(obj).make_item()
256
+ self.main_item = item
257
+ self.__modified: bool | None = None
258
+ self._tools: list[InteractiveTool] = []
259
+
260
+ # Create ROI associated with the object
261
+ if mode == "define":
262
+ # In "define" mode, we do not want to show the object's ROI to avoid any
263
+ # confusion with the ROI being defined
264
+ roi = None
265
+ else:
266
+ # In "apply" or "extract" mode, we want to show the object's ROI
267
+ # if it exists, otherwise create a new empty ROI
268
+ roi = obj.roi
269
+ if roi is None:
270
+ roi = self.get_obj_roi_class()()
271
+ self.__roi: TypeROI = roi
272
+
273
+ if options is None:
274
+ options = self.ADDITIONAL_OPTIONS
275
+ else:
276
+ options = options.copy(self.ADDITIONAL_OPTIONS)
277
+
278
+ roi_s = _("Regions of interest")
279
+ super().__init__(
280
+ parent=parent,
281
+ toolbar=mode != "define",
282
+ options=options,
283
+ title=f"{roi_s} - {obj.title}",
284
+ icon="DataLab.svg",
285
+ edit=True,
286
+ size=size,
287
+ )
288
+ self.setObjectName(f"{obj.PREFIX}_roi_editor")
289
+ self.accepted.connect(self.dialog_accepted)
290
+
291
+ # Create the ROI items
292
+ fmt = create_adapter_from_object(obj).get_obj_option("format")
293
+ roi_adapter = create_adapter_from_object(self.__roi)
294
+ self.roi_items: list[TypeROIItem] = list(
295
+ roi_adapter.iterate_roi_items(obj, fmt, True, True)
296
+ )
297
+
298
+ self.toolbar = QW.QToolBar(self)
299
+
300
+ self.add_tools_to_plot_dialog()
301
+ self.setup_editor_layout()
302
+ self.setup_items()
303
+
304
+ # force update of ROI titles and remove_all_btn state
305
+ self.items_changed(self.get_plot())
306
+
307
+ self.get_plot().SIG_ITEMS_CHANGED.connect(self.items_changed)
308
+ self.get_plot().SIG_ITEM_REMOVED.connect(self.item_removed)
309
+ self.get_plot().SIG_RANGE_CHANGED.connect(
310
+ lambda _rng, _min, _max: self.item_moved()
311
+ )
312
+ self.get_plot().SIG_ANNOTATION_CHANGED.connect(lambda _plt: self.item_moved())
313
+
314
+ # In "extract mode", the dialog box OK button should always been enabled
315
+ # when at least one ROI is defined,
316
+ # whereas in non-extract mode (when editing ROIs) the OK button is by default
317
+ # disabled (until ROI data is modified)
318
+ if self.mode == "extract":
319
+ self.modified = len(self.roi_items) > 0
320
+ else:
321
+ self.modified = False
322
+
323
+ def setup_layout(self) -> None: # Reimplement PlotDialog method
324
+ """Populate the plot layout"""
325
+ super().setup_layout()
326
+ self.editor_layout = QW.QHBoxLayout()
327
+ self.button_layout.insertLayout(0, self.editor_layout)
328
+
329
+ def setup_editor_layout(self) -> None:
330
+ """Setup editor layout"""
331
+ self.toolbar.setToolButtonStyle(QC.Qt.ToolButtonTextUnderIcon)
332
+ add_actions(self.toolbar, self.create_actions())
333
+ for action in self.toolbar.actions():
334
+ if action.menu() is not None:
335
+ widget = self.toolbar.widgetForAction(action)
336
+ widget.setPopupMode(QW.QToolButton.ToolButtonPopupMode.InstantPopup)
337
+ self.editor_layout.addWidget(self.toolbar)
338
+ if self.mode == "extract":
339
+ self.singleobj_btn = QW.QCheckBox(
340
+ _("Extract all ROIs\ninto a single %s") % self.OBJ_NAME,
341
+ self,
342
+ )
343
+ self.editor_layout.addWidget(self.singleobj_btn)
344
+ self.singleobj_btn.setChecked(Conf.proc.extract_roi_singleobj.get())
345
+ self.editor_layout.addStretch()
346
+
347
+ def setup_items(self) -> None:
348
+ """Setup items"""
349
+ self.main_item.set_selectable(False)
350
+ self.main_item.set_readonly(True)
351
+ plot = self.get_plot()
352
+ plot.add_item(self.main_item)
353
+ plot.set_active_item(self.main_item)
354
+ self.main_item.unselect()
355
+ for roi_item in self.roi_items:
356
+ plot.add_item(roi_item)
357
+ plot.set_active_item(roi_item)
358
+
359
+ @abc.abstractmethod
360
+ def get_obj_roi_class(self) -> type[TypeROI]:
361
+ """Get object ROI class"""
362
+
363
+ def add_tools_to_plot_dialog(self) -> None:
364
+ """Add tools to plot dialog"""
365
+ mgr = self.get_manager()
366
+ select_tool = mgr.get_tool(SelectTool)
367
+ add_actions(self.toolbar, [select_tool.action])
368
+
369
+ @property
370
+ def modified(self) -> bool:
371
+ """Return dialog modified state"""
372
+ return self.__modified
373
+
374
+ @modified.setter
375
+ def modified(self, value: bool) -> None:
376
+ """Set dialog modified state"""
377
+ self.__modified = value
378
+ if self.mode in ("extract", "define"):
379
+ # In "extract" mode or in "define" mode, OK button is enabled
380
+ # when at least one ROI is defined
381
+ value = value and len(self.roi_items) > 0
382
+ self.button_box.button(QW.QDialogButtonBox.Ok).setEnabled(value)
383
+
384
+ def dialog_accepted(self) -> None:
385
+ """Parent dialog was accepted: updating ROI Editor data"""
386
+ self.__roi.empty()
387
+ for roi_item in self.roi_items:
388
+ self.__roi.add_roi(plotitem_to_singleroi(roi_item))
389
+ if self.singleobj_btn is not None:
390
+ Conf.proc.extract_roi_singleobj.set(self.singleobj_btn.isChecked())
391
+
392
+ def get_roieditor_results(self) -> tuple[TypeROI, bool]:
393
+ """Get ROI editor results
394
+
395
+ Returns:
396
+ A tuple containing the ROI data parameters and ROI modified state.
397
+ ROI modified state is True if the ROI data has been modified within
398
+ the dialog box.
399
+ """
400
+ return self.__roi, self.modified
401
+
402
+ def create_coordinate_based_roi_actions(self) -> list[QW.QAction]:
403
+ """Create coordinate-based ROI actions"""
404
+ return []
405
+
406
+ def __new_action_menu(
407
+ self, title: str, icon: str, actions: list[QW.QAction]
408
+ ) -> QW.QAction:
409
+ """Create a new action menu"""
410
+ menu = QW.QMenu(title)
411
+ for action in actions:
412
+ menu.addAction(action)
413
+ action = QW.QAction(get_icon(icon), title, self)
414
+ action.setMenu(menu)
415
+ return action
416
+
417
+ def create_actions(self) -> list[QW.QAction]:
418
+ """Create actions"""
419
+ g_menu_act = self.__new_action_menu(
420
+ _("Graphical ROI"),
421
+ "roi_graphical.svg",
422
+ [tool.action for tool in self._tools],
423
+ )
424
+ c_menu_act = self.__new_action_menu(
425
+ _("Coordinate-based ROI"),
426
+ "roi_coordinate.svg",
427
+ self.create_coordinate_based_roi_actions(),
428
+ )
429
+ self.remove_all_action = create_action(
430
+ self,
431
+ _("Remove all"),
432
+ icon=get_icon("roi_delete.svg"),
433
+ triggered=self.remove_all_rois,
434
+ )
435
+ return [g_menu_act, c_menu_act, None, self.remove_all_action]
436
+
437
+ def remove_all_rois(self) -> None:
438
+ """Remove all ROIs"""
439
+ if (
440
+ execenv.unattended
441
+ or QW.QMessageBox.question(
442
+ self,
443
+ _("Remove all ROIs"),
444
+ _("Are you sure you want to remove all ROIs?"),
445
+ )
446
+ == QW.QMessageBox.Yes
447
+ ):
448
+ self.get_plot().del_items(self.roi_items)
449
+
450
+ def get_roi_items(self) -> list[TypeROIItem]:
451
+ """Get ROI items"""
452
+ return self.roi_items
453
+
454
+ def update_roi_items(self) -> None:
455
+ """Update ROI items"""
456
+ old_nb_items = len(self.roi_items)
457
+ self.roi_items = [
458
+ item
459
+ for item in self.get_plot().get_items()
460
+ if isinstance(item, self.ROI_ITEM_TYPES)
461
+ ]
462
+ self.get_plot().select_some_items([])
463
+ if old_nb_items != len(self.roi_items):
464
+ self.modified = True
465
+
466
+ def items_changed(self, _plot: BasePlot) -> None:
467
+ """Items have changed"""
468
+ self.update_roi_items()
469
+ self.remove_all_action.setEnabled(len(self.roi_items) > 0)
470
+
471
+ def item_removed(self, item) -> None:
472
+ """Item was removed. Since all items are read-only except ROIs...
473
+ this must be an ROI."""
474
+ assert item in self.roi_items
475
+ self.update_roi_items()
476
+ self.modified = True
477
+
478
+ def item_moved(self) -> None:
479
+ """ROI plot item has just been moved"""
480
+ self.modified = True
481
+
482
+
483
+ class SignalROIEditor(BaseROIEditor[SignalObj, SignalROI, CurveItem, AnnotatedXRange]):
484
+ """Signal ROI Editor
485
+
486
+ Args:
487
+ parent: Parent plot dialog
488
+ obj: Object to edit (:class:`sigima.objects.SignalObj` or
489
+ :class:`sigima.objects.ImageObj`)
490
+ mode: Mode of operation, either "apply" (define ROI, then apply it to
491
+ selected objects), "extract" (define ROI, then extract data from it),
492
+ or "define" (define ROI without applying or extracting).
493
+ item: Optional plot item to add to the plot (if None, a new item is created
494
+ from the object)
495
+ """
496
+
497
+ ICON_NAME = "roi_sig.svg"
498
+ OBJ_NAME = _("signal")
499
+ ROI_ITEM_TYPES = (AnnotatedXRange,)
500
+
501
+ def __init__(
502
+ self,
503
+ parent: QW.QWidget | None,
504
+ obj: SignalObj | ImageObj,
505
+ mode: Literal["apply", "extract", "define"] = "apply",
506
+ item: TypePlotItem | None = None,
507
+ options: PlotOptions | dict[str, Any] | None = None,
508
+ size: tuple[int, int] | None = None,
509
+ ) -> None:
510
+ super().__init__(
511
+ parent=parent,
512
+ obj=obj,
513
+ mode=mode,
514
+ item=item,
515
+ options=options,
516
+ size=size,
517
+ )
518
+
519
+ def get_obj_roi_class(self) -> type[SignalROI]:
520
+ """Get object ROI class"""
521
+ return SignalROI
522
+
523
+ def add_tools_to_plot_dialog(self) -> None:
524
+ """Add tools to plot dialog"""
525
+ super().add_tools_to_plot_dialog()
526
+ mgr = self.get_manager()
527
+ segm_tool = mgr.add_tool(ROISegmentTool, self.obj)
528
+ self._tools.append(segm_tool)
529
+ segm_tool.activate()
530
+
531
+ def manually_add_roi(self) -> None:
532
+ """Manually add segment ROI"""
533
+ param = ROI1DParam()
534
+ if param.edit(parent=self):
535
+ segment_roi = param.to_single_roi(self.obj)
536
+ shape = create_adapter_from_object(segment_roi).to_plot_item(self.obj)
537
+ configure_roi_item_in_tool(shape, self.obj)
538
+ self.get_plot().add_item(shape)
539
+ self.get_plot().set_active_item(shape)
540
+
541
+ def create_coordinate_based_roi_actions(self) -> list[QW.QAction]:
542
+ """Create coordinate-based ROI actions"""
543
+ segcoord_act = create_action(
544
+ self,
545
+ _("Range ROI"),
546
+ icon=get_icon("roi_sig.svg"),
547
+ triggered=self.manually_add_roi,
548
+ )
549
+ return [segcoord_act]
550
+
551
+
552
+ class ImageROIEditor(
553
+ BaseROIEditor[
554
+ ImageObj,
555
+ ImageROI,
556
+ MaskedXYImageItem,
557
+ # `Union` is mandatory here for Python 3.9-3.10 compatibility:
558
+ Union[AnnotatedPolygon, AnnotatedRectangle, AnnotatedCircle],
559
+ ]
560
+ ):
561
+ """Image ROI Editor
562
+
563
+ Args:
564
+ parent: Parent plot dialog
565
+ obj: Object to edit (:class:`sigima.objects.SignalObj` or
566
+ :class:`sigima.objects.ImageObj`)
567
+ mode: Mode of operation, either "apply" (define ROI, then apply it to
568
+ selected objects), "extract" (define ROI, then extract data from it),
569
+ or "define" (define ROI without applying or extracting).
570
+ item: Optional plot item to add to the plot (if None, a new item is created
571
+ from the object)
572
+ """
573
+
574
+ ICON_NAME = "roi_ima.svg"
575
+ OBJ_NAME = _("image")
576
+ ROI_ITEM_TYPES = (AnnotatedRectangle, AnnotatedCircle, AnnotatedPolygon)
577
+ ADDITIONAL_OPTIONS = {"show_itemlist": True, "show_contrast": False}
578
+
579
+ def get_obj_roi_class(self) -> type[ImageROI]:
580
+ """Get object ROI class"""
581
+ return ImageROI
582
+
583
+ def add_tools_to_plot_dialog(self) -> None:
584
+ """Add tools to plot dialog"""
585
+ super().add_tools_to_plot_dialog()
586
+ mgr = self.get_manager()
587
+ rect_tool = mgr.add_tool(ROIRectangleTool, self.obj)
588
+ circ_tool = mgr.add_tool(ROICircleTool, self.obj)
589
+ poly_tool = mgr.add_tool(ROIPolygonTool, self.obj)
590
+ self._tools.extend([rect_tool, circ_tool, poly_tool])
591
+ rect_tool.activate()
592
+
593
+ def manually_add_roi(
594
+ self, roi_type: Literal["rectangle", "circle", "polygon"]
595
+ ) -> None:
596
+ """Manually add image ROI"""
597
+ assert roi_type in ("rectangle", "circle", "polygon")
598
+ if roi_type == "polygon":
599
+ raise NotImplementedError("Manual polygonal ROI creation is not supported")
600
+ param = ROI2DParam()
601
+ param.geometry = roi_type
602
+ if param.edit(parent=self):
603
+ roi = param.to_single_roi(self.obj)
604
+ shape = create_adapter_from_object(roi).to_plot_item(self.obj)
605
+ configure_roi_item_in_tool(shape, self.obj)
606
+ self.get_plot().add_item(shape)
607
+ self.get_plot().set_active_item(shape)
608
+
609
+ def create_coordinate_based_roi_actions(self) -> list[QW.QAction]:
610
+ """Create coordinate-based ROI actions"""
611
+ rectcoord_act = create_action(
612
+ self,
613
+ _("Rectangular ROI"),
614
+ icon=get_icon("roi_new_rectangle.svg"),
615
+ triggered=lambda: self.manually_add_roi("rectangle"),
616
+ )
617
+ circcoord_act = create_action(
618
+ self,
619
+ _("Circular ROI"),
620
+ icon=get_icon("roi_new_circle.svg"),
621
+ triggered=lambda: self.manually_add_roi("circle"),
622
+ )
623
+ return [rectcoord_act, circcoord_act]
624
+
625
+ def setup_items(self) -> None:
626
+ """Setup items"""
627
+ super().setup_items()
628
+ # In "define" mode, we want to show the mask that is associated with the
629
+ # image's ROI, if it exists, because the ROI that is being defined has nothing
630
+ # to do with the image's ROI: it is just a temporary ROI that will for example
631
+ # be used in a processing function, so the user need to visualize the mask that
632
+ # corresponds to the data on which the processing function will be applied.
633
+ self.main_item.set_mask_visible(self.mode == "define")