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,786 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ DataLab Text Import Wizard
5
+ --------------------------
6
+
7
+ The DataLab Import Wizard is a tool for importing data from a text source:
8
+
9
+ - Clipboard
10
+ - File (csv, txt, etc.)
11
+
12
+ It is based on the DataLab Wizard widget, which is a widget that guides the user
13
+ through a series of steps to complete a task. It is implemented as a series of
14
+ pages, each of which is a separate widget.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import io
20
+ import os.path as osp
21
+ from typing import TYPE_CHECKING, Generator
22
+
23
+ import guidata.dataset as gds
24
+ import guidata.dataset.qtwidgets as gdq
25
+ import numpy as np
26
+ import pandas as pd
27
+ from guidata.configtools import get_icon
28
+ from guidata.widgets.codeeditor import CodeEditor
29
+ from plotpy.plot import PlotOptions, PlotWidget
30
+ from qtpy import QtCore as QC
31
+ from qtpy import QtGui as QG
32
+ from qtpy import QtWidgets as QW
33
+ from sigima import ImageObj, SignalObj, create_image, create_signal
34
+ from sigima.io.common.textreader import count_lines, read_first_n_lines
35
+ from sigima.io.signal.funcs import get_labels_units_from_dataframe, read_csv_by_chunks
36
+
37
+ from datalab.adapters_plotpy import CURVESTYLES, create_adapter_from_object
38
+ from datalab.config import Conf, _
39
+ from datalab.utils.qthelpers import (
40
+ CallbackWorker,
41
+ create_progress_bar,
42
+ qt_long_callback,
43
+ )
44
+ from datalab.widgets.wizard import Wizard, WizardPage
45
+
46
+ if TYPE_CHECKING:
47
+ from plotpy.items import CurveItem, MaskedXYImageItem
48
+ from plotpy.plot import BasePlot
49
+ from qtpy.QtWidgets import QWidget
50
+
51
+
52
+ class SourceParam(gds.DataSet):
53
+ """Source parameters dataset"""
54
+
55
+ def __init__(self, source_page: SourcePage) -> None:
56
+ super().__init__()
57
+ self.source_page = source_page
58
+
59
+ # pylint: disable=unused-argument
60
+ def source_callback(self, item: gds.ChoiceItem, value: str) -> None:
61
+ """Source callback"""
62
+ if value == "clipboard":
63
+ is_valid = bool(QW.QApplication.clipboard().text())
64
+ else:
65
+ is_valid = self.path is not None and osp.isfile(self.path)
66
+ self.source_page.set_valid(is_valid)
67
+
68
+ def file_callback(self, item: gds.FileOpenItem, value: str | None) -> None:
69
+ """File callback"""
70
+ self.source_page.set_valid(value is not None and osp.isfile(value))
71
+
72
+ _prop = gds.GetAttrProp("choice")
73
+ source = (
74
+ gds.ChoiceItem(
75
+ _("Source"),
76
+ [("clipboard", _("Clipboard")), ("file", _("File"))],
77
+ default="file",
78
+ help=_("Source of the data"),
79
+ radio=True,
80
+ )
81
+ .set_prop("display", store=_prop)
82
+ .set_prop("display", callback=source_callback)
83
+ )
84
+ path = (
85
+ gds.FileOpenItem(
86
+ _("File"),
87
+ formats=("txt", "csv", "dat", "asc", "mca"),
88
+ check=False,
89
+ help=_("File containing the data"),
90
+ )
91
+ .set_prop("display", active=gds.FuncProp(_prop, lambda x: x == "file"))
92
+ .set_prop("display", callback=file_callback)
93
+ )
94
+ _bg = gds.BeginGroup(_("Preview parameters"))
95
+ preview_max_rows = gds.IntItem(
96
+ _("Maximum Number of Rows"),
97
+ default=100000,
98
+ min=1,
99
+ check=False,
100
+ help=_("Maximum number of rows to display"),
101
+ ).set_prop("display", active=gds.FuncProp(_prop, lambda x: x == "file"))
102
+ _eg = gds.EndGroup(_("Preview parameters"))
103
+
104
+
105
+ class SourcePage(WizardPage):
106
+ """Source page"""
107
+
108
+ def __init__(self) -> None:
109
+ super().__init__()
110
+ self.__text = ""
111
+ self.__path = ""
112
+ self.__loaded_partially = True
113
+ self.set_title(_("Source"))
114
+ self.set_subtitle(_("Select the source of the data:"))
115
+
116
+ self.param_widget = gdq.DataSetEditGroupBox(
117
+ _("Source Parameters"), SourceParam, show_button=False, source_page=self
118
+ )
119
+ self.param = self.param_widget.dataset
120
+ self.add_to_layout(self.param_widget)
121
+
122
+ self.add_stretch()
123
+ self.set_valid(False)
124
+
125
+ def get_source_path(self) -> str | None:
126
+ """Return the selected source path, or None if clipboard is selected"""
127
+ return self.param.path if self.param.source == "file" else None
128
+
129
+ def get_source_text(self, preview: bool) -> str:
130
+ """Return the source text"""
131
+ if not self.__loaded_partially or preview:
132
+ return self.__text
133
+ with open(self.__path, "r", encoding="utf-8") as file:
134
+ self.__text = file.read()
135
+ self.__loaded_partially = False
136
+ return self.__text
137
+
138
+ def validate_page(self) -> bool:
139
+ """Validate the page"""
140
+ self.__text = ""
141
+ self.param_widget.set()
142
+ if self.param.source == "file":
143
+ self.__path = self.get_source_path()
144
+ if self.__path is not None and osp.isfile(self.__path):
145
+ try:
146
+ self.__text = read_first_n_lines(
147
+ self.__path, n=self.param.preview_max_rows
148
+ )
149
+ except Exception: # pylint:disable=broad-except
150
+ return False
151
+ self.__loaded_partially = (
152
+ count_lines(self.__path) > self.param.preview_max_rows
153
+ )
154
+ else:
155
+ return False
156
+ else:
157
+ self.__text = QW.QApplication.clipboard().text()
158
+ self.__loaded_partially = False
159
+ return bool(self.__text)
160
+
161
+
162
+ class BaseImportParam(gds.DataSet):
163
+ """Import parameters dataset"""
164
+
165
+ delimiter_choice = gds.ChoiceItem(
166
+ _("Delimiter"),
167
+ [
168
+ (",", ","),
169
+ (";", ";"),
170
+ ("\t", _("Tab")),
171
+ (" ", _("Space")),
172
+ ],
173
+ help=_("Column delimiter character"),
174
+ )
175
+ decimal_choice = gds.ChoiceItem(
176
+ _("Decimal"),
177
+ [(".", _("Point")), (",", _("Comma"))],
178
+ help=_("Decimal separator character"),
179
+ default=".",
180
+ ).set_pos(col=1)
181
+ comment_char = gds.StringItem(
182
+ _("Comments"),
183
+ default="#",
184
+ help=_("Character that indicates a comment line"),
185
+ ).set_pos(col=2)
186
+ skip_rows = gds.IntItem(
187
+ _("Rows to Skip"),
188
+ default=0,
189
+ help=_(
190
+ "Number of rows to skip at the beginning of the file (including comments)"
191
+ ),
192
+ )
193
+ max_rows = gds.IntItem(
194
+ _("Max. nb of rows"),
195
+ default=None,
196
+ min=1,
197
+ check=False,
198
+ help=_("Maximum number of rows to import"),
199
+ ).set_pos(col=1)
200
+ header = gds.ChoiceItem(
201
+ _("Header"),
202
+ ((None, _("None")), ("infer", _("Infer")), (0, _("First row"))),
203
+ default="infer",
204
+ help=_("Row index to use as the column names"),
205
+ ).set_pos(col=2)
206
+ transpose = gds.BoolItem(
207
+ _("Transpose"),
208
+ default=False,
209
+ help=_("Transpose the data (swap rows and columns)"),
210
+ )
211
+
212
+
213
+ class SignalImportParam(BaseImportParam):
214
+ """Signal import parameters dataset"""
215
+
216
+ VALID_DTYPES_STRLIST = SignalObj.get_valid_dtypenames()
217
+
218
+ dtype_str = gds.ChoiceItem(
219
+ _("Data type"),
220
+ list(zip(VALID_DTYPES_STRLIST, VALID_DTYPES_STRLIST)),
221
+ help=_("Output signal data type."),
222
+ default="float64",
223
+ ).set_pos(col=1)
224
+ first_col_is_x = gds.BoolItem(
225
+ _("First Column is X"),
226
+ default=True,
227
+ help=_(
228
+ "First column contains the X values\n(ignored if there is only one column)"
229
+ ),
230
+ ).set_pos(col=2)
231
+
232
+
233
+ class ImageImportParam(BaseImportParam):
234
+ """Image import parameters dataset"""
235
+
236
+ VALID_DTYPES_STRLIST = ImageObj.get_valid_dtypenames()
237
+
238
+ dtype_str = gds.ChoiceItem(
239
+ _("Data type"),
240
+ list(zip(VALID_DTYPES_STRLIST, VALID_DTYPES_STRLIST)),
241
+ help=_("Output image data type."),
242
+ default="uint16",
243
+ ).set_pos(col=1)
244
+
245
+
246
+ class ArrayModel(QC.QAbstractTableModel):
247
+ """Array model
248
+
249
+ Args:
250
+ parent: Parent widget
251
+ data: Data array
252
+ horizontal_headers: Horizontal headers
253
+ """
254
+
255
+ # pylint: disable=invalid-name
256
+
257
+ def __init__(
258
+ self,
259
+ parent: QWidget,
260
+ data: np.ndarray,
261
+ horizontal_headers: list[str] | None = None,
262
+ ) -> None:
263
+ super().__init__(parent)
264
+ self.__data = data
265
+ self.__horizontal_headers = horizontal_headers
266
+
267
+ def rowCount(self, _parent: QC.QModelIndex) -> int:
268
+ """Return the row count
269
+ (reimplement the `QC.QAbstractTableModel` method)"""
270
+ return self.__data.shape[0]
271
+
272
+ def columnCount(self, _parent: QC.QModelIndex) -> int:
273
+ """Return the column count
274
+ (reimplement the `QC.QAbstractTableModel` method)"""
275
+ return self.__data.shape[1]
276
+
277
+ def data(self, index: QC.QModelIndex, role: int) -> str | None:
278
+ """Return the data
279
+ (reimplement the `QC.QAbstractTableModel` method)"""
280
+ if role == QC.Qt.DisplayRole:
281
+ return str(self.__data[index.row(), index.column()])
282
+ return None
283
+
284
+ def headerData(self, section: int, orientation: int, role: int) -> str | None:
285
+ """Return the header data
286
+ (reimplement the `QC.QAbstractTableModel` method)"""
287
+ if (
288
+ role == QC.Qt.DisplayRole
289
+ and orientation == QC.Qt.Horizontal
290
+ and self.__horizontal_headers is not None
291
+ ):
292
+ return self.__horizontal_headers[section]
293
+ return super().headerData(section, orientation, role)
294
+
295
+
296
+ class ArrayView(QW.QTableView):
297
+ """Array view
298
+
299
+ Args:
300
+ parent: Parent widget
301
+ """
302
+
303
+ def __init__(self, parent: QWidget) -> None:
304
+ super().__init__(parent)
305
+ self.setShowGrid(True)
306
+ self.setAlternatingRowColors(True)
307
+
308
+ def set_data(
309
+ self, data: np.ndarray, horizontal_headers: list[str] | None = None
310
+ ) -> None:
311
+ """Set the data
312
+
313
+ Args:
314
+ data: Data array
315
+ horizontal_headers: Horizontal headers
316
+ """
317
+ model = ArrayModel(self, data, horizontal_headers)
318
+ self.setModel(model)
319
+
320
+
321
+ class PreviewWidget(QW.QWidget):
322
+ """Widget showing the raw data, the prefiltered data and a preview of the data"""
323
+
324
+ def __init__(self, parent: QWidget, destination: str) -> None:
325
+ super().__init__(parent)
326
+ self.destination = destination
327
+ main_layout = QW.QVBoxLayout()
328
+ self.setLayout(main_layout)
329
+
330
+ self.tabwidget = tw = QW.QTabWidget()
331
+ self._raw_text_edit = self.create_editor()
332
+ tw.addTab(
333
+ self._raw_text_edit, get_icon("libre-gui-questions.svg"), _("Raw Data")
334
+ )
335
+ self._preview_table = ArrayView(self)
336
+ self._preview_table.setFont(self._raw_text_edit.font())
337
+ self._preview_table.setEditTriggers(QW.QAbstractItemView.NoEditTriggers)
338
+ tw.addTab(self._preview_table, get_icon("table.svg"), _("Preview"))
339
+ main_layout.addWidget(tw)
340
+
341
+ def create_editor(self) -> CodeEditor:
342
+ """Create a code editor"""
343
+ editor = CodeEditor()
344
+ font = editor.font()
345
+ font.setPointSize(font.pointSize() - 2)
346
+ editor.setFont(font)
347
+ editor.setReadOnly(True)
348
+ editor.setWordWrapMode(QG.QTextOption.NoWrap)
349
+ return editor
350
+
351
+ def set_raw_data(self, data: str) -> None:
352
+ """Set the raw data"""
353
+ self._raw_text_edit.setPlainText(data)
354
+
355
+ def __clear_preview_table(self, enable: bool) -> None:
356
+ """Clear the preview table"""
357
+ self._preview_table.setModel(None)
358
+ self._preview_table.setEnabled(enable)
359
+ idx = self.tabwidget.indexOf(self._preview_table)
360
+ icon_name = "table.svg" if enable else "table_unavailable.svg"
361
+ self.tabwidget.setTabIcon(idx, get_icon(icon_name))
362
+ if enable:
363
+ self.tabwidget.setCurrentIndex(idx)
364
+
365
+ def set_preview_data(
366
+ self, df: pd.DataFrame | None, param: SignalImportParam | ImageImportParam
367
+ ) -> None:
368
+ """Set the preview data"""
369
+ data = df.to_numpy(np.dtype(param.dtype_str)) if df is not None else None
370
+ if data is None or len(data.shape) not in (1, 2) or data.size == 0:
371
+ self.__clear_preview_table(False)
372
+ else:
373
+ self.__clear_preview_table(True)
374
+ if self.destination == "signal":
375
+ assert param.first_col_is_x is not None
376
+ h_headers = df.columns.tolist()
377
+ else:
378
+ h_headers = None
379
+ self._preview_table.set_data(data, horizontal_headers=h_headers)
380
+
381
+
382
+ def str_to_dataframe(
383
+ raw_data: str,
384
+ param: SignalImportParam | ImageImportParam,
385
+ worker: CallbackWorker | None = None,
386
+ ) -> pd.DataFrame | None:
387
+ """Convert raw data to a DataFrame
388
+
389
+ Args:
390
+ raw_data: Raw data
391
+ param: Import parameters
392
+ worker: Callback worker object
393
+ parent: Parent widget
394
+
395
+ Returns:
396
+ The DataFrame, or None if the conversion failed
397
+ """
398
+ if not raw_data:
399
+ return None
400
+ textstream = io.StringIO(raw_data)
401
+ nlines = raw_data.count("\n") + (not raw_data.endswith("\n"))
402
+ try:
403
+ df = read_csv_by_chunks(
404
+ textstream,
405
+ nlines,
406
+ worker=worker,
407
+ decimal=param.decimal_choice,
408
+ delimiter=param.delimiter_choice,
409
+ skiprows=param.skip_rows,
410
+ nrows=param.max_rows,
411
+ comment=param.comment_char,
412
+ header=param.header,
413
+ )
414
+ df.to_numpy(np.dtype(param.dtype_str)) # To eventually raise ValueError
415
+ except Exception: # pylint:disable=broad-except
416
+ return None
417
+ # Remove rows and columns where all values are NaN in the DataFrame:
418
+ df = df.dropna(axis=0, how="all").dropna(axis=1, how="all")
419
+ if param.transpose:
420
+ return df.T
421
+ return df
422
+
423
+
424
+ class DataPreviewPage(WizardPage):
425
+ """Data preview page
426
+
427
+ Args:
428
+ destination: Destination type ('signal' or 'image')
429
+ """
430
+
431
+ def __init__(self, source_page: SourcePage, destination: str) -> None:
432
+ super().__init__()
433
+ self.__quick_update = False
434
+ self.source_page = source_page
435
+ self.destination = destination
436
+ self.__preview_df: pd.DataFrame | None = None
437
+ self.set_title(_("Data Preview"))
438
+ self.set_subtitle(_("Preview and modify the import settings:"))
439
+
440
+ self.param_widget = gdq.DataSetEditGroupBox(
441
+ _("Import Parameters"),
442
+ SignalImportParam if destination == "signal" else ImageImportParam,
443
+ )
444
+ self.param_widget.SIG_APPLY_BUTTON_CLICKED.connect(self.update_preview)
445
+ self.param_widget.set_apply_button_state(False)
446
+ self.param = self.param_widget.dataset
447
+ self.add_to_layout(self.param_widget)
448
+
449
+ self.preview_widget = PreviewWidget(self, destination)
450
+ self.preview_widget.setSizePolicy(
451
+ QW.QSizePolicy(QW.QSizePolicy.Expanding, QW.QSizePolicy.Expanding)
452
+ )
453
+ self.add_to_layout(self.preview_widget)
454
+
455
+ def read_data_callback(self, worker: CallbackWorker) -> pd.DataFrame:
456
+ """Read data callback
457
+
458
+ Args:
459
+ worker: Callback worker object
460
+
461
+ Returns:
462
+ The DataFrame
463
+ """
464
+ source_text = self.source_page.get_source_text(preview=False)
465
+ df = str_to_dataframe(source_text, self.param, worker)
466
+ return df
467
+
468
+ def get_dataframe(self) -> pd.DataFrame | None:
469
+ """Return the data
470
+
471
+ Returns:
472
+ The data frame, or None if the data could not be converted
473
+ """
474
+ worker = CallbackWorker(self.read_data_callback)
475
+ df = qt_long_callback(self, _("Reading data"), worker, 100)
476
+ return df
477
+
478
+ def update_preview(self) -> None:
479
+ """Update the preview"""
480
+ # Raw data
481
+ raw_data = self.source_page.get_source_text(preview=True)
482
+ self.preview_widget.set_raw_data(raw_data)
483
+ # Preview
484
+ df = str_to_dataframe(raw_data, self.param)
485
+ if not self.__quick_update:
486
+ self.preview_widget.set_preview_data(df, param=self.param)
487
+ self.__preview_df = df
488
+ self.set_valid(df is not None)
489
+
490
+ def initialize_page(self) -> None:
491
+ """Initialize the page"""
492
+ super().initialize_page()
493
+ self.param_widget.get()
494
+ self.update_preview()
495
+
496
+ def validate_page(self) -> bool:
497
+ """Validate the page"""
498
+ self.__quick_update = True
499
+ self.param_widget.set()
500
+ self.__quick_update = False
501
+ if self.destination == "signal":
502
+ nb_sig = len(self.__preview_df.columns)
503
+ if self.param.first_col_is_x:
504
+ nb_sig -= 1
505
+ if (
506
+ nb_sig > 20
507
+ and QW.QMessageBox.warning(
508
+ self,
509
+ _("Warning"),
510
+ _(
511
+ "The number of signals to import is very high (%d).\n"
512
+ "This may be an error.\n\n"
513
+ "Are you sure you want to continue?"
514
+ )
515
+ % nb_sig,
516
+ QW.QMessageBox.Yes | QW.QMessageBox.No,
517
+ )
518
+ == QW.QMessageBox.No
519
+ ):
520
+ return False
521
+ return super().validate_page()
522
+
523
+
524
+ class GraphicalRepresentationPage(WizardPage):
525
+ """Graphical representation page"""
526
+
527
+ def __init__(self, data_page: DataPreviewPage, destination: str) -> None:
528
+ super().__init__()
529
+ self.__curve_styles: Generator[tuple[str, str], None, None] | None = None
530
+ self.__objitmlist: list[
531
+ tuple[SignalObj | ImageObj, CurveItem | MaskedXYImageItem]
532
+ ] = []
533
+ self.set_title(_("Graphical Representation"))
534
+ self.set_subtitle(_("Graphical representation of the imported data"))
535
+ self.data_page = data_page
536
+ self.destination = destination
537
+ layout = QW.QVBoxLayout()
538
+ instruction = QW.QLabel(
539
+ _("Unselect the %s that you do not want to import:")
540
+ % (_("signals") if destination == "signal" else _("images"))
541
+ )
542
+ layout.addWidget(instruction)
543
+ cb_all = QW.QCheckBox(_("Select all"))
544
+ cb_all.setChecked(True)
545
+ cb_all.stateChanged.connect(self.toggle_all)
546
+ layout.addWidget(cb_all)
547
+ plot_type = "curve" if destination == "signal" else "image"
548
+ # Get appropriate autoscale margin from configuration
549
+ if plot_type == "curve":
550
+ autoscale_margin = Conf.view.sig_autoscale_margin_percent.get()
551
+ else:
552
+ autoscale_margin = Conf.view.ima_autoscale_margin_percent.get()
553
+ self.plot_widget = PlotWidget(
554
+ self,
555
+ toolbar=True,
556
+ options=PlotOptions(
557
+ type=plot_type,
558
+ show_itemlist=True,
559
+ show_contrast=True,
560
+ curve_antialiasing=True,
561
+ show_axes_tab=False,
562
+ autoscale_margin_percent=autoscale_margin,
563
+ ),
564
+ )
565
+ plot = self.plot_widget.get_plot()
566
+ plot.SIG_ITEMS_CHANGED.connect(self.items_changed)
567
+ layout.addWidget(self.plot_widget)
568
+ self.add_to_layout(layout)
569
+
570
+ def toggle_all(self, state: int) -> None:
571
+ """Toggle all items selection"""
572
+ plot = self.plot_widget.get_plot()
573
+ for _obj, item in self.__objitmlist:
574
+ plot.set_item_visible(item, state == QC.Qt.Checked, replot=False)
575
+ plot.replot()
576
+
577
+ def items_changed(self, _plot: BasePlot) -> None:
578
+ """Item selection changed"""
579
+ objs = self.get_objs()
580
+ self.set_valid(len(objs) > 0)
581
+
582
+ def get_objs(self) -> list[SignalObj | ImageObj]:
583
+ """Return the objects"""
584
+ return [obj for obj, item in self.__objitmlist if item.isVisible()]
585
+
586
+ def __plot_signal(
587
+ self,
588
+ x: np.ndarray,
589
+ y: np.ndarray,
590
+ title: str,
591
+ labels: tuple[str, str] | None = None,
592
+ units: tuple[str, str] | None = None,
593
+ zorder: int | None = None,
594
+ ) -> None:
595
+ """Plot signals"""
596
+ obj = create_signal(title, x=x, y=y, labels=labels, units=units)
597
+ with CURVESTYLES.alternative(self.__curve_styles):
598
+ item = create_adapter_from_object(obj).make_item()
599
+ plot = self.plot_widget.get_plot()
600
+ plot.add_item(item, z=zorder)
601
+ maxpoints = 20000
602
+ if len(x) >= 2 * maxpoints:
603
+ item.param.use_dsamp = True
604
+ item.param.dsamp_factor = len(x) // maxpoints
605
+ self.__objitmlist.append((obj, item))
606
+
607
+ def __show_image(self, data: np.ndarray) -> None:
608
+ """Show image"""
609
+ obj = create_image("", data)
610
+ item = create_adapter_from_object(obj).make_item()
611
+ plot = self.plot_widget.get_plot()
612
+ plot.add_item(item)
613
+ self.__objitmlist.append((obj, item))
614
+ plot.set_active_item(item)
615
+ item.unselect()
616
+
617
+ def initialize_page(self) -> None:
618
+ """Initialize the page"""
619
+ self.__curve_styles = CURVESTYLES.style_generator()
620
+ df = self.data_page.get_dataframe()
621
+ assert df is not None
622
+ data = df.to_numpy(np.dtype(self.data_page.param.dtype_str))
623
+ param = self.data_page.param
624
+ plot = self.plot_widget.get_plot()
625
+ plot.del_all_items()
626
+ self.__objitmlist = []
627
+ if self.destination == "signal":
628
+ xydata = data.T
629
+ x = np.arange(len(xydata[0]), dtype=self.data_page.param.dtype_str)
630
+ if len(xydata) == 1:
631
+ self.__plot_signal(x, xydata[0], "")
632
+ else:
633
+ xlabel, ylabels, xunit, yunits = get_labels_units_from_dataframe(df)
634
+ if param.first_col_is_x:
635
+ x = xydata[0]
636
+ plot.set_axis_title("bottom", xlabel)
637
+ zorder = 1000
638
+ with create_progress_bar(
639
+ self, _("Adding data to the plot"), max_=len(xydata) - 1
640
+ ) as progress:
641
+ for ycol in range(1 if param.first_col_is_x else 0, len(xydata)):
642
+ progress.setValue(ycol - 1)
643
+ if progress.wasCanceled():
644
+ break
645
+ yidx = ycol if param.first_col_is_x else ycol - 1
646
+ self.__plot_signal(
647
+ x,
648
+ xydata[yidx],
649
+ ylabels[ycol - 1],
650
+ labels=(xlabel, ylabels[ycol - 1]),
651
+ units=(xunit, yunits[ycol - 1]),
652
+ zorder=zorder,
653
+ )
654
+ zorder -= 1
655
+ QW.QApplication.processEvents()
656
+ else:
657
+ self.__show_image(data)
658
+ plot.do_autoscale()
659
+ self.items_changed(plot)
660
+ return super().initialize_page()
661
+
662
+ def validate_page(self) -> bool:
663
+ """Validate the page"""
664
+ objs = self.get_objs()
665
+ if len(objs) == 0:
666
+ return False
667
+ return super().validate_page()
668
+
669
+
670
+ class SignalParam(gds.DataSet):
671
+ """Signal parameters dataset"""
672
+
673
+ title = gds.StringItem(_("Title"), default="").set_pos(col=0, colspan=2)
674
+ xlabel = gds.StringItem(_("X label"), default="")
675
+ ylabel = gds.StringItem(_("Y label"), default="").set_pos(col=1)
676
+ xunit = gds.StringItem(_("X unit"), default="")
677
+ yunit = gds.StringItem(_("Y unit"), default="").set_pos(col=1)
678
+
679
+
680
+ class ImageParam(gds.DataSet):
681
+ """Image parameters dataset"""
682
+
683
+ title = gds.StringItem(_("Title"), default="").set_pos(col=0, colspan=3)
684
+ xlabel = gds.StringItem(_("X label"), default="")
685
+ ylabel = gds.StringItem(_("Y label"), default="").set_pos(col=1)
686
+ zlabel = gds.StringItem(_("Z label"), default="").set_pos(col=2)
687
+ xunit = gds.StringItem(_("X unit"), default="")
688
+ yunit = gds.StringItem(_("Y unit"), default="").set_pos(col=1)
689
+ zunit = gds.StringItem(_("Z unit"), default="").set_pos(col=2)
690
+
691
+
692
+ def update_dataset_non_empty_values(dest: gds.DataSet, source: gds.DataSet) -> None:
693
+ """Update the destination dataset from the non-empty values of the source dataset
694
+
695
+ Args:
696
+ dest: Destination dataset
697
+ source: Source dataset
698
+ """
699
+ for item in source.get_items():
700
+ key = item.get_name()
701
+ value = getattr(source, key)
702
+ if value not in (None, "") and hasattr(dest, key):
703
+ setattr(dest, key, value)
704
+
705
+
706
+ class LabelsPage(WizardPage):
707
+ """Labels page"""
708
+
709
+ def __init__(
710
+ self,
711
+ source_page: SourcePage,
712
+ plot_page: GraphicalRepresentationPage,
713
+ destination: str,
714
+ ) -> None:
715
+ super().__init__()
716
+ self.set_title(_("Labels and units"))
717
+ self.set_subtitle(_("Set the labels and units for the imported data"))
718
+ self.source_page = source_page
719
+ self.plot_page = plot_page
720
+ self.param_widget = gdq.DataSetEditGroupBox(
721
+ _("Parameters"),
722
+ SignalParam if destination == "signal" else ImageParam,
723
+ show_button=False,
724
+ )
725
+ self.param = self.param_widget.dataset
726
+ label = QW.QLabel(
727
+ _(
728
+ "The following title, labels and units will be applied to the data."
729
+ "<br><br><i><u>Note</u>: "
730
+ "Leave empty the labels and units to keep the default values "
731
+ "(i.e. the values which were inferred from the data).</i>"
732
+ )
733
+ )
734
+ self.add_to_layout(label)
735
+ self.add_to_layout(self.param_widget)
736
+ self.add_stretch()
737
+
738
+ def get_objs(self) -> list[SignalObj | ImageObj]:
739
+ """Return the objects"""
740
+ objs = self.plot_page.get_objs()
741
+ for idx, obj in enumerate(objs):
742
+ update_dataset_non_empty_values(obj, self.param)
743
+ if len(objs) > 1:
744
+ obj.title = f"{obj.title} {idx + 1:02d}"
745
+ return objs
746
+
747
+ def initialize_page(self) -> None:
748
+ """Initialize the page"""
749
+ path = self.source_page.get_source_path()
750
+ if path is None:
751
+ path = _("clipboard")
752
+ else:
753
+ path = osp.basename(path)
754
+ self.param.title = _("Imported from:") + " " + path
755
+ self.param_widget.get()
756
+ return super().initialize_page()
757
+
758
+ def validate_page(self) -> bool:
759
+ """Validate the page"""
760
+ self.param_widget.set()
761
+ return super().validate_page()
762
+
763
+
764
+ class TextImportWizard(Wizard):
765
+ """Text data import wizard
766
+
767
+ Args:
768
+ destination: Destination type ('signal' or 'image')
769
+ """
770
+
771
+ def __init__(self, destination: str, parent: QWidget | None = None) -> None:
772
+ super().__init__(parent)
773
+ assert destination in ("signal", "image")
774
+ self.setWindowTitle(_("DataLab Import Wizard"))
775
+ self.source_page = SourcePage()
776
+ self.add_page(self.source_page)
777
+ self.data_page = DataPreviewPage(self.source_page, destination)
778
+ self.add_page(self.data_page)
779
+ self.plot_page = GraphicalRepresentationPage(self.data_page, destination)
780
+ self.add_page(self.plot_page)
781
+ self.labels_page = LabelsPage(self.source_page, self.plot_page, destination)
782
+ self.add_page(self.labels_page, last_page=True)
783
+
784
+ def get_objs(self) -> list[SignalObj | ImageObj]:
785
+ """Return the objects"""
786
+ return self.labels_page.get_objs()