datalab-platform 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.0.dist-info/METADATA +121 -0
- datalab_platform-1.0.0.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.0.dist-info}/WHEEL +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/entry_points.txt +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {datalab_platform-0.0.1.dev0.dist-info → datalab_platform-1.0.0.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()
|