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.
- datalab/__init__.py +35 -2
- datalab/adapters_metadata/__init__.py +31 -0
- datalab/adapters_metadata/base_adapter.py +316 -0
- datalab/adapters_metadata/common.py +422 -0
- datalab/adapters_metadata/geometry_adapter.py +98 -0
- datalab/adapters_metadata/table_adapter.py +84 -0
- datalab/adapters_plotpy/__init__.py +54 -0
- datalab/adapters_plotpy/annotations.py +124 -0
- datalab/adapters_plotpy/base.py +110 -0
- datalab/adapters_plotpy/converters.py +86 -0
- datalab/adapters_plotpy/factories.py +80 -0
- datalab/adapters_plotpy/objects/__init__.py +0 -0
- datalab/adapters_plotpy/objects/base.py +197 -0
- datalab/adapters_plotpy/objects/image.py +157 -0
- datalab/adapters_plotpy/objects/scalar.py +565 -0
- datalab/adapters_plotpy/objects/signal.py +264 -0
- datalab/adapters_plotpy/roi/__init__.py +0 -0
- datalab/adapters_plotpy/roi/base.py +146 -0
- datalab/adapters_plotpy/roi/factory.py +93 -0
- datalab/adapters_plotpy/roi/image.py +207 -0
- datalab/adapters_plotpy/roi/signal.py +72 -0
- datalab/app.py +98 -0
- datalab/config.py +817 -0
- datalab/control/__init__.py +0 -0
- datalab/control/baseproxy.py +776 -0
- datalab/control/proxy.py +343 -0
- datalab/control/remote.py +1005 -0
- datalab/data/doc/DataLab_en.pdf +0 -0
- datalab/data/doc/DataLab_fr.pdf +0 -0
- datalab/data/icons/analysis/delete_results.svg +109 -0
- datalab/data/icons/analysis/fw1e2.svg +156 -0
- datalab/data/icons/analysis/fwhm.svg +156 -0
- datalab/data/icons/analysis/histogram.svg +49 -0
- datalab/data/icons/analysis/peak_detect.svg +160 -0
- datalab/data/icons/analysis/plot_results.svg +151 -0
- datalab/data/icons/analysis/show_results.svg +83 -0
- datalab/data/icons/analysis/stats.svg +49 -0
- datalab/data/icons/analysis.svg +120 -0
- datalab/data/icons/apply.svg +3 -0
- datalab/data/icons/check_all.svg +15 -0
- datalab/data/icons/collapse.svg +44 -0
- datalab/data/icons/collapse_selection.svg +63 -0
- datalab/data/icons/console.svg +101 -0
- datalab/data/icons/create/1d-normal.svg +8 -0
- datalab/data/icons/create/1d-poisson.svg +9 -0
- datalab/data/icons/create/1d-uniform.svg +8 -0
- datalab/data/icons/create/1d-zero.svg +57 -0
- datalab/data/icons/create/2d-gaussian.svg +56 -0
- datalab/data/icons/create/2d-normal.svg +38 -0
- datalab/data/icons/create/2d-poisson.svg +38 -0
- datalab/data/icons/create/2d-ramp.svg +90 -0
- datalab/data/icons/create/2d-sinc.svg +62 -0
- datalab/data/icons/create/2d-uniform.svg +38 -0
- datalab/data/icons/create/2d-zero.svg +13 -0
- datalab/data/icons/create/checkerboard.svg +39 -0
- datalab/data/icons/create/cosine.svg +12 -0
- datalab/data/icons/create/exponential.svg +55 -0
- datalab/data/icons/create/gaussian.svg +12 -0
- datalab/data/icons/create/grating.svg +29 -0
- datalab/data/icons/create/linear_chirp.svg +7 -0
- datalab/data/icons/create/logistic.svg +7 -0
- datalab/data/icons/create/lorentzian.svg +12 -0
- datalab/data/icons/create/planck.svg +12 -0
- datalab/data/icons/create/polynomial.svg +7 -0
- datalab/data/icons/create/pulse.svg +12 -0
- datalab/data/icons/create/ring.svg +18 -0
- datalab/data/icons/create/sawtooth.svg +7 -0
- datalab/data/icons/create/siemens.svg +35 -0
- datalab/data/icons/create/sinc.svg +12 -0
- datalab/data/icons/create/sine.svg +7 -0
- datalab/data/icons/create/square.svg +7 -0
- datalab/data/icons/create/square_pulse.svg +7 -0
- datalab/data/icons/create/step.svg +7 -0
- datalab/data/icons/create/step_pulse.svg +12 -0
- datalab/data/icons/create/triangle.svg +7 -0
- datalab/data/icons/create/voigt.svg +12 -0
- datalab/data/icons/edit/annotations.svg +72 -0
- datalab/data/icons/edit/annotations_copy.svg +114 -0
- datalab/data/icons/edit/annotations_delete.svg +83 -0
- datalab/data/icons/edit/annotations_edit.svg +98 -0
- datalab/data/icons/edit/annotations_export.svg +85 -0
- datalab/data/icons/edit/annotations_import.svg +85 -0
- datalab/data/icons/edit/annotations_paste.svg +100 -0
- datalab/data/icons/edit/copy_titles.svg +109 -0
- datalab/data/icons/edit/delete.svg +84 -0
- datalab/data/icons/edit/delete_all.svg +214 -0
- datalab/data/icons/edit/duplicate.svg +64 -0
- datalab/data/icons/edit/goto_source.svg +60 -0
- datalab/data/icons/edit/metadata.svg +60 -0
- datalab/data/icons/edit/metadata_add.svg +80 -0
- datalab/data/icons/edit/metadata_copy.svg +96 -0
- datalab/data/icons/edit/metadata_delete.svg +62 -0
- datalab/data/icons/edit/metadata_export.svg +68 -0
- datalab/data/icons/edit/metadata_import.svg +68 -0
- datalab/data/icons/edit/metadata_paste.svg +79 -0
- datalab/data/icons/edit/move_down.svg +55 -0
- datalab/data/icons/edit/move_up.svg +54 -0
- datalab/data/icons/edit/new_group.svg +76 -0
- datalab/data/icons/edit/recompute.svg +60 -0
- datalab/data/icons/edit/rename.svg +49 -0
- datalab/data/icons/edit.svg +16 -0
- datalab/data/icons/expand.svg +44 -0
- datalab/data/icons/expand_selection.svg +63 -0
- datalab/data/icons/fit/cdf_fit.svg +56 -0
- datalab/data/icons/fit/exponential_fit.svg +55 -0
- datalab/data/icons/fit/gaussian_fit.svg +62 -0
- datalab/data/icons/fit/interactive_fit.svg +101 -0
- datalab/data/icons/fit/linear_fit.svg +57 -0
- datalab/data/icons/fit/lorentzian_fit.svg +209 -0
- datalab/data/icons/fit/multigaussian_fit.svg +85 -0
- datalab/data/icons/fit/multilorentzian_fit.svg +85 -0
- datalab/data/icons/fit/piecewiseexponential_fit.svg +209 -0
- datalab/data/icons/fit/planckian_fit.svg +62 -0
- datalab/data/icons/fit/polynomial_fit.svg +59 -0
- datalab/data/icons/fit/sigmoid_fit.svg +56 -0
- datalab/data/icons/fit/sinusoidal_fit.svg +72 -0
- datalab/data/icons/fit/twohalfgaussian_fit.svg +63 -0
- datalab/data/icons/fit/voigt_fit.svg +57 -0
- datalab/data/icons/group.svg +56 -0
- datalab/data/icons/h5/h5array.svg +59 -0
- datalab/data/icons/h5/h5attrs.svg +75 -0
- datalab/data/icons/h5/h5browser.svg +133 -0
- datalab/data/icons/h5/h5file.svg +69 -0
- datalab/data/icons/h5/h5group.svg +49 -0
- datalab/data/icons/h5/h5scalar.svg +1 -0
- datalab/data/icons/help_pdf.svg +46 -0
- datalab/data/icons/history.svg +7 -0
- datalab/data/icons/image.svg +135 -0
- datalab/data/icons/io/fileopen_directory.svg +60 -0
- datalab/data/icons/io/fileopen_h5.svg +84 -0
- datalab/data/icons/io/fileopen_ima.svg +187 -0
- datalab/data/icons/io/fileopen_py.svg +123 -0
- datalab/data/icons/io/fileopen_sig.svg +138 -0
- datalab/data/icons/io/filesave_h5.svg +97 -0
- datalab/data/icons/io/filesave_ima.svg +200 -0
- datalab/data/icons/io/filesave_py.svg +136 -0
- datalab/data/icons/io/filesave_sig.svg +151 -0
- datalab/data/icons/io/import_text.svg +144 -0
- datalab/data/icons/io/save_to_directory.svg +134 -0
- datalab/data/icons/io.svg +84 -0
- datalab/data/icons/libre-camera-flash-off.svg +1 -0
- datalab/data/icons/libre-camera-flash-on.svg +1 -0
- datalab/data/icons/libre-gui-about.svg +1 -0
- datalab/data/icons/libre-gui-action-delete.svg +1 -0
- datalab/data/icons/libre-gui-add.svg +1 -0
- datalab/data/icons/libre-gui-arrow-down.svg +1 -0
- datalab/data/icons/libre-gui-arrow-left.svg +1 -0
- datalab/data/icons/libre-gui-arrow-right.svg +1 -0
- datalab/data/icons/libre-gui-arrow-up.svg +1 -0
- datalab/data/icons/libre-gui-close.svg +40 -0
- datalab/data/icons/libre-gui-cogs.svg +1 -0
- datalab/data/icons/libre-gui-globe.svg +1 -0
- datalab/data/icons/libre-gui-help.svg +1 -0
- datalab/data/icons/libre-gui-link.svg +1 -0
- datalab/data/icons/libre-gui-menu.svg +1 -0
- datalab/data/icons/libre-gui-pencil.svg +1 -0
- datalab/data/icons/libre-gui-plugin.svg +1 -0
- datalab/data/icons/libre-gui-questions.svg +1 -0
- datalab/data/icons/libre-gui-settings.svg +1 -0
- datalab/data/icons/libre-gui-unlink.svg +1 -0
- datalab/data/icons/libre-tech-ram.svg +1 -0
- datalab/data/icons/libre-toolbox.svg +1 -0
- datalab/data/icons/logs.svg +1 -0
- datalab/data/icons/markers.svg +74 -0
- datalab/data/icons/menu.svg +13 -0
- datalab/data/icons/new_ima.svg +148 -0
- datalab/data/icons/new_sig.svg +123 -0
- datalab/data/icons/operations/abs.svg +116 -0
- datalab/data/icons/operations/arithmetic.svg +123 -0
- datalab/data/icons/operations/average.svg +124 -0
- datalab/data/icons/operations/complex_from_magnitude_phase.svg +116 -0
- datalab/data/icons/operations/complex_from_real_imag.svg +124 -0
- datalab/data/icons/operations/constant.svg +116 -0
- datalab/data/icons/operations/constant_add.svg +109 -0
- datalab/data/icons/operations/constant_divide.svg +109 -0
- datalab/data/icons/operations/constant_multiply.svg +109 -0
- datalab/data/icons/operations/constant_subtract.svg +109 -0
- datalab/data/icons/operations/convert_dtype.svg +117 -0
- datalab/data/icons/operations/convolution.svg +46 -0
- datalab/data/icons/operations/deconvolution.svg +57 -0
- datalab/data/icons/operations/derivative.svg +127 -0
- datalab/data/icons/operations/difference.svg +52 -0
- datalab/data/icons/operations/division.svg +139 -0
- datalab/data/icons/operations/exp.svg +116 -0
- datalab/data/icons/operations/flip_horizontally.svg +69 -0
- datalab/data/icons/operations/flip_vertically.svg +74 -0
- datalab/data/icons/operations/im.svg +124 -0
- datalab/data/icons/operations/integral.svg +50 -0
- datalab/data/icons/operations/inverse.svg +143 -0
- datalab/data/icons/operations/log10.svg +109 -0
- datalab/data/icons/operations/phase.svg +116 -0
- datalab/data/icons/operations/power.svg +118 -0
- datalab/data/icons/operations/product.svg +124 -0
- datalab/data/icons/operations/profile.svg +379 -0
- datalab/data/icons/operations/profile_average.svg +399 -0
- datalab/data/icons/operations/profile_radial.svg +261 -0
- datalab/data/icons/operations/profile_segment.svg +262 -0
- datalab/data/icons/operations/quadratic_difference.svg +84 -0
- datalab/data/icons/operations/re.svg +124 -0
- datalab/data/icons/operations/rotate_left.svg +72 -0
- datalab/data/icons/operations/rotate_right.svg +72 -0
- datalab/data/icons/operations/signals_to_image.svg +314 -0
- datalab/data/icons/operations/sqrt.svg +110 -0
- datalab/data/icons/operations/std.svg +124 -0
- datalab/data/icons/operations/sum.svg +102 -0
- datalab/data/icons/play_demo.svg +9 -0
- datalab/data/icons/processing/axis_transform.svg +62 -0
- datalab/data/icons/processing/bandpass.svg +79 -0
- datalab/data/icons/processing/bandstop.svg +71 -0
- datalab/data/icons/processing/binning.svg +126 -0
- datalab/data/icons/processing/clip.svg +119 -0
- datalab/data/icons/processing/detrending.svg +173 -0
- datalab/data/icons/processing/distribute_on_grid.svg +769 -0
- datalab/data/icons/processing/edge_detection.svg +46 -0
- datalab/data/icons/processing/erase.svg +1 -0
- datalab/data/icons/processing/exposure.svg +143 -0
- datalab/data/icons/processing/fourier.svg +104 -0
- datalab/data/icons/processing/highpass.svg +59 -0
- datalab/data/icons/processing/interpolation.svg +71 -0
- datalab/data/icons/processing/level_adjustment.svg +70 -0
- datalab/data/icons/processing/lowpass.svg +60 -0
- datalab/data/icons/processing/morphology.svg +49 -0
- datalab/data/icons/processing/noise_addition.svg +114 -0
- datalab/data/icons/processing/noise_reduction.svg +38 -0
- datalab/data/icons/processing/normalize.svg +84 -0
- datalab/data/icons/processing/offset_correction.svg +131 -0
- datalab/data/icons/processing/resampling1d.svg +101 -0
- datalab/data/icons/processing/resampling2d.svg +240 -0
- datalab/data/icons/processing/reset_positions.svg +185 -0
- datalab/data/icons/processing/resize.svg +9 -0
- datalab/data/icons/processing/reverse_signal_x.svg +171 -0
- datalab/data/icons/processing/stability.svg +11 -0
- datalab/data/icons/processing/swap_x_y.svg +65 -0
- datalab/data/icons/processing/thresholding.svg +63 -0
- datalab/data/icons/processing/windowing.svg +45 -0
- datalab/data/icons/properties.svg +26 -0
- datalab/data/icons/reset.svg +9 -0
- datalab/data/icons/restore.svg +40 -0
- datalab/data/icons/roi/roi.svg +76 -0
- datalab/data/icons/roi/roi_coordinate.svg +78 -0
- datalab/data/icons/roi/roi_copy.svg +112 -0
- datalab/data/icons/roi/roi_delete.svg +81 -0
- datalab/data/icons/roi/roi_export.svg +87 -0
- datalab/data/icons/roi/roi_graphical.svg +78 -0
- datalab/data/icons/roi/roi_grid.svg +67 -0
- datalab/data/icons/roi/roi_ima.svg +188 -0
- datalab/data/icons/roi/roi_import.svg +87 -0
- datalab/data/icons/roi/roi_new.svg +81 -0
- datalab/data/icons/roi/roi_new_circle.svg +95 -0
- datalab/data/icons/roi/roi_new_polygon.svg +110 -0
- datalab/data/icons/roi/roi_new_rectangle.svg +70 -0
- datalab/data/icons/roi/roi_paste.svg +98 -0
- datalab/data/icons/roi/roi_sig.svg +124 -0
- datalab/data/icons/shapes.svg +134 -0
- datalab/data/icons/signal.svg +103 -0
- datalab/data/icons/table.svg +85 -0
- datalab/data/icons/table_unavailable.svg +102 -0
- datalab/data/icons/to_signal.svg +124 -0
- datalab/data/icons/tour/next.svg +44 -0
- datalab/data/icons/tour/previous.svg +44 -0
- datalab/data/icons/tour/rewind.svg +51 -0
- datalab/data/icons/tour/stop.svg +47 -0
- datalab/data/icons/tour/tour.svg +16 -0
- datalab/data/icons/uncheck_all.svg +78 -0
- datalab/data/icons/view/curve_antialiasing.svg +50 -0
- datalab/data/icons/view/new_window.svg +98 -0
- datalab/data/icons/view/refresh-auto.svg +57 -0
- datalab/data/icons/view/refresh-manual.svg +51 -0
- datalab/data/icons/view/reset_curve_styles.svg +96 -0
- datalab/data/icons/view/show_first.svg +55 -0
- datalab/data/icons/view/show_titles.svg +46 -0
- datalab/data/icons/visualization.svg +51 -0
- datalab/data/logo/DataLab-Banner-150.png +0 -0
- datalab/data/logo/DataLab-Banner-200.png +0 -0
- datalab/data/logo/DataLab-Banner2-100.png +0 -0
- datalab/data/logo/DataLab-Splash.png +0 -0
- datalab/data/logo/DataLab-watermark.png +0 -0
- datalab/data/logo/DataLab.svg +83 -0
- datalab/data/tests/reordering_test.h5 +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot1.jpg +0 -0
- datalab/data/tutorials/fabry_perot/fabry-perot2.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_13.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_18.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_23.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_30.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_35.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_40.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_45.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_50.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_55.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_60.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_65.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_70.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_75.jpg +0 -0
- datalab/data/tutorials/laser_beam/TEM00_z_80.jpg +0 -0
- datalab/env.py +542 -0
- datalab/gui/__init__.py +89 -0
- datalab/gui/actionhandler.py +1701 -0
- datalab/gui/docks.py +473 -0
- datalab/gui/h5io.py +150 -0
- datalab/gui/macroeditor.py +310 -0
- datalab/gui/main.py +2081 -0
- datalab/gui/newobject.py +217 -0
- datalab/gui/objectview.py +766 -0
- datalab/gui/panel/__init__.py +48 -0
- datalab/gui/panel/base.py +3254 -0
- datalab/gui/panel/image.py +157 -0
- datalab/gui/panel/macro.py +607 -0
- datalab/gui/panel/signal.py +164 -0
- datalab/gui/plothandler.py +800 -0
- datalab/gui/processor/__init__.py +84 -0
- datalab/gui/processor/base.py +2456 -0
- datalab/gui/processor/catcher.py +75 -0
- datalab/gui/processor/image.py +1214 -0
- datalab/gui/processor/signal.py +755 -0
- datalab/gui/profiledialog.py +333 -0
- datalab/gui/roieditor.py +633 -0
- datalab/gui/roigrideditor.py +208 -0
- datalab/gui/settings.py +612 -0
- datalab/gui/tour.py +908 -0
- datalab/h5/__init__.py +12 -0
- datalab/h5/common.py +314 -0
- datalab/h5/generic.py +580 -0
- datalab/h5/native.py +39 -0
- datalab/h5/utils.py +95 -0
- datalab/objectmodel.py +640 -0
- datalab/plugins/_readme_.txt +9 -0
- datalab/plugins/datalab_imageformats.py +175 -0
- datalab/plugins/datalab_testdata.py +190 -0
- datalab/plugins.py +355 -0
- datalab/tests/__init__.py +199 -0
- datalab/tests/backbone/__init__.py +1 -0
- datalab/tests/backbone/config_unit_test.py +170 -0
- datalab/tests/backbone/config_versioning_unit_test.py +34 -0
- datalab/tests/backbone/dictlistserial_app_test.py +38 -0
- datalab/tests/backbone/errorcatcher_unit_test.py +69 -0
- datalab/tests/backbone/errormsgbox_unit_test.py +50 -0
- datalab/tests/backbone/execenv_unit.py +262 -0
- datalab/tests/backbone/loadtest_gdi.py +147 -0
- datalab/tests/backbone/long_callback.py +96 -0
- datalab/tests/backbone/main_app_test.py +137 -0
- datalab/tests/backbone/memory_leak.py +43 -0
- datalab/tests/backbone/procisolation1_unit.py +128 -0
- datalab/tests/backbone/procisolation2_unit.py +171 -0
- datalab/tests/backbone/procisolation_unit_test.py +22 -0
- datalab/tests/backbone/profiling_app.py +27 -0
- datalab/tests/backbone/strings_unit_test.py +65 -0
- datalab/tests/backbone/title_formatting_unit_test.py +82 -0
- datalab/tests/conftest.py +131 -0
- datalab/tests/features/__init__.py +1 -0
- datalab/tests/features/applauncher/__init__.py +1 -0
- datalab/tests/features/applauncher/launcher1_app_test.py +28 -0
- datalab/tests/features/applauncher/launcher2_app_test.py +30 -0
- datalab/tests/features/common/__init__.py +1 -0
- datalab/tests/features/common/add_metadata_app_test.py +134 -0
- datalab/tests/features/common/add_metadata_unit_test.py +267 -0
- datalab/tests/features/common/annotations_management_unit_test.py +152 -0
- datalab/tests/features/common/auto_analysis_recompute_unit_test.py +240 -0
- datalab/tests/features/common/createobject_unit_test.py +50 -0
- datalab/tests/features/common/geometry_results_app_test.py +135 -0
- datalab/tests/features/common/interactive_processing_test.py +1109 -0
- datalab/tests/features/common/io_app_test.py +75 -0
- datalab/tests/features/common/large_results_app_test.py +187 -0
- datalab/tests/features/common/metadata_all_patterns_test.py +103 -0
- datalab/tests/features/common/metadata_app_test.py +139 -0
- datalab/tests/features/common/metadata_io_unit_test.py +60 -0
- datalab/tests/features/common/misc_app_test.py +236 -0
- datalab/tests/features/common/multiple_geometry_results_unit_test.py +122 -0
- datalab/tests/features/common/multiple_table_results_unit_test.py +64 -0
- datalab/tests/features/common/operation_modes_app_test.py +392 -0
- datalab/tests/features/common/plot_results_app_test.py +278 -0
- datalab/tests/features/common/reorder_app_test.py +75 -0
- datalab/tests/features/common/result_deletion_unit_test.py +96 -0
- datalab/tests/features/common/result_merged_label_unit_test.py +154 -0
- datalab/tests/features/common/result_shape_settings_unit_test.py +223 -0
- datalab/tests/features/common/roi_plotitem_unit_test.py +64 -0
- datalab/tests/features/common/roieditor_unit_test.py +102 -0
- datalab/tests/features/common/save_to_dir_app_test.py +163 -0
- datalab/tests/features/common/save_to_dir_unit_test.py +474 -0
- datalab/tests/features/common/stat_app_test.py +40 -0
- datalab/tests/features/common/stats_tools_unit_test.py +77 -0
- datalab/tests/features/common/table_results_app_test.py +52 -0
- datalab/tests/features/common/textimport_unit_test.py +131 -0
- datalab/tests/features/common/uuid_preservation_test.py +281 -0
- datalab/tests/features/common/worker_unit_test.py +402 -0
- datalab/tests/features/control/__init__.py +1 -0
- datalab/tests/features/control/connect_dialog.py +28 -0
- datalab/tests/features/control/embedded1_unit_test.py +304 -0
- datalab/tests/features/control/embedded2_unit_test.py +52 -0
- datalab/tests/features/control/remoteclient_app_test.py +219 -0
- datalab/tests/features/control/remoteclient_unit.py +75 -0
- datalab/tests/features/control/simpleclient_unit_test.py +321 -0
- datalab/tests/features/hdf5/__init__.py +1 -0
- datalab/tests/features/hdf5/h5browser1_unit_test.py +31 -0
- datalab/tests/features/hdf5/h5browser2_unit.py +55 -0
- datalab/tests/features/hdf5/h5browser_app_test.py +77 -0
- datalab/tests/features/hdf5/h5import_app_test.py +25 -0
- datalab/tests/features/hdf5/h5importer_app_test.py +34 -0
- datalab/tests/features/image/__init__.py +1 -0
- datalab/tests/features/image/annotations_app_test.py +28 -0
- datalab/tests/features/image/annotations_unit_test.py +80 -0
- datalab/tests/features/image/average_app_test.py +46 -0
- datalab/tests/features/image/background_dialog_test.py +70 -0
- datalab/tests/features/image/blobs_app_test.py +50 -0
- datalab/tests/features/image/contour_app_test.py +42 -0
- datalab/tests/features/image/contour_fabryperot_app_test.py +51 -0
- datalab/tests/features/image/denoise_app_test.py +31 -0
- datalab/tests/features/image/distribute_on_grid_app_test.py +95 -0
- datalab/tests/features/image/edges_app_test.py +31 -0
- datalab/tests/features/image/erase_app_test.py +21 -0
- datalab/tests/features/image/fft2d_app_test.py +27 -0
- datalab/tests/features/image/flatfield_app_test.py +40 -0
- datalab/tests/features/image/geometry_transform_unit_test.py +396 -0
- datalab/tests/features/image/imagetools_app_test.py +51 -0
- datalab/tests/features/image/imagetools_unit_test.py +27 -0
- datalab/tests/features/image/load_app_test.py +73 -0
- datalab/tests/features/image/morph_app_test.py +32 -0
- datalab/tests/features/image/offsetcorrection_app_test.py +30 -0
- datalab/tests/features/image/peak2d_app_test.py +53 -0
- datalab/tests/features/image/profile_app_test.py +73 -0
- datalab/tests/features/image/profile_dialog_test.py +56 -0
- datalab/tests/features/image/roi_app_test.py +98 -0
- datalab/tests/features/image/roi_circ_app_test.py +62 -0
- datalab/tests/features/image/roi_manipulation_app_test.py +268 -0
- datalab/tests/features/image/roigrid_unit_test.py +60 -0
- datalab/tests/features/image/side_by_side_app_test.py +52 -0
- datalab/tests/features/macro/__init__.py +1 -0
- datalab/tests/features/macro/macro_app_test.py +28 -0
- datalab/tests/features/macro/macroeditor_unit_test.py +102 -0
- datalab/tests/features/signal/__init__.py +1 -0
- datalab/tests/features/signal/baseline_dialog_test.py +53 -0
- datalab/tests/features/signal/deltax_dialog_unit_test.py +34 -0
- datalab/tests/features/signal/fft1d_app_test.py +26 -0
- datalab/tests/features/signal/filter_app_test.py +44 -0
- datalab/tests/features/signal/fitdialog_unit_test.py +50 -0
- datalab/tests/features/signal/interpolation_app_test.py +110 -0
- datalab/tests/features/signal/loadbigsignal_app_test.py +80 -0
- datalab/tests/features/signal/multiple_rois_unit_test.py +132 -0
- datalab/tests/features/signal/pulse_features_app_test.py +118 -0
- datalab/tests/features/signal/pulse_features_roi_app_test.py +55 -0
- datalab/tests/features/signal/roi_app_test.py +78 -0
- datalab/tests/features/signal/roi_manipulation_app_test.py +261 -0
- datalab/tests/features/signal/select_xy_cursor_unit_test.py +46 -0
- datalab/tests/features/signal/signalpeakdetection_dialog_test.py +33 -0
- datalab/tests/features/signal/signals_to_image_app_test.py +98 -0
- datalab/tests/features/signal/xarray_compat_app_test.py +128 -0
- datalab/tests/features/tour_unit_test.py +22 -0
- datalab/tests/features/utilities/__init__.py +1 -0
- datalab/tests/features/utilities/installconf_unit_test.py +21 -0
- datalab/tests/features/utilities/logview_app_test.py +21 -0
- datalab/tests/features/utilities/logview_error.py +24 -0
- datalab/tests/features/utilities/logview_unit_test.py +21 -0
- datalab/tests/features/utilities/memstatus_app_test.py +42 -0
- datalab/tests/features/utilities/settings_unit_test.py +88 -0
- datalab/tests/scenarios/__init__.py +1 -0
- datalab/tests/scenarios/beautiful_app.py +121 -0
- datalab/tests/scenarios/common.py +463 -0
- datalab/tests/scenarios/demo.py +212 -0
- datalab/tests/scenarios/example_app_test.py +47 -0
- datalab/tests/scenarios/scenario_h5_app_test.py +75 -0
- datalab/tests/scenarios/scenario_ima1_app_test.py +34 -0
- datalab/tests/scenarios/scenario_ima2_app_test.py +34 -0
- datalab/tests/scenarios/scenario_mac_app_test.py +58 -0
- datalab/tests/scenarios/scenario_sig1_app_test.py +36 -0
- datalab/tests/scenarios/scenario_sig2_app_test.py +35 -0
- datalab/utils/__init__.py +1 -0
- datalab/utils/conf.py +304 -0
- datalab/utils/dephash.py +105 -0
- datalab/utils/qthelpers.py +633 -0
- datalab/utils/strings.py +34 -0
- datalab/utils/tests.py +0 -0
- datalab/widgets/__init__.py +1 -0
- datalab/widgets/connection.py +138 -0
- datalab/widgets/filedialog.py +91 -0
- datalab/widgets/fileviewer.py +84 -0
- datalab/widgets/fitdialog.py +788 -0
- datalab/widgets/h5browser.py +1048 -0
- datalab/widgets/imagebackground.py +111 -0
- datalab/widgets/instconfviewer.py +175 -0
- datalab/widgets/logviewer.py +80 -0
- datalab/widgets/signalbaseline.py +90 -0
- datalab/widgets/signalcursor.py +208 -0
- datalab/widgets/signaldeltax.py +151 -0
- datalab/widgets/signalpeak.py +199 -0
- datalab/widgets/status.py +249 -0
- datalab/widgets/textimport.py +786 -0
- datalab/widgets/warningerror.py +223 -0
- datalab/widgets/wizard.py +286 -0
- datalab_platform-1.0.1.dist-info/METADATA +121 -0
- datalab_platform-1.0.1.dist-info/RECORD +494 -0
- datalab_platform-0.0.1.dev0.dist-info/METADATA +0 -67
- datalab_platform-0.0.1.dev0.dist-info/RECORD +0 -7
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/WHEEL +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/entry_points.txt +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.1.dist-info}/top_level.txt +0 -0
datalab/gui/roieditor.py
ADDED
|
@@ -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")
|