summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2022-11-03 10:02:44 +0100
committerPicca Frédéric-Emmanuel <picca@debian.org>2022-11-03 10:02:44 +0100
commit1c380bfeff1e13a9f7d506460336659502ca052d (patch)
tree48081d47748d4563eeaa76662287eb19638c8591 /src
parent4e774db12d5ebe7a20eded6dd434a289e27999e5 (diff)
New upstream version 1.1.0+dfsg
Diffstat (limited to 'src')
-rw-r--r--src/silx.egg-info/PKG-INFO148
-rw-r--r--src/silx.egg-info/SOURCES.txt1522
-rw-r--r--src/silx.egg-info/dependency_links.txt1
-rw-r--r--src/silx.egg-info/entry_points.txt3
-rw-r--r--src/silx.egg-info/not-zip-safe1
-rw-r--r--src/silx.egg-info/requires.txt20
-rw-r--r--src/silx.egg-info/top_level.txt1
-rw-r--r--src/silx/__init__.py3
-rw-r--r--src/silx/__main__.py1
-rw-r--r--src/silx/_config.py1
-rw-r--r--src/silx/_version.py6
-rw-r--r--src/silx/app/__init__.py1
-rw-r--r--src/silx/app/convert.py1
-rw-r--r--src/silx/app/setup.py41
-rw-r--r--src/silx/app/test/__init__.py1
-rw-r--r--src/silx/app/test/test_convert.py1
-rw-r--r--src/silx/app/test_.py1
-rw-r--r--src/silx/app/view/About.py7
-rw-r--r--src/silx/app/view/ApplicationContext.py1
-rw-r--r--src/silx/app/view/CustomNxdataWidget.py1
-rw-r--r--src/silx/app/view/DataPanel.py1
-rw-r--r--src/silx/app/view/Viewer.py26
-rw-r--r--src/silx/app/view/__init__.py1
-rw-r--r--src/silx/app/view/main.py46
-rw-r--r--src/silx/app/view/setup.py40
-rw-r--r--src/silx/app/view/test/__init__.py1
-rw-r--r--src/silx/app/view/test/test_launcher.py1
-rw-r--r--src/silx/app/view/test/test_view.py1
-rw-r--r--src/silx/app/view/utils.py1
-rw-r--r--src/silx/conftest.py5
-rw-r--r--src/silx/gui/__init__.py1
-rw-r--r--src/silx/gui/_glutils/Context.py1
-rw-r--r--src/silx/gui/_glutils/FramebufferTexture.py1
-rw-r--r--src/silx/gui/_glutils/OpenGLWidget.py7
-rw-r--r--src/silx/gui/_glutils/Program.py1
-rw-r--r--src/silx/gui/_glutils/Texture.py1
-rw-r--r--src/silx/gui/_glutils/VertexBuffer.py1
-rw-r--r--src/silx/gui/_glutils/__init__.py1
-rw-r--r--src/silx/gui/_glutils/font.py73
-rw-r--r--src/silx/gui/_glutils/gl.py15
-rw-r--r--src/silx/gui/_glutils/utils.py1
-rwxr-xr-xsrc/silx/gui/colors.py3
-rw-r--r--src/silx/gui/console.py10
-rw-r--r--src/silx/gui/data/ArrayTableModel.py10
-rw-r--r--src/silx/gui/data/ArrayTableWidget.py2
-rw-r--r--src/silx/gui/data/DataViewer.py20
-rw-r--r--src/silx/gui/data/DataViewerFrame.py16
-rw-r--r--src/silx/gui/data/DataViewerSelector.py2
-rw-r--r--src/silx/gui/data/DataViews.py19
-rw-r--r--src/silx/gui/data/Hdf5TableView.py7
-rw-r--r--src/silx/gui/data/HexaTableView.py2
-rw-r--r--src/silx/gui/data/NXdataWidgets.py14
-rw-r--r--src/silx/gui/data/NumpyAxesSelector.py2
-rw-r--r--src/silx/gui/data/RecordTableView.py2
-rw-r--r--src/silx/gui/data/TextFormatter.py1
-rw-r--r--src/silx/gui/data/_VolumeWindow.py1
-rw-r--r--src/silx/gui/data/__init__.py1
-rw-r--r--src/silx/gui/data/setup.py41
-rw-r--r--src/silx/gui/data/test/__init__.py1
-rw-r--r--src/silx/gui/data/test/test_arraywidget.py1
-rw-r--r--src/silx/gui/data/test/test_dataviewer.py21
-rw-r--r--src/silx/gui/data/test/test_numpyaxesselector.py1
-rw-r--r--src/silx/gui/data/test/test_textformatter.py1
-rw-r--r--src/silx/gui/dialog/AbstractDataFileDialog.py22
-rw-r--r--src/silx/gui/dialog/ColormapDialog.py317
-rw-r--r--src/silx/gui/dialog/DataFileDialog.py1
-rw-r--r--src/silx/gui/dialog/DatasetDialog.py1
-rw-r--r--src/silx/gui/dialog/FileTypeComboBox.py1
-rw-r--r--src/silx/gui/dialog/GroupDialog.py1
-rw-r--r--src/silx/gui/dialog/ImageFileDialog.py1
-rw-r--r--src/silx/gui/dialog/SafeFileIconProvider.py1
-rw-r--r--src/silx/gui/dialog/SafeFileSystemModel.py1
-rw-r--r--src/silx/gui/dialog/__init__.py1
-rw-r--r--src/silx/gui/dialog/setup.py40
-rw-r--r--src/silx/gui/dialog/test/__init__.py1
-rw-r--r--src/silx/gui/dialog/test/test_colormapdialog.py22
-rw-r--r--src/silx/gui/dialog/test/test_datafiledialog.py13
-rw-r--r--src/silx/gui/dialog/test/test_imagefiledialog.py13
-rw-r--r--src/silx/gui/dialog/utils.py1
-rw-r--r--src/silx/gui/fit/BackgroundWidget.py1
-rw-r--r--src/silx/gui/fit/FitConfig.py1
-rw-r--r--src/silx/gui/fit/FitWidget.py1
-rw-r--r--src/silx/gui/fit/FitWidgets.py1
-rw-r--r--src/silx/gui/fit/Parameters.py1
-rw-r--r--src/silx/gui/fit/__init__.py1
-rw-r--r--src/silx/gui/fit/setup.py43
-rw-r--r--src/silx/gui/fit/test/__init__.py1
-rw-r--r--src/silx/gui/fit/test/testBackgroundWidget.py1
-rw-r--r--src/silx/gui/fit/test/testFitConfig.py1
-rw-r--r--src/silx/gui/fit/test/testFitWidget.py1
-rw-r--r--src/silx/gui/hdf5/Hdf5Formatter.py1
-rw-r--r--src/silx/gui/hdf5/Hdf5HeaderView.py1
-rwxr-xr-xsrc/silx/gui/hdf5/Hdf5Item.py21
-rw-r--r--src/silx/gui/hdf5/Hdf5LoadingItem.py12
-rw-r--r--src/silx/gui/hdf5/Hdf5Node.py17
-rw-r--r--src/silx/gui/hdf5/Hdf5TreeModel.py61
-rw-r--r--src/silx/gui/hdf5/Hdf5TreeView.py1
-rw-r--r--src/silx/gui/hdf5/NexusSortFilterProxyModel.py1
-rw-r--r--src/silx/gui/hdf5/__init__.py1
-rw-r--r--src/silx/gui/hdf5/_utils.py1
-rw-r--r--src/silx/gui/hdf5/setup.py41
-rw-r--r--src/silx/gui/hdf5/test/__init__.py1
-rwxr-xr-xsrc/silx/gui/hdf5/test/test_hdf5.py1
-rw-r--r--src/silx/gui/icons.py1
-rw-r--r--src/silx/gui/plot/AlphaSlider.py1
-rw-r--r--src/silx/gui/plot/ColorBar.py3
-rw-r--r--src/silx/gui/plot/Colormap.py1
-rw-r--r--src/silx/gui/plot/ColormapDialog.py3
-rw-r--r--src/silx/gui/plot/Colors.py3
-rw-r--r--src/silx/gui/plot/CompareImages.py1
-rw-r--r--src/silx/gui/plot/ComplexImageView.py3
-rw-r--r--src/silx/gui/plot/CurvesROIWidget.py15
-rw-r--r--src/silx/gui/plot/ImageStack.py1
-rw-r--r--src/silx/gui/plot/ImageView.py4
-rw-r--r--src/silx/gui/plot/Interaction.py1
-rw-r--r--src/silx/gui/plot/ItemsSelectionDialog.py1
-rwxr-xr-xsrc/silx/gui/plot/LegendSelector.py10
-rw-r--r--src/silx/gui/plot/LimitsHistory.py1
-rw-r--r--src/silx/gui/plot/MaskToolsWidget.py2
-rw-r--r--src/silx/gui/plot/PlotActions.py1
-rw-r--r--src/silx/gui/plot/PlotEvents.py1
-rw-r--r--src/silx/gui/plot/PlotInteraction.py1
-rw-r--r--src/silx/gui/plot/PlotToolButtons.py1
-rw-r--r--src/silx/gui/plot/PlotTools.py3
-rwxr-xr-xsrc/silx/gui/plot/PlotWidget.py68
-rw-r--r--src/silx/gui/plot/PlotWindow.py47
-rw-r--r--src/silx/gui/plot/PrintPreviewToolButton.py2
-rw-r--r--src/silx/gui/plot/Profile.py1
-rw-r--r--src/silx/gui/plot/ProfileMainWindow.py1
-rw-r--r--src/silx/gui/plot/ROIStatsWidget.py1
-rw-r--r--src/silx/gui/plot/ScatterMaskToolsWidget.py3
-rw-r--r--src/silx/gui/plot/ScatterView.py1
-rw-r--r--src/silx/gui/plot/StackView.py17
-rw-r--r--src/silx/gui/plot/StatsWidget.py1
-rw-r--r--src/silx/gui/plot/_BaseMaskToolsWidget.py17
-rw-r--r--src/silx/gui/plot/__init__.py1
-rw-r--r--src/silx/gui/plot/_utils/__init__.py1
-rw-r--r--src/silx/gui/plot/_utils/delaunay.py4
-rw-r--r--src/silx/gui/plot/_utils/dtime_ticklayout.py20
-rw-r--r--src/silx/gui/plot/_utils/panzoom.py1
-rw-r--r--src/silx/gui/plot/_utils/setup.py42
-rw-r--r--src/silx/gui/plot/_utils/test/__init__.py1
-rw-r--r--src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py81
-rw-r--r--src/silx/gui/plot/_utils/test/test_ticklayout.py3
-rw-r--r--src/silx/gui/plot/_utils/ticklayout.py3
-rw-r--r--src/silx/gui/plot/actions/PlotAction.py4
-rw-r--r--src/silx/gui/plot/actions/PlotToolAction.py4
-rw-r--r--src/silx/gui/plot/actions/__init__.py1
-rwxr-xr-xsrc/silx/gui/plot/actions/control.py3
-rw-r--r--src/silx/gui/plot/actions/fit.py3
-rw-r--r--src/silx/gui/plot/actions/histogram.py5
-rw-r--r--src/silx/gui/plot/actions/io.py3
-rw-r--r--src/silx/gui/plot/actions/medfilt.py3
-rw-r--r--src/silx/gui/plot/actions/mode.py3
-rwxr-xr-xsrc/silx/gui/plot/backends/BackendBase.py7
-rwxr-xr-xsrc/silx/gui/plot/backends/BackendMatplotlib.py32
-rwxr-xr-xsrc/silx/gui/plot/backends/BackendOpenGL.py66
-rw-r--r--src/silx/gui/plot/backends/__init__.py1
-rw-r--r--src/silx/gui/plot/backends/glutils/GLPlotCurve.py96
-rw-r--r--src/silx/gui/plot/backends/glutils/GLPlotFrame.py66
-rw-r--r--src/silx/gui/plot/backends/glutils/GLPlotImage.py30
-rw-r--r--src/silx/gui/plot/backends/glutils/GLPlotItem.py11
-rw-r--r--src/silx/gui/plot/backends/glutils/GLPlotTriangles.py1
-rw-r--r--src/silx/gui/plot/backends/glutils/GLSupport.py1
-rw-r--r--src/silx/gui/plot/backends/glutils/GLText.py3
-rw-r--r--src/silx/gui/plot/backends/glutils/GLTexture.py1
-rw-r--r--src/silx/gui/plot/backends/glutils/PlotImageFile.py1
-rw-r--r--src/silx/gui/plot/backends/glutils/__init__.py1
-rw-r--r--src/silx/gui/plot/items/__init__.py5
-rw-r--r--src/silx/gui/plot/items/_arc_roi.py8
-rw-r--r--src/silx/gui/plot/items/_band_roi.py370
-rw-r--r--src/silx/gui/plot/items/_pick.py1
-rw-r--r--src/silx/gui/plot/items/_roi_base.py1
-rw-r--r--src/silx/gui/plot/items/axis.py27
-rw-r--r--src/silx/gui/plot/items/complex.py3
-rw-r--r--src/silx/gui/plot/items/core.py50
-rw-r--r--src/silx/gui/plot/items/curve.py1
-rw-r--r--src/silx/gui/plot/items/histogram.py1
-rw-r--r--src/silx/gui/plot/items/image.py1
-rw-r--r--src/silx/gui/plot/items/image_aggregated.py1
-rwxr-xr-xsrc/silx/gui/plot/items/marker.py1
-rw-r--r--src/silx/gui/plot/items/roi.py4
-rw-r--r--src/silx/gui/plot/items/scatter.py10
-rw-r--r--src/silx/gui/plot/items/shape.py225
-rw-r--r--src/silx/gui/plot/matplotlib/Colormap.py1
-rw-r--r--src/silx/gui/plot/matplotlib/__init__.py1
-rw-r--r--src/silx/gui/plot/setup.py54
-rw-r--r--src/silx/gui/plot/stats/__init__.py1
-rw-r--r--src/silx/gui/plot/stats/stats.py5
-rw-r--r--src/silx/gui/plot/stats/statshandler.py15
-rw-r--r--src/silx/gui/plot/test/__init__.py1
-rw-r--r--src/silx/gui/plot/test/testAlphaSlider.py1
-rw-r--r--src/silx/gui/plot/test/testColorBar.py1
-rw-r--r--src/silx/gui/plot/test/testCompareImages.py1
-rw-r--r--src/silx/gui/plot/test/testComplexImageView.py1
-rw-r--r--src/silx/gui/plot/test/testCurvesROIWidget.py14
-rw-r--r--src/silx/gui/plot/test/testImageStack.py1
-rw-r--r--src/silx/gui/plot/test/testImageView.py1
-rw-r--r--src/silx/gui/plot/test/testInteraction.py1
-rw-r--r--src/silx/gui/plot/test/testItem.py1
-rw-r--r--src/silx/gui/plot/test/testLegendSelector.py1
-rw-r--r--src/silx/gui/plot/test/testLimitConstraints.py1
-rw-r--r--src/silx/gui/plot/test/testMaskToolsWidget.py1
-rw-r--r--src/silx/gui/plot/test/testPixelIntensityHistoAction.py1
-rw-r--r--src/silx/gui/plot/test/testPlotActions.py1
-rw-r--r--src/silx/gui/plot/test/testPlotInteraction.py1
-rwxr-xr-xsrc/silx/gui/plot/test/testPlotWidget.py23
-rw-r--r--src/silx/gui/plot/test/testPlotWidgetNoBackend.py1
-rw-r--r--src/silx/gui/plot/test/testPlotWindow.py1
-rw-r--r--src/silx/gui/plot/test/testRoiStatsWidget.py1
-rw-r--r--src/silx/gui/plot/test/testSaveAction.py1
-rw-r--r--src/silx/gui/plot/test/testScatterMaskToolsWidget.py1
-rw-r--r--src/silx/gui/plot/test/testScatterView.py1
-rw-r--r--src/silx/gui/plot/test/testStackView.py1
-rw-r--r--src/silx/gui/plot/test/testStats.py1
-rw-r--r--src/silx/gui/plot/test/testUtilsAxis.py1
-rw-r--r--src/silx/gui/plot/test/utils.py1
-rw-r--r--src/silx/gui/plot/tools/CurveLegendsWidget.py3
-rw-r--r--src/silx/gui/plot/tools/LimitsToolBar.py4
-rw-r--r--src/silx/gui/plot/tools/PositionInfo.py48
-rw-r--r--src/silx/gui/plot/tools/RadarView.py1
-rw-r--r--src/silx/gui/plot/tools/__init__.py1
-rw-r--r--src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py1
-rw-r--r--src/silx/gui/plot/tools/profile/__init__.py1
-rw-r--r--src/silx/gui/plot/tools/profile/core.py1
-rw-r--r--src/silx/gui/plot/tools/profile/editors.py6
-rw-r--r--src/silx/gui/plot/tools/profile/manager.py3
-rw-r--r--src/silx/gui/plot/tools/profile/rois.py20
-rw-r--r--src/silx/gui/plot/tools/profile/toolbar.py1
-rw-r--r--src/silx/gui/plot/tools/roi.py4
-rw-r--r--src/silx/gui/plot/tools/test/__init__.py1
-rw-r--r--src/silx/gui/plot/tools/test/testCurveLegendsWidget.py1
-rw-r--r--src/silx/gui/plot/tools/test/testProfile.py1
-rw-r--r--src/silx/gui/plot/tools/test/testROI.py62
-rw-r--r--src/silx/gui/plot/tools/test/testScatterProfileToolBar.py1
-rw-r--r--src/silx/gui/plot/tools/test/testTools.py1
-rw-r--r--src/silx/gui/plot/tools/toolbars.py1
-rw-r--r--src/silx/gui/plot/utils/__init__.py1
-rw-r--r--src/silx/gui/plot/utils/axis.py1
-rw-r--r--src/silx/gui/plot/utils/intersections.py1
-rw-r--r--src/silx/gui/plot3d/ParamTreeView.py3
-rw-r--r--src/silx/gui/plot3d/Plot3DWidget.py33
-rw-r--r--src/silx/gui/plot3d/Plot3DWindow.py3
-rw-r--r--src/silx/gui/plot3d/SFViewParamTree.py3
-rw-r--r--src/silx/gui/plot3d/ScalarFieldView.py3
-rw-r--r--src/silx/gui/plot3d/SceneWidget.py3
-rw-r--r--src/silx/gui/plot3d/SceneWindow.py3
-rw-r--r--src/silx/gui/plot3d/__init__.py2
-rw-r--r--src/silx/gui/plot3d/_model/__init__.py3
-rw-r--r--src/silx/gui/plot3d/_model/core.py3
-rw-r--r--src/silx/gui/plot3d/_model/items.py3
-rw-r--r--src/silx/gui/plot3d/_model/model.py3
-rw-r--r--src/silx/gui/plot3d/actions/Plot3DAction.py3
-rw-r--r--src/silx/gui/plot3d/actions/__init__.py1
-rw-r--r--src/silx/gui/plot3d/actions/io.py3
-rw-r--r--src/silx/gui/plot3d/actions/mode.py3
-rw-r--r--src/silx/gui/plot3d/actions/viewpoint.py3
-rw-r--r--src/silx/gui/plot3d/items/__init__.py3
-rw-r--r--src/silx/gui/plot3d/items/_pick.py3
-rw-r--r--src/silx/gui/plot3d/items/clipplane.py3
-rw-r--r--src/silx/gui/plot3d/items/core.py3
-rw-r--r--src/silx/gui/plot3d/items/image.py3
-rw-r--r--src/silx/gui/plot3d/items/mesh.py3
-rw-r--r--src/silx/gui/plot3d/items/mixins.py1
-rw-r--r--src/silx/gui/plot3d/items/scatter.py3
-rw-r--r--src/silx/gui/plot3d/items/volume.py3
-rw-r--r--src/silx/gui/plot3d/scene/__init__.py1
-rw-r--r--src/silx/gui/plot3d/scene/axes.py3
-rw-r--r--src/silx/gui/plot3d/scene/camera.py3
-rw-r--r--src/silx/gui/plot3d/scene/core.py3
-rw-r--r--src/silx/gui/plot3d/scene/cutplane.py3
-rw-r--r--src/silx/gui/plot3d/scene/event.py3
-rw-r--r--src/silx/gui/plot3d/scene/function.py3
-rw-r--r--src/silx/gui/plot3d/scene/interaction.py3
-rw-r--r--src/silx/gui/plot3d/scene/primitives.py3
-rw-r--r--src/silx/gui/plot3d/scene/test/__init__.py1
-rw-r--r--src/silx/gui/plot3d/scene/test/test_transform.py3
-rw-r--r--src/silx/gui/plot3d/scene/test/test_utils.py3
-rw-r--r--src/silx/gui/plot3d/scene/text.py3
-rw-r--r--src/silx/gui/plot3d/scene/transform.py3
-rw-r--r--src/silx/gui/plot3d/scene/utils.py3
-rw-r--r--src/silx/gui/plot3d/scene/viewport.py3
-rw-r--r--src/silx/gui/plot3d/scene/window.py3
-rw-r--r--src/silx/gui/plot3d/setup.py50
-rw-r--r--src/silx/gui/plot3d/test/__init__.py1
-rw-r--r--src/silx/gui/plot3d/test/testGL.py4
-rw-r--r--src/silx/gui/plot3d/test/testScalarFieldView.py4
-rw-r--r--src/silx/gui/plot3d/test/testSceneWidget.py4
-rw-r--r--src/silx/gui/plot3d/test/testSceneWidgetPicking.py4
-rw-r--r--src/silx/gui/plot3d/test/testSceneWindow.py5
-rw-r--r--src/silx/gui/plot3d/test/testStatsWidget.py4
-rw-r--r--src/silx/gui/plot3d/tools/GroupPropertiesWidget.py3
-rw-r--r--src/silx/gui/plot3d/tools/PositionInfoWidget.py3
-rw-r--r--src/silx/gui/plot3d/tools/ViewpointTools.py3
-rw-r--r--src/silx/gui/plot3d/tools/__init__.py1
-rw-r--r--src/silx/gui/plot3d/tools/test/__init__.py1
-rw-r--r--src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py1
-rw-r--r--src/silx/gui/plot3d/tools/toolbars.py3
-rw-r--r--src/silx/gui/plot3d/utils/__init__.py1
-rw-r--r--src/silx/gui/plot3d/utils/mng.py3
-rw-r--r--src/silx/gui/printer.py3
-rw-r--r--src/silx/gui/qt/__init__.py6
-rw-r--r--src/silx/gui/qt/_pyqt6.py64
-rw-r--r--src/silx/gui/qt/_pyside_dynamic.py1
-rw-r--r--src/silx/gui/qt/_qt.py113
-rw-r--r--src/silx/gui/qt/_utils.py14
-rw-r--r--src/silx/gui/qt/inspect.py16
-rw-r--r--src/silx/gui/setup.py55
-rw-r--r--src/silx/gui/test/__init__.py1
-rwxr-xr-xsrc/silx/gui/test/test_colors.py3
-rw-r--r--src/silx/gui/test/test_console.py3
-rw-r--r--src/silx/gui/test/test_icons.py1
-rw-r--r--src/silx/gui/test/test_qt.py1
-rw-r--r--src/silx/gui/test/utils.py3
-rwxr-xr-xsrc/silx/gui/utils/__init__.py1
-rw-r--r--src/silx/gui/utils/concurrent.py3
-rw-r--r--src/silx/gui/utils/glutils/__init__.py34
-rw-r--r--src/silx/gui/utils/image.py8
-rw-r--r--src/silx/gui/utils/matplotlib.py106
-rw-r--r--src/silx/gui/utils/projecturl.py3
-rwxr-xr-xsrc/silx/gui/utils/qtutils.py1
-rw-r--r--src/silx/gui/utils/signal.py1
-rwxr-xr-xsrc/silx/gui/utils/test/__init__.py1
-rw-r--r--src/silx/gui/utils/test/test.py3
-rw-r--r--src/silx/gui/utils/test/test_async.py3
-rw-r--r--src/silx/gui/utils/test/test_glutils.py33
-rw-r--r--src/silx/gui/utils/test/test_image.py1
-rwxr-xr-xsrc/silx/gui/utils/test/test_qtutils.py3
-rw-r--r--src/silx/gui/utils/test/test_testutils.py1
-rw-r--r--src/silx/gui/utils/testutils.py33
-rw-r--r--src/silx/gui/widgets/BoxLayoutDockWidget.py1
-rw-r--r--src/silx/gui/widgets/ColormapNameComboBox.py3
-rw-r--r--src/silx/gui/widgets/ElidedLabel.py42
-rw-r--r--src/silx/gui/widgets/FloatEdit.py3
-rw-r--r--src/silx/gui/widgets/FlowLayout.py3
-rw-r--r--src/silx/gui/widgets/FormGridLayout.py74
-rw-r--r--src/silx/gui/widgets/FrameBrowser.py1
-rw-r--r--src/silx/gui/widgets/HierarchicalTableView.py1
-rwxr-xr-xsrc/silx/gui/widgets/LegendIconWidget.py1
-rw-r--r--src/silx/gui/widgets/MedianFilterDialog.py1
-rw-r--r--src/silx/gui/widgets/MultiModeAction.py1
-rw-r--r--src/silx/gui/widgets/PeriodicTable.py1
-rw-r--r--src/silx/gui/widgets/PrintGeometryDialog.py1
-rw-r--r--src/silx/gui/widgets/PrintPreview.py1
-rw-r--r--src/silx/gui/widgets/RangeSlider.py2
-rw-r--r--src/silx/gui/widgets/TableWidget.py1
-rw-r--r--src/silx/gui/widgets/ThreadPoolPushButton.py1
-rw-r--r--src/silx/gui/widgets/WaitingPushButton.py1
-rw-r--r--src/silx/gui/widgets/__init__.py1
-rw-r--r--src/silx/gui/widgets/setup.py41
-rw-r--r--src/silx/gui/widgets/test/__init__.py1
-rw-r--r--src/silx/gui/widgets/test/test_boxlayoutdockwidget.py1
-rw-r--r--src/silx/gui/widgets/test/test_elidedlabel.py32
-rw-r--r--src/silx/gui/widgets/test/test_flowlayout.py1
-rw-r--r--src/silx/gui/widgets/test/test_framebrowser.py1
-rw-r--r--src/silx/gui/widgets/test/test_hierarchicaltableview.py1
-rw-r--r--src/silx/gui/widgets/test/test_legendiconwidget.py1
-rw-r--r--src/silx/gui/widgets/test/test_periodictable.py1
-rw-r--r--src/silx/gui/widgets/test/test_printpreview.py1
-rw-r--r--src/silx/gui/widgets/test/test_rangeslider.py1
-rw-r--r--src/silx/gui/widgets/test/test_tablewidget.py1
-rw-r--r--src/silx/gui/widgets/test/test_threadpoolpushbutton.py1
-rw-r--r--src/silx/image/__init__.py1
-rw-r--r--src/silx/image/_boundingbox.py1
-rw-r--r--src/silx/image/backprojection.py1
-rw-r--r--src/silx/image/bilinear.pyx1
-rw-r--r--src/silx/image/marchingsquares/__init__.py1
-rw-r--r--src/silx/image/marchingsquares/_mergeimpl.pyx1
-rw-r--r--src/silx/image/marchingsquares/_skimage.py1
-rw-r--r--src/silx/image/marchingsquares/setup.py51
-rw-r--r--src/silx/image/marchingsquares/test/__init__.py1
-rw-r--r--src/silx/image/marchingsquares/test/test_funcapi.py1
-rw-r--r--src/silx/image/marchingsquares/test/test_mergeimpl.py1
-rw-r--r--src/silx/image/medianfilter.py1
-rw-r--r--src/silx/image/phantomgenerator.py1
-rw-r--r--src/silx/image/projection.py1
-rw-r--r--src/silx/image/reconstruction.py1
-rw-r--r--src/silx/image/setup.py47
-rw-r--r--src/silx/image/shapes.pyx1
-rw-r--r--src/silx/image/sift.py1
-rw-r--r--src/silx/image/test/__init__.py1
-rw-r--r--src/silx/image/test/test_bb.py1
-rw-r--r--src/silx/image/test/test_bilinear.py1
-rw-r--r--src/silx/image/test/test_medianfilter.py1
-rw-r--r--src/silx/image/test/test_shapes.py1
-rw-r--r--src/silx/image/test/test_tomography.py1
-rw-r--r--src/silx/image/tomography.py1
-rw-r--r--src/silx/image/utils.py1
-rw-r--r--src/silx/io/__init__.py1
-rw-r--r--src/silx/io/commonh5.py1
-rw-r--r--src/silx/io/convert.py1
-rw-r--r--src/silx/io/dictdump.py21
-rwxr-xr-xsrc/silx/io/fabioh5.py1
-rw-r--r--src/silx/io/fioh5.py1
-rw-r--r--src/silx/io/h5py_utils.py1
-rw-r--r--src/silx/io/nxdata/__init__.py1
-rw-r--r--src/silx/io/nxdata/_utils.py1
-rw-r--r--src/silx/io/nxdata/parse.py87
-rw-r--r--src/silx/io/nxdata/write.py1
-rw-r--r--src/silx/io/octaveh5.py1
-rw-r--r--src/silx/io/rawh5.py1
-rw-r--r--src/silx/io/setup.py87
-rw-r--r--src/silx/io/specfile.pyx1
-rw-r--r--src/silx/io/specfile/include/SpecFileCython.h1
-rw-r--r--src/silx/io/specfile/src/sflabel.c18
-rw-r--r--src/silx/io/specfile/src/sfmca.c5
-rw-r--r--src/silx/io/specfile_wrapper.pxd1
-rw-r--r--src/silx/io/specfilewrapper.py1
-rw-r--r--src/silx/io/spech5.py1
-rw-r--r--src/silx/io/spectoh5.py1
-rw-r--r--src/silx/io/test/__init__.py1
-rw-r--r--src/silx/io/test/test_commonh5.py1
-rw-r--r--src/silx/io/test/test_dictdump.py58
-rwxr-xr-xsrc/silx/io/test/test_fabioh5.py1
-rw-r--r--src/silx/io/test/test_fioh5.py1
-rw-r--r--src/silx/io/test/test_h5py_utils.py33
-rw-r--r--src/silx/io/test/test_nxdata.py147
-rw-r--r--src/silx/io/test/test_octaveh5.py1
-rw-r--r--src/silx/io/test/test_rawh5.py1
-rw-r--r--src/silx/io/test/test_specfile.py1
-rw-r--r--src/silx/io/test/test_specfilewrapper.py1
-rw-r--r--src/silx/io/test/test_spech5.py1
-rw-r--r--src/silx/io/test/test_spectoh5.py1
-rw-r--r--src/silx/io/test/test_url.py1
-rw-r--r--src/silx/io/test/test_utils.py35
-rw-r--r--src/silx/io/test/test_write_to_h5.py1
-rw-r--r--src/silx/io/url.py1
-rw-r--r--src/silx/io/utils.py24
-rw-r--r--src/silx/math/__init__.py1
-rw-r--r--src/silx/math/_colormap.pyx1
-rw-r--r--src/silx/math/calibration.py1
-rw-r--r--src/silx/math/chistogramnd.pyx37
-rw-r--r--src/silx/math/chistogramnd_lut.pyx10
-rw-r--r--src/silx/math/colormap.py1
-rw-r--r--src/silx/math/combo.pyx1
-rw-r--r--src/silx/math/fft/__init__.py1
-rw-r--r--src/silx/math/fft/basefft.py1
-rw-r--r--src/silx/math/fft/clfft.py3
-rw-r--r--src/silx/math/fft/cufft.py3
-rw-r--r--src/silx/math/fft/fft.py35
-rw-r--r--src/silx/math/fft/fftw.py215
-rw-r--r--src/silx/math/fft/npfft.py68
-rw-r--r--src/silx/math/fft/setup.py41
-rw-r--r--src/silx/math/fft/test/__init__.py1
-rw-r--r--src/silx/math/fft/test/test_fft.py148
-rw-r--r--src/silx/math/fit/__init__.py1
-rw-r--r--src/silx/math/fit/bgtheories.py1
-rw-r--r--src/silx/math/fit/filters.pyx1
-rw-r--r--src/silx/math/fit/filters_wrapper.pxd1
-rw-r--r--src/silx/math/fit/fitmanager.py1
-rw-r--r--src/silx/math/fit/fittheories.py1
-rw-r--r--src/silx/math/fit/fittheory.py1
-rw-r--r--src/silx/math/fit/functions.pyx1
-rw-r--r--src/silx/math/fit/functions_wrapper.pxd1
-rw-r--r--src/silx/math/fit/leastsq.py1
-rw-r--r--src/silx/math/fit/peaks.pyx2
-rw-r--r--src/silx/math/fit/peaks_wrapper.pxd1
-rw-r--r--src/silx/math/fit/setup.py85
-rw-r--r--src/silx/math/fit/test/__init__.py1
-rw-r--r--src/silx/math/fit/test/test_bgtheories.py1
-rw-r--r--src/silx/math/fit/test/test_filters.py1
-rw-r--r--src/silx/math/fit/test/test_fit.py1
-rw-r--r--src/silx/math/fit/test/test_fitmanager.py1
-rw-r--r--src/silx/math/fit/test/test_functions.py1
-rw-r--r--src/silx/math/fit/test/test_peaks.py1
-rw-r--r--src/silx/math/histogram.py1
-rw-r--r--src/silx/math/histogramnd/include/histogramnd_c.h74
-rw-r--r--src/silx/math/histogramnd/src/histogramnd_template.c62
-rw-r--r--src/silx/math/histogramnd_c.pxd37
-rw-r--r--src/silx/math/interpolate.pyx1
-rw-r--r--src/silx/math/marchingcubes.pyx1
-rw-r--r--src/silx/math/math_compatibility.pxd1
-rw-r--r--src/silx/math/mc.pxd1
-rw-r--r--src/silx/math/medianfilter/__init__.py1
-rw-r--r--src/silx/math/medianfilter/median_filter.pxd1
-rw-r--r--src/silx/math/medianfilter/medianfilter.pyx1
-rw-r--r--src/silx/math/medianfilter/setup.py59
-rw-r--r--src/silx/math/medianfilter/test/__init__.py1
-rw-r--r--src/silx/math/medianfilter/test/benchmark.py1
-rw-r--r--src/silx/math/medianfilter/test/test_medianfilter.py1
-rw-r--r--src/silx/math/setup.py99
-rw-r--r--src/silx/math/test/__init__.py1
-rw-r--r--src/silx/math/test/benchmark_combo.py3
-rw-r--r--src/silx/math/test/histo_benchmarks.py1
-rw-r--r--src/silx/math/test/test_HistogramndLut_nominal.py1
-rw-r--r--src/silx/math/test/test_calibration.py3
-rw-r--r--src/silx/math/test/test_colormap.py3
-rw-r--r--src/silx/math/test/test_combo.py3
-rw-r--r--src/silx/math/test/test_histogramnd_error.py1
-rw-r--r--src/silx/math/test/test_histogramnd_nominal.py1
-rw-r--r--src/silx/math/test/test_histogramnd_vs_np.py37
-rw-r--r--src/silx/math/test/test_interpolate.py1
-rw-r--r--src/silx/math/test/test_marchingcubes.py3
-rw-r--r--src/silx/opencl/__init__.py1
-rw-r--r--src/silx/opencl/backprojection.py3
-rw-r--r--src/silx/opencl/codec/byte_offset.py3
-rw-r--r--src/silx/opencl/codec/setup.py43
-rw-r--r--src/silx/opencl/codec/test/__init__.py1
-rw-r--r--src/silx/opencl/codec/test/test_byte_offset.py3
-rw-r--r--src/silx/opencl/common.py1
-rw-r--r--src/silx/opencl/convolution.py3
-rw-r--r--src/silx/opencl/image.py3
-rw-r--r--src/silx/opencl/linalg.py3
-rw-r--r--src/silx/opencl/medfilt.py3
-rw-r--r--src/silx/opencl/processing.py114
-rw-r--r--src/silx/opencl/projection.py3
-rw-r--r--src/silx/opencl/reconstruction.py3
-rw-r--r--src/silx/opencl/setup.py48
-rw-r--r--src/silx/opencl/sinofilter.py3
-rw-r--r--src/silx/opencl/sparse.py3
-rw-r--r--src/silx/opencl/statistics.py1
-rw-r--r--src/silx/opencl/test/__init__.py1
-rw-r--r--src/silx/opencl/test/test_addition.py1
-rw-r--r--src/silx/opencl/test/test_array_utils.py3
-rw-r--r--src/silx/opencl/test/test_backprojection.py3
-rw-r--r--src/silx/opencl/test/test_convolution.py3
-rw-r--r--src/silx/opencl/test/test_doubleword.py1
-rw-r--r--src/silx/opencl/test/test_image.py3
-rw-r--r--src/silx/opencl/test/test_kahan.py1
-rw-r--r--src/silx/opencl/test/test_linalg.py3
-rw-r--r--src/silx/opencl/test/test_medfilt.py3
-rw-r--r--src/silx/opencl/test/test_projection.py3
-rw-r--r--src/silx/opencl/test/test_sparse.py1
-rw-r--r--src/silx/opencl/test/test_stats.py1
-rw-r--r--src/silx/opencl/utils.py3
-rw-r--r--src/silx/resources/__init__.py1
-rw-r--r--src/silx/resources/gui/icons/add-shape-rotated-rectangle.pngbin0 -> 1263 bytes
-rw-r--r--src/silx/resources/gui/icons/add-shape-rotated-rectangle.svg2
-rw-r--r--src/silx/resources/gui/icons/scale-auto.pngbin0 -> 704 bytes
-rw-r--r--src/silx/resources/gui/icons/scale-auto.svg2
-rw-r--r--src/silx/resources/gui/icons/scale-fixed.pngbin0 -> 1163 bytes
-rw-r--r--src/silx/resources/gui/icons/scale-fixed.svg2
-rw-r--r--src/silx/setup.py54
-rw-r--r--src/silx/sx/__init__.py5
-rw-r--r--src/silx/sx/_plot.py1
-rw-r--r--src/silx/sx/_plot3d.py1
-rw-r--r--src/silx/test/__init__.py5
-rw-r--r--src/silx/test/test_resources.py1
-rw-r--r--src/silx/test/test_sx.py1
-rw-r--r--src/silx/test/test_version.py1
-rw-r--r--src/silx/test/utils.py1
-rw-r--r--src/silx/third_party/__init__.py1
-rw-r--r--src/silx/third_party/scipy_spatial.py3
-rw-r--r--src/silx/third_party/setup.py49
-rw-r--r--src/silx/utils/ExternalResources.py80
-rw-r--r--src/silx/utils/__init__.py1
-rw-r--r--src/silx/utils/_have_openmp.pxd1
-rw-r--r--src/silx/utils/array_like.py3
-rw-r--r--src/silx/utils/debug.py1
-rw-r--r--src/silx/utils/deprecation.py3
-rw-r--r--src/silx/utils/enum.py3
-rw-r--r--src/silx/utils/exceptions.py1
-rw-r--r--src/silx/utils/files.py1
-rw-r--r--src/silx/utils/html.py1
-rw-r--r--src/silx/utils/launcher.py1
-rwxr-xr-xsrc/silx/utils/number.py1
-rw-r--r--src/silx/utils/property.py3
-rw-r--r--src/silx/utils/proxy.py3
-rw-r--r--src/silx/utils/retry.py96
-rw-r--r--src/silx/utils/setup.py43
-rwxr-xr-xsrc/silx/utils/test/__init__.py1
-rw-r--r--src/silx/utils/test/test_array_like.py1
-rw-r--r--src/silx/utils/test/test_debug.py1
-rw-r--r--src/silx/utils/test/test_deprecation.py1
-rw-r--r--src/silx/utils/test/test_enum.py3
-rw-r--r--src/silx/utils/test/test_external_resources.py5
-rw-r--r--src/silx/utils/test/test_launcher.py1
-rw-r--r--src/silx/utils/test/test_launcher_command.py1
-rw-r--r--src/silx/utils/test/test_number.py1
-rw-r--r--src/silx/utils/test/test_proxy.py1
-rw-r--r--src/silx/utils/test/test_retry.py45
-rwxr-xr-xsrc/silx/utils/test/test_testutils.py1
-rw-r--r--src/silx/utils/test/test_weakref.py1
-rwxr-xr-xsrc/silx/utils/testutils.py1
-rw-r--r--src/silx/utils/weakref.py2
575 files changed, 4986 insertions, 3001 deletions
diff --git a/src/silx.egg-info/PKG-INFO b/src/silx.egg-info/PKG-INFO
new file mode 100644
index 0000000..f953bc6
--- /dev/null
+++ b/src/silx.egg-info/PKG-INFO
@@ -0,0 +1,148 @@
+Metadata-Version: 2.1
+Name: silx
+Version: 1.1.0
+Summary: Software library for X-ray data analysis
+Home-page: http://www.silx.org/
+Author: data analysis unit
+Author-email: silx@esrf.fr
+License: MIT
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Console
+Classifier: Environment :: MacOS X
+Classifier: Environment :: Win32 (MS Windows)
+Classifier: Environment :: X11 Applications :: Qt
+Classifier: Intended Audience :: Education
+Classifier: Intended Audience :: Science/Research
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Operating System :: MacOS
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Programming Language :: Cython
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Topic :: Scientific/Engineering :: Physics
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=3.5
+Provides-Extra: full
+Provides-Extra: test
+License-File: LICENSE
+
+
+silx toolkit
+============
+
+.. |silxView| image:: http://www.silx.org/doc/silx/img/silx-view-v1-0.gif
+ :height: 480px
+
+The purpose of the *silx* project is to provide a collection of Python packages to support the
+development of data assessment, reduction and analysis applications at synchrotron
+radiation facilities.
+*silx* aims to provide reading/writing tools for different file formats, data reduction routines
+and a set of Qt widgets to browse and visualise data.
+
+The current version features:
+
+* Support of `HDF5 <https://www.hdfgroup.org/HDF5/>`_,
+ `SPEC <https://certif.com/spec.html>`_ and
+ `FabIO <http://www.silx.org/doc/fabio/dev/getting_started.html#list-of-file-formats-that-fabio-can-read-and-write>`_
+ images file formats.
+* OpenCL-based data processing: image alignment (SIFT),
+ image processing (median filter, histogram),
+ filtered backprojection for tomography,
+ convolution
+* Data reduction: histogramming, fitting, median filter
+* A set of Qt widgets, including:
+
+ * 1D and 2D visualization widgets with a set of associated tools using multiple backends (matplotlib or OpenGL)
+ * OpenGL-based widgets to visualize data in 3D (scalar field with isosurface and cut plane, scatter plot)
+ * a unified browser for HDF5, SPEC and image file formats supporting inspection and
+ visualization of n-dimensional datasets.
+
+* a set of applications:
+
+ * a unified viewer (*silx view filename*) for HDF5, SPEC and image file formats
+
+ |silxView|
+
+ * a unified converter to HDF5 format (*silx convert filename*)
+
+
+Installation
+------------
+
+To install silx (and all its dependencies), run:
+
+.. code-block:: bash
+
+ pip install silx[full]
+
+To install silx with a minimal set of dependencies, run:
+
+.. code-block:: bash
+
+ pip install silx
+
+Or using Anaconda on Linux and MacOS:
+
+.. code-block:: bash
+
+ conda install silx -c conda-forge
+
+Unofficial packages for different distributions are available:
+
+- Unofficial Debian10 and Ubuntu20.04 packages are available at http://www.silx.org/pub/linux-repo/
+- CentOS 7 rpm packages are provided by Max IV at: http://pubrepo.maxiv.lu.se/rpm/el7/x86_64/
+- Fedora 23 rpm packages are provided by Max IV at http://pubrepo.maxiv.lu.se/rpm/fc23/x86_64/
+- Arch Linux (AUR) packages are also available: https://aur.archlinux.org/packages/python-silx
+
+`Detailed installation instructions <http://www.silx.org/doc/silx/dev/install.html>`_
+are available in the documentation.
+
+Documentation
+-------------
+
+The documentation of `latest release <http://www.silx.org/doc/silx/latest/>`_ and
+the documentation of `the nightly build <http://www.silx.org/doc/silx/dev>`_ are
+available at http://www.silx.org/doc/silx/
+
+Testing
+-------
+
+*silx* features a comprehensive test-suite used in continuous integration for
+all major operating systems:
+
+- Github Actions CI status: |Github Actions Status|
+- Appveyor CI status: |Appveyor Status|
+
+Please refer to the `documentation on testing <http://www.silx.org/doc/silx/dev/install.html#testing>`_
+for details.
+
+Examples
+--------
+
+Some examples of sample code using silx are provided with the
+`silx documentation <http://www.silx.org/doc/silx/dev/sample_code/index.html>`_.
+
+
+License
+-------
+
+The source code of *silx* is licensed under the MIT license.
+See the `LICENSE <https://github.com/silx-kit/silx/blob/master/LICENSE>`_ and
+`copyright <https://github.com/silx-kit/silx/blob/master/copyright>`_ files for details.
+
+Citation
+--------
+
+*silx* releases can be cited via their DOI on Zenodo: |zenodo DOI|
+
+.. |Github Actions Status| image:: https://github.com/silx-kit/silx/workflows/CI/badge.svg
+ :target: https://github.com/silx-kit/silx/actions
+.. |Appveyor Status| image:: https://ci.appveyor.com/api/projects/status/qgox9ei0wxwfagrb/branch/master?svg=true
+ :target: https://ci.appveyor.com/project/ESRF/silx?branch=master
+.. |zenodo DOI| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.591709.svg
+ :target: https://doi.org/10.5281/zenodo.591709
+
+
diff --git a/src/silx.egg-info/SOURCES.txt b/src/silx.egg-info/SOURCES.txt
new file mode 100644
index 0000000..6d81290
--- /dev/null
+++ b/src/silx.egg-info/SOURCES.txt
@@ -0,0 +1,1522 @@
+CHANGELOG.rst
+LICENSE
+MANIFEST.in
+README.rst
+build-deb.sh
+copyright
+pyproject.toml
+requirements-dev.txt
+requirements.txt
+run_tests.py
+setup.py
+stdeb.cfg
+doc/source/changelog.rst
+doc/source/conf.py
+doc/source/index.rst
+doc/source/install.rst
+doc/source/license.rst
+doc/source/overview.rst
+doc/source/troubleshooting.rst
+doc/source/tutorials.rst
+doc/source/virtualenv.rst
+doc/source/Tutorials/Image.ipynb
+doc/source/Tutorials/array_widget.rst
+doc/source/Tutorials/convert.rst
+doc/source/Tutorials/fit.rst
+doc/source/Tutorials/fitconfig.rst
+doc/source/Tutorials/io.rst
+doc/source/Tutorials/specfile_to_hdf5.rst
+doc/source/Tutorials/writing_NXdata.rst
+doc/source/Tutorials/Sift/sift.ipynb
+doc/source/Tutorials/img/arraywidget3D_0.png
+doc/source/Tutorials/img/arraywidget3D_1.png
+doc/source/Tutorials/img/arraywidget5D_0.png
+doc/source/Tutorials/img/arraywidget5D_1.png
+doc/source/Tutorials/img/custom_config_scale0.5.png
+doc/source/Tutorials/img/custom_config_scale1.0.png
+doc/source/Tutorials/img/custom_config_scale2.1.png
+doc/source/Tutorials/img/fitwidget1.png
+doc/source/Tutorials/img/fitwidget2.png
+doc/source/Tutorials/img/fitwidget3.png
+doc/source/Tutorials/img/fitwidget4.png
+doc/source/Tutorials/img/fitwidget5.png
+doc/source/Tutorials/img/silx_view_edf.png
+doc/source/Tutorials/img/stripbg_plot1.png
+doc/source/Tutorials/img/stripbg_plot2.png
+doc/source/applications/convert.rst
+doc/source/applications/index.rst
+doc/source/applications/view.rst
+doc/source/applications/img/silx-view-hdf5.png
+doc/source/applications/img/silx-view-image.png
+doc/source/applications/img/silx-view-table.png
+doc/source/description/index.rst
+doc/source/description/sift.rst
+doc/source/description/img/sift_bench_cpu0.png
+doc/source/description/img/sift_bench_cpu_kp.png
+doc/source/description/img/sift_bench_cpu_res.png
+doc/source/description/img/sift_bench_gpu0.png
+doc/source/description/img/sift_bench_gpu_kp.png
+doc/source/description/img/sift_bench_gpu_res.png
+doc/source/description/img/sift_dog1.png
+doc/source/description/img/sift_frame_ROI.png
+doc/source/description/img/sift_match1.png
+doc/source/description/img/sift_match2.png
+doc/source/description/img/sift_orientation.png
+doc/source/ext/snapshotqt_directive.py
+doc/source/ext/sphinxext-archive.py
+doc/source/img/silx.ico
+doc/source/img/silx_large.png
+doc/source/img/silx_small.png
+doc/source/modules/index.rst
+doc/source/modules/resources.rst
+doc/source/modules/sx.rst
+doc/source/modules/gui/colors.rst
+doc/source/modules/gui/console.rst
+doc/source/modules/gui/designer.rst
+doc/source/modules/gui/gallery.rst
+doc/source/modules/gui/icons.rst
+doc/source/modules/gui/index.rst
+doc/source/modules/gui/qt.rst
+doc/source/modules/gui/utils.rst
+doc/source/modules/gui/data/arraytable.rst
+doc/source/modules/gui/data/dataviewer.rst
+doc/source/modules/gui/data/dataviewerframe.rst
+doc/source/modules/gui/data/index.rst
+doc/source/modules/gui/data/numpyaxesselector.rst
+doc/source/modules/gui/data/textformatter.rst
+doc/source/modules/gui/data/img/ArrayTableWidget.png
+doc/source/modules/gui/data/img/DataViewer.png
+doc/source/modules/gui/data/img/DataViewerFrame.png
+doc/source/modules/gui/data/img/NumpyAxesSelector.png
+doc/source/modules/gui/dialog/abstractdatafiledialog.rst
+doc/source/modules/gui/dialog/colormapdialog.rst
+doc/source/modules/gui/dialog/datafiledialog.rst
+doc/source/modules/gui/dialog/datasetdialog.rst
+doc/source/modules/gui/dialog/groupdialog.rst
+doc/source/modules/gui/dialog/imagefiledialog.rst
+doc/source/modules/gui/dialog/index.rst
+doc/source/modules/gui/dialog/img/abstractdatafiledialog.png
+doc/source/modules/gui/dialog/img/colormapdialog.png
+doc/source/modules/gui/dialog/img/datafiledialog.png
+doc/source/modules/gui/dialog/img/datasetdialog.png
+doc/source/modules/gui/dialog/img/groupdialog.png
+doc/source/modules/gui/dialog/img/imagefiledialog_edf.png
+doc/source/modules/gui/dialog/img/imagefiledialog_h5.png
+doc/source/modules/gui/fit/backgroundwidget.rst
+doc/source/modules/gui/fit/fitwidget.rst
+doc/source/modules/gui/fit/index.rst
+doc/source/modules/gui/fit/img/BackgroundDialog.png
+doc/source/modules/gui/fit/img/FitWidget.png
+doc/source/modules/gui/hdf5/examples_hdf5widget.rst
+doc/source/modules/gui/hdf5/getting_started.rst
+doc/source/modules/gui/hdf5/h5node.rst
+doc/source/modules/gui/hdf5/hdf5contextmenuevent.rst
+doc/source/modules/gui/hdf5/hdf5headerview.rst
+doc/source/modules/gui/hdf5/hdf5treemodel.rst
+doc/source/modules/gui/hdf5/hdf5treeview.rst
+doc/source/modules/gui/hdf5/index.rst
+doc/source/modules/gui/hdf5/nexussortfilterproxymodel.rst
+doc/source/modules/gui/hdf5/img/Hdf5Example.png
+doc/source/modules/gui/hdf5/img/Hdf5TreeView.png
+doc/source/modules/gui/img/IPythonDockWidget.png
+doc/source/modules/gui/img/IPythonWidget.png
+doc/source/modules/gui/plot/compareimages.rst
+doc/source/modules/gui/plot/compleximageview.rst
+doc/source/modules/gui/plot/dev.rst
+doc/source/modules/gui/plot/getting_started.rst
+doc/source/modules/gui/plot/imageview.rst
+doc/source/modules/gui/plot/index.rst
+doc/source/modules/gui/plot/items.rst
+doc/source/modules/gui/plot/plotsignal.rst
+doc/source/modules/gui/plot/plottoolbuttons.rst
+doc/source/modules/gui/plot/plotwidget.rst
+doc/source/modules/gui/plot/plotwindow.rst
+doc/source/modules/gui/plot/printpreviewtoolbutton.rst
+doc/source/modules/gui/plot/profile.rst
+doc/source/modules/gui/plot/roi.rst
+doc/source/modules/gui/plot/roistatswidget.rst
+doc/source/modules/gui/plot/scatterview.rst
+doc/source/modules/gui/plot/stackview.rst
+doc/source/modules/gui/plot/statswidget.rst
+doc/source/modules/gui/plot/utils.rst
+doc/source/modules/gui/plot/actions/control.rst
+doc/source/modules/gui/plot/actions/examples.rst
+doc/source/modules/gui/plot/actions/fit.rst
+doc/source/modules/gui/plot/actions/histogram.rst
+doc/source/modules/gui/plot/actions/index.rst
+doc/source/modules/gui/plot/actions/io.rst
+doc/source/modules/gui/plot/actions/medfilt.rst
+doc/source/modules/gui/plot/actions/img/fftAction0.png
+doc/source/modules/gui/plot/actions/img/fftAction1.png
+doc/source/modules/gui/plot/actions/img/shiftAction0.png
+doc/source/modules/gui/plot/actions/img/shiftAction3.png
+doc/source/modules/gui/plot/img/BasicGridStatsWidget.png
+doc/source/modules/gui/plot/img/BasicStatsWidget.png
+doc/source/modules/gui/plot/img/CompareImages.png
+doc/source/modules/gui/plot/img/ComplexImageView.png
+doc/source/modules/gui/plot/img/ImageView.png
+doc/source/modules/gui/plot/img/LimitsToolBar.png
+doc/source/modules/gui/plot/img/Plot1D.png
+doc/source/modules/gui/plot/img/Plot2D.png
+doc/source/modules/gui/plot/img/PlotWidget.png
+doc/source/modules/gui/plot/img/PlotWindow.png
+doc/source/modules/gui/plot/img/PositionInfo.png
+doc/source/modules/gui/plot/img/ROIStatsWidget.png
+doc/source/modules/gui/plot/img/ScatterView.png
+doc/source/modules/gui/plot/img/StackView.png
+doc/source/modules/gui/plot/img/StackViewMainWindow.png
+doc/source/modules/gui/plot/img/colorScale.png
+doc/source/modules/gui/plot/img/colorScaleBar.png
+doc/source/modules/gui/plot/img/logColorbar.png
+doc/source/modules/gui/plot/img/netArea.png
+doc/source/modules/gui/plot/img/netCounts.png
+doc/source/modules/gui/plot/img/plot_and_backend.png
+doc/source/modules/gui/plot/img/printPreviewMultiPlot.png
+doc/source/modules/gui/plot/img/rawArea.png
+doc/source/modules/gui/plot/img/rawCounts.png
+doc/source/modules/gui/plot/img/roiwidget.png
+doc/source/modules/gui/plot/img/statsWidget.png
+doc/source/modules/gui/plot/img/tickbar.png
+doc/source/modules/gui/plot/stats/index.rst
+doc/source/modules/gui/plot/stats/stats.rst
+doc/source/modules/gui/plot/stats/statshandler.rst
+doc/source/modules/gui/plot/tools/index.rst
+doc/source/modules/gui/plot/tools/profile.rst
+doc/source/modules/gui/plot/tools/img/CurveLegendsWidget.png
+doc/source/modules/gui/plot/tools/img/linearColorbar.png
+doc/source/modules/gui/plot3d/actions.rst
+doc/source/modules/gui/plot3d/dev.rst
+doc/source/modules/gui/plot3d/glutils.rst
+doc/source/modules/gui/plot3d/index.rst
+doc/source/modules/gui/plot3d/items.rst
+doc/source/modules/gui/plot3d/plot3dwidget.rst
+doc/source/modules/gui/plot3d/plot3dwindow.rst
+doc/source/modules/gui/plot3d/scalarfieldview.rst
+doc/source/modules/gui/plot3d/scene.rst
+doc/source/modules/gui/plot3d/scenewidget.rst
+doc/source/modules/gui/plot3d/scenewindow.rst
+doc/source/modules/gui/plot3d/sfviewparamtree.rst
+doc/source/modules/gui/plot3d/tools.rst
+doc/source/modules/gui/plot3d/utils.rst
+doc/source/modules/gui/plot3d/img/GroupPropertiesWidget.png
+doc/source/modules/gui/plot3d/img/Plot3DWidget.png
+doc/source/modules/gui/plot3d/img/Plot3DWindow.png
+doc/source/modules/gui/plot3d/img/PositionInfoWidget.png
+doc/source/modules/gui/plot3d/img/SFViewParamTree.png
+doc/source/modules/gui/plot3d/img/ScalarFieldView.png
+doc/source/modules/gui/plot3d/img/SceneWidget.png
+doc/source/modules/gui/plot3d/img/SceneWindow.png
+doc/source/modules/gui/widgets/flowlayout.rst
+doc/source/modules/gui/widgets/framebrowser.rst
+doc/source/modules/gui/widgets/index.rst
+doc/source/modules/gui/widgets/periodictable.rst
+doc/source/modules/gui/widgets/printpreview.rst
+doc/source/modules/gui/widgets/rangeslider.rst
+doc/source/modules/gui/widgets/tablewidget.rst
+doc/source/modules/gui/widgets/threadpoolpushbutton.rst
+doc/source/modules/gui/widgets/waitingpushbutton.rst
+doc/source/modules/gui/widgets/img/FrameBrowser.png
+doc/source/modules/gui/widgets/img/HorizontalSliderWithBrowser.png
+doc/source/modules/gui/widgets/img/PeriodicCombo.png
+doc/source/modules/gui/widgets/img/PeriodicList.png
+doc/source/modules/gui/widgets/img/PeriodicTable.png
+doc/source/modules/gui/widgets/img/RangeSlider.png
+doc/source/modules/gui/widgets/img/TableWidget.png
+doc/source/modules/gui/widgets/img/ThreadPoolPushButton.png
+doc/source/modules/gui/widgets/img/WaitingPushButton.png
+doc/source/modules/image/backprojection.rst
+doc/source/modules/image/bilinear.rst
+doc/source/modules/image/index.rst
+doc/source/modules/image/marchingsquares.rst
+doc/source/modules/image/medianfilter.rst
+doc/source/modules/image/projection.rst
+doc/source/modules/image/reconstruction.rst
+doc/source/modules/image/shapes.rst
+doc/source/modules/image/sift.rst
+doc/source/modules/io/commonh5.rst
+doc/source/modules/io/configdict.rst
+doc/source/modules/io/convert.rst
+doc/source/modules/io/dictdump.rst
+doc/source/modules/io/fioh5.rst
+doc/source/modules/io/h5py_utils.rst
+doc/source/modules/io/index.rst
+doc/source/modules/io/nxdata.rst
+doc/source/modules/io/octaveh5.rst
+doc/source/modules/io/specfile.rst
+doc/source/modules/io/specfilewrapper.rst
+doc/source/modules/io/spech5.rst
+doc/source/modules/io/url.rst
+doc/source/modules/io/utils.rst
+doc/source/modules/math/colormap.rst
+doc/source/modules/math/combo.rst
+doc/source/modules/math/histogram.rst
+doc/source/modules/math/index.rst
+doc/source/modules/math/medianfilter.rst
+doc/source/modules/math/fit/bgtheories.rst
+doc/source/modules/math/fit/filters.rst
+doc/source/modules/math/fit/fitmanager.rst
+doc/source/modules/math/fit/fittheories.rst
+doc/source/modules/math/fit/fittheory.rst
+doc/source/modules/math/fit/functions.rst
+doc/source/modules/math/fit/index.rst
+doc/source/modules/math/fit/leastsq.rst
+doc/source/modules/math/fit/peaksearch.rst
+doc/source/modules/opencl/codec_cbf.rst
+doc/source/modules/opencl/convolution.rst
+doc/source/modules/opencl/fbp.rst
+doc/source/modules/opencl/index.rst
+doc/source/modules/opencl/medfilt.rst
+doc/source/modules/opencl/processing.rst
+doc/source/modules/opencl/sinofilter.rst
+doc/source/modules/opencl/statistics.rst
+doc/source/modules/opencl/sift/align.rst
+doc/source/modules/opencl/sift/index.rst
+doc/source/modules/opencl/sift/match.rst
+doc/source/modules/opencl/sift/plan.rst
+doc/source/modules/test/index.rst
+doc/source/modules/utils/array_like.rst
+doc/source/modules/utils/decorators.rst
+doc/source/modules/utils/html.rst
+doc/source/modules/utils/index.rst
+doc/source/modules/utils/retry.rst
+doc/source/modules/utils/testutils.rst
+doc/source/modules/utils/weakref.rst
+doc/source/sample_code/index.rst
+doc/source/sample_code/img/animatedicons.png
+doc/source/sample_code/img/colormapDialog.png
+doc/source/sample_code/img/compareImages.png
+doc/source/sample_code/img/compositeline.png
+doc/source/sample_code/img/customDataView.png
+doc/source/sample_code/img/customHdf5TreeModel.png
+doc/source/sample_code/img/customSilxView.png
+doc/source/sample_code/img/dropZones.png
+doc/source/sample_code/img/exampleBaseline.png
+doc/source/sample_code/img/fftPlotAction.png
+doc/source/sample_code/img/fileDialog.png
+doc/source/sample_code/img/findContours.png
+doc/source/sample_code/img/hdf5widget.png
+doc/source/sample_code/img/icons.png
+doc/source/sample_code/img/imageStack.png
+doc/source/sample_code/img/imageview.png
+doc/source/sample_code/img/periodicTable.png
+doc/source/sample_code/img/plot3dContextMenu.png
+doc/source/sample_code/img/plot3dSceneWindow.png
+doc/source/sample_code/img/plot3dUpdateScatterFromThread.png
+doc/source/sample_code/img/plotClearAction.png
+doc/source/sample_code/img/plotContextMenu.png
+doc/source/sample_code/img/plotCurveLegendWidget.png
+doc/source/sample_code/img/plotInteractiveImageROI.png
+doc/source/sample_code/img/plotItemsSelector.png
+doc/source/sample_code/img/plotLimits.png
+doc/source/sample_code/img/plotProfile.png
+doc/source/sample_code/img/plotROIStats.png
+doc/source/sample_code/img/plotStats.png
+doc/source/sample_code/img/plotUpdateCurveFromThread.png
+doc/source/sample_code/img/plotUpdateImageFromGevent.png
+doc/source/sample_code/img/plotUpdateImageFromThread.png
+doc/source/sample_code/img/plotWidget.png
+doc/source/sample_code/img/printPreview.png
+doc/source/sample_code/img/scatterMask.png
+doc/source/sample_code/img/scatterview.png
+doc/source/sample_code/img/shiftPlotAction.png
+doc/source/sample_code/img/simplewidget.png
+doc/source/sample_code/img/stackView.png
+doc/source/sample_code/img/syncPlotLocation.png
+doc/source/sample_code/img/syncaxis.png
+doc/source/sample_code/img/viewer3DVolume.png
+examples/__init__.py
+examples/colormapDialog.py
+examples/compareImages.py
+examples/compositeline.py
+examples/customDataView.py
+examples/customHdf5TreeModel.py
+examples/customSilxView.py
+examples/dropZones.py
+examples/exampleBaseline.py
+examples/fft.png
+examples/fftPlotAction.py
+examples/fileDialog.py
+examples/findContours.py
+examples/hdf5widget.py
+examples/icons.py
+examples/imageStack.py
+examples/imageview.py
+examples/periodicTable.py
+examples/plot3dContextMenu.py
+examples/plot3dSceneWindow.py
+examples/plot3dUpdateScatterFromThread.py
+examples/plotClearAction.py
+examples/plotContextMenu.py
+examples/plotCurveLegendWidget.py
+examples/plotInteractiveImageROI.py
+examples/plotItemsSelector.py
+examples/plotLimits.py
+examples/plotProfile.py
+examples/plotROIStats.py
+examples/plotStats.py
+examples/plotUpdateCurveFromThread.py
+examples/plotUpdateImageFromGevent.py
+examples/plotUpdateImageFromThread.py
+examples/plotWidget.py
+examples/printPreview.py
+examples/scatterMask.py
+examples/scatterview.py
+examples/shiftPlotAction.py
+examples/simplewidget.py
+examples/stackView.py
+examples/syncPlotLocation.py
+examples/syncaxis.py
+examples/viewer3DVolume.py
+examples/writetoh5.py
+package/debian10/changelog
+package/debian10/compat
+package/debian10/control
+package/debian10/gbp.conf
+package/debian10/py3dist-overrides
+package/debian10/python-silx-doc.doc-base
+package/debian10/rules
+package/debian10/watch
+package/debian10/patches/0002-use-the-system-mathjax-privacy-breach.patch
+package/debian10/patches/0003-do-not-modify-PYTHONPATH-from-setup.py.patch
+package/debian10/patches/series
+package/debian10/source/format
+package/debian10/source/options
+package/debian10/tests/control
+package/debian11/changelog
+package/debian11/control
+package/debian11/gbp.conf
+package/debian11/py3dist-overrides
+package/debian11/python-silx-doc.doc-base
+package/debian11/rules
+package/debian11/watch
+package/debian11/patches/0002-use-the-system-mathjax-privacy-breach.patch
+package/debian11/patches/0003-do-not-modify-PYTHONPATH-from-setup.py.patch
+package/debian11/patches/series
+package/debian11/source/format
+package/debian11/source/options
+package/debian11/tests/control
+package/desktop/org.silx.SilxView.desktop
+package/desktop/silx.png
+package/desktop/silx.svg
+package/desktop/silx.xml
+package/windows/README.rst
+package/windows/bootstrap-silx-view.py
+package/windows/bootstrap.py
+package/windows/create-installer.iss.template
+package/windows/pyinstaller.spec
+package/windows/silx.ico
+qtdesigner_plugins/README.rst
+qtdesigner_plugins/plot1dplugin.py
+qtdesigner_plugins/plot2dplugin.py
+qtdesigner_plugins/plotwidgetplugin.py
+qtdesigner_plugins/plotwindowplugin.py
+src/silx/__init__.py
+src/silx/__main__.py
+src/silx/_config.py
+src/silx/_version.py
+src/silx/conftest.py
+src/silx.egg-info/PKG-INFO
+src/silx.egg-info/SOURCES.txt
+src/silx.egg-info/dependency_links.txt
+src/silx.egg-info/entry_points.txt
+src/silx.egg-info/not-zip-safe
+src/silx.egg-info/requires.txt
+src/silx.egg-info/top_level.txt
+src/silx/app/__init__.py
+src/silx/app/convert.py
+src/silx/app/test_.py
+src/silx/app/test/__init__.py
+src/silx/app/test/test_convert.py
+src/silx/app/view/About.py
+src/silx/app/view/ApplicationContext.py
+src/silx/app/view/CustomNxdataWidget.py
+src/silx/app/view/DataPanel.py
+src/silx/app/view/Viewer.py
+src/silx/app/view/__init__.py
+src/silx/app/view/main.py
+src/silx/app/view/utils.py
+src/silx/app/view/test/__init__.py
+src/silx/app/view/test/test_launcher.py
+src/silx/app/view/test/test_view.py
+src/silx/gui/__init__.py
+src/silx/gui/colors.py
+src/silx/gui/conftest.py
+src/silx/gui/console.py
+src/silx/gui/icons.py
+src/silx/gui/printer.py
+src/silx/gui/_glutils/Context.py
+src/silx/gui/_glutils/FramebufferTexture.py
+src/silx/gui/_glutils/OpenGLWidget.py
+src/silx/gui/_glutils/Program.py
+src/silx/gui/_glutils/Texture.py
+src/silx/gui/_glutils/VertexBuffer.py
+src/silx/gui/_glutils/__init__.py
+src/silx/gui/_glutils/font.py
+src/silx/gui/_glutils/gl.py
+src/silx/gui/_glutils/utils.py
+src/silx/gui/data/ArrayTableModel.py
+src/silx/gui/data/ArrayTableWidget.py
+src/silx/gui/data/DataViewer.py
+src/silx/gui/data/DataViewerFrame.py
+src/silx/gui/data/DataViewerSelector.py
+src/silx/gui/data/DataViews.py
+src/silx/gui/data/Hdf5TableView.py
+src/silx/gui/data/HexaTableView.py
+src/silx/gui/data/NXdataWidgets.py
+src/silx/gui/data/NumpyAxesSelector.py
+src/silx/gui/data/RecordTableView.py
+src/silx/gui/data/TextFormatter.py
+src/silx/gui/data/_RecordPlot.py
+src/silx/gui/data/_VolumeWindow.py
+src/silx/gui/data/__init__.py
+src/silx/gui/data/test/__init__.py
+src/silx/gui/data/test/test_arraywidget.py
+src/silx/gui/data/test/test_dataviewer.py
+src/silx/gui/data/test/test_numpyaxesselector.py
+src/silx/gui/data/test/test_textformatter.py
+src/silx/gui/dialog/AbstractDataFileDialog.py
+src/silx/gui/dialog/ColormapDialog.py
+src/silx/gui/dialog/DataFileDialog.py
+src/silx/gui/dialog/DatasetDialog.py
+src/silx/gui/dialog/FileTypeComboBox.py
+src/silx/gui/dialog/GroupDialog.py
+src/silx/gui/dialog/ImageFileDialog.py
+src/silx/gui/dialog/SafeFileIconProvider.py
+src/silx/gui/dialog/SafeFileSystemModel.py
+src/silx/gui/dialog/__init__.py
+src/silx/gui/dialog/utils.py
+src/silx/gui/dialog/test/__init__.py
+src/silx/gui/dialog/test/test_colormapdialog.py
+src/silx/gui/dialog/test/test_datafiledialog.py
+src/silx/gui/dialog/test/test_imagefiledialog.py
+src/silx/gui/fit/BackgroundWidget.py
+src/silx/gui/fit/FitConfig.py
+src/silx/gui/fit/FitWidget.py
+src/silx/gui/fit/FitWidgets.py
+src/silx/gui/fit/Parameters.py
+src/silx/gui/fit/__init__.py
+src/silx/gui/fit/test/__init__.py
+src/silx/gui/fit/test/testBackgroundWidget.py
+src/silx/gui/fit/test/testFitConfig.py
+src/silx/gui/fit/test/testFitWidget.py
+src/silx/gui/hdf5/Hdf5Formatter.py
+src/silx/gui/hdf5/Hdf5HeaderView.py
+src/silx/gui/hdf5/Hdf5Item.py
+src/silx/gui/hdf5/Hdf5LoadingItem.py
+src/silx/gui/hdf5/Hdf5Node.py
+src/silx/gui/hdf5/Hdf5TreeModel.py
+src/silx/gui/hdf5/Hdf5TreeView.py
+src/silx/gui/hdf5/NexusSortFilterProxyModel.py
+src/silx/gui/hdf5/__init__.py
+src/silx/gui/hdf5/_utils.py
+src/silx/gui/hdf5/test/__init__.py
+src/silx/gui/hdf5/test/test_hdf5.py
+src/silx/gui/plot/AlphaSlider.py
+src/silx/gui/plot/ColorBar.py
+src/silx/gui/plot/Colormap.py
+src/silx/gui/plot/ColormapDialog.py
+src/silx/gui/plot/Colors.py
+src/silx/gui/plot/CompareImages.py
+src/silx/gui/plot/ComplexImageView.py
+src/silx/gui/plot/CurvesROIWidget.py
+src/silx/gui/plot/ImageStack.py
+src/silx/gui/plot/ImageView.py
+src/silx/gui/plot/Interaction.py
+src/silx/gui/plot/ItemsSelectionDialog.py
+src/silx/gui/plot/LegendSelector.py
+src/silx/gui/plot/LimitsHistory.py
+src/silx/gui/plot/MaskToolsWidget.py
+src/silx/gui/plot/PlotActions.py
+src/silx/gui/plot/PlotEvents.py
+src/silx/gui/plot/PlotInteraction.py
+src/silx/gui/plot/PlotToolButtons.py
+src/silx/gui/plot/PlotTools.py
+src/silx/gui/plot/PlotWidget.py
+src/silx/gui/plot/PlotWindow.py
+src/silx/gui/plot/PrintPreviewToolButton.py
+src/silx/gui/plot/Profile.py
+src/silx/gui/plot/ProfileMainWindow.py
+src/silx/gui/plot/ROIStatsWidget.py
+src/silx/gui/plot/ScatterMaskToolsWidget.py
+src/silx/gui/plot/ScatterView.py
+src/silx/gui/plot/StackView.py
+src/silx/gui/plot/StatsWidget.py
+src/silx/gui/plot/_BaseMaskToolsWidget.py
+src/silx/gui/plot/__init__.py
+src/silx/gui/plot/_utils/__init__.py
+src/silx/gui/plot/_utils/delaunay.py
+src/silx/gui/plot/_utils/dtime_ticklayout.py
+src/silx/gui/plot/_utils/panzoom.py
+src/silx/gui/plot/_utils/ticklayout.py
+src/silx/gui/plot/_utils/test/__init__.py
+src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py
+src/silx/gui/plot/_utils/test/test_ticklayout.py
+src/silx/gui/plot/actions/PlotAction.py
+src/silx/gui/plot/actions/PlotToolAction.py
+src/silx/gui/plot/actions/__init__.py
+src/silx/gui/plot/actions/control.py
+src/silx/gui/plot/actions/fit.py
+src/silx/gui/plot/actions/histogram.py
+src/silx/gui/plot/actions/io.py
+src/silx/gui/plot/actions/medfilt.py
+src/silx/gui/plot/actions/mode.py
+src/silx/gui/plot/backends/BackendBase.py
+src/silx/gui/plot/backends/BackendMatplotlib.py
+src/silx/gui/plot/backends/BackendOpenGL.py
+src/silx/gui/plot/backends/__init__.py
+src/silx/gui/plot/backends/glutils/GLPlotCurve.py
+src/silx/gui/plot/backends/glutils/GLPlotFrame.py
+src/silx/gui/plot/backends/glutils/GLPlotImage.py
+src/silx/gui/plot/backends/glutils/GLPlotItem.py
+src/silx/gui/plot/backends/glutils/GLPlotTriangles.py
+src/silx/gui/plot/backends/glutils/GLSupport.py
+src/silx/gui/plot/backends/glutils/GLText.py
+src/silx/gui/plot/backends/glutils/GLTexture.py
+src/silx/gui/plot/backends/glutils/PlotImageFile.py
+src/silx/gui/plot/backends/glutils/__init__.py
+src/silx/gui/plot/items/__init__.py
+src/silx/gui/plot/items/_arc_roi.py
+src/silx/gui/plot/items/_band_roi.py
+src/silx/gui/plot/items/_pick.py
+src/silx/gui/plot/items/_roi_base.py
+src/silx/gui/plot/items/axis.py
+src/silx/gui/plot/items/complex.py
+src/silx/gui/plot/items/core.py
+src/silx/gui/plot/items/curve.py
+src/silx/gui/plot/items/histogram.py
+src/silx/gui/plot/items/image.py
+src/silx/gui/plot/items/image_aggregated.py
+src/silx/gui/plot/items/marker.py
+src/silx/gui/plot/items/roi.py
+src/silx/gui/plot/items/scatter.py
+src/silx/gui/plot/items/shape.py
+src/silx/gui/plot/matplotlib/Colormap.py
+src/silx/gui/plot/matplotlib/__init__.py
+src/silx/gui/plot/stats/__init__.py
+src/silx/gui/plot/stats/stats.py
+src/silx/gui/plot/stats/statshandler.py
+src/silx/gui/plot/test/__init__.py
+src/silx/gui/plot/test/testAlphaSlider.py
+src/silx/gui/plot/test/testColorBar.py
+src/silx/gui/plot/test/testCompareImages.py
+src/silx/gui/plot/test/testComplexImageView.py
+src/silx/gui/plot/test/testCurvesROIWidget.py
+src/silx/gui/plot/test/testImageStack.py
+src/silx/gui/plot/test/testImageView.py
+src/silx/gui/plot/test/testInteraction.py
+src/silx/gui/plot/test/testItem.py
+src/silx/gui/plot/test/testLegendSelector.py
+src/silx/gui/plot/test/testLimitConstraints.py
+src/silx/gui/plot/test/testMaskToolsWidget.py
+src/silx/gui/plot/test/testPixelIntensityHistoAction.py
+src/silx/gui/plot/test/testPlotActions.py
+src/silx/gui/plot/test/testPlotInteraction.py
+src/silx/gui/plot/test/testPlotWidget.py
+src/silx/gui/plot/test/testPlotWidgetNoBackend.py
+src/silx/gui/plot/test/testPlotWindow.py
+src/silx/gui/plot/test/testRoiStatsWidget.py
+src/silx/gui/plot/test/testSaveAction.py
+src/silx/gui/plot/test/testScatterMaskToolsWidget.py
+src/silx/gui/plot/test/testScatterView.py
+src/silx/gui/plot/test/testStackView.py
+src/silx/gui/plot/test/testStats.py
+src/silx/gui/plot/test/testUtilsAxis.py
+src/silx/gui/plot/test/utils.py
+src/silx/gui/plot/tools/CurveLegendsWidget.py
+src/silx/gui/plot/tools/LimitsToolBar.py
+src/silx/gui/plot/tools/PositionInfo.py
+src/silx/gui/plot/tools/RadarView.py
+src/silx/gui/plot/tools/__init__.py
+src/silx/gui/plot/tools/roi.py
+src/silx/gui/plot/tools/toolbars.py
+src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py
+src/silx/gui/plot/tools/profile/__init__.py
+src/silx/gui/plot/tools/profile/core.py
+src/silx/gui/plot/tools/profile/editors.py
+src/silx/gui/plot/tools/profile/manager.py
+src/silx/gui/plot/tools/profile/rois.py
+src/silx/gui/plot/tools/profile/toolbar.py
+src/silx/gui/plot/tools/test/__init__.py
+src/silx/gui/plot/tools/test/testCurveLegendsWidget.py
+src/silx/gui/plot/tools/test/testProfile.py
+src/silx/gui/plot/tools/test/testROI.py
+src/silx/gui/plot/tools/test/testScatterProfileToolBar.py
+src/silx/gui/plot/tools/test/testTools.py
+src/silx/gui/plot/utils/__init__.py
+src/silx/gui/plot/utils/axis.py
+src/silx/gui/plot/utils/intersections.py
+src/silx/gui/plot3d/ParamTreeView.py
+src/silx/gui/plot3d/Plot3DWidget.py
+src/silx/gui/plot3d/Plot3DWindow.py
+src/silx/gui/plot3d/SFViewParamTree.py
+src/silx/gui/plot3d/ScalarFieldView.py
+src/silx/gui/plot3d/SceneWidget.py
+src/silx/gui/plot3d/SceneWindow.py
+src/silx/gui/plot3d/__init__.py
+src/silx/gui/plot3d/conftest.py
+src/silx/gui/plot3d/_model/__init__.py
+src/silx/gui/plot3d/_model/core.py
+src/silx/gui/plot3d/_model/items.py
+src/silx/gui/plot3d/_model/model.py
+src/silx/gui/plot3d/actions/Plot3DAction.py
+src/silx/gui/plot3d/actions/__init__.py
+src/silx/gui/plot3d/actions/io.py
+src/silx/gui/plot3d/actions/mode.py
+src/silx/gui/plot3d/actions/viewpoint.py
+src/silx/gui/plot3d/items/__init__.py
+src/silx/gui/plot3d/items/_pick.py
+src/silx/gui/plot3d/items/clipplane.py
+src/silx/gui/plot3d/items/core.py
+src/silx/gui/plot3d/items/image.py
+src/silx/gui/plot3d/items/mesh.py
+src/silx/gui/plot3d/items/mixins.py
+src/silx/gui/plot3d/items/scatter.py
+src/silx/gui/plot3d/items/volume.py
+src/silx/gui/plot3d/scene/__init__.py
+src/silx/gui/plot3d/scene/axes.py
+src/silx/gui/plot3d/scene/camera.py
+src/silx/gui/plot3d/scene/core.py
+src/silx/gui/plot3d/scene/cutplane.py
+src/silx/gui/plot3d/scene/event.py
+src/silx/gui/plot3d/scene/function.py
+src/silx/gui/plot3d/scene/interaction.py
+src/silx/gui/plot3d/scene/primitives.py
+src/silx/gui/plot3d/scene/text.py
+src/silx/gui/plot3d/scene/transform.py
+src/silx/gui/plot3d/scene/utils.py
+src/silx/gui/plot3d/scene/viewport.py
+src/silx/gui/plot3d/scene/window.py
+src/silx/gui/plot3d/scene/test/__init__.py
+src/silx/gui/plot3d/scene/test/test_transform.py
+src/silx/gui/plot3d/scene/test/test_utils.py
+src/silx/gui/plot3d/test/__init__.py
+src/silx/gui/plot3d/test/testGL.py
+src/silx/gui/plot3d/test/testScalarFieldView.py
+src/silx/gui/plot3d/test/testSceneWidget.py
+src/silx/gui/plot3d/test/testSceneWidgetPicking.py
+src/silx/gui/plot3d/test/testSceneWindow.py
+src/silx/gui/plot3d/test/testStatsWidget.py
+src/silx/gui/plot3d/tools/GroupPropertiesWidget.py
+src/silx/gui/plot3d/tools/PositionInfoWidget.py
+src/silx/gui/plot3d/tools/ViewpointTools.py
+src/silx/gui/plot3d/tools/__init__.py
+src/silx/gui/plot3d/tools/toolbars.py
+src/silx/gui/plot3d/tools/test/__init__.py
+src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py
+src/silx/gui/plot3d/utils/__init__.py
+src/silx/gui/plot3d/utils/mng.py
+src/silx/gui/qt/__init__.py
+src/silx/gui/qt/_pyqt6.py
+src/silx/gui/qt/_pyside_dynamic.py
+src/silx/gui/qt/_qt.py
+src/silx/gui/qt/_utils.py
+src/silx/gui/qt/inspect.py
+src/silx/gui/test/__init__.py
+src/silx/gui/test/test_colors.py
+src/silx/gui/test/test_console.py
+src/silx/gui/test/test_icons.py
+src/silx/gui/test/test_qt.py
+src/silx/gui/test/utils.py
+src/silx/gui/utils/__init__.py
+src/silx/gui/utils/concurrent.py
+src/silx/gui/utils/image.py
+src/silx/gui/utils/matplotlib.py
+src/silx/gui/utils/projecturl.py
+src/silx/gui/utils/qtutils.py
+src/silx/gui/utils/signal.py
+src/silx/gui/utils/testutils.py
+src/silx/gui/utils/glutils/__init__.py
+src/silx/gui/utils/test/__init__.py
+src/silx/gui/utils/test/test.py
+src/silx/gui/utils/test/test_async.py
+src/silx/gui/utils/test/test_glutils.py
+src/silx/gui/utils/test/test_image.py
+src/silx/gui/utils/test/test_qtutils.py
+src/silx/gui/utils/test/test_testutils.py
+src/silx/gui/widgets/BoxLayoutDockWidget.py
+src/silx/gui/widgets/ColormapNameComboBox.py
+src/silx/gui/widgets/ElidedLabel.py
+src/silx/gui/widgets/FloatEdit.py
+src/silx/gui/widgets/FlowLayout.py
+src/silx/gui/widgets/FormGridLayout.py
+src/silx/gui/widgets/FrameBrowser.py
+src/silx/gui/widgets/HierarchicalTableView.py
+src/silx/gui/widgets/LegendIconWidget.py
+src/silx/gui/widgets/MedianFilterDialog.py
+src/silx/gui/widgets/MultiModeAction.py
+src/silx/gui/widgets/PeriodicTable.py
+src/silx/gui/widgets/PrintGeometryDialog.py
+src/silx/gui/widgets/PrintPreview.py
+src/silx/gui/widgets/RangeSlider.py
+src/silx/gui/widgets/TableWidget.py
+src/silx/gui/widgets/ThreadPoolPushButton.py
+src/silx/gui/widgets/UrlSelectionTable.py
+src/silx/gui/widgets/WaitingPushButton.py
+src/silx/gui/widgets/__init__.py
+src/silx/gui/widgets/test/__init__.py
+src/silx/gui/widgets/test/test_boxlayoutdockwidget.py
+src/silx/gui/widgets/test/test_elidedlabel.py
+src/silx/gui/widgets/test/test_flowlayout.py
+src/silx/gui/widgets/test/test_framebrowser.py
+src/silx/gui/widgets/test/test_hierarchicaltableview.py
+src/silx/gui/widgets/test/test_legendiconwidget.py
+src/silx/gui/widgets/test/test_periodictable.py
+src/silx/gui/widgets/test/test_printpreview.py
+src/silx/gui/widgets/test/test_rangeslider.py
+src/silx/gui/widgets/test/test_tablewidget.py
+src/silx/gui/widgets/test/test_threadpoolpushbutton.py
+src/silx/image/__init__.py
+src/silx/image/_boundingbox.py
+src/silx/image/backprojection.py
+src/silx/image/bilinear.pyx
+src/silx/image/medianfilter.py
+src/silx/image/phantomgenerator.py
+src/silx/image/projection.py
+src/silx/image/reconstruction.py
+src/silx/image/shapes.pyx
+src/silx/image/sift.py
+src/silx/image/tomography.py
+src/silx/image/utils.py
+src/silx/image/marchingsquares/__init__.py
+src/silx/image/marchingsquares/_mergeimpl.pyx
+src/silx/image/marchingsquares/_skimage.py
+src/silx/image/marchingsquares/include/patterns.h
+src/silx/image/marchingsquares/test/__init__.py
+src/silx/image/marchingsquares/test/test_funcapi.py
+src/silx/image/marchingsquares/test/test_mergeimpl.py
+src/silx/image/test/__init__.py
+src/silx/image/test/test_bb.py
+src/silx/image/test/test_bilinear.py
+src/silx/image/test/test_medianfilter.py
+src/silx/image/test/test_shapes.py
+src/silx/image/test/test_tomography.py
+src/silx/io/__init__.py
+src/silx/io/commonh5.py
+src/silx/io/configdict.py
+src/silx/io/convert.py
+src/silx/io/dictdump.py
+src/silx/io/fabioh5.py
+src/silx/io/fioh5.py
+src/silx/io/h5py_utils.py
+src/silx/io/octaveh5.py
+src/silx/io/rawh5.py
+src/silx/io/specfile.pyx
+src/silx/io/specfile_wrapper.pxd
+src/silx/io/specfilewrapper.py
+src/silx/io/spech5.py
+src/silx/io/spectoh5.py
+src/silx/io/url.py
+src/silx/io/utils.py
+src/silx/io/nxdata/__init__.py
+src/silx/io/nxdata/_utils.py
+src/silx/io/nxdata/parse.py
+src/silx/io/nxdata/write.py
+src/silx/io/specfile/include/Lists.h
+src/silx/io/specfile/include/SpecFile.h
+src/silx/io/specfile/include/SpecFileCython.h
+src/silx/io/specfile/include/SpecFileP.h
+src/silx/io/specfile/include/locale_management.h
+src/silx/io/specfile/src/locale_management.c
+src/silx/io/specfile/src/sfdata.c
+src/silx/io/specfile/src/sfheader.c
+src/silx/io/specfile/src/sfindex.c
+src/silx/io/specfile/src/sfinit.c
+src/silx/io/specfile/src/sflabel.c
+src/silx/io/specfile/src/sflists.c
+src/silx/io/specfile/src/sfmca.c
+src/silx/io/specfile/src/sftools.c
+src/silx/io/specfile/src/sfwrite.c
+src/silx/io/test/__init__.py
+src/silx/io/test/test_commonh5.py
+src/silx/io/test/test_dictdump.py
+src/silx/io/test/test_fabioh5.py
+src/silx/io/test/test_fioh5.py
+src/silx/io/test/test_h5py_utils.py
+src/silx/io/test/test_nxdata.py
+src/silx/io/test/test_octaveh5.py
+src/silx/io/test/test_rawh5.py
+src/silx/io/test/test_specfile.py
+src/silx/io/test/test_specfilewrapper.py
+src/silx/io/test/test_spech5.py
+src/silx/io/test/test_spectoh5.py
+src/silx/io/test/test_url.py
+src/silx/io/test/test_utils.py
+src/silx/io/test/test_write_to_h5.py
+src/silx/math/__init__.py
+src/silx/math/_colormap.pyx
+src/silx/math/calibration.py
+src/silx/math/chistogramnd.pyx
+src/silx/math/chistogramnd_lut.pyx
+src/silx/math/colormap.py
+src/silx/math/combo.pyx
+src/silx/math/histogram.py
+src/silx/math/histogramnd_c.pxd
+src/silx/math/interpolate.pyx
+src/silx/math/marchingcubes.pyx
+src/silx/math/math_compatibility.pxd
+src/silx/math/mc.pxd
+src/silx/math/fft/__init__.py
+src/silx/math/fft/basefft.py
+src/silx/math/fft/clfft.py
+src/silx/math/fft/cufft.py
+src/silx/math/fft/fft.py
+src/silx/math/fft/fftw.py
+src/silx/math/fft/npfft.py
+src/silx/math/fft/test/__init__.py
+src/silx/math/fft/test/test_fft.py
+src/silx/math/fit/__init__.py
+src/silx/math/fit/bgtheories.py
+src/silx/math/fit/filters.pyx
+src/silx/math/fit/filters_wrapper.pxd
+src/silx/math/fit/fitmanager.py
+src/silx/math/fit/fittheories.py
+src/silx/math/fit/fittheory.py
+src/silx/math/fit/functions.pyx
+src/silx/math/fit/functions_wrapper.pxd
+src/silx/math/fit/leastsq.py
+src/silx/math/fit/peaks.pyx
+src/silx/math/fit/peaks_wrapper.pxd
+src/silx/math/fit/filters/include/filters.h
+src/silx/math/fit/filters/src/smoothnd.c
+src/silx/math/fit/filters/src/snip1d.c
+src/silx/math/fit/filters/src/snip2d.c
+src/silx/math/fit/filters/src/snip3d.c
+src/silx/math/fit/filters/src/strip.c
+src/silx/math/fit/functions/include/functions.h
+src/silx/math/fit/functions/src/funs.c
+src/silx/math/fit/peaks/include/peaks.h
+src/silx/math/fit/peaks/src/peaks.c
+src/silx/math/fit/test/__init__.py
+src/silx/math/fit/test/test_bgtheories.py
+src/silx/math/fit/test/test_filters.py
+src/silx/math/fit/test/test_fit.py
+src/silx/math/fit/test/test_fitmanager.py
+src/silx/math/fit/test/test_functions.py
+src/silx/math/fit/test/test_peaks.py
+src/silx/math/histogramnd/include/histogramnd_c.h
+src/silx/math/histogramnd/include/templates.h
+src/silx/math/histogramnd/include/msvc/stdint.h
+src/silx/math/histogramnd/src/histogramnd_c.c
+src/silx/math/histogramnd/src/histogramnd_template.c
+src/silx/math/include/math_compatibility.h
+src/silx/math/marchingcubes/mc.hpp
+src/silx/math/marchingcubes/mc_lut.cpp
+src/silx/math/medianfilter/__init__.py
+src/silx/math/medianfilter/median_filter.pxd
+src/silx/math/medianfilter/medianfilter.pyx
+src/silx/math/medianfilter/include/median_filter.hpp
+src/silx/math/medianfilter/test/__init__.py
+src/silx/math/medianfilter/test/benchmark.py
+src/silx/math/medianfilter/test/test_medianfilter.py
+src/silx/math/test/__init__.py
+src/silx/math/test/benchmark_combo.py
+src/silx/math/test/histo_benchmarks.py
+src/silx/math/test/test_HistogramndLut_nominal.py
+src/silx/math/test/test_calibration.py
+src/silx/math/test/test_colormap.py
+src/silx/math/test/test_combo.py
+src/silx/math/test/test_histogramnd_error.py
+src/silx/math/test/test_histogramnd_nominal.py
+src/silx/math/test/test_histogramnd_vs_np.py
+src/silx/math/test/test_interpolate.py
+src/silx/math/test/test_marchingcubes.py
+src/silx/opencl/__init__.py
+src/silx/opencl/backprojection.py
+src/silx/opencl/common.py
+src/silx/opencl/conftest.py
+src/silx/opencl/convolution.py
+src/silx/opencl/image.py
+src/silx/opencl/linalg.py
+src/silx/opencl/medfilt.py
+src/silx/opencl/processing.py
+src/silx/opencl/projection.py
+src/silx/opencl/reconstruction.py
+src/silx/opencl/sinofilter.py
+src/silx/opencl/sparse.py
+src/silx/opencl/statistics.py
+src/silx/opencl/utils.py
+src/silx/opencl/codec/__init__.py
+src/silx/opencl/codec/byte_offset.py
+src/silx/opencl/codec/test/__init__.py
+src/silx/opencl/codec/test/test_byte_offset.py
+src/silx/opencl/sift/__init__.py
+src/silx/opencl/sift/alignment.py
+src/silx/opencl/sift/match.py
+src/silx/opencl/sift/param.py
+src/silx/opencl/sift/plan.py
+src/silx/opencl/sift/sift.py
+src/silx/opencl/sift/utils.py
+src/silx/opencl/sift/test/__init__.py
+src/silx/opencl/sift/test/test_algebra.py
+src/silx/opencl/sift/test/test_align.py
+src/silx/opencl/sift/test/test_convol.py
+src/silx/opencl/sift/test/test_gaussian.py
+src/silx/opencl/sift/test/test_image.py
+src/silx/opencl/sift/test/test_image_functions.py
+src/silx/opencl/sift/test/test_image_setup.py
+src/silx/opencl/sift/test/test_keypoints.py
+src/silx/opencl/sift/test/test_matching.py
+src/silx/opencl/sift/test/test_preproc.py
+src/silx/opencl/sift/test/test_reductions.py
+src/silx/opencl/sift/test/test_transform.py
+src/silx/opencl/test/__init__.py
+src/silx/opencl/test/test_addition.py
+src/silx/opencl/test/test_array_utils.py
+src/silx/opencl/test/test_backprojection.py
+src/silx/opencl/test/test_convolution.py
+src/silx/opencl/test/test_doubleword.py
+src/silx/opencl/test/test_image.py
+src/silx/opencl/test/test_kahan.py
+src/silx/opencl/test/test_linalg.py
+src/silx/opencl/test/test_medfilt.py
+src/silx/opencl/test/test_projection.py
+src/silx/opencl/test/test_sparse.py
+src/silx/opencl/test/test_stats.py
+src/silx/resources/__init__.py
+src/silx/resources/gui/colormaps/cividis.npy
+src/silx/resources/gui/colormaps/inferno.npy
+src/silx/resources/gui/colormaps/magma.npy
+src/silx/resources/gui/colormaps/plasma.npy
+src/silx/resources/gui/colormaps/viridis.npy
+src/silx/resources/gui/icons/3d-plane-normal-x.png
+src/silx/resources/gui/icons/3d-plane-normal-x.svg
+src/silx/resources/gui/icons/3d-plane-normal-y.png
+src/silx/resources/gui/icons/3d-plane-normal-y.svg
+src/silx/resources/gui/icons/3d-plane-normal-z.png
+src/silx/resources/gui/icons/3d-plane-normal-z.svg
+src/silx/resources/gui/icons/3d-plane-pan.png
+src/silx/resources/gui/icons/3d-plane-pan.svg
+src/silx/resources/gui/icons/3d-plane.png
+src/silx/resources/gui/icons/3d-plane.svg
+src/silx/resources/gui/icons/add-range-horizontal.png
+src/silx/resources/gui/icons/add-range-horizontal.svg
+src/silx/resources/gui/icons/add-shape-arc.png
+src/silx/resources/gui/icons/add-shape-arc.svg
+src/silx/resources/gui/icons/add-shape-circle.png
+src/silx/resources/gui/icons/add-shape-circle.svg
+src/silx/resources/gui/icons/add-shape-cross.png
+src/silx/resources/gui/icons/add-shape-cross.svg
+src/silx/resources/gui/icons/add-shape-diagonal.png
+src/silx/resources/gui/icons/add-shape-diagonal.svg
+src/silx/resources/gui/icons/add-shape-ellipse.png
+src/silx/resources/gui/icons/add-shape-ellipse.svg
+src/silx/resources/gui/icons/add-shape-horizontal.png
+src/silx/resources/gui/icons/add-shape-horizontal.svg
+src/silx/resources/gui/icons/add-shape-point.png
+src/silx/resources/gui/icons/add-shape-point.svg
+src/silx/resources/gui/icons/add-shape-polygon.png
+src/silx/resources/gui/icons/add-shape-polygon.svg
+src/silx/resources/gui/icons/add-shape-rectangle.png
+src/silx/resources/gui/icons/add-shape-rectangle.svg
+src/silx/resources/gui/icons/add-shape-rotated-rectangle.png
+src/silx/resources/gui/icons/add-shape-rotated-rectangle.svg
+src/silx/resources/gui/icons/add-shape-unknown.png
+src/silx/resources/gui/icons/add-shape-unknown.svg
+src/silx/resources/gui/icons/add-shape-vertical.png
+src/silx/resources/gui/icons/add-shape-vertical.svg
+src/silx/resources/gui/icons/add.png
+src/silx/resources/gui/icons/add.svg
+src/silx/resources/gui/icons/aggregation-mode.png
+src/silx/resources/gui/icons/aggregation-mode.svg
+src/silx/resources/gui/icons/arrow-keys.png
+src/silx/resources/gui/icons/arrow-keys.svg
+src/silx/resources/gui/icons/axis.png
+src/silx/resources/gui/icons/axis.svg
+src/silx/resources/gui/icons/backend-opengl.png
+src/silx/resources/gui/icons/backend-opengl.svg
+src/silx/resources/gui/icons/camera.png
+src/silx/resources/gui/icons/camera.svg
+src/silx/resources/gui/icons/clipboard.png
+src/silx/resources/gui/icons/clipboard.svg
+src/silx/resources/gui/icons/close.png
+src/silx/resources/gui/icons/close.svg
+src/silx/resources/gui/icons/colorbar.png
+src/silx/resources/gui/icons/colorbar.svg
+src/silx/resources/gui/icons/colormap-histogram.png
+src/silx/resources/gui/icons/colormap-histogram.svg
+src/silx/resources/gui/icons/colormap-none.png
+src/silx/resources/gui/icons/colormap-none.svg
+src/silx/resources/gui/icons/colormap-norm-arcsinh.png
+src/silx/resources/gui/icons/colormap-norm-arcsinh.svg
+src/silx/resources/gui/icons/colormap-norm-gamma.png
+src/silx/resources/gui/icons/colormap-norm-gamma.svg
+src/silx/resources/gui/icons/colormap-norm-linear.png
+src/silx/resources/gui/icons/colormap-norm-linear.svg
+src/silx/resources/gui/icons/colormap-norm-log.png
+src/silx/resources/gui/icons/colormap-norm-log.svg
+src/silx/resources/gui/icons/colormap-norm-sqrt.png
+src/silx/resources/gui/icons/colormap-norm-sqrt.svg
+src/silx/resources/gui/icons/colormap-range.png
+src/silx/resources/gui/icons/colormap-range.svg
+src/silx/resources/gui/icons/colormap.png
+src/silx/resources/gui/icons/colormap.svg
+src/silx/resources/gui/icons/compare-align-auto.png
+src/silx/resources/gui/icons/compare-align-auto.svg
+src/silx/resources/gui/icons/compare-align-center.png
+src/silx/resources/gui/icons/compare-align-center.svg
+src/silx/resources/gui/icons/compare-align-origin.png
+src/silx/resources/gui/icons/compare-align-origin.svg
+src/silx/resources/gui/icons/compare-align-stretch.png
+src/silx/resources/gui/icons/compare-align-stretch.svg
+src/silx/resources/gui/icons/compare-keypoints.png
+src/silx/resources/gui/icons/compare-keypoints.svg
+src/silx/resources/gui/icons/compare-mode-a-minus-b.png
+src/silx/resources/gui/icons/compare-mode-a-minus-b.svg
+src/silx/resources/gui/icons/compare-mode-a.png
+src/silx/resources/gui/icons/compare-mode-a.svg
+src/silx/resources/gui/icons/compare-mode-b.png
+src/silx/resources/gui/icons/compare-mode-b.svg
+src/silx/resources/gui/icons/compare-mode-hline.png
+src/silx/resources/gui/icons/compare-mode-hline.svg
+src/silx/resources/gui/icons/compare-mode-rb-channel.png
+src/silx/resources/gui/icons/compare-mode-rb-channel.svg
+src/silx/resources/gui/icons/compare-mode-rbneg-channel.png
+src/silx/resources/gui/icons/compare-mode-rbneg-channel.svg
+src/silx/resources/gui/icons/compare-mode-vline.png
+src/silx/resources/gui/icons/compare-mode-vline.svg
+src/silx/resources/gui/icons/crop.png
+src/silx/resources/gui/icons/crop.svg
+src/silx/resources/gui/icons/crosshair.png
+src/silx/resources/gui/icons/crosshair.svg
+src/silx/resources/gui/icons/cube-back.png
+src/silx/resources/gui/icons/cube-back.svg
+src/silx/resources/gui/icons/cube-bottom.png
+src/silx/resources/gui/icons/cube-bottom.svg
+src/silx/resources/gui/icons/cube-front.png
+src/silx/resources/gui/icons/cube-front.svg
+src/silx/resources/gui/icons/cube-left.png
+src/silx/resources/gui/icons/cube-left.svg
+src/silx/resources/gui/icons/cube-right.png
+src/silx/resources/gui/icons/cube-right.svg
+src/silx/resources/gui/icons/cube-rotate.png
+src/silx/resources/gui/icons/cube-rotate.svg
+src/silx/resources/gui/icons/cube-top.png
+src/silx/resources/gui/icons/cube-top.svg
+src/silx/resources/gui/icons/cube.png
+src/silx/resources/gui/icons/cube.svg
+src/silx/resources/gui/icons/description-description.png
+src/silx/resources/gui/icons/description-description.svg
+src/silx/resources/gui/icons/description-error.png
+src/silx/resources/gui/icons/description-error.svg
+src/silx/resources/gui/icons/description-name.png
+src/silx/resources/gui/icons/description-name.svg
+src/silx/resources/gui/icons/description-program.png
+src/silx/resources/gui/icons/description-program.svg
+src/silx/resources/gui/icons/description-title.png
+src/silx/resources/gui/icons/description-title.svg
+src/silx/resources/gui/icons/description-value.png
+src/silx/resources/gui/icons/description-value.svg
+src/silx/resources/gui/icons/document-open.png
+src/silx/resources/gui/icons/document-open.svg
+src/silx/resources/gui/icons/document-print.png
+src/silx/resources/gui/icons/document-print.svg
+src/silx/resources/gui/icons/document-save.png
+src/silx/resources/gui/icons/document-save.svg
+src/silx/resources/gui/icons/draw-brush.png
+src/silx/resources/gui/icons/draw-brush.svg
+src/silx/resources/gui/icons/draw-pencil.png
+src/silx/resources/gui/icons/draw-pencil.svg
+src/silx/resources/gui/icons/draw-rubber.png
+src/silx/resources/gui/icons/draw-rubber.svg
+src/silx/resources/gui/icons/edit-copy.png
+src/silx/resources/gui/icons/edit-copy.svg
+src/silx/resources/gui/icons/eye.png
+src/silx/resources/gui/icons/eye.svg
+src/silx/resources/gui/icons/first.png
+src/silx/resources/gui/icons/first.svg
+src/silx/resources/gui/icons/folder.png
+src/silx/resources/gui/icons/folder.svg
+src/silx/resources/gui/icons/image-mask.png
+src/silx/resources/gui/icons/image-mask.svg
+src/silx/resources/gui/icons/image-select-add.png
+src/silx/resources/gui/icons/image-select-add.svg
+src/silx/resources/gui/icons/image-select-box.png
+src/silx/resources/gui/icons/image-select-box.svg
+src/silx/resources/gui/icons/image-select-brush.png
+src/silx/resources/gui/icons/image-select-brush.svg
+src/silx/resources/gui/icons/image-select-erase-rubber.png
+src/silx/resources/gui/icons/image-select-erase-rubber.svg
+src/silx/resources/gui/icons/image-select-erase.png
+src/silx/resources/gui/icons/image-select-erase.svg
+src/silx/resources/gui/icons/image.png
+src/silx/resources/gui/icons/image.svg
+src/silx/resources/gui/icons/item-0dim.png
+src/silx/resources/gui/icons/item-0dim.svg
+src/silx/resources/gui/icons/item-1dim.png
+src/silx/resources/gui/icons/item-1dim.svg
+src/silx/resources/gui/icons/item-2dim.png
+src/silx/resources/gui/icons/item-2dim.svg
+src/silx/resources/gui/icons/item-3dim.png
+src/silx/resources/gui/icons/item-3dim.svg
+src/silx/resources/gui/icons/item-ndim.png
+src/silx/resources/gui/icons/item-ndim.svg
+src/silx/resources/gui/icons/item-none.png
+src/silx/resources/gui/icons/item-none.svg
+src/silx/resources/gui/icons/item-object.png
+src/silx/resources/gui/icons/item-object.svg
+src/silx/resources/gui/icons/last.png
+src/silx/resources/gui/icons/last.svg
+src/silx/resources/gui/icons/layer-nx.png
+src/silx/resources/gui/icons/layer-nx.svg
+src/silx/resources/gui/icons/mask-clear-all.png
+src/silx/resources/gui/icons/mask-clear-all.svg
+src/silx/resources/gui/icons/mask-clear.png
+src/silx/resources/gui/icons/mask-clear.svg
+src/silx/resources/gui/icons/mask-invert.png
+src/silx/resources/gui/icons/mask-invert.svg
+src/silx/resources/gui/icons/math-amplitude.png
+src/silx/resources/gui/icons/math-amplitude.svg
+src/silx/resources/gui/icons/math-average.png
+src/silx/resources/gui/icons/math-average.svg
+src/silx/resources/gui/icons/math-derive.png
+src/silx/resources/gui/icons/math-derive.svg
+src/silx/resources/gui/icons/math-energy.png
+src/silx/resources/gui/icons/math-energy.svg
+src/silx/resources/gui/icons/math-fit.png
+src/silx/resources/gui/icons/math-fit.svg
+src/silx/resources/gui/icons/math-imaginary.png
+src/silx/resources/gui/icons/math-imaginary.svg
+src/silx/resources/gui/icons/math-mean.png
+src/silx/resources/gui/icons/math-mean.svg
+src/silx/resources/gui/icons/math-normalize.png
+src/silx/resources/gui/icons/math-normalize.svg
+src/silx/resources/gui/icons/math-peak-reset.png
+src/silx/resources/gui/icons/math-peak-reset.svg
+src/silx/resources/gui/icons/math-peak-search.png
+src/silx/resources/gui/icons/math-peak-search.svg
+src/silx/resources/gui/icons/math-peak.png
+src/silx/resources/gui/icons/math-peak.svg
+src/silx/resources/gui/icons/math-phase-color-log.png
+src/silx/resources/gui/icons/math-phase-color-log.svg
+src/silx/resources/gui/icons/math-phase-color.png
+src/silx/resources/gui/icons/math-phase-color.svg
+src/silx/resources/gui/icons/math-phase.png
+src/silx/resources/gui/icons/math-phase.svg
+src/silx/resources/gui/icons/math-real.png
+src/silx/resources/gui/icons/math-real.svg
+src/silx/resources/gui/icons/math-sigma.png
+src/silx/resources/gui/icons/math-sigma.svg
+src/silx/resources/gui/icons/math-smooth.png
+src/silx/resources/gui/icons/math-smooth.svg
+src/silx/resources/gui/icons/math-square-amplitude.png
+src/silx/resources/gui/icons/math-square-amplitude.svg
+src/silx/resources/gui/icons/math-substract.png
+src/silx/resources/gui/icons/math-substract.svg
+src/silx/resources/gui/icons/math-swap-sign.png
+src/silx/resources/gui/icons/math-swap-sign.svg
+src/silx/resources/gui/icons/math-ymin-to-zero.png
+src/silx/resources/gui/icons/math-ymin-to-zero.svg
+src/silx/resources/gui/icons/median-filter.png
+src/silx/resources/gui/icons/median-filter.svg
+src/silx/resources/gui/icons/next.png
+src/silx/resources/gui/icons/next.svg
+src/silx/resources/gui/icons/normal.png
+src/silx/resources/gui/icons/normal.svg
+src/silx/resources/gui/icons/nxdata-axis-add.png
+src/silx/resources/gui/icons/nxdata-axis-add.svg
+src/silx/resources/gui/icons/nxdata-axis-remove.png
+src/silx/resources/gui/icons/nxdata-axis-remove.svg
+src/silx/resources/gui/icons/nxdata-create.png
+src/silx/resources/gui/icons/nxdata-create.svg
+src/silx/resources/gui/icons/nxdata-remove.png
+src/silx/resources/gui/icons/nxdata-remove.svg
+src/silx/resources/gui/icons/pan.png
+src/silx/resources/gui/icons/pan.svg
+src/silx/resources/gui/icons/pixel-intensities.png
+src/silx/resources/gui/icons/pixel-intensities.svg
+src/silx/resources/gui/icons/plot-grid.png
+src/silx/resources/gui/icons/plot-grid.svg
+src/silx/resources/gui/icons/plot-roi-above.png
+src/silx/resources/gui/icons/plot-roi-above.svg
+src/silx/resources/gui/icons/plot-roi-below.png
+src/silx/resources/gui/icons/plot-roi-below.svg
+src/silx/resources/gui/icons/plot-roi-between.png
+src/silx/resources/gui/icons/plot-roi-between.svg
+src/silx/resources/gui/icons/plot-roi-reset.png
+src/silx/resources/gui/icons/plot-roi-reset.svg
+src/silx/resources/gui/icons/plot-roi.png
+src/silx/resources/gui/icons/plot-roi.svg
+src/silx/resources/gui/icons/plot-symbols.png
+src/silx/resources/gui/icons/plot-symbols.svg
+src/silx/resources/gui/icons/plot-toggle-points.png
+src/silx/resources/gui/icons/plot-toggle-points.svg
+src/silx/resources/gui/icons/plot-widget.png
+src/silx/resources/gui/icons/plot-widget.svg
+src/silx/resources/gui/icons/plot-window-image.png
+src/silx/resources/gui/icons/plot-window-image.svg
+src/silx/resources/gui/icons/plot-window.png
+src/silx/resources/gui/icons/plot-window.svg
+src/silx/resources/gui/icons/plot-xauto.png
+src/silx/resources/gui/icons/plot-xauto.svg
+src/silx/resources/gui/icons/plot-xlog.png
+src/silx/resources/gui/icons/plot-xlog.svg
+src/silx/resources/gui/icons/plot-yauto.png
+src/silx/resources/gui/icons/plot-yauto.svg
+src/silx/resources/gui/icons/plot-ydown.png
+src/silx/resources/gui/icons/plot-ydown.svg
+src/silx/resources/gui/icons/plot-ylog.png
+src/silx/resources/gui/icons/plot-ylog.svg
+src/silx/resources/gui/icons/plot-yup.png
+src/silx/resources/gui/icons/plot-yup.svg
+src/silx/resources/gui/icons/pointing-hand.png
+src/silx/resources/gui/icons/pointing-hand.svg
+src/silx/resources/gui/icons/previous.png
+src/silx/resources/gui/icons/previous.svg
+src/silx/resources/gui/icons/process-working.mng
+src/silx/resources/gui/icons/profile-clear.png
+src/silx/resources/gui/icons/profile-clear.svg
+src/silx/resources/gui/icons/profile1D.png
+src/silx/resources/gui/icons/profile1D.svg
+src/silx/resources/gui/icons/profile2D.png
+src/silx/resources/gui/icons/profile2D.svg
+src/silx/resources/gui/icons/remove.png
+src/silx/resources/gui/icons/remove.svg
+src/silx/resources/gui/icons/rm.png
+src/silx/resources/gui/icons/rm.svg
+src/silx/resources/gui/icons/rotate-3d.png
+src/silx/resources/gui/icons/rotate-3d.svg
+src/silx/resources/gui/icons/rudder.png
+src/silx/resources/gui/icons/rudder.svg
+src/silx/resources/gui/icons/scale-auto.png
+src/silx/resources/gui/icons/scale-auto.svg
+src/silx/resources/gui/icons/scale-fixed.png
+src/silx/resources/gui/icons/scale-fixed.svg
+src/silx/resources/gui/icons/selected.png
+src/silx/resources/gui/icons/selected.svg
+src/silx/resources/gui/icons/shape-circle-solid.png
+src/silx/resources/gui/icons/shape-circle-solid.svg
+src/silx/resources/gui/icons/shape-circle.png
+src/silx/resources/gui/icons/shape-circle.svg
+src/silx/resources/gui/icons/shape-cross.png
+src/silx/resources/gui/icons/shape-cross.svg
+src/silx/resources/gui/icons/shape-diagonal-directed.png
+src/silx/resources/gui/icons/shape-diagonal-directed.svg
+src/silx/resources/gui/icons/shape-diagonal.png
+src/silx/resources/gui/icons/shape-diagonal.svg
+src/silx/resources/gui/icons/shape-ellipse-solid.png
+src/silx/resources/gui/icons/shape-ellipse-solid.svg
+src/silx/resources/gui/icons/shape-ellipse.png
+src/silx/resources/gui/icons/shape-ellipse.svg
+src/silx/resources/gui/icons/shape-horizontal.png
+src/silx/resources/gui/icons/shape-horizontal.svg
+src/silx/resources/gui/icons/shape-polygon.png
+src/silx/resources/gui/icons/shape-polygon.svg
+src/silx/resources/gui/icons/shape-rectangle.png
+src/silx/resources/gui/icons/shape-rectangle.svg
+src/silx/resources/gui/icons/shape-square.png
+src/silx/resources/gui/icons/shape-square.svg
+src/silx/resources/gui/icons/shape-vertical.png
+src/silx/resources/gui/icons/shape-vertical.svg
+src/silx/resources/gui/icons/side-histograms.png
+src/silx/resources/gui/icons/side-histograms.svg
+src/silx/resources/gui/icons/silx.png
+src/silx/resources/gui/icons/silx.svg
+src/silx/resources/gui/icons/slice-cross.png
+src/silx/resources/gui/icons/slice-cross.svg
+src/silx/resources/gui/icons/slice-horizontal.png
+src/silx/resources/gui/icons/slice-horizontal.svg
+src/silx/resources/gui/icons/slice-vertical.png
+src/silx/resources/gui/icons/slice-vertical.svg
+src/silx/resources/gui/icons/sliders-off.png
+src/silx/resources/gui/icons/sliders-off.svg
+src/silx/resources/gui/icons/sliders-on.png
+src/silx/resources/gui/icons/sliders-on.svg
+src/silx/resources/gui/icons/spec.png
+src/silx/resources/gui/icons/spec.svg
+src/silx/resources/gui/icons/stats-active-items.png
+src/silx/resources/gui/icons/stats-active-items.svg
+src/silx/resources/gui/icons/stats-visible-data.png
+src/silx/resources/gui/icons/stats-visible-data.svg
+src/silx/resources/gui/icons/stats-whole-data.png
+src/silx/resources/gui/icons/stats-whole-data.svg
+src/silx/resources/gui/icons/stats-whole-items.png
+src/silx/resources/gui/icons/stats-whole-items.svg
+src/silx/resources/gui/icons/tree-collapse-all.png
+src/silx/resources/gui/icons/tree-collapse-all.svg
+src/silx/resources/gui/icons/tree-expand-all.png
+src/silx/resources/gui/icons/tree-expand-all.svg
+src/silx/resources/gui/icons/tree-sort.png
+src/silx/resources/gui/icons/tree-sort.svg
+src/silx/resources/gui/icons/view-1d.png
+src/silx/resources/gui/icons/view-1d.svg
+src/silx/resources/gui/icons/view-2d-stack.png
+src/silx/resources/gui/icons/view-2d-stack.svg
+src/silx/resources/gui/icons/view-2d.png
+src/silx/resources/gui/icons/view-2d.svg
+src/silx/resources/gui/icons/view-3d.png
+src/silx/resources/gui/icons/view-3d.svg
+src/silx/resources/gui/icons/view-fullscreen.png
+src/silx/resources/gui/icons/view-fullscreen.svg
+src/silx/resources/gui/icons/view-hdf5.png
+src/silx/resources/gui/icons/view-hdf5.svg
+src/silx/resources/gui/icons/view-nexus.png
+src/silx/resources/gui/icons/view-nexus.svg
+src/silx/resources/gui/icons/view-nofullscreen.png
+src/silx/resources/gui/icons/view-nofullscreen.svg
+src/silx/resources/gui/icons/view-raw.png
+src/silx/resources/gui/icons/view-raw.svg
+src/silx/resources/gui/icons/view-refresh.png
+src/silx/resources/gui/icons/view-refresh.svg
+src/silx/resources/gui/icons/view-text.png
+src/silx/resources/gui/icons/view-text.svg
+src/silx/resources/gui/icons/window-new.png
+src/silx/resources/gui/icons/window-new.svg
+src/silx/resources/gui/icons/zoom-back.png
+src/silx/resources/gui/icons/zoom-back.svg
+src/silx/resources/gui/icons/zoom-in.png
+src/silx/resources/gui/icons/zoom-in.svg
+src/silx/resources/gui/icons/zoom-original.png
+src/silx/resources/gui/icons/zoom-original.svg
+src/silx/resources/gui/icons/zoom-out.png
+src/silx/resources/gui/icons/zoom-out.svg
+src/silx/resources/gui/icons/zoom.png
+src/silx/resources/gui/icons/zoom.svg
+src/silx/resources/gui/icons/process-working/00.png
+src/silx/resources/gui/icons/process-working/01.png
+src/silx/resources/gui/icons/process-working/02.png
+src/silx/resources/gui/icons/process-working/03.png
+src/silx/resources/gui/icons/process-working/04.png
+src/silx/resources/gui/icons/process-working/05.png
+src/silx/resources/gui/icons/process-working/06.png
+src/silx/resources/gui/icons/process-working/07.png
+src/silx/resources/gui/icons/process-working/08.png
+src/silx/resources/gui/icons/process-working/09.png
+src/silx/resources/gui/icons/process-working/10.png
+src/silx/resources/gui/icons/process-working/11.png
+src/silx/resources/gui/icons/process-working/12.png
+src/silx/resources/gui/icons/process-working/13.png
+src/silx/resources/gui/icons/process-working/14.png
+src/silx/resources/gui/icons/process-working/15.png
+src/silx/resources/gui/icons/process-working/16.png
+src/silx/resources/gui/icons/process-working/17.png
+src/silx/resources/gui/icons/process-working/18.png
+src/silx/resources/gui/icons/process-working/19.png
+src/silx/resources/gui/icons/process-working/20.png
+src/silx/resources/gui/icons/process-working/21.png
+src/silx/resources/gui/icons/process-working/22.png
+src/silx/resources/gui/icons/process-working/23.png
+src/silx/resources/gui/icons/process-working/24.png
+src/silx/resources/gui/icons/process-working/25.png
+src/silx/resources/gui/icons/process-working/26.png
+src/silx/resources/gui/icons/process-working/27.png
+src/silx/resources/gui/icons/process-working/28.png
+src/silx/resources/gui/icons/process-working/29.png
+src/silx/resources/gui/icons/process-working/30.png
+src/silx/resources/gui/logo/silx.png
+src/silx/resources/gui/logo/silx.svg
+src/silx/resources/opencl/addition.cl
+src/silx/resources/opencl/array_utils.cl
+src/silx/resources/opencl/backproj.cl
+src/silx/resources/opencl/backproj_helper.cl
+src/silx/resources/opencl/bitonic.cl
+src/silx/resources/opencl/convolution.cl
+src/silx/resources/opencl/convolution_textures.cl
+src/silx/resources/opencl/doubleword.cl
+src/silx/resources/opencl/kahan.cl
+src/silx/resources/opencl/linalg.cl
+src/silx/resources/opencl/medfilt.cl
+src/silx/resources/opencl/preprocess.cl
+src/silx/resources/opencl/proj.cl
+src/silx/resources/opencl/sparse.cl
+src/silx/resources/opencl/statistics.cl
+src/silx/resources/opencl/codec/byte_offset.cl
+src/silx/resources/opencl/image/cast.cl
+src/silx/resources/opencl/image/histogram.cl
+src/silx/resources/opencl/image/map.cl
+src/silx/resources/opencl/image/max_min.cl
+src/silx/resources/opencl/sift/addition.cl
+src/silx/resources/opencl/sift/algebra.cl
+src/silx/resources/opencl/sift/convolution.cl
+src/silx/resources/opencl/sift/descriptor_cpu.cl
+src/silx/resources/opencl/sift/descriptor_gpu1.cl
+src/silx/resources/opencl/sift/descriptor_gpu2.cl
+src/silx/resources/opencl/sift/gaussian.cl
+src/silx/resources/opencl/sift/image.cl
+src/silx/resources/opencl/sift/interpolation.cl
+src/silx/resources/opencl/sift/matching_cpu.cl
+src/silx/resources/opencl/sift/matching_gpu.cl
+src/silx/resources/opencl/sift/memset.cl
+src/silx/resources/opencl/sift/orientation_cpu.cl
+src/silx/resources/opencl/sift/orientation_gpu.cl
+src/silx/resources/opencl/sift/preprocess.cl
+src/silx/resources/opencl/sift/reductions.cl
+src/silx/resources/opencl/sift/sift.cl
+src/silx/resources/opencl/sift/transform.cl
+src/silx/sx/__init__.py
+src/silx/sx/_plot.py
+src/silx/sx/_plot3d.py
+src/silx/test/__init__.py
+src/silx/test/test_resources.py
+src/silx/test/test_sx.py
+src/silx/test/test_version.py
+src/silx/test/utils.py
+src/silx/third_party/EdfFile.py
+src/silx/third_party/TiffIO.py
+src/silx/third_party/__init__.py
+src/silx/third_party/scipy_spatial.py
+src/silx/third_party/_local/__init__.py
+src/silx/third_party/_local/scipy_spatial/__init__.py
+src/silx/third_party/_local/scipy_spatial/qhull.pxd
+src/silx/third_party/_local/scipy_spatial/qhull.pyx
+src/silx/third_party/_local/scipy_spatial/qhull_misc.h
+src/silx/third_party/_local/scipy_spatial/setlist.pxd
+src/silx/third_party/_local/scipy_spatial/qhull/COPYING.txt
+src/silx/third_party/_local/scipy_spatial/qhull/src/geom2_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/geom_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/geom_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/global_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/io_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/io_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/libqhull_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/libqhull_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/mem_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/mem_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/merge_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/merge_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/poly2_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/poly_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/poly_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/qhull_ra.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/qset_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/qset_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/random_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/random_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/rboxlib_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/stat_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/stat_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/user_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/user_r.h
+src/silx/third_party/_local/scipy_spatial/qhull/src/usermem_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/userprintf_r.c
+src/silx/third_party/_local/scipy_spatial/qhull/src/userprintf_rbox_r.c
+src/silx/utils/ExternalResources.py
+src/silx/utils/__init__.py
+src/silx/utils/_have_openmp.pxd
+src/silx/utils/array_like.py
+src/silx/utils/debug.py
+src/silx/utils/deprecation.py
+src/silx/utils/enum.py
+src/silx/utils/exceptions.py
+src/silx/utils/files.py
+src/silx/utils/html.py
+src/silx/utils/launcher.py
+src/silx/utils/number.py
+src/silx/utils/property.py
+src/silx/utils/proxy.py
+src/silx/utils/retry.py
+src/silx/utils/testutils.py
+src/silx/utils/weakref.py
+src/silx/utils/include/silx_store_openmp.h
+src/silx/utils/test/__init__.py
+src/silx/utils/test/test_array_like.py
+src/silx/utils/test/test_debug.py
+src/silx/utils/test/test_deprecation.py
+src/silx/utils/test/test_enum.py
+src/silx/utils/test/test_external_resources.py
+src/silx/utils/test/test_launcher.py
+src/silx/utils/test/test_launcher_command.py
+src/silx/utils/test/test_number.py
+src/silx/utils/test/test_proxy.py
+src/silx/utils/test/test_retry.py
+src/silx/utils/test/test_testutils.py
+src/silx/utils/test/test_weakref.py \ No newline at end of file
diff --git a/src/silx.egg-info/dependency_links.txt b/src/silx.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/silx.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/silx.egg-info/entry_points.txt b/src/silx.egg-info/entry_points.txt
new file mode 100644
index 0000000..898d662
--- /dev/null
+++ b/src/silx.egg-info/entry_points.txt
@@ -0,0 +1,3 @@
+[console_scripts]
+silx = silx.__main__:main
+
diff --git a/src/silx.egg-info/not-zip-safe b/src/silx.egg-info/not-zip-safe
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/silx.egg-info/not-zip-safe
@@ -0,0 +1 @@
+
diff --git a/src/silx.egg-info/requires.txt b/src/silx.egg-info/requires.txt
new file mode 100644
index 0000000..11d2418
--- /dev/null
+++ b/src/silx.egg-info/requires.txt
@@ -0,0 +1,20 @@
+numpy>=1.12.0
+setuptools
+h5py
+fabio>=0.9
+
+[full]
+pyopencl
+Mako
+qtconsole
+matplotlib>=1.2.0
+PyOpenGL
+python-dateutil
+PyQt5
+hdf5plugin
+scipy
+Pillow
+
+[test]
+pytest
+pytest-xvfb
diff --git a/src/silx.egg-info/top_level.txt b/src/silx.egg-info/top_level.txt
new file mode 100644
index 0000000..dbcf435
--- /dev/null
+++ b/src/silx.egg-info/top_level.txt
@@ -0,0 +1 @@
+silx
diff --git a/src/silx/__init__.py b/src/silx/__init__.py
index 0ad0357..c8d6e5b 100644
--- a/src/silx/__init__.py
+++ b/src/silx/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
@@ -35,8 +34,6 @@
See silx documentation: http://www.silx.org/doc/silx/latest/
"""
-from __future__ import absolute_import, print_function, division
-
__authors__ = ["Jérôme Kieffer"]
__license__ = "MIT"
__date__ = "26/04/2018"
diff --git a/src/silx/__main__.py b/src/silx/__main__.py
index f832a09..0f8727c 100644
--- a/src/silx/__main__.py
+++ b/src/silx/__main__.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/_config.py b/src/silx/_config.py
index fb0e409..5d7b445 100644
--- a/src/silx/_config.py
+++ b/src/silx/_config.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/_version.py b/src/silx/_version.py
index feb2639..511e823 100644
--- a/src/silx/_version.py
+++ b/src/silx/_version.py
@@ -1,8 +1,7 @@
#!/usr/bin/env python3
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -49,7 +48,6 @@ Thus 2.1.0a3 is hexversion 0x020100a3.
"""
-from __future__ import absolute_import, print_function, division
__authors__ = ["Jérôme Kieffer"]
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
@@ -71,7 +69,7 @@ PRERELEASE_NORMALIZED_NAME = {"dev": "a",
"candidate": "rc"}
MAJOR = 1
-MINOR = 0
+MINOR = 1
MICRO = 0
RELEV = "final" # <16
SERIAL = 0 # <16
diff --git a/src/silx/app/__init__.py b/src/silx/app/__init__.py
index 3af680c..4c0bc00 100644
--- a/src/silx/app/__init__.py
+++ b/src/silx/app/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/app/convert.py b/src/silx/app/convert.py
index 43baf7e..78c1ebf 100644
--- a/src/silx/app/convert.py
+++ b/src/silx/app/convert.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/setup.py b/src/silx/app/setup.py
deleted file mode 100644
index 85c3662..0000000
--- a/src/silx/app/setup.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "23/04/2018"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('app', parent_package, top_path)
- config.add_subpackage('test')
- config.add_subpackage('view')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/app/test/__init__.py b/src/silx/app/test/__init__.py
index 7790ee5..1d8207b 100644
--- a/src/silx/app/test/__init__.py
+++ b/src/silx/app/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/app/test/test_convert.py b/src/silx/app/test/test_convert.py
index 2148db5..f3ca269 100644
--- a/src/silx/app/test/test_convert.py
+++ b/src/silx/app/test/test_convert.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/app/test_.py b/src/silx/app/test_.py
index 2b6bdf8..9696eb2 100644
--- a/src/silx/app/test_.py
+++ b/src/silx/app/test_.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/view/About.py b/src/silx/app/view/About.py
index 85f1450..2af7ed4 100644
--- a/src/silx/app/view/About.py
+++ b/src/silx/app/view/About.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +24,7 @@
__authors__ = ["V. Valls"]
__license__ = "MIT"
-__date__ = "05/07/2018"
+__date__ = "18/01/2022"
import os
import sys
@@ -233,7 +232,7 @@ class About(qt.QDialog):
hardLimit = min(screenSize.width() - 480, 1000)
if screenSize.width() <= 1024:
hardLimit = screenSize.width()
- softLimit = min(screenSize.width() / 2, 420)
+ softLimit = min(screenSize.width() // 2, 420)
layoutMinimumSize = self.layout().totalMinimumSize()
width = layoutMinimumSize.width()
diff --git a/src/silx/app/view/ApplicationContext.py b/src/silx/app/view/ApplicationContext.py
index 324f3b8..30dad7d 100644
--- a/src/silx/app/view/ApplicationContext.py
+++ b/src/silx/app/view/ApplicationContext.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/view/CustomNxdataWidget.py b/src/silx/app/view/CustomNxdataWidget.py
index 8c6cd39..3c79c0d 100644
--- a/src/silx/app/view/CustomNxdataWidget.py
+++ b/src/silx/app/view/CustomNxdataWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/view/DataPanel.py b/src/silx/app/view/DataPanel.py
index 5d87381..d4a0e63 100644
--- a/src/silx/app/view/DataPanel.py
+++ b/src/silx/app/view/DataPanel.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/view/Viewer.py b/src/silx/app/view/Viewer.py
index 7e5e4c9..d9ecf6a 100644
--- a/src/silx/app/view/Viewer.py
+++ b/src/silx/app/view/Viewer.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +31,7 @@ import os
import collections
import logging
import functools
+from typing import Optional
import silx.io.nxdata
from silx.gui import qt
@@ -169,7 +169,7 @@ class Viewer(qt.QMainWindow):
# Another shortcut for refresh
action = qt.QAction(toolbar)
- action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_R))
+ action.setShortcut(qt.QKeySequence(qt.Qt.CTRL | qt.Qt.Key_R))
treeView.addAction(action)
action.triggered.connect(self.__refreshSelected)
@@ -189,7 +189,7 @@ class Viewer(qt.QMainWindow):
action.setText("Expand all")
action.setToolTip("Expand all selected items")
action.triggered.connect(self.__expandAllSelected)
- action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_Plus))
+ action.setShortcut(qt.QKeySequence(qt.Qt.CTRL | qt.Qt.Key_Plus))
toolbar.addAction(action)
treeView.addAction(action)
self.__expandAllAction = action
@@ -199,7 +199,7 @@ class Viewer(qt.QMainWindow):
action.setText("Collapse all")
action.setToolTip("Collapse all selected items")
action.triggered.connect(self.__collapseAllSelected)
- action.setShortcut(qt.QKeySequence(qt.Qt.ControlModifier + qt.Qt.Key_Minus))
+ action.setShortcut(qt.QKeySequence(qt.Qt.CTRL | qt.Qt.Key_Minus))
toolbar.addAction(action)
treeView.addAction(action)
self.__collapseAllAction = action
@@ -262,12 +262,11 @@ class Viewer(qt.QMainWindow):
indexes = selection.selectedIndexes()
selectedItems = []
model = self.__treeview.model()
- h5files = set([])
+ h5files = []
while len(indexes) > 0:
index = indexes.pop(0)
if index.column() != 0:
continue
- h5 = model.data(index, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
rootIndex = index
# Reach the root of the tree
while rootIndex.parent().isValid():
@@ -275,15 +274,17 @@ class Viewer(qt.QMainWindow):
rootRow = rootIndex.row()
relativePath = self.__getRelativePath(model, rootIndex, index)
selectedItems.append((rootRow, relativePath))
- h5files.add(h5.file)
+ h5 = model.data(rootIndex, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_OBJECT_ROLE)
+ item = model.data(rootIndex, role=silx.gui.hdf5.Hdf5TreeModel.H5PY_ITEM_ROLE)
+ h5files.append((h5, item._openedPath))
if len(h5files) == 0:
qt.QApplication.restoreOverrideCursor()
return
model = self.__treeview.findHdf5TreeModel()
- for h5 in h5files:
- self.__synchronizeH5pyObject(h5)
+ for h5, filename in h5files:
+ self.__synchronizeH5pyObject(h5, filename)
model = self.__treeview.model()
itemSelection = qt.QItemSelection()
@@ -298,14 +299,15 @@ class Viewer(qt.QMainWindow):
qt.QApplication.restoreOverrideCursor()
- def __synchronizeH5pyObject(self, h5):
+ def __synchronizeH5pyObject(self, h5, filename: Optional[str] = None):
model = self.__treeview.findHdf5TreeModel()
# This is buggy right now while h5py do not allow to close a file
# while references are still used.
# FIXME: The architecture have to be reworked to support this feature.
# model.synchronizeH5pyObject(h5)
- filename = h5.filename
+ if filename is None:
+ filename = f"{h5.file.filename}::{h5.name}"
row = model.h5pyObjectRow(h5)
index = self.__treeview.model().index(row, 0, qt.QModelIndex())
paths = self.__getPathFromExpandedNodes(self.__treeview, index)
diff --git a/src/silx/app/view/__init__.py b/src/silx/app/view/__init__.py
index 229c44e..97c64ef 100644
--- a/src/silx/app/view/__init__.py
+++ b/src/silx/app/view/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/app/view/main.py b/src/silx/app/view/main.py
index dbc6a2b..c37b8aa 100644
--- a/src/silx/app/view/main.py
+++ b/src/silx/app/view/main.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,10 +27,12 @@ __license__ = "MIT"
__date__ = "17/01/2019"
import argparse
+import glob
import logging
import os
import signal
import sys
+from typing import Generator, Iterable
_logger = logging.getLogger(__name__)
@@ -71,6 +72,40 @@ def createParser():
return parser
+def filesArgToUrls(filenames: Iterable[str]) -> Generator[object, None, None]:
+ """Expand filenames and HDF5 data path in files input argument"""
+ # Imports here so they are performed after setting HDF5_USE_FILE_LOCKING and logging level
+ import silx.io
+ from silx.io.utils import match
+ from silx.io.url import DataUrl
+ import silx.utils.files
+
+ for filename in filenames:
+ url = DataUrl(filename)
+
+ for file_path in sorted(silx.utils.files.expand_filenames([url.file_path()])):
+ if url.data_path() is not None and glob.has_magic(url.data_path()):
+ try:
+ with silx.io.open(file_path) as f:
+ data_paths = list(match(f, url.data_path()))
+ except BaseException as e:
+ _logger.error(
+ f"Error searching HDF5 path pattern '{url.data_path()}' in file '{file_path}': Ignored")
+ _logger.error(e.args[0])
+ _logger.debug("Backtrace", exc_info=True)
+ continue
+ else:
+ data_paths = [url.data_path()]
+
+ for data_path in data_paths:
+ yield DataUrl(
+ file_path=file_path,
+ data_path=data_path,
+ data_slice=url.data_slice(),
+ scheme=url.scheme(),
+ )
+
+
def createWindow(parent, settings):
from .Viewer import Viewer
window = Viewer(parent=None, settings=settings)
@@ -115,7 +150,6 @@ def mainQt(options):
import h5py
import silx
- import silx.utils.files
from silx.gui import qt
# Make sure matplotlib is configured
# Needed for Debian 8: compatibility between Qt4/Qt5 and old matplotlib
@@ -152,13 +186,11 @@ def mainQt(options):
# It have to be done after the settings (after the Viewer creation)
silx.config.DEFAULT_PLOT_BACKEND = "opengl"
- # NOTE: under Windows, cmd does not convert `*.tif` into existing files
- options.files = silx.utils.files.expand_filenames(options.files)
- for filename in options.files:
+ for url in filesArgToUrls(options.files):
# TODO: Would be nice to add a process widget and a cancel button
try:
- window.appendFile(filename)
+ window.appendFile(url.path())
except IOError as e:
_logger.error(e.args[0])
_logger.debug("Backtrace", exc_info=True)
diff --git a/src/silx/app/view/setup.py b/src/silx/app/view/setup.py
deleted file mode 100644
index fa076cb..0000000
--- a/src/silx/app/view/setup.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "06/06/2018"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('view', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/app/view/test/__init__.py b/src/silx/app/view/test/__init__.py
index 7790ee5..1d8207b 100644
--- a/src/silx/app/view/test/__init__.py
+++ b/src/silx/app/view/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/app/view/test/test_launcher.py b/src/silx/app/view/test/test_launcher.py
index 4f7aaa5..8ccf4af 100644
--- a/src/silx/app/view/test/test_launcher.py
+++ b/src/silx/app/view/test/test_launcher.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/app/view/test/test_view.py b/src/silx/app/view/test/test_view.py
index e236e42..362995a 100644
--- a/src/silx/app/view/test/test_view.py
+++ b/src/silx/app/view/test/test_view.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/app/view/utils.py b/src/silx/app/view/utils.py
index 80167c8..6a980e9 100644
--- a/src/silx/app/view/utils.py
+++ b/src/silx/app/view/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/conftest.py b/src/silx/conftest.py
index 53b3edc..bec67c0 100644
--- a/src/silx/conftest.py
+++ b/src/silx/conftest.py
@@ -18,13 +18,16 @@ def _set_qt_binding(binding):
elif binding == "pyside6":
logger.info("Force using PySide6")
import PySide6.QtCore # noqa
+ elif binding == "pyqt6":
+ logger.info("Force using PyQt6")
+ import PyQt6.QtCore # noqa
else:
raise ValueError("Qt binding '%s' is unknown" % binding)
def pytest_addoption(parser):
parser.addoption("--qt-binding", type=str, default=None, dest="qt_binding",
- help="Force using a Qt binding: 'PyQt5', 'PySide2', 'PySide6'")
+ help="Force using a Qt binding: 'PyQt5', 'PySide2', 'PySide6', 'PyQt6'")
parser.addoption("--no-gui", dest="gui", default=True,
action="store_false",
help="Disable the test of the graphical use interface")
diff --git a/src/silx/gui/__init__.py b/src/silx/gui/__init__.py
index b796e20..31bb38e 100644
--- a/src/silx/gui/__init__.py
+++ b/src/silx/gui/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/Context.py b/src/silx/gui/_glutils/Context.py
index c62dbb9..d2ddaa3 100644
--- a/src/silx/gui/_glutils/Context.py
+++ b/src/silx/gui/_glutils/Context.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/FramebufferTexture.py b/src/silx/gui/_glutils/FramebufferTexture.py
index d12a6e0..75db264 100644
--- a/src/silx/gui/_glutils/FramebufferTexture.py
+++ b/src/silx/gui/_glutils/FramebufferTexture.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/OpenGLWidget.py b/src/silx/gui/_glutils/OpenGLWidget.py
index 2ca4649..d35bb73 100644
--- a/src/silx/gui/_glutils/OpenGLWidget.py
+++ b/src/silx/gui/_glutils/OpenGLWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -45,7 +44,7 @@ _logger = logging.getLogger(__name__)
if not hasattr(qt, 'QOpenGLWidget') and not hasattr(qt, 'QGLWidget'):
- OpenGLWidget = None
+ _OpenGLWidget = None
else:
if hasattr(qt, 'QOpenGLWidget'): # PyQt>=5.4
@@ -70,7 +69,7 @@ else:
depthBufferSize=24,
stencilBufferSize=8,
version=(2, 0),
- f=qt.Qt.WindowFlags()):
+ f=qt.Qt.Widget):
# True if using QGLWidget, False if using QOpenGLWidget
self.__legacy = not hasattr(qt, 'QOpenGLWidget')
@@ -262,7 +261,7 @@ class OpenGLWidget(qt.QWidget):
depthBufferSize=24,
stencilBufferSize=8,
version=(2, 0),
- f=qt.Qt.WindowFlags()):
+ f=qt.Qt.Widget):
super(OpenGLWidget, self).__init__(parent, f)
layout = qt.QHBoxLayout(self)
diff --git a/src/silx/gui/_glutils/Program.py b/src/silx/gui/_glutils/Program.py
index 87eec5f..d61c07d 100644
--- a/src/silx/gui/_glutils/Program.py
+++ b/src/silx/gui/_glutils/Program.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/Texture.py b/src/silx/gui/_glutils/Texture.py
index c72135a..76bdcd8 100644
--- a/src/silx/gui/_glutils/Texture.py
+++ b/src/silx/gui/_glutils/Texture.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/VertexBuffer.py b/src/silx/gui/_glutils/VertexBuffer.py
index b74b748..65fff86 100644
--- a/src/silx/gui/_glutils/VertexBuffer.py
+++ b/src/silx/gui/_glutils/VertexBuffer.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/__init__.py b/src/silx/gui/_glutils/__init__.py
index e88affd..a7a4bee 100644
--- a/src/silx/gui/_glutils/__init__.py
+++ b/src/silx/gui/_glutils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/_glutils/font.py b/src/silx/gui/_glutils/font.py
index 3ea474d..bee9745 100644
--- a/src/silx/gui/_glutils/font.py
+++ b/src/silx/gui/_glutils/font.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,8 +31,13 @@ __date__ = "13/10/2016"
import logging
import numpy
-from ..utils.image import convertQImageToArray
from .. import qt
+from ..utils.image import convertQImageToArray
+
+try:
+ from ..utils.matplotlib import rasterMathText
+except ImportError:
+ rasterMathText = None
_logger = logging.getLogger(__name__)
@@ -66,11 +70,7 @@ ULTRA_BLACK = 99
"""Thickest characters: Maximum font weight"""
-def rasterText(text, font,
- size=-1,
- weight=-1,
- italic=False,
- devicePixelRatio=1.0):
+def rasterTextQt(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0):
"""Raster text using Qt.
It supports multiple lines.
@@ -95,7 +95,7 @@ def rasterText(text, font,
"""
if not text:
_logger.info("Trying to raster empty text, replaced by white space")
- text = ' ' # Replace empty text by white space to produce an image
+ text = " " # Replace empty text by white space to produce an image
if not isinstance(font, qt.QFont):
font = qt.QFont(font, size, weight, italic)
@@ -107,7 +107,8 @@ def rasterText(text, font,
painter.setPen(qt.Qt.white)
painter.setFont(font)
bounds = painter.boundingRect(
- qt.QRect(0, 0, 4096, 4096), qt.Qt.TextExpandTabs, text)
+ qt.QRect(0, 0, 4096, 4096), qt.Qt.TextExpandTabs, text
+ )
painter.end()
metrics = qt.QFontMetrics(font)
@@ -123,9 +124,9 @@ def rasterText(text, font,
width = bounds.width() * devicePixelRatio + 2
# align line size to 32 bits to ease conversion to numpy array
width = 4 * ((width + 3) // 4)
- image = qt.QImage(int(width),
- int(bounds.height() * devicePixelRatio + 2),
- qt.QImage.Format_RGB888)
+ image = qt.QImage(
+ int(width), int(bounds.height() * devicePixelRatio + 2), qt.QImage.Format_RGB888
+ )
image.setDevicePixelRatio(devicePixelRatio)
# TODO if Qt5 use Format_Grayscale8 instead
@@ -144,13 +145,45 @@ def rasterText(text, font,
# RGB to R
array = numpy.ascontiguousarray(array[:, :, 0])
- # Remove leading and trailing empty columns but one on each side
- column_cumsum = numpy.cumsum(numpy.sum(array, axis=0))
- array = array[:, column_cumsum.argmin():column_cumsum.argmax() + 2]
+ # Remove leading and trailing empty columns/rows but one on each side
+ filled_rows = numpy.nonzero(numpy.sum(array, axis=1))[0]
+ filled_columns = numpy.nonzero(numpy.sum(array, axis=0))[0]
+ if len(filled_rows) == 0 or len(filled_columns) == 0:
+ return array, metrics.ascent()
- # Remove leading and trailing empty rows but one on each side
- row_cumsum = numpy.cumsum(numpy.sum(array, axis=1))
- min_row = row_cumsum.argmin()
- array = array[min_row:row_cumsum.argmax() + 2, :]
+ min_row = max(0, filled_rows[0] - 1)
+ array = array[
+ min_row : filled_rows[-1] + 2,
+ max(0, filled_columns[0] - 1) : filled_columns[-1] + 2,
+ ]
return array, metrics.ascent() - min_row
+
+
+def rasterText(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0):
+ """Raster text using Qt or matplotlib if there may be math syntax.
+
+ It supports multiple lines.
+
+ :param str text: The text to raster
+ :param font: Font name or QFont to use
+ :type font: str or :class:`QFont`
+ :param int size:
+ Font size in points
+ Used only if font is given as name.
+ :param int weight:
+ Font weight in [0, 99], see QFont.Weight.
+ Used only if font is given as name.
+ :param bool italic:
+ True for italic font (default: False).
+ Used only if font is given as name.
+ :param float devicePixelRatio:
+ The current ratio between device and device-independent pixel
+ (default: 1.0)
+ :return: Corresponding image in gray scale and baseline offset from top
+ :rtype: (HxW numpy.ndarray of uint8, int)
+ """
+ if rasterMathText is not None and text.count("$") >= 2:
+ return rasterMathText(text, font, size, weight, italic, devicePixelRatio)
+ else:
+ return rasterTextQt(text, font, size, weight, italic, devicePixelRatio)
diff --git a/src/silx/gui/_glutils/gl.py b/src/silx/gui/_glutils/gl.py
index 608d9ce..d33cf49 100644
--- a/src/silx/gui/_glutils/gl.py
+++ b/src/silx/gui/_glutils/gl.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2017 European Synchrotron Radiation Facility
@@ -64,7 +63,7 @@ except NameError:
GLchar = c_char
-def testGL():
+def testGL() -> bool:
"""Test if required OpenGL version and extensions are available.
This MUST be run with an active OpenGL context.
@@ -72,18 +71,20 @@ def testGL():
version = glGetString(GL_VERSION).split()[0] # get version number
major, minor = int(version[0]), int(version[2])
if major < 2 or (major == 2 and minor < 1):
- raise RuntimeError(
- "Requires at least OpenGL version 2.1, running with %s" % version)
+ _logger.error("OpenGL version >=2.1 required, running with %s" % version)
+ return False
from OpenGL.GL.ARB.framebuffer_object import glInitFramebufferObjectARB
from OpenGL.GL.ARB.texture_rg import glInitTextureRgARB
if not glInitFramebufferObjectARB():
- raise RuntimeError(
- "OpenGL GL_ARB_framebuffer_object extension required !")
+ _logger.error("OpenGL GL_ARB_framebuffer_object extension required!")
+ return False
if not glInitTextureRgARB():
- raise RuntimeError("OpenGL GL_ARB_texture_rg extension required !")
+ _logger.error("OpenGL GL_ARB_texture_rg extension required!")
+ return False
+ return True
# Additional setup
diff --git a/src/silx/gui/_glutils/utils.py b/src/silx/gui/_glutils/utils.py
index 5886599..49b431a 100644
--- a/src/silx/gui/_glutils/utils.py
+++ b/src/silx/gui/_glutils/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/colors.py b/src/silx/gui/colors.py
index 12046cf..4a5f278 100755
--- a/src/silx/gui/colors.py
+++ b/src/silx/gui/colors.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides API to manage colors.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent", "H.Payno"]
__license__ = "MIT"
__date__ = "29/01/2019"
diff --git a/src/silx/gui/console.py b/src/silx/gui/console.py
index 953b6a1..c66d44a 100644
--- a/src/silx/gui/console.py
+++ b/src/silx/gui/console.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -182,13 +181,6 @@ class IPythonDockWidget(qt.QDockWidget):
if available_vars is not None:
self.ipyconsole.pushVariables(available_vars)
- def showEvent(self, event):
- """Make sure this widget is raised when it is shown
- (when it is first created as a tab in PlotWindow or when it is shown
- again after hiding).
- """
- self.raise_()
-
def main():
"""Run a Qt app with an IPython console"""
diff --git a/src/silx/gui/data/ArrayTableModel.py b/src/silx/gui/data/ArrayTableModel.py
index 23b0bb2..00cc235 100644
--- a/src/silx/gui/data/ArrayTableModel.py
+++ b/src/silx/gui/data/ArrayTableModel.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +25,6 @@
This module defines a data model for displaying and editing arrays of any
number of dimensions in a table view.
"""
-from __future__ import division
import numpy
import logging
from silx.gui import qt
@@ -34,7 +32,7 @@ from silx.gui.data.TextFormatter import TextFormatter
__authors__ = ["V.A. Sole"]
__license__ = "MIT"
-__date__ = "27/09/2017"
+__date__ = "18/01/2022"
_logger = logging.getLogger(__name__)
@@ -75,7 +73,7 @@ class ArrayTableModel(qt.QAbstractTableModel):
of :meth:`setPerspective`.
"""
- MAX_NUMBER_OF_SECTIONS = 10e6
+ MAX_NUMBER_OF_SECTIONS = 10000000
"""Maximum number of displayed rows and columns"""
def __init__(self, parent=None, data=None, perspective=None):
@@ -235,7 +233,7 @@ class ArrayTableModel(qt.QAbstractTableModel):
selection = self._getIndexTuple(row, column)
- if role == qt.Qt.DisplayRole:
+ if role == qt.Qt.DisplayRole or role == qt.Qt.EditRole:
return self._formatter.toString(self._array[selection], self._array.dtype)
if role == qt.Qt.BackgroundRole and self._bgcolors is not None:
diff --git a/src/silx/gui/data/ArrayTableWidget.py b/src/silx/gui/data/ArrayTableWidget.py
index baef5f4..2f7762d 100644
--- a/src/silx/gui/data/ArrayTableWidget.py
+++ b/src/silx/gui/data/ArrayTableWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -30,7 +29,6 @@ sliders.
The widget uses a TableView that relies on a custom abstract item
model: :class:`silx.gui.data.ArrayTableModel`.
"""
-from __future__ import division
import sys
from silx.gui import qt
diff --git a/src/silx/gui/data/DataViewer.py b/src/silx/gui/data/DataViewer.py
index 2e51439..2c93c65 100644
--- a/src/silx/gui/data/DataViewer.py
+++ b/src/silx/gui/data/DataViewer.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +24,6 @@
"""This module defines a widget designed to display data using the most adapted
view from the ones provided by silx.
"""
-from __future__ import division
import logging
import os.path
@@ -83,6 +81,14 @@ class DataViewer(qt.QFrame):
dataChanged = qt.Signal()
"""Emitted when the data changes"""
+ selectionChanged = qt.Signal(object, object)
+ """Emitted when the data selection changes.
+
+ It provides:
+ - the slicing as a tuple of slice or None.
+ - the permutation as a tuple of int or None.
+ """
+
currentAvailableViewsChanged = qt.Signal()
"""Emitted when the current available views (which support the current
data) change"""
@@ -118,6 +124,7 @@ class DataViewer(qt.QFrame):
self.__useAxisSelection = False
self.__userSelectedView = None
self.__hooks = None
+ self.__previousSelection = DataSelection(None, None, None, None)
self.__views = []
self.__index = {}
@@ -279,6 +286,13 @@ class DataViewer(qt.QFrame):
def __setDataInView(self):
self.__currentView.setData(self.__displayedData)
self.__currentView.setDataSelection(self.__displayedSelection)
+ # Emit signal only when selection has changed
+ if (self.__previousSelection.slice != self.__displayedSelection.slice or
+ self.__previousSelection.permutation != self.__displayedSelection.permutation
+ ):
+ self.selectionChanged.emit(
+ self.__displayedSelection.slice, self.__displayedSelection.permutation)
+ self.__previousSelection = self.__displayedSelection
def setDisplayedView(self, view):
"""Set the displayed view.
diff --git a/src/silx/gui/data/DataViewerFrame.py b/src/silx/gui/data/DataViewerFrame.py
index 9bfb95b..912ca1c 100644
--- a/src/silx/gui/data/DataViewerFrame.py
+++ b/src/silx/gui/data/DataViewerFrame.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +59,14 @@ class DataViewerFrame(qt.QWidget):
dataChanged = qt.Signal()
"""Emitted when the data changes"""
+ selectionChanged = qt.Signal(object, object)
+ """Emitted when the data selection changes.
+
+ It provides:
+ - the slicing as a tuple of slice or None.
+ - the permutation as a tuple of int or None.
+ """
+
def __init__(self, parent=None):
"""
Constructor
@@ -104,6 +111,7 @@ class DataViewerFrame(qt.QWidget):
self.__dataViewer.dataChanged.connect(self.__dataChanged)
self.__dataViewer.displayedViewChanged.connect(self.__displayedViewChanged)
+ self.__dataViewer.selectionChanged.connect(self.__selectionChanged)
def __dataChanged(self):
"""Called when the data is changed"""
@@ -113,6 +121,10 @@ class DataViewerFrame(qt.QWidget):
"""Called when the displayed view changes"""
self.displayedViewChanged.emit(view)
+ def __selectionChanged(self, slices, permutation):
+ """Called when the data selection has changed"""
+ self.selectionChanged.emit(slices, permutation)
+
def setGlobalHooks(self, hooks):
"""Set a data view hooks for all the views
diff --git a/src/silx/gui/data/DataViewerSelector.py b/src/silx/gui/data/DataViewerSelector.py
index a1e9947..d67908e 100644
--- a/src/silx/gui/data/DataViewerSelector.py
+++ b/src/silx/gui/data/DataViewerSelector.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
@@ -25,7 +24,6 @@
"""This module defines a widget to be able to select the available view
of the DataViewer.
"""
-from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py
index b18a813..0a4569f 100644
--- a/src/silx/gui/data/DataViews.py
+++ b/src/silx/gui/data/DataViews.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -876,7 +875,9 @@ class _Plot1dView(DataView):
def createWidget(self, parent):
from silx.gui import plot
- return plot.Plot1D(parent=parent)
+ widget = plot.Plot1D(parent=parent)
+ widget.setGraphGrid(True)
+ return widget
def clear(self):
self.getWidget().clear()
@@ -1759,6 +1760,8 @@ class _NXdataImageView(_NXdataBaseDataView):
y_axis, x_axis = nxd.axes[img_slicing]
y_label, x_label = nxd.axes_names[img_slicing]
y_scale, x_scale = nxd.plot_style.axes_scale_types[img_slicing]
+ x_units = get_attr_as_unicode(x_axis, 'units') if x_axis else None
+ y_units = get_attr_as_unicode(y_axis, 'units') if y_axis else None
self.getWidget().setImageData(
[nxd.signal] + nxd.auxiliary_signals,
@@ -1766,7 +1769,9 @@ class _NXdataImageView(_NXdataBaseDataView):
signals_names=[nxd.signal_name] + nxd.auxiliary_signals_names,
xlabel=x_label, ylabel=y_label,
title=nxd.title, isRgba=isRgba,
- xscale=x_scale, yscale=y_scale)
+ xscale=x_scale, yscale=y_scale,
+ keep_ratio=(x_units == y_units),
+ )
def getDataPriority(self, data, info):
data = self.normalizeData(data)
@@ -1804,13 +1809,17 @@ class _NXdataComplexImageView(_NXdataBaseDataView):
img_slicing = slice(-2, None)
y_axis, x_axis = nxd.axes[img_slicing]
y_label, x_label = nxd.axes_names[img_slicing]
+ x_units = get_attr_as_unicode(x_axis, 'units') if x_axis else None
+ y_units = get_attr_as_unicode(y_axis, 'units') if y_axis else None
self.getWidget().setImageData(
[nxd.signal] + nxd.auxiliary_signals,
x_axis=x_axis, y_axis=y_axis,
signals_names=[nxd.signal_name] + nxd.auxiliary_signals_names,
xlabel=x_label, ylabel=y_label,
- title=nxd.title)
+ title=nxd.title,
+ keep_ratio=(x_units == y_units),
+ )
def axesNames(self, data, info):
# disabled (used by default axis selector widget in Hdf5Viewer)
diff --git a/src/silx/gui/data/Hdf5TableView.py b/src/silx/gui/data/Hdf5TableView.py
index 9d65a84..f3fbb69 100644
--- a/src/silx/gui/data/Hdf5TableView.py
+++ b/src/silx/gui/data/Hdf5TableView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -26,7 +25,6 @@
This module define model and widget to display 1D slices from numpy
array using compound data types or hdf5 databases.
"""
-from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
@@ -450,8 +448,9 @@ class Hdf5TableModel(HierarchicalTableView.HierarchicalTableModel):
return firstExtSource
if firstExtSource[0] == ".":
- firstExtSource.pop(0)
- return os.path.join(os.path.dirname(filename), firstExtSource)
+ return filename + firstExtSource[1:]
+ else:
+ return os.path.join(os.path.dirname(filename), firstExtSource)
self.__data.addHeaderRow(headerLabel="External sources")
self.__data.addHeaderValueRow("Type", extType)
diff --git a/src/silx/gui/data/HexaTableView.py b/src/silx/gui/data/HexaTableView.py
index 9e00a7b..30f62f0 100644
--- a/src/silx/gui/data/HexaTableView.py
+++ b/src/silx/gui/data/HexaTableView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -26,7 +25,6 @@
This module defines model and widget to display raw data using an
hexadecimal viewer.
"""
-from __future__ import division
import collections
diff --git a/src/silx/gui/data/NXdataWidgets.py b/src/silx/gui/data/NXdataWidgets.py
index 54ea287..b9e34d2 100644
--- a/src/silx/gui/data/NXdataWidgets.py
+++ b/src/silx/gui/data/NXdataWidgets.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -76,6 +75,7 @@ class ArrayCurvePlot(qt.QWidget):
self.__values = None
self._plot = Plot1D(self)
+ self._plot.setGraphGrid(True)
self._selector = NumpyAxesSelector(self)
self._selector.setNamedAxesSelectorVisibility(False)
@@ -412,7 +412,8 @@ class ArrayImagePlot(qt.QWidget):
signals_names=None,
xlabel=None, ylabel=None,
title=None, isRgba=False,
- xscale=None, yscale=None):
+ xscale=None, yscale=None,
+ keep_ratio: bool=True):
"""
:param signals: list of n-D datasets, whose last 2 dimensions are used as the
@@ -430,6 +431,7 @@ class ArrayImagePlot(qt.QWidget):
:param isRgba: True if data is a 3D RGBA image
:param str xscale: Scale of X axis in (None, 'linear', 'log')
:param str yscale: Scale of Y axis in (None, 'linear', 'log')
+ :param keep_ratio: Toggle plot keep aspect ratio
"""
self._selector.selectionChanged.disconnect(self._updateImage)
self._auxSigSlider.valueChanged.disconnect(self._sliderIdxChanged)
@@ -465,6 +467,7 @@ class ArrayImagePlot(qt.QWidget):
self._axis_scales = xscale, yscale
self._updateImage()
+ self._plot.setKeepDataAspectRatio(keep_ratio)
self._plot.resetZoom()
self._selector.selectionChanged.connect(self._updateImage)
@@ -629,7 +632,8 @@ class ArrayComplexImagePlot(qt.QWidget):
x_axis=None, y_axis=None,
signals_names=None,
xlabel=None, ylabel=None,
- title=None):
+ title=None,
+ keep_ratio: bool=True):
"""
:param signals: list of n-D datasets, whose last 2 dimensions are used as the
@@ -644,6 +648,7 @@ class ArrayComplexImagePlot(qt.QWidget):
:param xlabel: Label for X axis
:param ylabel: Label for Y axis
:param title: Graph title
+ :param keep_ratio: Toggle plot keep aspect ratio
"""
self._selector.selectionChanged.disconnect(self._updateImage)
self._auxSigSlider.valueChanged.disconnect(self._sliderIdxChanged)
@@ -673,6 +678,7 @@ class ArrayComplexImagePlot(qt.QWidget):
self._auxSigSlider.setValue(0)
self._updateImage()
+ self._plot.setKeepDataAspectRatio(keep_ratio)
self._plot.getPlot().resetZoom()
self._selector.selectionChanged.connect(self._updateImage)
diff --git a/src/silx/gui/data/NumpyAxesSelector.py b/src/silx/gui/data/NumpyAxesSelector.py
index e6da0d4..50b8dcd 100644
--- a/src/silx/gui/data/NumpyAxesSelector.py
+++ b/src/silx/gui/data/NumpyAxesSelector.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
@@ -25,7 +24,6 @@
"""This module defines a widget able to convert a numpy array from n-dimensions
to a numpy array with less dimensions.
"""
-from __future__ import division
__authors__ = ["V. Valls"]
__license__ = "MIT"
diff --git a/src/silx/gui/data/RecordTableView.py b/src/silx/gui/data/RecordTableView.py
index ea73c62..9079ba6 100644
--- a/src/silx/gui/data/RecordTableView.py
+++ b/src/silx/gui/data/RecordTableView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -26,7 +25,6 @@
This module define model and widget to display 1D slices from numpy
array using compound data types or hdf5 databases.
"""
-from __future__ import division
import itertools
import numpy
diff --git a/src/silx/gui/data/TextFormatter.py b/src/silx/gui/data/TextFormatter.py
index b6baca4..d409381 100644
--- a/src/silx/gui/data/TextFormatter.py
+++ b/src/silx/gui/data/TextFormatter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/_VolumeWindow.py b/src/silx/gui/data/_VolumeWindow.py
index 03b6876..fa2730c 100644
--- a/src/silx/gui/data/_VolumeWindow.py
+++ b/src/silx/gui/data/_VolumeWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/__init__.py b/src/silx/gui/data/__init__.py
index 560062d..59d32f1 100644
--- a/src/silx/gui/data/__init__.py
+++ b/src/silx/gui/data/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/setup.py b/src/silx/gui/data/setup.py
deleted file mode 100644
index 23ccbdd..0000000
--- a/src/silx/gui/data/setup.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["P. Knobel"]
-__license__ = "MIT"
-__date__ = "16/01/2017"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('data', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/gui/data/test/__init__.py b/src/silx/gui/data/test/__init__.py
index 7790ee5..1d8207b 100644
--- a/src/silx/gui/data/test/__init__.py
+++ b/src/silx/gui/data/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/test/test_arraywidget.py b/src/silx/gui/data/test/test_arraywidget.py
index c84a34f..024383d 100644
--- a/src/silx/gui/data/test/test_arraywidget.py
+++ b/src/silx/gui/data/test/test_arraywidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/test/test_dataviewer.py b/src/silx/gui/data/test/test_dataviewer.py
index 30b76ce..80f47b7 100644
--- a/src/silx/gui/data/test/test_dataviewer.py
+++ b/src/silx/gui/data/test/test_dataviewer.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -192,18 +191,36 @@ class _TestAbstractDataViewer(TestCaseQt):
listener.clear()
def test_change_display_mode(self):
+ listener = SignalListener()
data = numpy.arange(10 ** 4)
data.shape = [10] * 4
widget = self.create_widget()
+ widget.selectionChanged.connect(listener)
widget.setData(data)
+
widget.setDisplayMode(DataViews.PLOT1D_MODE)
self.assertEqual(widget.displayedView().modeId(), DataViews.PLOT1D_MODE)
+ self.qWait(200)
+ assert listener.arguments() == [((0, 0, 0, slice(None)), None)]
+ listener.clear()
+
widget.setDisplayMode(DataViews.IMAGE_MODE)
self.assertEqual(widget.displayedView().modeId(), DataViews.IMAGE_MODE)
+ self.qWait(200)
+ assert listener.arguments() == [((0, 0, slice(None), slice(None)), None)]
+ listener.clear()
+
widget.setDisplayMode(DataViews.RAW_MODE)
self.assertEqual(widget.displayedView().modeId(), DataViews.RAW_MODE)
+ self.qWait(200)
+ # Changing from 2D to 2D view: Selection didn't changed
+ assert listener.callCount() == 0
+
widget.setDisplayMode(DataViews.EMPTY_MODE)
self.assertEqual(widget.displayedView().modeId(), DataViews.EMPTY_MODE)
+ self.qWait(200)
+ assert listener.arguments() == [(None, None)]
+ listener.clear()
def test_create_default_views(self):
widget = self.create_widget()
diff --git a/src/silx/gui/data/test/test_numpyaxesselector.py b/src/silx/gui/data/test/test_numpyaxesselector.py
index 37b8d3e..4a53149 100644
--- a/src/silx/gui/data/test/test_numpyaxesselector.py
+++ b/src/silx/gui/data/test/test_numpyaxesselector.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/data/test/test_textformatter.py b/src/silx/gui/data/test/test_textformatter.py
index af41def..b82cc7a 100644
--- a/src/silx/gui/data/test/test_textformatter.py
+++ b/src/silx/gui/data/test/test_textformatter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/AbstractDataFileDialog.py b/src/silx/gui/dialog/AbstractDataFileDialog.py
index 5272f48..f656bb2 100644
--- a/src/silx/gui/dialog/AbstractDataFileDialog.py
+++ b/src/silx/gui/dialog/AbstractDataFileDialog.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,7 +34,6 @@ import sys
import os
import logging
import functools
-from distutils.version import LooseVersion
import numpy
@@ -149,13 +147,13 @@ class _SideBar(qt.QListView):
:rtype: List[str]
"""
urls = []
- version = LooseVersion(qt.qVersion())
+ version = tuple(map(int, qt.qVersion().split('.')[:3]))
feed_sidebar = True
if not DEFAULT_SIDEBAR_URL:
_logger.debug("Skip default sidebar URLs (from setted variable)")
feed_sidebar = False
- elif version < LooseVersion("5.11.2") and qt.BINDING == "PyQt5" and sys.platform in ["linux", "linux2"]:
+ elif version < (5, 11, 2) and qt.BINDING == "PyQt5" and sys.platform in ["linux", "linux2"]:
# Avoid segfault on PyQt5 + gtk
_logger.debug("Skip default sidebar URLs (avoid PyQt5 segfault)")
feed_sidebar = False
@@ -429,7 +427,7 @@ class _Browser(qt.QStackedWidget):
self.__detailView.header().restoreState(headerData)
viewMode = stream.readInt32()
- self.setViewMode(viewMode)
+ self.setViewMode(qt.QFileDialog.ViewMode(viewMode))
return True
def saveState(self):
@@ -444,7 +442,10 @@ class _Browser(qt.QStackedWidget):
stream.writeQString(nameId)
stream.writeInt32(self.__serialVersion)
stream.writeQVariant(self.__detailView.header().saveState())
- stream.writeInt32(self.viewMode())
+ viewMode = self.viewMode()
+ if qt.BINDING == 'PyQt6': # No auto conversion to int
+ viewMode = viewMode.value
+ stream.writeInt32(viewMode)
return data
@@ -1695,7 +1696,7 @@ class AbstractDataFileDialog(qt.QDialog):
if workingDirectory is not None:
self.setDirectory(workingDirectory)
result &= self.__browser.restoreState(browserData)
- self.setViewMode(viewMode)
+ self.setViewMode(qt.QFileDialog.ViewMode(viewMode))
colormap = self.colormap()
if colormap is not None:
result &= self.colormap().restoreState(colormapData)
@@ -1721,7 +1722,10 @@ class AbstractDataFileDialog(qt.QDialog):
stream.writeQStringList(strings)
stream.writeQString(u"%s" % self.directory())
stream.writeQVariant(self.__browser.saveState())
- stream.writeInt32(self.viewMode())
+ viewMode = self.viewMode()
+ if qt.BINDING == 'PyQt6': # No auto conversion to int
+ viewMode = viewMode.value
+ stream.writeInt32(viewMode)
colormap = self.colormap()
if colormap is not None:
stream.writeQVariant(self.colormap().saveState())
diff --git a/src/silx/gui/dialog/ColormapDialog.py b/src/silx/gui/dialog/ColormapDialog.py
index 2506e2a..f3f38b5 100644
--- a/src/silx/gui/dialog/ColormapDialog.py
+++ b/src/silx/gui/dialog/ColormapDialog.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -81,7 +80,7 @@ from silx.gui.plot import items
from silx.gui import icons
from silx.gui.qt import inspect as qtinspect
from silx.gui.widgets.ColormapNameComboBox import ColormapNameComboBox
-from silx.gui.widgets.WaitingPushButton import WaitingPushButton
+from silx.gui.widgets.FormGridLayout import FormGridLayout
from silx.math.histogram import Histogramnd
from silx.utils import deprecation
from silx.gui.plot.items.roi import RectangleROI
@@ -128,6 +127,20 @@ class _BoundaryWidget(qt.QWidget):
self.setLayout(qt.QHBoxLayout())
self.layout().setContentsMargins(0, 0, 0, 0)
self._numVal = FloatEdit(parent=self, value=value)
+
+ self._iconAuto = icons.getQIcon('scale-auto')
+ self._iconFixed = icons.getQIcon('scale-fixed')
+
+ self._autoToggleAction = qt.QAction(self)
+ self._autoToggleAction.setText("Auto scale")
+ self._autoToggleAction.setToolTip("Toggle auto scale")
+ self._autoToggleAction.setCheckable(True)
+ self._autoToggleAction.setIcon(self._iconFixed)
+ self._autoToggleAction.setChecked(False)
+ self._autoToggleAction.toggled.connect(self._autoToggled)
+
+ self._numVal.addAction(self._autoToggleAction, qt.QLineEdit.LeadingPosition)
+
self.layout().addWidget(self._numVal)
self._autoCB = qt.QCheckBox('auto', parent=self)
self.layout().addWidget(self._autoCB)
@@ -174,7 +187,7 @@ class _BoundaryWidget(qt.QWidget):
return self._numVal.value()
def _autoToggled(self, enabled):
- self._numVal.setEnabled(not enabled)
+ self._updateAutoScaleState(enabled)
self._updateDisplayedText()
self.sigAutoScaleChanged.emit(enabled)
@@ -198,14 +211,27 @@ class _BoundaryWidget(qt.QWidget):
if not self.__textWasEdited:
self._numVal.setValue(value)
self.__realValue = value
- self._numVal.setEnabled(not isAuto)
+ self._updateAutoScaleState(isAuto)
+
+ def _updateAutoScaleState(self, isAutoScale):
+ self._numVal.setReadOnly(isAutoScale)
+ palette = qt.QPalette()
+ if isAutoScale:
+ color = palette.color(qt.QPalette.Disabled, qt.QPalette.Base)
+ icon = self._iconAuto
+ else:
+ color = palette.color(qt.QPalette.Normal, qt.QPalette.Base)
+ icon = self._iconFixed
+ palette.setColor(qt.QPalette.Base, color)
+ self._numVal.setPalette(palette)
+ self._autoToggleAction.setIcon(icon)
class _AutoscaleModeComboBox(qt.QComboBox):
DATA = {
Colormap.MINMAX: ("Min/max", "Use the data min/max"),
- Colormap.STDDEV3: ("Mean ± 3 × stddev", "Use the data mean ± 3 × standard deviation"),
+ Colormap.STDDEV3: ("Mean±3std", "Use the data mean ± 3 × standard deviation"),
}
def __init__(self, parent: qt.QWidget):
@@ -248,80 +274,31 @@ class _AutoscaleModeComboBox(qt.QComboBox):
self.setCurrentIndex(self.count() - 1)
-class _AutoScaleButtons(qt.QWidget):
+class _AutoScaleButton(qt.QPushButton):
autoRangeChanged = qt.Signal(object)
def __init__(self, parent=None):
- qt.QWidget.__init__(self, parent=parent)
- layout = qt.QHBoxLayout(self)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
-
- self.setFocusPolicy(qt.Qt.NoFocus)
-
- self._bothAuto = qt.QPushButton(self)
- self._bothAuto.setText("Autoscale")
- self._bothAuto.setToolTip("Enable/disable the autoscale for both min and max")
- self._bothAuto.setCheckable(True)
- self._bothAuto.toggled[bool].connect(self.__bothToggled)
- self._bothAuto.setFocusPolicy(qt.Qt.TabFocus)
-
- self._minAuto = qt.QCheckBox(self)
- self._minAuto.setText("")
- self._minAuto.setToolTip("Enable/disable the autoscale for min")
- self._minAuto.toggled[bool].connect(self.__minToggled)
- self._minAuto.setFocusPolicy(qt.Qt.TabFocus)
-
- self._maxAuto = qt.QCheckBox(self)
- self._maxAuto.setText("")
- self._maxAuto.setToolTip("Enable/disable the autoscale for max")
- self._maxAuto.toggled[bool].connect(self.__maxToggled)
- self._maxAuto.setFocusPolicy(qt.Qt.TabFocus)
-
- layout.addStretch(1)
- layout.addWidget(self._minAuto)
- layout.addSpacing(20)
- layout.addWidget(self._bothAuto)
- layout.addSpacing(20)
- layout.addWidget(self._maxAuto)
- layout.addStretch(1)
-
- def __bothToggled(self, checked):
+ qt.QPushButton.__init__(self, parent=parent)
+ self.setText("Autoscale")
+ self.setToolTip("Enable/disable the autoscale for both min and max")
+ self.setCheckable(True)
+ self.toggled[bool].connect(self.__toggled)
+ self.setFocusPolicy(qt.Qt.TabFocus)
+
+ def __toggled(self, checked):
autoRange = checked, checked
self.setAutoRange(autoRange)
self.autoRangeChanged.emit(autoRange)
- def __minToggled(self, checked):
- autoRange = self.getAutoRange()
- self.setAutoRange(autoRange)
- self.autoRangeChanged.emit(autoRange)
-
- def __maxToggled(self, checked):
- autoRange = self.getAutoRange()
- self.setAutoRange(autoRange)
- self.autoRangeChanged.emit(autoRange)
-
def setAutoRangeFromColormap(self, colormap):
vRange = colormap.getVRange()
autoRange = vRange[0] is None, vRange[1] is None
self.setAutoRange(autoRange)
def setAutoRange(self, autoRange):
- if autoRange[0] == autoRange[1]:
- with utils.blockSignals(self._bothAuto):
- self._bothAuto.setChecked(autoRange[0])
- else:
- with utils.blockSignals(self._bothAuto):
- self._bothAuto.setChecked(False)
- with utils.blockSignals(self._minAuto):
- self._minAuto.setChecked(autoRange[0])
- with utils.blockSignals(self._maxAuto):
- self._maxAuto.setChecked(autoRange[1])
-
- def getAutoRange(self):
- return self._minAuto.isChecked(), self._maxAuto.isChecked()
-
+ with utils.blockSignals(self):
+ self.setChecked(autoRange[0] if autoRange[0] == autoRange[1] else False)
@enum.unique
class _DataInPlotMode(enum.Enum):
@@ -333,7 +310,7 @@ class _DataInPlotMode(enum.Enum):
class _ColormapHistogram(qt.QWidget):
"""Display the colormap and the data as a plot."""
- sigRangeMoving = qt.Signal(object, object)
+ sigRangeMoving = qt.Signal(object, object, object)
"""Emitted when a mouse interaction moves the location
of the colormap range in the plot.
@@ -341,15 +318,17 @@ class _ColormapHistogram(qt.QWidget):
- vmin: A float value if this range was moved, else None
- vmax: A float value if this range was moved, else None
+ - gammaPos: A float value if this range was moved, else None
"""
- sigRangeMoved = qt.Signal(object, object)
+ sigRangeMoved = qt.Signal(object, object, object)
"""Emitted when a mouse interaction stop.
This signal contains 2 elements:
- vmin: A float value if this range was moved, else None
- vmax: A float value if this range was moved, else None
+ - gammaPos: A float value if this range was moved, else None
"""
def __init__(self, parent):
@@ -361,7 +340,7 @@ class _ColormapHistogram(qt.QWidget):
self._histogramData = {}
"""Histogram displayed in the plot"""
- self._dragging = False, False
+ self._dragging = False, False, False
"""True, if the min or the max handle is dragging"""
self._dataRange = {}
@@ -528,7 +507,8 @@ class _ColormapHistogram(qt.QWidget):
def _initPlot(self):
"""Init the plot to display the range and the values"""
self._plot = PlotWidget(self)
- self._plot.setDataMargins(0.125, 0.125, 0.125, 0.125)
+ self._plot.setAxesDisplayed(False)
+ self._plot.setDataMargins(0.125, 0.125, 0.01, 0.01)
self._plot.getXAxis().setLabel("Data Values")
self._plot.getYAxis().setLabel("")
self._plot.setInteractiveMode('select', zoomOnWheel=False)
@@ -600,20 +580,26 @@ class _ColormapHistogram(qt.QWidget):
if kind == 'markerMoving':
value = event['xdata']
if event['label'] == 'Min':
- self._dragging = True, False
+ self._dragging = True, False, False
self._finiteRange = value, self._finiteRange[1]
- self._last = value, None
+ self._last = value, None, None
+ self._updateGammaPosition()
self.sigRangeMoving.emit(*self._last)
elif event['label'] == 'Max':
- self._dragging = False, True
+ self._dragging = False, True, False
self._finiteRange = self._finiteRange[0], value
- self._last = None, value
+ self._last = None, value, None
+ self._updateGammaPosition()
+ self.sigRangeMoving.emit(*self._last)
+ elif event['label'] == 'Gamma':
+ self._dragging = False, False, True
+ self._last = None, None, value
self.sigRangeMoving.emit(*self._last)
self._updateLutItem(self._finiteRange)
elif kind == 'markerMoved':
self.sigRangeMoved.emit(*self._last)
self._plot.resetZoom()
- self._dragging = False, False
+ self._dragging = False, False, False
else:
pass
@@ -635,11 +621,12 @@ class _ColormapHistogram(qt.QWidget):
draggable=isDraggable,
color="blue",
constraint=self._plotMinMarkerConstraint)
+ self._updateGammaPosition()
if posMax is not None and not self._dragging[1]:
self._plot.addXMarker(
posMax,
legend='Max',
- text='Max',
+ text='\n\nMax',
draggable=isDraggable,
color="blue",
constraint=self._plotMaxMarkerConstraint)
@@ -647,6 +634,42 @@ class _ColormapHistogram(qt.QWidget):
self._updateLutItem((posMin, posMax))
self._plot.resetZoom()
+ def _updateGammaPosition(self):
+ colormap = self.getColormap()
+ posMin, posMax = self._getDisplayableRange()
+
+ if colormap is None:
+ gamma = None
+ else:
+ if colormap.getNormalization() == Colormap.GAMMA:
+ gamma = colormap.getGammaNormalizationParameter()
+ else:
+ gamma = None
+
+ if gamma is not None:
+ if not self._dragging[2]:
+ posRange = posMax - posMin
+ if posRange > 0:
+ gammaPos = posMin + posRange * 0.5**(1/gamma)
+ else:
+ gammaPos = posMin
+ marker = self._plot._getMarker(
+ self._plot.addXMarker(
+ gammaPos,
+ legend='Gamma',
+ text='\nGamma',
+ draggable=True,
+ color="blue",
+ constraint=self._plotGammaMarkerConstraint,
+ )
+ )
+ marker.setZValue(2)
+ else:
+ try:
+ self._plot.removeMarker('Gamma')
+ except Exception:
+ pass
+
def _updateLutItem(self, vRange):
colormap = self.getColormap()
if colormap is None:
@@ -718,6 +741,15 @@ class _ColormapHistogram(qt.QWidget):
return x, y
return max(x, vmin), y
+ def _plotGammaMarkerConstraint(self, x, y):
+ """Constraint of the gamma marker"""
+ vmin, vmax = self.getFiniteRange()
+ if vmin is not None:
+ x = max(x, vmin)
+ if vmax is not None:
+ x = min(x, vmax)
+ return x, y
+
def _setDataInPlotMode(self, mode):
if self._dataInPlotMode == mode:
return
@@ -829,6 +861,9 @@ class ColormapDialog(qt.QDialog):
self._item = None
"""Weak ref to an external item"""
+ self._colormapped = None
+ """Weak ref to reduce data update"""
+
self._colormapChange = utils.LockReentrant()
"""Used as a semaphore to avoid editing the colormap object when we are
only attempt to display it.
@@ -873,7 +908,7 @@ class ColormapDialog(qt.QDialog):
self._gammaSpinBox = qt.QDoubleSpinBox(parent=self)
self._gammaSpinBox.setEnabled(False)
- self._gammaSpinBox.setRange(0., 1000.)
+ self._gammaSpinBox.setRange(0.01, 100.)
self._gammaSpinBox.setDecimals(4)
if hasattr(qt.QDoubleSpinBox, "setStepType"):
# Introduced in Qt 5.12
@@ -891,13 +926,15 @@ class ColormapDialog(qt.QDialog):
self._minValue = _BoundaryWidget(parent=self, value=1.0)
self._minValue.sigAutoScaleChanged.connect(self._minAutoscaleUpdated)
self._minValue.sigValueChanged.connect(self._minValueUpdated)
+ self._minValue.setMinimumWidth(140)
# Max row
self._maxValue = _BoundaryWidget(parent=self, value=10.0)
self._maxValue.sigAutoScaleChanged.connect(self._maxAutoscaleUpdated)
self._maxValue.sigValueChanged.connect(self._maxValueUpdated)
+ self._maxValue.setMinimumWidth(140)
- self._autoButtons = _AutoScaleButtons(self)
+ self._autoButtons = _AutoScaleButton(self)
self._autoButtons.autoRangeChanged.connect(self._autoRangeButtonsUpdated)
rangeLayout = qt.QGridLayout()
@@ -909,15 +946,20 @@ class ColormapDialog(qt.QDialog):
labelMax = qt.QLabel("Max", self)
labelMax.setAlignment(qt.Qt.AlignHCenter)
labelMax.setFont(miniFont)
- rangeLayout.addWidget(labelMin, 0, 0)
- rangeLayout.addWidget(labelMax, 0, 1)
- rangeLayout.addWidget(self._minValue, 1, 0)
- rangeLayout.addWidget(self._maxValue, 1, 1)
- rangeLayout.addWidget(self._autoButtons, 2, 0, 1, -1, qt.Qt.AlignCenter)
+ rangeLayout.addWidget(labelMin, 0, 1)
+ rangeLayout.addWidget(labelMax, 0, 3)
+ rangeLayout.addWidget(self._minValue, 1, 1)
+ rangeLayout.addWidget(self._maxValue, 1, 3)
+ rangeLayout.setColumnStretch(0, 1)
+ rangeLayout.setColumnStretch(1, 2)
+ rangeLayout.setColumnStretch(2, 1)
+ rangeLayout.setColumnStretch(3, 2)
+ rangeLayout.setColumnStretch(4, 1)
self._histoWidget = _ColormapHistogram(self)
self._histoWidget.sigRangeMoving.connect(self._histogramRangeMoving)
self._histoWidget.sigRangeMoved.connect(self._histogramRangeMoved)
+ self._histoWidget.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding)
# Scale to buttons
self._visibleAreaButton = qt.QPushButton(self)
@@ -930,12 +972,12 @@ class ColormapDialog(qt.QDialog):
# Place-holder for selected area ROI manager
self._roiForColormapManager = None
- self._selectedAreaButton = WaitingPushButton(self)
+ self._selectedAreaButton = qt.QPushButton(self)
+ self._selectedAreaButton.setCheckable(True)
self._selectedAreaButton.setEnabled(False)
self._selectedAreaButton.setText("Selection")
self._selectedAreaButton.setIcon(icons.getQIcon("add-shape-rectangle"))
self._selectedAreaButton.setCheckable(True)
- self._selectedAreaButton.setDisabledWhenWaiting(False)
self._selectedAreaButton.toggled.connect(
self._handleScaleToSelectionToggled,
type=qt.Qt.QueuedConnection)
@@ -966,31 +1008,38 @@ class ColormapDialog(qt.QDialog):
self.setModal(self.isModal())
- formLayout = qt.QFormLayout(self)
- formLayout.setContentsMargins(10, 10, 10, 10)
- formLayout.addRow('Colormap:', self._comboBoxColormap)
- formLayout.addRow('Normalization:', self._comboBoxNormalization)
- formLayout.addRow('Gamma:', self._gammaSpinBox)
- formLayout.addRow(self._histoWidget)
- formLayout.addRow(rangeLayout)
- label = qt.QLabel('Mode:', self)
- self._autoscaleModeLabel = label
- label.setToolTip("Mode for autoscale. Algorithm used to find range in auto scale.")
- formLayout.addItem(qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed))
- formLayout.addRow(label, autoScaleCombo)
-
layout = qt.QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self._visibleAreaButton)
layout.addWidget(self._selectedAreaButton)
- self._scaleToAreaGroup = qt.QGroupBox('Scale to:', self)
+ layout.addStretch()
+ self._scaleToAreaGroup = qt.QWidget(self)
self._scaleToAreaGroup.setLayout(layout)
self._scaleToAreaGroup.setVisible(False)
- formLayout.addRow(self._scaleToAreaGroup)
+ layoutScale = qt.QHBoxLayout()
+ layoutScale.setContentsMargins(0, 0, 0, 0)
+ layoutScale.addWidget(self._autoButtons)
+ layoutScale.addWidget(self._autoScaleCombo)
+ layoutScale.addStretch()
+
+
+ formLayout = FormGridLayout(self)
+ formLayout.setContentsMargins(10, 10, 10, 10)
+
+ formLayout.addRow('Colormap:', self._comboBoxColormap)
+ formLayout.addRow('Normalization:', self._comboBoxNormalization)
+ formLayout.addRow('Gamma:', self._gammaSpinBox)
+
+ formLayout.addItem(qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed))
+ formLayout.addRow(self._histoWidget)
+ formLayout.addRow(rangeLayout)
+ formLayout.addItem(qt.QSpacerItem(1, 1, qt.QSizePolicy.Fixed, qt.QSizePolicy.Fixed))
+ formLayout.addRow('Scale:', layoutScale)
+ formLayout.addRow("Fixed scale on:", self._scaleToAreaGroup)
formLayout.addRow(self._buttonsModal)
formLayout.addRow(self._buttonsNonModal)
- formLayout.setSizeConstraint(qt.QLayout.SetMinimumSize)
+ formLayout.setSizeConstraint(qt.QLayout.SetMinAndMaxSize)
self.setTabOrder(self._comboBoxColormap, self._comboBoxNormalization)
self.setTabOrder(self._comboBoxNormalization, self._gammaSpinBox)
@@ -1003,7 +1052,6 @@ class ColormapDialog(qt.QDialog):
self.setTabOrder(self._selectedAreaButton, self._buttonsModal)
self.setTabOrder(self._buttonsModal, self._buttonsNonModal)
- self.setFixedSize(self.sizeHint())
self._applyColormap()
def _invalidateColormap(self):
@@ -1041,10 +1089,14 @@ class ColormapDialog(qt.QDialog):
super(ColormapDialog, self).closeEvent(event)
def hideEvent(self, event):
+ if self._selectedAreaButton.isChecked():
+ self._selectedAreaButton.setChecked(False)
self.visibleChanged.emit(False)
super(ColormapDialog, self).hideEvent(event)
def close(self):
+ if self._selectedAreaButton.isChecked():
+ self._selectedAreaButton.setChecked(False)
self.accept()
qt.QDialog.close(self)
@@ -1196,10 +1248,21 @@ class ColormapDialog(qt.QDialog):
the data range or the histogram of the data using :meth:`setDataRange`
and :meth:`setHistogram`
"""
- # While event from items are not supported, we can't ignore dup items
- # old = self._getItem()
- # if old is item:
- # return
+ old = self._getItem()
+ if old is item:
+ # While event from items are not supported, we can't ignore dup items
+ if item is not None:
+ array = item.getColormappedData(copy=False)
+ else:
+ array = None
+ colormapped = self._colormapped
+ if colormapped is not None:
+ oldArray = colormapped()
+ else:
+ oldArray = None
+ if oldArray is array:
+ return
+
self._data = None
self._itemHolder = None
try:
@@ -1252,7 +1315,12 @@ class ColormapDialog(qt.QDialog):
return data
item = self._getItem()
if item is not None:
- return item.getColormappedData(copy=False)
+ colormapped = item.getColormappedData(copy=False)
+ if colormapped is not None:
+ self._colormapped = weakref.ref(colormapped)
+ else:
+ self._colormapped = None
+ return colormapped
return None
def _colormapAboutToFinalize(self, weakrefColormap):
@@ -1418,7 +1486,6 @@ class ColormapDialog(qt.QDialog):
self._histoWidget.setFiniteRange((xmin, xmax))
with utils.blockSignals(self._autoButtons):
self._autoButtons.setAutoRange((autoMin, autoMax))
- self._autoscaleModeLabel.setEnabled(autoMin or autoMax)
def accept(self):
self.storeCurrentState()
@@ -1487,7 +1554,6 @@ class ColormapDialog(qt.QDialog):
self._minValue.setEnabled(False)
self._maxValue.setEnabled(False)
self._autoButtons.setEnabled(False)
- self._autoscaleModeLabel.setEnabled(False)
self._histoWidget.setVisible(False)
self._histoWidget.setFiniteRange((None, None))
else:
@@ -1508,7 +1574,7 @@ class ColormapDialog(qt.QDialog):
self._gammaSpinBox.setValue(
colormap.getGammaNormalizationParameter())
self._gammaSpinBox.setEnabled(
- colormap.getNormalization() == 'gamma' and
+ colormap.getNormalization() == Colormap.GAMMA and
colormap.isEditable())
with utils.blockSignals(self._autoScaleCombo):
self._autoScaleCombo.setCurrentMode(colormap.getAutoscaleMode())
@@ -1530,7 +1596,6 @@ class ColormapDialog(qt.QDialog):
with utils.blockSignals(self._maxValue):
self._maxValue.setValue(vmax or dataRange[1], isAuto=vmax is None)
self._maxValue.setEnabled(colormap.isEditable())
- self._autoscaleModeLabel.setEnabled(vmin is None or vmax is None)
with utils.blockSignals(self._histoWidget):
self._histoWidget.setVisible(True)
@@ -1653,12 +1718,13 @@ class ColormapDialog(qt.QDialog):
self._maxValue.setValue(xmax)
self._setColormapRange(xmin, xmax)
- def _histogramRangeMoving(self, vmin, vmax):
+ def _histogramRangeMoving(self, vmin, vmax, gammaPos):
"""Callback executed when for colormap range displayed in
the histogram widget is moving.
:param vmin: Update of the minimum range, else None
:param vmax: Update of the maximum range, else None
+ :param gammaPos: Update of the gamma location, else None
"""
colormap = self.getColormap()
if vmin is not None:
@@ -1669,11 +1735,31 @@ class ColormapDialog(qt.QDialog):
with self._colormapChange:
colormap.setVMax(vmax)
self._maxValue.setValue(vmax)
+ if gammaPos is not None:
+ vmin, vmax = self._histoWidget.getFiniteRange()
+ if vmax < vmin:
+ gamma = 1
+ elif gammaPos >= vmax:
+ gamma = self._gammaSpinBox.maximum()
+ elif gammaPos <= vmin:
+ gamma = self._gammaSpinBox.minimum()
+ else:
+ gamma = numpy.clip(
+ numpy.log(0.5)/numpy.log((gammaPos - vmin) / (vmax - vmin)),
+ self._gammaSpinBox.minimum(),
+ self._gammaSpinBox.maximum(),
+ )
+ with self._colormapChange:
+ colormap.setGammaNormalizationParameter(gamma)
+ with utils.blockSignals(self._gammaSpinBox):
+ self._gammaSpinBox.setValue(gamma)
- def _histogramRangeMoved(self, vmin, vmax):
+ def _histogramRangeMoved(self, vmin, vmax, gammaPos):
"""Callback executed when for colormap range displayed in
the histogram widget has finished to move
"""
+ if vmin is None and vmax is None:
+ return
xmin = self._minValue.getValue()
xmax = self._maxValue.getValue()
if vmin is None:
@@ -1713,7 +1799,6 @@ class ColormapDialog(qt.QDialog):
self._roiForColormapManager = None
if not checked: # Reset button status
- self._selectedAreaButton.setWaiting(False)
self._selectedAreaButton.setText("Selection")
return
@@ -1727,7 +1812,6 @@ class ColormapDialog(qt.QDialog):
self._selectedAreaButton.setChecked(False)
return # no-op
- self._selectedAreaButton.setWaiting(True)
self._selectedAreaButton.setText("Draw Area...")
self._roiForColormapManager = RegionOfInterestManager(parent=plotWidget)
@@ -1743,11 +1827,12 @@ class ColormapDialog(qt.QDialog):
self._selectedAreaButton.setChecked(False)
def __roiFinalized(self, roi):
- self._selectedAreaButton.setChecked(False)
if roi is not None:
ox, oy = roi.getOrigin()
width, height = roi.getSize()
self.setColormapRangeFromDataBounds((ox, ox+width, oy, oy+height))
+ # clear ROI
+ self._roiForColormapManager.removeRoi(roi)
def keyPressEvent(self, event):
"""Override key handling.
diff --git a/src/silx/gui/dialog/DataFileDialog.py b/src/silx/gui/dialog/DataFileDialog.py
index 0d0382d..75b1721 100644
--- a/src/silx/gui/dialog/DataFileDialog.py
+++ b/src/silx/gui/dialog/DataFileDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/DatasetDialog.py b/src/silx/gui/dialog/DatasetDialog.py
index c5ee295..5d8af0d 100644
--- a/src/silx/gui/dialog/DatasetDialog.py
+++ b/src/silx/gui/dialog/DatasetDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/FileTypeComboBox.py b/src/silx/gui/dialog/FileTypeComboBox.py
index 92529bc..0ffc3a5 100644
--- a/src/silx/gui/dialog/FileTypeComboBox.py
+++ b/src/silx/gui/dialog/FileTypeComboBox.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/GroupDialog.py b/src/silx/gui/dialog/GroupDialog.py
index e129a51..fb85d83 100644
--- a/src/silx/gui/dialog/GroupDialog.py
+++ b/src/silx/gui/dialog/GroupDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/ImageFileDialog.py b/src/silx/gui/dialog/ImageFileDialog.py
index 83c6d95..ed455f3 100644
--- a/src/silx/gui/dialog/ImageFileDialog.py
+++ b/src/silx/gui/dialog/ImageFileDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/SafeFileIconProvider.py b/src/silx/gui/dialog/SafeFileIconProvider.py
index 1e06b64..141bedf 100644
--- a/src/silx/gui/dialog/SafeFileIconProvider.py
+++ b/src/silx/gui/dialog/SafeFileIconProvider.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/SafeFileSystemModel.py b/src/silx/gui/dialog/SafeFileSystemModel.py
index 1ec7153..b9f3913 100644
--- a/src/silx/gui/dialog/SafeFileSystemModel.py
+++ b/src/silx/gui/dialog/SafeFileSystemModel.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/__init__.py b/src/silx/gui/dialog/__init__.py
index 77c5949..c1dc89a 100644
--- a/src/silx/gui/dialog/__init__.py
+++ b/src/silx/gui/dialog/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/setup.py b/src/silx/gui/dialog/setup.py
deleted file mode 100644
index 48ab8d8..0000000
--- a/src/silx/gui/dialog/setup.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "23/10/2017"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('dialog', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/gui/dialog/test/__init__.py b/src/silx/gui/dialog/test/__init__.py
index 71128fb..b03339f 100644
--- a/src/silx/gui/dialog/test/__init__.py
+++ b/src/silx/gui/dialog/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/dialog/test/test_colormapdialog.py b/src/silx/gui/dialog/test/test_colormapdialog.py
index 16a5ab2..1bfd584 100644
--- a/src/silx/gui/dialog/test/test_colormapdialog.py
+++ b/src/silx/gui/dialog/test/test_colormapdialog.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -51,7 +50,7 @@ def colormap():
@pytest.fixture
-def colormapDialog(qapp, qapp_utils):
+def colormapDialog(qapp):
dialog = ColormapDialog.ColormapDialog()
dialog.setAttribute(qt.Qt.WA_DeleteOnClose)
yield weakref.proxy(dialog)
@@ -59,6 +58,7 @@ def colormapDialog(qapp, qapp_utils):
from silx.gui.qt import inspect
if inspect.isValid(dialog):
dialog.close()
+ del dialog
qapp.processEvents()
@@ -85,6 +85,7 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase):
modification are correctly updated if an other colormapdialog is
editing the same colormap"""
colormapDiag2 = ColormapDialog.ColormapDialog()
+ colormapDiag2.setAttribute(qt.Qt.WA_DeleteOnClose)
colormapDiag2.setColormap(self.colormap)
colormapDiag2.show()
self.colormapDiag.setColormap(self.colormap)
@@ -106,6 +107,8 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase):
self.assertTrue(int(colormapDiag2._minValue.getValue()) == 10)
self.assertTrue(int(colormapDiag2._maxValue.getValue()) == 20)
colormapDiag2.close()
+ del colormapDiag2
+ self.qapp.processEvents()
def testGUIModalOk(self):
"""Make sure the colormap is modified if gone through accept"""
@@ -214,8 +217,8 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase):
self.assertTrue(self.colormapDiag._minValue.isEnabled())
self.assertTrue(self.colormapDiag._maxValue.isEnabled())
else:
- self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled())
- self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled())
+ self.assertTrue(self.colormapDiag._minValue._numVal.isReadOnly())
+ self.assertTrue(self.colormapDiag._maxValue._numVal.isReadOnly())
def testColormapDel(self):
"""Check behavior if the colormap has been deleted outside. For now
@@ -244,13 +247,14 @@ class TestColormapDialog(TestCaseQt, ParametricTestCase):
self.colormap.setVRange(11, 201)
self.assertTrue(self.colormapDiag._minValue.getValue() == 11)
self.assertTrue(self.colormapDiag._maxValue.getValue() == 201)
- self.assertTrue(self.colormapDiag._minValue._numVal.isEnabled())
- self.assertTrue(self.colormapDiag._maxValue._numVal.isEnabled())
+ self.assertFalse(self.colormapDiag._minValue._numVal.isReadOnly())
+ self.assertFalse(self.colormapDiag._maxValue._numVal.isReadOnly())
self.assertFalse(self.colormapDiag._minValue.isAutoChecked())
self.assertFalse(self.colormapDiag._maxValue.isAutoChecked())
self.colormap.setVRange(None, None)
- self.assertFalse(self.colormapDiag._minValue._numVal.isEnabled())
- self.assertFalse(self.colormapDiag._maxValue._numVal.isEnabled())
+ self.qapp.processEvents()
+ self.assertTrue(self.colormapDiag._minValue._numVal.isReadOnly())
+ self.assertTrue(self.colormapDiag._maxValue._numVal.isReadOnly())
self.assertTrue(self.colormapDiag._minValue.isAutoChecked())
self.assertTrue(self.colormapDiag._maxValue.isAutoChecked())
diff --git a/src/silx/gui/dialog/test/test_datafiledialog.py b/src/silx/gui/dialog/test/test_datafiledialog.py
index 8411c67..32d75c2 100644
--- a/src/silx/gui/dialog/test/test_datafiledialog.py
+++ b/src/silx/gui/dialog/test/test_datafiledialog.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -89,7 +88,13 @@ def setUpModule():
def tearDownModule():
global _tmpDirectory
- shutil.rmtree(_tmpDirectory)
+ for _ in range(10):
+ try:
+ shutil.rmtree(_tmpDirectory)
+ except PermissionError: # Might fail on appveyor
+ testutils.TestCaseQt.qWait(500)
+ else:
+ break
_tmpDirectory = None
@@ -491,7 +496,7 @@ class TestDataFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin):
for i in range(model.rowCount(rootIndex)):
index = model.index(i, 0, rootIndex)
flags = model.flags(index)
- isEnabled = (int(flags) & qt.Qt.ItemIsEnabled) != 0
+ isEnabled = flags & qt.Qt.ItemIsEnabled == qt.Qt.ItemIsEnabled
if isEnabled:
selectable += 1
return selectable
diff --git a/src/silx/gui/dialog/test/test_imagefiledialog.py b/src/silx/gui/dialog/test/test_imagefiledialog.py
index 9e204b9..79c12ed 100644
--- a/src/silx/gui/dialog/test/test_imagefiledialog.py
+++ b/src/silx/gui/dialog/test/test_imagefiledialog.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -96,7 +95,13 @@ def setUpModule():
def tearDownModule():
global _tmpDirectory
- shutil.rmtree(_tmpDirectory)
+ for _ in range(10):
+ try:
+ shutil.rmtree(_tmpDirectory)
+ except PermissionError: # Might fail on appveyor
+ testutils.TestCaseQt.qWait(500)
+ else:
+ break
_tmpDirectory = None
@@ -516,7 +521,7 @@ class TestImageFileDialogInteraction(testutils.TestCaseQt, _UtilsMixin):
for i in range(model.rowCount(rootIndex)):
index = model.index(i, 0, rootIndex)
flags = model.flags(index)
- isEnabled = (int(flags) & qt.Qt.ItemIsEnabled) != 0
+ isEnabled = flags & qt.Qt.ItemIsEnabled == qt.Qt.ItemIsEnabled
if isEnabled:
selectable += 1
return selectable
diff --git a/src/silx/gui/dialog/utils.py b/src/silx/gui/dialog/utils.py
index 4c48930..e07cf9f 100644
--- a/src/silx/gui/dialog/utils.py
+++ b/src/silx/gui/dialog/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/fit/BackgroundWidget.py b/src/silx/gui/fit/BackgroundWidget.py
index 7703ee1..9ab63e4 100644
--- a/src/silx/gui/fit/BackgroundWidget.py
+++ b/src/silx/gui/fit/BackgroundWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2004-2021 V.A. Sole, European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/fit/FitConfig.py b/src/silx/gui/fit/FitConfig.py
index 48ebca2..09dbfaa 100644
--- a/src/silx/gui/fit/FitConfig.py
+++ b/src/silx/gui/fit/FitConfig.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2004-2021 V.A. Sole, European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/fit/FitWidget.py b/src/silx/gui/fit/FitWidget.py
index 52ecafe..88f95cf 100644
--- a/src/silx/gui/fit/FitWidget.py
+++ b/src/silx/gui/fit/FitWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/fit/FitWidgets.py b/src/silx/gui/fit/FitWidgets.py
index 0fcc6b7..7bcf28c 100644
--- a/src/silx/gui/fit/FitWidgets.py
+++ b/src/silx/gui/fit/FitWidgets.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2004-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/fit/Parameters.py b/src/silx/gui/fit/Parameters.py
index daa72f3..e9601a8 100644
--- a/src/silx/gui/fit/Parameters.py
+++ b/src/silx/gui/fit/Parameters.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2004-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/fit/__init__.py b/src/silx/gui/fit/__init__.py
index e4fd3ab..478ea22 100644
--- a/src/silx/gui/fit/__init__.py
+++ b/src/silx/gui/fit/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/fit/setup.py b/src/silx/gui/fit/setup.py
deleted file mode 100644
index 6672363..0000000
--- a/src/silx/gui/fit/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["P. Knobel"]
-__license__ = "MIT"
-__date__ = "21/07/2016"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('fit', parent_package, top_path)
- config.add_subpackage('test')
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/gui/fit/test/__init__.py b/src/silx/gui/fit/test/__init__.py
index 71128fb..b03339f 100644
--- a/src/silx/gui/fit/test/__init__.py
+++ b/src/silx/gui/fit/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/fit/test/testBackgroundWidget.py b/src/silx/gui/fit/test/testBackgroundWidget.py
index b8570f7..353d3d5 100644
--- a/src/silx/gui/fit/test/testBackgroundWidget.py
+++ b/src/silx/gui/fit/test/testBackgroundWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/fit/test/testFitConfig.py b/src/silx/gui/fit/test/testFitConfig.py
index 53da2dd..114ff62 100644
--- a/src/silx/gui/fit/test/testFitConfig.py
+++ b/src/silx/gui/fit/test/testFitConfig.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/fit/test/testFitWidget.py b/src/silx/gui/fit/test/testFitWidget.py
index abe9d89..fe61268 100644
--- a/src/silx/gui/fit/test/testFitWidget.py
+++ b/src/silx/gui/fit/test/testFitWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/Hdf5Formatter.py b/src/silx/gui/hdf5/Hdf5Formatter.py
index 6c3de41..4dbb0fc 100644
--- a/src/silx/gui/hdf5/Hdf5Formatter.py
+++ b/src/silx/gui/hdf5/Hdf5Formatter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/Hdf5HeaderView.py b/src/silx/gui/hdf5/Hdf5HeaderView.py
index 7255ce0..6d306e5 100644
--- a/src/silx/gui/hdf5/Hdf5HeaderView.py
+++ b/src/silx/gui/hdf5/Hdf5HeaderView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/Hdf5Item.py b/src/silx/gui/hdf5/Hdf5Item.py
index e07f835..8f20649 100755
--- a/src/silx/gui/hdf5/Hdf5Item.py
+++ b/src/silx/gui/hdf5/Hdf5Item.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
@@ -31,6 +30,7 @@ __date__ = "17/01/2019"
import logging
import collections
import enum
+from typing import Optional
from .. import qt
from .. import icons
@@ -62,10 +62,21 @@ class Hdf5Item(Hdf5Node):
tree structure.
"""
- def __init__(self, text, obj, parent, key=None, h5Class=None, linkClass=None, populateAll=False):
+ def __init__(
+ self,
+ text: Optional[str],
+ obj,
+ parent,
+ key=None,
+ h5Class=None,
+ linkClass=None,
+ populateAll=False,
+ openedPath: Optional[str] = None,
+ ):
"""
- :param str text: text displayed
+ :param text: text displayed
:param object obj: Pointer to a h5py-link object. See the `obj` attribute.
+ :param openedPath: The path with which the item was opened if any
"""
self.__obj = obj
self.__key = key
@@ -76,7 +87,7 @@ class Hdf5Item(Hdf5Node):
self.__linkClass = linkClass
self.__description = None
self.__nx_class = None
- Hdf5Node.__init__(self, parent, populateAll=populateAll)
+ Hdf5Node.__init__(self, parent, populateAll=populateAll, openedPath=openedPath)
def _getCanonicalName(self):
parent = self.parent
@@ -209,7 +220,7 @@ class Hdf5Item(Hdf5Node):
self.__isBroken = True
else:
self.__obj = obj
- if not self.isGroupObj():
+ if silx.io.utils.get_h5_class(obj) not in [silx.io.utils.H5Type.GROUP, silx.io.utils.H5Type.FILE]:
try:
# pre-fetch of the data
if obj.shape is None:
diff --git a/src/silx/gui/hdf5/Hdf5LoadingItem.py b/src/silx/gui/hdf5/Hdf5LoadingItem.py
index f11d252..70d015c 100644
--- a/src/silx/gui/hdf5/Hdf5LoadingItem.py
+++ b/src/silx/gui/hdf5/Hdf5LoadingItem.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -27,6 +26,7 @@ __authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "06/07/2018"
+from typing import Optional
from .. import qt
from .Hdf5Node import Hdf5Node
@@ -39,9 +39,15 @@ class Hdf5LoadingItem(Hdf5Node):
At the end of the loading this item is replaced by the loaded one.
"""
- def __init__(self, text, parent, animatedIcon):
+ def __init__(
+ self,
+ text,
+ parent,
+ animatedIcon,
+ openedPath: Optional[str] = None,
+ ):
"""Constructor"""
- Hdf5Node.__init__(self, parent)
+ Hdf5Node.__init__(self, parent, openedPath=openedPath)
self.__text = text
self.__animatedIcon = animatedIcon
self.__animatedIcon.register(self)
diff --git a/src/silx/gui/hdf5/Hdf5Node.py b/src/silx/gui/hdf5/Hdf5Node.py
index be16535..0d58748 100644
--- a/src/silx/gui/hdf5/Hdf5Node.py
+++ b/src/silx/gui/hdf5/Hdf5Node.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -28,6 +27,7 @@ __license__ = "MIT"
__date__ = "24/07/2018"
import weakref
+from typing import Optional
class Hdf5Node(object):
@@ -36,16 +36,24 @@ class Hdf5Node(object):
It provides link to the childs and to the parents, and a link to an
external object.
"""
- def __init__(self, parent=None, populateAll=False):
+ def __init__(
+ self,
+ parent=None,
+ populateAll=False,
+ openedPath: Optional[str]=None,
+ ):
"""
Constructor
:param Hdf5Node parent: Parent of the node, if exists, else None
:param bool populateAll: If true, populate all the tree node. Else
everything is lazy loaded.
+ :param openedPath:
+ The url or filename the node was created from, None if not directly created
"""
self.__child = None
self.__parent = None
+ self.__openedPath = openedPath
if parent is not None:
self.__parent = weakref.ref(parent)
if populateAll:
@@ -60,6 +68,11 @@ class Hdf5Node(object):
return "%s/?" % (parent._getCanonicalName())
@property
+ def _openedPath(self) -> Optional[str]:
+ """url or filename the node was created from, None if not directly created"""
+ return self.__openedPath
+
+ @property
def parent(self):
"""Parent of the node, or None if the node is a root
diff --git a/src/silx/gui/hdf5/Hdf5TreeModel.py b/src/silx/gui/hdf5/Hdf5TreeModel.py
index a32f7cf..8ac800a 100644
--- a/src/silx/gui/hdf5/Hdf5TreeModel.py
+++ b/src/silx/gui/hdf5/Hdf5TreeModel.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -30,6 +29,7 @@ __date__ = "12/03/2019"
import os
import logging
+from typing import Optional
import functools
from .. import qt
from .. import icons
@@ -39,6 +39,9 @@ from .Hdf5LoadingItem import Hdf5LoadingItem
from . import _utils
from ... import io as silx_io
+import h5py
+
+
_logger = logging.getLogger(__name__)
@@ -98,7 +101,13 @@ class LoadingItemRunnable(qt.QRunnable):
:rtpye: Hdf5Node
"""
text = _createRootLabel(h5obj)
- item = Hdf5Item(text=text, obj=h5obj, parent=oldItem.parent, populateAll=True)
+ item = Hdf5Item(
+ text=text,
+ obj=h5obj,
+ parent=oldItem.parent,
+ populateAll=True,
+ openedPath=oldItem._openedPath,
+ )
return item
def run(self):
@@ -554,10 +563,25 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
filename = node.obj.filename
self.insertFileAsync(filename, index.row(), synchronizingNode=node)
+ @staticmethod
+ def __areH5pyObjectEqual(obj1, obj2):
+ """Compare commonh5/h5py object without comparing data"""
+ if isinstance(obj1, h5py.HLObject): # Priority to h5py __eq__
+ return obj1 == obj2
+
+ # else compare commonh5 objects
+ if not isinstance(obj2, type(obj1)):
+ return False
+ def key(item):
+ if item.file is None:
+ return item.name
+ return item.file.filename, item.file.mode, item.name
+ return key(obj1) == key(obj2)
+
def h5pyObjectRow(self, h5pyObject):
for row in range(self.__root.childCount()):
item = self.__root.child(row)
- if item.obj == h5pyObject:
+ if self.__areH5pyObjectEqual(item.obj, h5pyObject):
return row
return -1
@@ -572,7 +596,7 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
index = 0
while index < self.__root.childCount():
item = self.__root.child(index)
- if item.obj == h5pyObject:
+ if self.__areH5pyObjectEqual(item.obj, h5pyObject):
qindex = self.index(index, 0, qt.QModelIndex())
self.synchronizeIndex(qindex)
index += 1
@@ -602,13 +626,19 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
index = 0
while index < self.__root.childCount():
item = self.__root.child(index)
- if item.obj == h5pyObject:
+ if self.__areH5pyObjectEqual(item.obj, h5pyObject):
qindex = self.index(index, 0, qt.QModelIndex())
self.removeIndex(qindex)
else:
index += 1
- def insertH5pyObject(self, h5pyObject, text=None, row=-1):
+ def insertH5pyObject(
+ self,
+ h5pyObject,
+ text: Optional[str] = None,
+ row: int = -1,
+ filename: Optional[str] = None,
+ ):
"""Append an HDF5 object from h5py to the tree.
:param h5pyObject: File handle/descriptor for a :class:`h5py.File`
@@ -618,7 +648,15 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
text = _createRootLabel(h5pyObject)
if row == -1:
row = self.__root.childCount()
- self.insertNode(row, Hdf5Item(text=text, obj=h5pyObject, parent=self.__root))
+ self.insertNode(
+ row,
+ Hdf5Item(
+ text=text,
+ obj=h5pyObject,
+ parent=self.__root,
+ openedPath=filename,
+ )
+ )
def hasPendingOperations(self):
return len(self.__runnerSet) > 0
@@ -630,7 +668,12 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
# create temporary item
if synchronizingNode is None:
text = os.path.basename(filename)
- item = Hdf5LoadingItem(text=text, parent=self.__root, animatedIcon=self.__animatedIcon)
+ item = Hdf5LoadingItem(
+ text=text,
+ parent=self.__root,
+ animatedIcon=self.__animatedIcon,
+ openedPath=filename,
+ )
self.insertNode(row, item)
else:
item = synchronizingNode
@@ -655,7 +698,7 @@ class Hdf5TreeModel(qt.QAbstractItemModel):
if self.__ownFiles:
self.__openedFiles.append(h5file)
self.sigH5pyObjectLoaded.emit(h5file)
- self.insertH5pyObject(h5file, row=row)
+ self.insertH5pyObject(h5file, row=row, filename=filename)
except IOError:
_logger.debug("File '%s' can't be read.", filename, exc_info=True)
raise
diff --git a/src/silx/gui/hdf5/Hdf5TreeView.py b/src/silx/gui/hdf5/Hdf5TreeView.py
index b276618..da35d15 100644
--- a/src/silx/gui/hdf5/Hdf5TreeView.py
+++ b/src/silx/gui/hdf5/Hdf5TreeView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/NexusSortFilterProxyModel.py b/src/silx/gui/hdf5/NexusSortFilterProxyModel.py
index 9c3533f..1b80c3e 100644
--- a/src/silx/gui/hdf5/NexusSortFilterProxyModel.py
+++ b/src/silx/gui/hdf5/NexusSortFilterProxyModel.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/__init__.py b/src/silx/gui/hdf5/__init__.py
index 1b5a602..2243484 100644
--- a/src/silx/gui/hdf5/__init__.py
+++ b/src/silx/gui/hdf5/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/_utils.py b/src/silx/gui/hdf5/_utils.py
index 8f32252..1d1b4cb 100644
--- a/src/silx/gui/hdf5/_utils.py
+++ b/src/silx/gui/hdf5/_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/setup.py b/src/silx/gui/hdf5/setup.py
deleted file mode 100644
index 786a851..0000000
--- a/src/silx/gui/hdf5/setup.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "28/09/2016"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('hdf5', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/gui/hdf5/test/__init__.py b/src/silx/gui/hdf5/test/__init__.py
index 71128fb..b03339f 100644
--- a/src/silx/gui/hdf5/test/__init__.py
+++ b/src/silx/gui/hdf5/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/hdf5/test/test_hdf5.py b/src/silx/gui/hdf5/test/test_hdf5.py
index 9b1b88a..6e77e1d 100755
--- a/src/silx/gui/hdf5/test/test_hdf5.py
+++ b/src/silx/gui/hdf5/test/test_hdf5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/icons.py b/src/silx/gui/icons.py
index 1493b92..b7a9000 100644
--- a/src/silx/gui/icons.py
+++ b/src/silx/gui/icons.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/AlphaSlider.py b/src/silx/gui/plot/AlphaSlider.py
index da55b1e..486ca6f 100644
--- a/src/silx/gui/plot/AlphaSlider.py
+++ b/src/silx/gui/plot/AlphaSlider.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ColorBar.py b/src/silx/gui/plot/ColorBar.py
index 8cafc06..247da07 100644
--- a/src/silx/gui/plot/ColorBar.py
+++ b/src/silx/gui/plot/ColorBar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -590,7 +589,7 @@ class _ColorScale(qt.QWidget):
def mouseMoveEvent(self, event):
tooltip = str(self.getValueFromRelativePosition(
- self._getRelativePosition(event.y())))
+ self._getRelativePosition(qt.getMouseEventPosition(event)[1])))
qt.QToolTip.showText(event.globalPos(), tooltip, self)
super(_ColorScale, self).mouseMoveEvent(event)
diff --git a/src/silx/gui/plot/Colormap.py b/src/silx/gui/plot/Colormap.py
index 22fea7f..8eaee84 100644
--- a/src/silx/gui/plot/Colormap.py
+++ b/src/silx/gui/plot/Colormap.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ColormapDialog.py b/src/silx/gui/plot/ColormapDialog.py
index 7c66cb8..0c0df2c 100644
--- a/src/silx/gui/plot/ColormapDialog.py
+++ b/src/silx/gui/plot/ColormapDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Deprecated module providing ColormapDialog."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent", "H.Payno"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot/Colors.py b/src/silx/gui/plot/Colors.py
index 277e104..34ee815 100644
--- a/src/silx/gui/plot/Colors.py
+++ b/src/silx/gui/plot/Colors.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Color conversion function, color dictionary and colormap tools."""
-from __future__ import absolute_import
-
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "14/06/2018"
diff --git a/src/silx/gui/plot/CompareImages.py b/src/silx/gui/plot/CompareImages.py
index 857fc79..80e0db3 100644
--- a/src/silx/gui/plot/CompareImages.py
+++ b/src/silx/gui/plot/CompareImages.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ComplexImageView.py b/src/silx/gui/plot/ComplexImageView.py
index 4eee3b0..7febd19 100644
--- a/src/silx/gui/plot/ComplexImageView.py
+++ b/src/silx/gui/plot/ComplexImageView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -28,8 +27,6 @@ The :class:`ComplexImageView` widget is dedicated to visualize a single 2D datas
of complex data.
"""
-from __future__ import absolute_import
-
__authors__ = ["Vincent Favre-Nicolin", "T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot/CurvesROIWidget.py b/src/silx/gui/plot/CurvesROIWidget.py
index 132d398..f0cc7f3 100644
--- a/src/silx/gui/plot/CurvesROIWidget.py
+++ b/src/silx/gui/plot/CurvesROIWidget.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -175,8 +174,8 @@ class CurvesROIWidget(qt.QWidget):
self._isConnected = False # True if connected to plot signals
self._isInit = False
- # expose API
- self.getROIListAndDict = self.roiTable.getROIListAndDict
+ def getROIListAndDict(self):
+ return self.roiTable.getROIListAndDict()
def getPlotWidget(self):
"""Returns the associated PlotWidget or None
@@ -1568,14 +1567,6 @@ class CurvesROIDockWidget(qt.QDockWidget):
action.setIcon(icons.getQIcon('plot-roi'))
return action
- def showEvent(self, event):
- """Make sure this widget is raised when it is shown
- (when it is first created as a tab in PlotWindow or when it is shown
- again after hiding).
- """
- self.raise_()
- qt.QDockWidget.showEvent(self, event)
-
@property
def currentROI(self):
return self.roiWidget.currentRoi
diff --git a/src/silx/gui/plot/ImageStack.py b/src/silx/gui/plot/ImageStack.py
index 1588a31..e2bed9d 100644
--- a/src/silx/gui/plot/ImageStack.py
+++ b/src/silx/gui/plot/ImageStack.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ImageView.py b/src/silx/gui/plot/ImageView.py
index f8b830a..a451b2d 100644
--- a/src/silx/gui/plot/ImageView.py
+++ b/src/silx/gui/plot/ImageView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
@@ -37,9 +36,6 @@ Basic usage of :class:`ImageView` is through the following methods:
For an example of use, see `imageview.py` in :ref:`sample-code`.
"""
-from __future__ import division
-
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "26/04/2018"
diff --git a/src/silx/gui/plot/Interaction.py b/src/silx/gui/plot/Interaction.py
index 6213889..053fbe5 100644
--- a/src/silx/gui/plot/Interaction.py
+++ b/src/silx/gui/plot/Interaction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ItemsSelectionDialog.py b/src/silx/gui/plot/ItemsSelectionDialog.py
index c0504b0..c303c6b 100644
--- a/src/silx/gui/plot/ItemsSelectionDialog.py
+++ b/src/silx/gui/plot/ItemsSelectionDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/LegendSelector.py b/src/silx/gui/plot/LegendSelector.py
index d439387..4d8ebe9 100755
--- a/src/silx/gui/plot/LegendSelector.py
+++ b/src/silx/gui/plot/LegendSelector.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -1030,10 +1029,3 @@ class LegendsDockWidget(qt.QDockWidget):
self.plot.sigContentChanged.disconnect(self.updateLegends)
self.plot.sigActiveCurveChanged.disconnect(self.updateLegends)
self._isConnected = False
-
- def showEvent(self, event):
- """Make sure this widget is raised when it is shown
- (when it is first created as a tab in PlotWindow or when it is shown
- again after hiding).
- """
- self.raise_()
diff --git a/src/silx/gui/plot/LimitsHistory.py b/src/silx/gui/plot/LimitsHistory.py
index a323548..7215e37 100644
--- a/src/silx/gui/plot/LimitsHistory.py
+++ b/src/silx/gui/plot/LimitsHistory.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/MaskToolsWidget.py b/src/silx/gui/plot/MaskToolsWidget.py
index 522be48..46b532c 100644
--- a/src/silx/gui/plot/MaskToolsWidget.py
+++ b/src/silx/gui/plot/MaskToolsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -30,7 +29,6 @@ This widget is meant to work with :class:`silx.gui.plot.PlotWidget`.
- :class:`MaskToolsWidget`: GUI for :class:`Mask`
- :class:`MaskToolsDockWidget`: DockWidget to integrate in :class:`PlotWindow`
"""
-from __future__ import division
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
diff --git a/src/silx/gui/plot/PlotActions.py b/src/silx/gui/plot/PlotActions.py
index dd16221..f32be3c 100644
--- a/src/silx/gui/plot/PlotActions.py
+++ b/src/silx/gui/plot/PlotActions.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/PlotEvents.py b/src/silx/gui/plot/PlotEvents.py
index 83f253c..be875d7 100644
--- a/src/silx/gui/plot/PlotEvents.py
+++ b/src/silx/gui/plot/PlotEvents.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/PlotInteraction.py b/src/silx/gui/plot/PlotInteraction.py
index 6ebe6b1..c4d64a5 100644
--- a/src/silx/gui/plot/PlotInteraction.py
+++ b/src/silx/gui/plot/PlotInteraction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/PlotToolButtons.py b/src/silx/gui/plot/PlotToolButtons.py
index 3970896..a810ce1 100644
--- a/src/silx/gui/plot/PlotToolButtons.py
+++ b/src/silx/gui/plot/PlotToolButtons.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/PlotTools.py b/src/silx/gui/plot/PlotTools.py
index 5929473..35d0f48 100644
--- a/src/silx/gui/plot/PlotTools.py
+++ b/src/silx/gui/plot/PlotTools.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""Set of widgets to associate with a :class:'PlotWidget'.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/03/2018"
diff --git a/src/silx/gui/plot/PlotWidget.py b/src/silx/gui/plot/PlotWidget.py
index 6cb5ef5..f07ef30 100755
--- a/src/silx/gui/plot/PlotWidget.py
+++ b/src/silx/gui/plot/PlotWidget.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,9 +25,6 @@
The :class:`PlotWidget` implements the plot API initially provided in PyMca.
"""
-from __future__ import division
-
-
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "21/12/2018"
@@ -42,6 +38,7 @@ from collections import OrderedDict, namedtuple
from contextlib import contextmanager
import datetime as dt
import itertools
+import numbers
import typing
import warnings
@@ -902,10 +899,13 @@ class PlotWidget(qt.QMainWindow):
'image': (items.ImageBase,),
'scatter': (items.Scatter,),
'marker': (items.MarkerBase,),
- 'item': (items.Shape,
- items.BoundingRect,
- items.XAxisExtent,
- items.YAxisExtent),
+ 'item': (
+ items.Line,
+ items.Shape,
+ items.BoundingRect,
+ items.XAxisExtent,
+ items.YAxisExtent,
+ ),
'histogram': (items.Histogram,),
}
"""Mapping kind to item classes of this kind"""
@@ -1130,8 +1130,8 @@ class PlotWidget(qt.QMainWindow):
:type xerror: A float, or a numpy.ndarray of float32.
If it is an array, it can either be a 1D array of
same length as the data or a 2D array with 2 rows
- of same length as the data: row 0 for positive errors,
- row 1 for negative errors.
+ of same length as the data: row 0 for lower errors,
+ row 1 for upper errors.
:param yerror: Values with the uncertainties on the y values
:type yerror: A float, or a numpy.ndarray of float32. See xerror.
:param int z: Layer on which to draw the curve (default: 1)
@@ -1540,8 +1540,8 @@ class PlotWidget(qt.QMainWindow):
:type xerror: A float, or a numpy.ndarray of float32.
If it is an array, it can either be a 1D array of
same length as the data or a 2D array with 2 rows
- of same length as the data: row 0 for positive errors,
- row 1 for negative errors.
+ of same length as the data: row 0 for lower errors,
+ row 1 for upper errors.
:param yerror: Values with the uncertainties on the y values
:type yerror: A float, or a numpy.ndarray of float32. See xerror.
:param int z: Layer on which to draw the scatter (default: 1)
@@ -3261,10 +3261,13 @@ class PlotWidget(qt.QMainWindow):
def dataToPixel(self, x=None, y=None, axis="left", check=True):
"""Convert a position in data coordinates to a position in pixels.
- :param float x: The X coordinate in data space. If None (default)
- the middle position of the displayed data is used.
- :param float y: The Y coordinate in data space. If None (default)
- the middle position of the displayed data is used.
+ :param x: The X coordinate in data space. If None (default)
+ the middle position of the displayed data is used.
+ :type x: float or 1D numpy array of float
+ :param y: The Y coordinate in data space. If None (default)
+ the middle position of the displayed data is used.
+ :type y: float or 1D numpy array of float
+
:param str axis: The Y axis to use for the conversion
('left' or 'right').
:param bool check: True to return None if outside displayed area,
@@ -3272,7 +3275,7 @@ class PlotWidget(qt.QMainWindow):
:returns: The corresponding position in pixels or
None if the data position is not in the displayed area and
check is True.
- :rtype: A tuple of 2 floats: (xPixel, yPixel) or None.
+ :rtype: A tuple of 2 floats or 2 arrays of float: (xPixel, yPixel) or None.
"""
assert axis in ("left", "right")
@@ -3285,12 +3288,26 @@ class PlotWidget(qt.QMainWindow):
if y is None:
y = 0.5 * (ymax + ymin)
+ if isinstance(x, numbers.Real) != isinstance(y, numbers.Real):
+ raise ValueError("x and y must be of the same type")
+ if not isinstance(x, numbers.Real) and (x.shape != y.shape or x.ndim != 1):
+ raise ValueError("x and y must be 1D arrays of the same length")
+
if check:
- if x > xmax or x < xmin:
- return None
+ isOutside = numpy.logical_or(
+ numpy.logical_or(x > xmax, x < xmin),
+ numpy.logical_or(y > ymax, y < ymin)
+ )
- if y > ymax or y < ymin:
- return None
+ if numpy.any(isOutside):
+ if isinstance(x, numbers.Real):
+ return None
+ else: # Filter-out points that are outside
+ x = numpy.array(x, copy=True, dtype=numpy.float64)
+ x[isOutside] = numpy.nan
+
+ y = numpy.array(y, copy=True, dtype=numpy.float64)
+ y[isOutside] = numpy.nan
return self._backend.dataToPixel(x, y, axis=axis)
@@ -3318,7 +3335,10 @@ class PlotWidget(qt.QMainWindow):
if check:
left, top, width, height = self.getPlotBoundsInPixels()
- if not (left <= x <= left + width and top <= y <= top + height):
+ isOutside = numpy.logical_or(
+ numpy.logical_or(x < left, x > left + width),
+ numpy.logical_or(y < top, y > top + height))
+ if numpy.any(isOutside):
return None
return self._backend.pixelToData(x, y, axis)
@@ -3603,7 +3623,7 @@ class PlotWidget(qt.QMainWindow):
qapp = qt.QApplication.instance()
event = qt.QMouseEvent(
qt.QEvent.MouseMove,
- self.getWidgetHandle().mapFromGlobal(qt.QCursor.pos()),
+ qt.QPointF(self.getWidgetHandle().mapFromGlobal(qt.QCursor.pos())),
qt.Qt.NoButton,
qapp.mouseButtons(),
qapp.keyboardModifiers())
diff --git a/src/silx/gui/plot/PlotWindow.py b/src/silx/gui/plot/PlotWindow.py
index 0349585..e8da174 100644
--- a/src/silx/gui/plot/PlotWindow.py
+++ b/src/silx/gui/plot/PlotWindow.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -215,7 +214,6 @@ class PlotWindow(PlotWidget):
# lazy loaded actions needed by the controlButton menu
self._consoleAction = None
- self._statsAction = None
self._panWithArrowKeysAction = None
self._crosshairAction = None
@@ -401,14 +399,19 @@ class PlotWindow(PlotWidget):
custom_banner=banner,
parent=self)
self.addTabbedDockWidget(self._consoleDockWidget)
- # self._consoleDockWidget.setVisible(True)
self._consoleDockWidget.toggleViewAction().toggled.connect(
- self.getConsoleAction().setChecked)
+ self._consoleDockWidgetToggled)
self._consoleDockWidget.setVisible(isChecked)
- def _toggleStatsVisibility(self, isChecked=False):
- self.getStatsWidget().parent().setVisible(isChecked)
+ def _consoleVisibilityTriggered(self, isChecked):
+ if isChecked and self.isVisible():
+ self._consoleDockWidget.show()
+ self._consoleDockWidget.raise_()
+
+ def _consoleDockWidgetToggled(self, isChecked):
+ if self.isVisible():
+ self.getConsoleAction().setChecked(isChecked)
def _createToolBar(self, title, parent):
"""Create a QToolBar from the QAction of the PlotWindow.
@@ -522,6 +525,17 @@ class PlotWindow(PlotWidget):
self._handleFirstDockWidgetShow)
self.addTabbedDockWidget(dockWidget)
+ def _handleDockWidgetViewActionTriggered(self, checked):
+ if checked:
+ action = self.sender()
+ if action is None:
+ return
+ dockWidget = action.parent()
+ if dockWidget is None:
+ return
+ dockWidget.show() # Show needed here for raise to have an effect
+ dockWidget.raise_()
+
def getColorBarWidget(self):
"""Returns the embedded :class:`ColorBarWidget` widget.
@@ -536,6 +550,8 @@ class PlotWindow(PlotWidget):
if self._legendsDockWidget is None:
self._legendsDockWidget = LegendsDockWidget(plot=self)
self._legendsDockWidget.hide()
+ self._legendsDockWidget.toggleViewAction().triggered.connect(
+ self._handleDockWidgetViewActionTriggered)
self._legendsDockWidget.visibilityChanged.connect(
self._handleFirstDockWidgetShow)
return self._legendsDockWidget
@@ -547,6 +563,8 @@ class PlotWindow(PlotWidget):
self._curvesROIDockWidget = CurvesROIDockWidget(
plot=self, name='Regions Of Interest')
self._curvesROIDockWidget.hide()
+ self._curvesROIDockWidget.toggleViewAction().triggered.connect(
+ self._handleDockWidgetViewActionTriggered)
self._curvesROIDockWidget.visibilityChanged.connect(
self._handleFirstDockWidgetShow)
return self._curvesROIDockWidget
@@ -568,6 +586,8 @@ class PlotWindow(PlotWidget):
self._maskToolsDockWidget = MaskToolsDockWidget(
plot=self, name='Mask')
self._maskToolsDockWidget.hide()
+ self._maskToolsDockWidget.toggleViewAction().triggered.connect(
+ self._handleDockWidgetViewActionTriggered)
self._maskToolsDockWidget.visibilityChanged.connect(
self._handleFirstDockWidgetShow)
return self._maskToolsDockWidget
@@ -583,9 +603,9 @@ class PlotWindow(PlotWidget):
self._statsDockWidget.layout().setContentsMargins(0, 0, 0, 0)
statsWidget = BasicStatsWidget(parent=self, plot=self)
self._statsDockWidget.setWidget(statsWidget)
- statsWidget.sigVisibilityChanged.connect(
- self.getStatsAction().setChecked)
self._statsDockWidget.hide()
+ self._statsDockWidget.toggleViewAction().triggered.connect(
+ self._handleDockWidgetViewActionTriggered)
self._statsDockWidget.visibilityChanged.connect(
self._handleFirstDockWidgetShow)
return self._statsDockWidget.widget()
@@ -618,6 +638,8 @@ class PlotWindow(PlotWidget):
self._consoleAction.setCheckable(True)
if IPythonDockWidget is not None:
self._consoleAction.toggled.connect(self._toggleConsoleVisibility)
+ self._consoleAction.triggered.connect(self._consoleVisibilityTriggered)
+
else:
self._consoleAction.setEnabled(False)
return self._consoleAction
@@ -648,12 +670,7 @@ class PlotWindow(PlotWidget):
return self._panWithArrowKeysAction
def getStatsAction(self):
- if self._statsAction is None:
- self._statsAction = qt.QAction('Curves stats', self)
- self._statsAction.setCheckable(True)
- self._statsAction.setChecked(self.getStatsWidget().parent().isVisible())
- self._statsAction.toggled.connect(self._toggleStatsVisibility)
- return self._statsAction
+ return self.getStatsWidget().parent().toggleViewAction()
def getRoiAction(self):
"""QAction toggling curve ROI dock widget
diff --git a/src/silx/gui/plot/PrintPreviewToolButton.py b/src/silx/gui/plot/PrintPreviewToolButton.py
index 30967e4..9069ac3 100644
--- a/src/silx/gui/plot/PrintPreviewToolButton.py
+++ b/src/silx/gui/plot/PrintPreviewToolButton.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -101,7 +100,6 @@ plots on the same page. The plots all instantiate a
app.exec()
"""
-from __future__ import absolute_import
import logging
from io import StringIO
diff --git a/src/silx/gui/plot/Profile.py b/src/silx/gui/plot/Profile.py
index 7565155..bf793c8 100644
--- a/src/silx/gui/plot/Profile.py
+++ b/src/silx/gui/plot/Profile.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ProfileMainWindow.py b/src/silx/gui/plot/ProfileMainWindow.py
index ce56cfd..09a5b41 100644
--- a/src/silx/gui/plot/ProfileMainWindow.py
+++ b/src/silx/gui/plot/ProfileMainWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ROIStatsWidget.py b/src/silx/gui/plot/ROIStatsWidget.py
index 32a1395..732c60f 100644
--- a/src/silx/gui/plot/ROIStatsWidget.py
+++ b/src/silx/gui/plot/ROIStatsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/ScatterMaskToolsWidget.py b/src/silx/gui/plot/ScatterMaskToolsWidget.py
index c242dfc..3f8c28b 100644
--- a/src/silx/gui/plot/ScatterMaskToolsWidget.py
+++ b/src/silx/gui/plot/ScatterMaskToolsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -31,8 +30,6 @@ This widget is meant to work with a modified :class:`silx.gui.plot.PlotWidget`
- :class:`ScatterMaskToolsDockWidget`: DockWidget to integrate in :class:`PlotWindow`
"""
-from __future__ import division
-
__authors__ = ["P. Knobel"]
__license__ = "MIT"
__date__ = "15/02/2019"
diff --git a/src/silx/gui/plot/ScatterView.py b/src/silx/gui/plot/ScatterView.py
index d3fd2e0..abacbef 100644
--- a/src/silx/gui/plot/ScatterView.py
+++ b/src/silx/gui/plot/ScatterView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/StackView.py b/src/silx/gui/plot/StackView.py
index 56793d7..5101f87 100644
--- a/src/silx/gui/plot/StackView.py
+++ b/src/silx/gui/plot/StackView.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -230,7 +229,8 @@ class StackView(qt.QMainWindow):
if silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == 'downward':
self._plot.getYAxis().setInverted(True)
- self._addColorBarAction()
+ self._plot.getColorBarAction().setVisible(True)
+ self._plot.getColorBarWidget().setVisible(True)
self._profileToolBar = Profile3DToolBar(parent=self._plot,
stackview=self)
@@ -283,15 +283,6 @@ class StackView(qt.QMainWindow):
signal=self.getStack(copy=False, returnNumpyArray=True)[0],
signal_name="image_stack")
- def _addColorBarAction(self):
- self._plot.getColorBarWidget().setVisible(True)
- actions = self._plot.toolBar().actions()
- for index, action in enumerate(actions):
- if action is self._plot.getColormapAction():
- break
- self._colorbarAction = actions_control.ColorBarAction(self._plot, self._plot)
- self._plot.toolBar().insertAction(actions[index + 1], self._colorbarAction)
-
def _plotCallback(self, eventDict):
"""Callback for plot events.
@@ -1056,7 +1047,7 @@ class StackView(qt.QMainWindow):
:rtype: QAction
"""
- return self._colorbarAction
+ return self._plot.getColorBarAction()
def remove(self, legend=None,
kind=('curve', 'image', 'item', 'marker')):
diff --git a/src/silx/gui/plot/StatsWidget.py b/src/silx/gui/plot/StatsWidget.py
index 00f78d0..b23946f 100644
--- a/src/silx/gui/plot/StatsWidget.py
+++ b/src/silx/gui/plot/StatsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/_BaseMaskToolsWidget.py b/src/silx/gui/plot/_BaseMaskToolsWidget.py
index 407ab11..dda75e1 100644
--- a/src/silx/gui/plot/_BaseMaskToolsWidget.py
+++ b/src/silx/gui/plot/_BaseMaskToolsWidget.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +24,6 @@
"""This module is a collection of base classes used in modules
:mod:`.MaskToolsWidget` (images) and :mod:`.ScatterMaskToolsWidget`
"""
-from __future__ import division
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
@@ -417,7 +415,7 @@ class BaseMaskToolsWidget(qt.QWidget):
self._lastPencilPos = None
self._multipleMasks = 'exclusive'
- self._maskFileDir = qt.QDir.home().absolutePath()
+ self._maskFileDir = qt.QDir.current().absolutePath()
self.plot.sigInteractiveModeChanged.connect(
self._interactiveModeChanged)
@@ -494,7 +492,7 @@ class BaseMaskToolsWidget(qt.QWidget):
def maskFileDir(self):
"""The directory from which to load/save mask from/to files."""
if not os.path.isdir(self._maskFileDir):
- self._maskFileDir = qt.QDir.home().absolutePath()
+ self._maskFileDir = qt.QDir.current().absolutePath()
return self._maskFileDir
@maskFileDir.setter
@@ -632,7 +630,7 @@ class BaseMaskToolsWidget(qt.QWidget):
invertAction.setText('Invert')
icon = icons.getQIcon("mask-invert")
invertAction.setIcon(icon)
- invertAction.setShortcut(qt.Qt.CTRL + qt.Qt.Key_I)
+ invertAction.setShortcut(qt.QKeySequence(qt.Qt.CTRL | qt.Qt.Key_I))
invertAction.setToolTip('Invert current mask <b>%s</b>' %
invertAction.shortcut().toString())
invertAction.triggered.connect(self._handleInvertMask)
@@ -1273,10 +1271,3 @@ class BaseMaskToolsDockWidget(qt.QDockWidget):
self.widget().setDirection(qt.QBoxLayout.LeftToRight)
self.resize(self.widget().minimumSize())
self.adjustSize()
-
- def showEvent(self, event):
- """Make sure this widget is raised when it is shown
- (when it is first created as a tab in PlotWindow or when it is shown
- again after hiding).
- """
- self.raise_()
diff --git a/src/silx/gui/plot/__init__.py b/src/silx/gui/plot/__init__.py
index 3a141b3..129c4de 100644
--- a/src/silx/gui/plot/__init__.py
+++ b/src/silx/gui/plot/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/_utils/__init__.py b/src/silx/gui/plot/_utils/__init__.py
index ed87b18..39fa7e4 100644
--- a/src/silx/gui/plot/_utils/__init__.py
+++ b/src/silx/gui/plot/_utils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/_utils/delaunay.py b/src/silx/gui/plot/_utils/delaunay.py
index 49ad05f..48b0db7 100644
--- a/src/silx/gui/plot/_utils/delaunay.py
+++ b/src/silx/gui/plot/_utils/delaunay.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -55,8 +54,7 @@ def delaunay(x, y):
try:
delaunay = _Delaunay(points)
except (RuntimeError, ValueError):
- _logger.error("Delaunay tesselation failed: %s",
- sys.exc_info()[1])
+ _logger.debug("Delaunay tesselation failed: %s", sys.exc_info()[1])
delaunay = None
return delaunay
diff --git a/src/silx/gui/plot/_utils/dtime_ticklayout.py b/src/silx/gui/plot/_utils/dtime_ticklayout.py
index ebf775b..3c355d7 100644
--- a/src/silx/gui/plot/_utils/dtime_ticklayout.py
+++ b/src/silx/gui/plot/_utils/dtime_ticklayout.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module implements date-time labels layout on graph axes."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["P. Kenter"]
__license__ = "MIT"
__date__ = "04/04/2018"
@@ -212,6 +209,7 @@ def addValueToDate(dateTime, value, unit):
:param float value: value to be added
:param DtUnit unit: of the value
:return:
+ :raises ValueError: unit is unsupported or result is out of datetime bounds
"""
#logger.debug("addValueToDate({}, {}, {})".format(dateTime, value, unit))
@@ -362,6 +360,9 @@ def findStartDate(dMin, dMax, nTicks):
else:
niceVal = math.floor(dVal / niceSpacing) * niceSpacing
+ if unit == DtUnit.YEARS and niceVal <= dt.MINYEAR:
+ niceVal = max(1, niceSpacing)
+
_logger.debug("StartValue: dVal = {}, niceVal: {} ({})"
.format(dVal, niceVal, unit.name))
@@ -394,7 +395,10 @@ def dateRange(dMin, dMax, step, unit, includeFirstBeyond = False):
dateTime = dMin
while dateTime < dMax:
yield dateTime
- dateTime = addValueToDate(dateTime, step, unit)
+ try:
+ dateTime = addValueToDate(dateTime, step, unit)
+ except ValueError:
+ return # current dateTime is out of datetime bounds
if includeFirstBeyond:
yield dateTime
@@ -420,12 +424,6 @@ def calcTicks(dMin, dMax, nTicks):
includeFirstBeyond=True):
result.append(d)
- assert result[0] <= dMin, \
- "First nice date ({}) should be <= dMin {}".format(result[0], dMin)
-
- assert result[-1] >= dMax, \
- "Last nice date ({}) should be >= dMax {}".format(result[-1], dMax)
-
return result, niceSpacing, unit
diff --git a/src/silx/gui/plot/_utils/panzoom.py b/src/silx/gui/plot/_utils/panzoom.py
index 77efd10..8592ad0 100644
--- a/src/silx/gui/plot/_utils/panzoom.py
+++ b/src/silx/gui/plot/_utils/panzoom.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/_utils/setup.py b/src/silx/gui/plot/_utils/setup.py
deleted file mode 100644
index 0271745..0000000
--- a/src/silx/gui/plot/_utils/setup.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "21/03/2017"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('_utils', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/gui/plot/_utils/test/__init__.py b/src/silx/gui/plot/_utils/test/__init__.py
index 3ad225d..78821ec 100644
--- a/src/silx/gui/plot/_utils/test/__init__.py
+++ b/src/silx/gui/plot/_utils/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py b/src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py
index 8d35acf..87c0742 100644
--- a/src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py
+++ b/src/silx/gui/plot/_utils/test/test_dtime_ticklayout.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,57 +22,67 @@
#
# ###########################################################################*/
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["P. Kenter"]
__license__ = "MIT"
__date__ = "06/04/2018"
import datetime as dt
-import unittest
+import pytest
+
+
+from silx.gui.plot._utils.dtime_ticklayout import calcTicks, DtUnit, SECONDS_PER_YEAR
-from silx.gui.plot._utils.dtime_ticklayout import (
- calcTicks, DtUnit, SECONDS_PER_YEAR)
+def testSmallMonthlySpacing():
+ """Tests a range that did result in a spacing of less than 1 month.
+ It is impossible to add fractional month so the unit must be in days
+ """
+ from dateutil import parser
+ d1 = parser.parse("2017-01-03 13:15:06.000044")
+ d2 = parser.parse("2017-03-08 09:16:16.307584")
+ _ticks, _units, spacing = calcTicks(d1, d2, nTicks=4)
-class TestTickLayout(unittest.TestCase):
- """Test ticks layout algorithms"""
+ assert spacing == DtUnit.DAYS
- def testSmallMonthlySpacing(self):
- """ Tests a range that did result in a spacing of less than 1 month.
- It is impossible to add fractional month so the unit must be in days
- """
- from dateutil import parser
- d1 = parser.parse("2017-01-03 13:15:06.000044")
- d2 = parser.parse("2017-03-08 09:16:16.307584")
- _ticks, _units, spacing = calcTicks(d1, d2, nTicks=4)
- self.assertEqual(spacing, DtUnit.DAYS)
+def testNoCrash():
+ """Creates many combinations of and number-of-ticks and end-dates;
+ tests that it doesn't give an exception and returns a reasonable number
+ of ticks.
+ """
+ d1 = dt.datetime(2017, 1, 3, 13, 15, 6, 44)
+ value = 100e-6 # Start at 100 micro sec range.
- def testNoCrash(self):
- """ Creates many combinations of and number-of-ticks and end-dates;
- tests that it doesn't give an exception and returns a reasonable number
- of ticks.
- """
- d1 = dt.datetime(2017, 1, 3, 13, 15, 6, 44)
+ while value <= 200 * SECONDS_PER_YEAR:
- value = 100e-6 # Start at 100 micro sec range.
+ d2 = d1 + dt.timedelta(microseconds=value * 1e6) # end date range
- while value <= 200 * SECONDS_PER_YEAR:
+ for numTicks in range(2, 12):
+ ticks, _, _ = calcTicks(d1, d2, numTicks)
- d2 = d1 + dt.timedelta(microseconds=value*1e6) # end date range
+ margin = 2.5
+ assert (
+ numTicks / margin <= len(ticks) <= numTicks * margin
+ ), "Condition {} <= {} <= {} failed for # ticks={} and d2={}:".format(
+ numTicks / margin, len(ticks), numTicks * margin, numTicks, d2
+ )
- for numTicks in range(2, 12):
- ticks, _, _ = calcTicks(d1, d2, numTicks)
+ value = value * 1.5 # let date period grow exponentially
- margin = 2.5
- self.assertTrue(
- numTicks/margin <= len(ticks) <= numTicks*margin,
- "Condition {} <= {} <= {} failed for # ticks={} and d2={}:"
- .format(numTicks/margin, len(ticks), numTicks * margin,
- numTicks, d2))
- value = value * 1.5 # let date period grow exponentially
+@pytest.mark.parametrize(
+ "dMin, dMax",
+ [
+ (dt.datetime(1, 1, 1), dt.datetime(400, 1, 1)),
+ (dt.datetime(4000, 1, 1), dt.datetime(9999, 1, 1)),
+ (dt.datetime(1, 1, 1), dt.datetime(9999, 12, 23)),
+ ],
+)
+def testCalcTicksOutOfBoundTicks(dMin, dMax):
+ """Test tick generation with values leading to out-of-bound ticks"""
+ ticks, _, unit = calcTicks(dMin, dMax, nTicks=5)
+ assert len(ticks) != 0
+ assert unit == DtUnit.YEARS
diff --git a/src/silx/gui/plot/_utils/test/test_ticklayout.py b/src/silx/gui/plot/_utils/test/test_ticklayout.py
index 884b71b..8388c7e 100644
--- a/src/silx/gui/plot/_utils/test/test_ticklayout.py
+++ b/src/silx/gui/plot/_utils/test/test_ticklayout.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
@@ -23,8 +22,6 @@
#
# ###########################################################################*/
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"
diff --git a/src/silx/gui/plot/_utils/ticklayout.py b/src/silx/gui/plot/_utils/ticklayout.py
index c9fd3e6..4266be0 100644
--- a/src/silx/gui/plot/_utils/ticklayout.py
+++ b/src/silx/gui/plot/_utils/ticklayout.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module implements labels layout on graph axes."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "18/10/2016"
diff --git a/src/silx/gui/plot/actions/PlotAction.py b/src/silx/gui/plot/actions/PlotAction.py
index 2983775..de041dc 100644
--- a/src/silx/gui/plot/actions/PlotAction.py
+++ b/src/silx/gui/plot/actions/PlotAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
@@ -27,9 +26,6 @@ The class :class:`.PlotAction` help the creation of a qt.QAction associated
with a :class:`.PlotWidget`.
"""
-from __future__ import division
-
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "03/01/2018"
diff --git a/src/silx/gui/plot/actions/PlotToolAction.py b/src/silx/gui/plot/actions/PlotToolAction.py
index fbb0b0f..8c3b3c2 100644
--- a/src/silx/gui/plot/actions/PlotToolAction.py
+++ b/src/silx/gui/plot/actions/PlotToolAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
@@ -27,9 +26,6 @@ The class :class:`.PlotToolAction` help the creation of a qt.QAction associating
a tool window with a :class:`.PlotWidget`.
"""
-from __future__ import division
-
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "10/10/2018"
diff --git a/src/silx/gui/plot/actions/__init__.py b/src/silx/gui/plot/actions/__init__.py
index 930c728..3e606c6 100644
--- a/src/silx/gui/plot/actions/__init__.py
+++ b/src/silx/gui/plot/actions/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/actions/control.py b/src/silx/gui/plot/actions/control.py
index 439985e..e75048a 100755
--- a/src/silx/gui/plot/actions/control.py
+++ b/src/silx/gui/plot/actions/control.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2019 European Synchrotron Radiation Facility
@@ -46,8 +45,6 @@ The following QAction are available:
- :class:`ZoomOutAction`
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "27/11/2020"
diff --git a/src/silx/gui/plot/actions/fit.py b/src/silx/gui/plot/actions/fit.py
index e130b24..3489f70 100644
--- a/src/silx/gui/plot/actions/fit.py
+++ b/src/silx/gui/plot/actions/fit.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -32,8 +31,6 @@ The following QAction are available:
.. autoclass:`.FitAction`
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "10/10/2018"
diff --git a/src/silx/gui/plot/actions/histogram.py b/src/silx/gui/plot/actions/histogram.py
index be9f5a7..448dd55 100644
--- a/src/silx/gui/plot/actions/histogram.py
+++ b/src/silx/gui/plot/actions/histogram.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -31,8 +30,6 @@ The following QAction are available:
- :class:`PixelIntensitiesHistoAction`
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__date__ = "01/12/2020"
__license__ = "MIT"
@@ -64,7 +61,7 @@ class _ElidedLabel(ElidedLabel):
def sizeHint(self):
hint = super().sizeHint()
- nbchar = max(len(self.getText()), 12)
+ nbchar = max(len(self.text()), 12)
width = self.fontMetrics().boundingRect('#' * nbchar).width()
return qt.QSize(max(hint.width(), width), hint.height())
diff --git a/src/silx/gui/plot/actions/io.py b/src/silx/gui/plot/actions/io.py
index 7f4edd3..6cdd4d0 100644
--- a/src/silx/gui/plot/actions/io.py
+++ b/src/silx/gui/plot/actions/io.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -33,8 +32,6 @@ The following QAction are available:
- :class:`SaveAction`
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "25/09/2020"
diff --git a/src/silx/gui/plot/actions/medfilt.py b/src/silx/gui/plot/actions/medfilt.py
index f86a377..25fcdb2 100644
--- a/src/silx/gui/plot/actions/medfilt.py
+++ b/src/silx/gui/plot/actions/medfilt.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
@@ -34,8 +33,6 @@ The following QAction are available:
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"]
__license__ = "MIT"
diff --git a/src/silx/gui/plot/actions/mode.py b/src/silx/gui/plot/actions/mode.py
index ee05256..7edc8bb 100644
--- a/src/silx/gui/plot/actions/mode.py
+++ b/src/silx/gui/plot/actions/mode.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
@@ -32,8 +31,6 @@ The following QAction are available:
- :class:`PanModeAction`
"""
-from __future__ import division
-
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "16/08/2017"
diff --git a/src/silx/gui/plot/backends/BackendBase.py b/src/silx/gui/plot/backends/BackendBase.py
index 1e86807..d7653f3 100755
--- a/src/silx/gui/plot/backends/BackendBase.py
+++ b/src/silx/gui/plot/backends/BackendBase.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -507,8 +506,10 @@ class BackendBase(object):
"""Convert a position in data space to a position in pixels
in the widget.
- :param float x: The X coordinate in data space.
- :param float y: The Y coordinate in data space.
+ :param x: The X coordinate in data space.
+ :type x: float or sequence of float
+ :param y: The Y coordinate in data space.
+ :type y: float or sequence of float
:param str axis: The Y axis to use for the conversion
('left' or 'right').
:returns: The corresponding position in pixels or
diff --git a/src/silx/gui/plot/backends/BackendMatplotlib.py b/src/silx/gui/plot/backends/BackendMatplotlib.py
index 7fe4ec0..8610ed1 100755
--- a/src/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/src/silx/gui/plot/backends/BackendMatplotlib.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Matplotlib Plot backend."""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent, H. Payno"]
__license__ = "MIT"
__date__ = "21/12/2018"
@@ -33,7 +30,7 @@ __date__ = "21/12/2018"
import logging
import datetime as dt
-from typing import Tuple
+from typing import Tuple, Union
import numpy
from pkg_resources import parse_version as _parse_version
@@ -64,6 +61,7 @@ from . import BackendBase
from .. import items
from .._utils import FLOAT32_MINPOS
from .._utils.dtime_ticklayout import calcTicks, bestFormatString, timestamp
+from ...qt import inspect as qt_inspect
_PATCH_LINESTYLE = {
"-": 'solid',
@@ -166,8 +164,13 @@ class NiceDateLocator(Locator):
vmin, vmax = vmax, vmin
# vmin and vmax should be timestamps (i.e. seconds since 1 Jan 1970)
- dtMin = dt.datetime.fromtimestamp(vmin, tz=self.tz)
- dtMax = dt.datetime.fromtimestamp(vmax, tz=self.tz)
+ try:
+ dtMin = dt.datetime.fromtimestamp(vmin, tz=self.tz)
+ dtMax = dt.datetime.fromtimestamp(vmax, tz=self.tz)
+ except ValueError:
+ _logger.warning("Data range cannot be displayed with time axis")
+ return []
+
dtTicks, self._spacing, self._unit = \
calcTicks(dtMin, dtMax, self.numTicks)
@@ -1220,7 +1223,11 @@ class BackendMatplotlib(BackendBase.BackendBase):
"""Compatibility wrapper for devicePixelRatioF"""
return 1.
- def _mplToQtPosition(self, x: float, y: float) -> Tuple[float, float]:
+ def _mplToQtPosition(
+ self,
+ x: Union[float,numpy.ndarray],
+ y: Union[float,numpy.ndarray]
+ ) -> Tuple[Union[float,numpy.ndarray], Union[float,numpy.ndarray]]:
"""Convert matplotlib "display" space coord to Qt widget logical pixel
"""
ratio = self._getDevicePixelRatio()
@@ -1238,7 +1245,8 @@ class BackendMatplotlib(BackendBase.BackendBase):
def dataToPixel(self, x, y, axis):
ax = self.ax2 if axis == "right" else self.ax
- displayPos = ax.transData.transform_point((x, y)).transpose()
+ points = numpy.transpose((x, y))
+ displayPos = ax.transData.transform(points).transpose()
return self._mplToQtPosition(*displayPos)
def pixelToData(self, x, y, axis):
@@ -1325,7 +1333,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
self._synchronizeForegroundColors()
-class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
+class BackendMatplotlibQt(BackendMatplotlib, FigureCanvasQTAgg):
"""QWidget matplotlib backend using a QtAgg canvas.
It adds fast overlay drawing and mouse event management.
@@ -1516,6 +1524,10 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
self._drawOverlays()
def replot(self):
+ if not qt_inspect.isValid(self):
+ _logger.info("replot requested but widget no longer exists")
+ return
+
with self._plot._paintContext():
BackendMatplotlib._replot(self)
diff --git a/src/silx/gui/plot/backends/BackendOpenGL.py b/src/silx/gui/plot/backends/BackendOpenGL.py
index f1a12af..d7e8346 100755
--- a/src/silx/gui/plot/backends/BackendOpenGL.py
+++ b/src/silx/gui/plot/backends/BackendOpenGL.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +23,6 @@
# ############################################################################*/
"""OpenGL Plot backend."""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "21/12/2018"
@@ -196,7 +193,7 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
So, the caller should not modify these arrays afterwards.
"""
- def __init__(self, plot, parent=None, f=qt.Qt.WindowFlags()):
+ def __init__(self, plot, parent=None, f=qt.Qt.Widget):
glu.OpenGLWidget.__init__(self, parent,
alphaBufferSize=8,
depthBufferSize=0,
@@ -205,6 +202,8 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
f=f)
BackendBase.BackendBase.__init__(self, plot, parent)
+ self.__isOpenGLValid = False
+
self._backgroundColor = 1., 1., 1., 1.
self._dataBackgroundColor = 1., 1., 1., 1.
@@ -236,7 +235,11 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# QWidget
- _MOUSE_BTNS = {1: 'left', 2: 'right', 4: 'middle'}
+ _MOUSE_BTNS = {
+ qt.Qt.LeftButton: 'left',
+ qt.Qt.RightButton: 'right',
+ qt.Qt.MiddleButton: 'middle',
+ }
def sizeHint(self):
return qt.QSize(8 * 80, 6 * 80) # Mimic MatplotlibBackend
@@ -244,12 +247,12 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
def mousePressEvent(self, event):
if event.button() not in self._MOUSE_BTNS:
return super(BackendOpenGL, self).mousePressEvent(event)
- self._plot.onMousePress(
- event.x(), event.y(), self._MOUSE_BTNS[event.button()])
+ x, y = qt.getMouseEventPosition(event)
+ self._plot.onMousePress(x, y, self._MOUSE_BTNS[event.button()])
event.accept()
def mouseMoveEvent(self, event):
- qtPos = event.x(), event.y()
+ qtPos = qt.getMouseEventPosition(event)
previousMousePosInPixels = self._mousePosInPixels
if qtPos == self._mouseInPlotArea(*qtPos):
@@ -270,17 +273,14 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
def mouseReleaseEvent(self, event):
if event.button() not in self._MOUSE_BTNS:
return super(BackendOpenGL, self).mouseReleaseEvent(event)
- self._plot.onMouseRelease(
- event.x(), event.y(), self._MOUSE_BTNS[event.button()])
+ x, y = qt.getMouseEventPosition(event)
+ self._plot.onMouseRelease(x, y, self._MOUSE_BTNS[event.button()])
event.accept()
def wheelEvent(self, event):
delta = event.angleDelta().y()
angleInDegrees = delta / 8.
- if qt.BINDING == "PySide6":
- x, y = event.position().x(), event.position().y()
- else:
- x, y = event.x(), event.y()
+ x, y = qt.getMouseEventPosition(event)
self._plot.onMouseWheel(x, y, angleInDegrees)
event.accept()
@@ -290,7 +290,9 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# OpenGLWidget API
def initializeGL(self):
- gl.testGL()
+ self.__isOpenGLValid = gl.testGL()
+ if not self.__isOpenGLValid:
+ return
gl.glClearStencil(0)
@@ -379,6 +381,9 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
self._renderOverlayGL()
def paintGL(self):
+ if not self.__isOpenGLValid:
+ return
+
plot = self._plotRef()
if plot is None:
return
@@ -422,7 +427,11 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
pixelOffset = 3
context = glutils.RenderContext(
- isXLog=isXLog, isYLog=isYLog, dpi=self.getDotsPerInch())
+ isXLog=isXLog,
+ isYLog=isYLog,
+ dpi=self.getDotsPerInch(),
+ plotFrame=self._plotFrame,
+ )
for plotItem in self.getItemsFromBackToFront(
condition=lambda i: i.isVisible() and i.isOverlay() == overlay):
@@ -526,7 +535,7 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
color = item['color']
intensity = color[0] * 0.299 + color[1] * 0.587 + color[2] * 0.114
- bgColor = (1., 1., 1., 0.5) if intensity <= 0.5 else (0., 0., 0., 0.5)
+ bgColor = (1., 1., 1., 0.75) if intensity <= 0.5 else (0., 0., 0., 0.75)
if xCoord is None or yCoord is None:
if xCoord is None: # Horizontal line in data space
pixelPos = self._plotFrame.dataToPixel(
@@ -612,20 +621,15 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# For now simple implementation: using a curve for each marker
# Should pack all markers to a single set of points
- markerCurve = glutils.GLPlotCurve2D(
- numpy.array((pixelPos[0],), dtype=numpy.float64),
- numpy.array((pixelPos[1],), dtype=numpy.float64),
+ marker = glutils.Points2D(
+ (pixelPos[0],),
+ (pixelPos[1],),
marker=item['symbol'],
- markerColor=item['color'],
- markerSize=11)
-
- context = glutils.RenderContext(
- matrix=self.matScreenProj,
- isXLog=False,
- isYLog=False,
- dpi=self.getDotsPerInch())
- markerCurve.render(context)
- markerCurve.discard()
+ color=item['color'],
+ size=11,
+ )
+ context.matrix = self.matScreenProj
+ marker.render(context)
else:
_logger.error('Unsupported item: %s', str(item))
diff --git a/src/silx/gui/plot/backends/__init__.py b/src/silx/gui/plot/backends/__init__.py
index 966d9df..d75a943 100644
--- a/src/silx/gui/plot/backends/__init__.py
+++ b/src/silx/gui/plot/backends/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/backends/glutils/GLPlotCurve.py b/src/silx/gui/plot/backends/glutils/GLPlotCurve.py
index e4667b4..65bb6f0 100644
--- a/src/silx/gui/plot/backends/glutils/GLPlotCurve.py
+++ b/src/silx/gui/plot/backends/glutils/GLPlotCurve.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,8 +25,6 @@
This module provides classes to render 2D lines and scatter plots
"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "03/04/2017"
@@ -303,7 +300,7 @@ class GLLines2D(object):
#version 120
uniform mat4 matrix;
- uniform vec2 halfViewportSize;
+ uniform float distanceScale;
attribute float xPos;
attribute float yPos;
attribute vec4 color;
@@ -314,11 +311,7 @@ class GLLines2D(object):
void main(void) {
gl_Position = matrix * vec4(xPos, yPos, 0., 1.);
- //Estimate distance in pixels
- vec2 probe = vec2(matrix * vec4(1., 1., 0., 0.)) *
- halfViewportSize;
- float pixelPerDataEstimate = length(probe)/sqrt(2.);
- vDist = distance * pixelPerDataEstimate;
+ vDist = distance * distanceScale;
vColor = color;
}
""",
@@ -427,10 +420,6 @@ class GLLines2D(object):
program = self._DASH_PROGRAM
program.use()
- x, y, viewWidth, viewHeight = gl.glGetFloatv(gl.GL_VIEWPORT)
- gl.glUniform2f(program.uniforms['halfViewportSize'],
- 0.5 * viewWidth, 0.5 * viewHeight)
-
dashPeriod = self.dashPeriod * width
if self.style == DOTTED:
dash = (0.2 * dashPeriod,
@@ -457,6 +446,13 @@ class GLLines2D(object):
dash2ndColor = self.dash2ndColor
gl.glUniform4f(program.uniforms['dash2ndColor'], *dash2ndColor)
+ viewWidth = gl.glGetFloatv(gl.GL_VIEWPORT)[2]
+ xNDCPerData = (
+ numpy.dot(context.matrix, [1., 0., 0., 1.])[0] -
+ numpy.dot(context.matrix, [0., 0., 0., 1.])[0])
+ xPixelPerData = 0.5 * viewWidth * xNDCPerData
+ gl.glUniform1f(program.uniforms['distanceScale'], xPixelPerData)
+
distAttrib = program.attributes['distance']
gl.glEnableVertexAttribArray(distAttrib)
if isinstance(self.distVboData, VertexBufferAttrib):
@@ -515,11 +511,12 @@ class GLLines2D(object):
gl.glDisable(gl.GL_LINE_SMOOTH)
-def distancesFromArrays(xData, yData):
+def distancesFromArrays(xData, yData, ratio: float=1.):
"""Returns distances between each points
:param numpy.ndarray xData: X coordinate of points
:param numpy.ndarray yData: Y coordinate of points
+ :param ratio: Y/X pixel per data resolution ratio
:rtype: numpy.ndarray
"""
# Split array into sub-shapes at not finite points
@@ -534,11 +531,11 @@ def distancesFromArrays(xData, yData):
if begin == end: # Empty shape
continue
elif end - begin == 1: # Single element
- distances.append([0])
+ distances.append(numpy.array([0], dtype=numpy.float32))
else:
deltas = numpy.dstack((
numpy.ediff1d(xData[begin:end], to_begin=numpy.float32(0.)),
- numpy.ediff1d(yData[begin:end], to_begin=numpy.float32(0.))))[0]
+ numpy.ediff1d(yData[begin:end] * ratio, to_begin=numpy.float32(0.))))[0]
distances.append(
numpy.cumsum(numpy.sqrt(numpy.sum(deltas ** 2, axis=1))))
return numpy.concatenate(distances)
@@ -561,7 +558,7 @@ CARET_UP = "caretup"
CARET_DOWN = "caretdown"
-class _Points2D(object):
+class Points2D(object):
"""Object rendering curve markers
:param xVboData: X coordinates VBO
@@ -809,8 +806,18 @@ class _Points2D(object):
self.size = size
self.offset = offset
+ if (xVboData is not None and
+ not isinstance(xVboData, VertexBufferAttrib)):
+ xVboData = numpy.array(xVboData, copy=False, dtype=numpy.float32)
self.xVboData = xVboData
+
+ if (yVboData is not None and
+ not isinstance(yVboData, VertexBufferAttrib)):
+ yVboData = numpy.array(yVboData, copy=False, dtype=numpy.float32)
self.yVboData = yVboData
+
+ if colorVboData is not None:
+ assert isinstance(colorVboData, VertexBufferAttrib)
self.colorVboData = colorVboData
self.useColorVboData = colorVboData is not None
@@ -894,18 +901,33 @@ class _Points2D(object):
gl.glDisableVertexAttribArray(cAttrib)
gl.glVertexAttrib4f(cAttrib, *self.color)
- xAttrib = program.attributes['xPos']
- gl.glEnableVertexAttribArray(xAttrib)
- self.xVboData.setVertexAttrib(xAttrib)
+ xPosAttrib = program.attributes['xPos']
+ gl.glEnableVertexAttribArray(xPosAttrib)
+ if isinstance(self.xVboData, VertexBufferAttrib):
+ self.xVboData.setVertexAttrib(xPosAttrib)
+ else:
+ gl.glVertexAttribPointer(xPosAttrib,
+ 1,
+ gl.GL_FLOAT,
+ False,
+ 0,
+ self.xVboData)
+
+ yPosAttrib = program.attributes['yPos']
+ gl.glEnableVertexAttribArray(yPosAttrib)
+ if isinstance(self.yVboData, VertexBufferAttrib):
+ self.yVboData.setVertexAttrib(yPosAttrib)
+ else:
+ gl.glVertexAttribPointer(yPosAttrib,
+ 1,
+ gl.GL_FLOAT,
+ False,
+ 0,
+ self.yVboData)
- yAttrib = program.attributes['yPos']
- gl.glEnableVertexAttribArray(yAttrib)
- self.yVboData.setVertexAttrib(yAttrib)
gl.glDrawArrays(gl.GL_POINTS, 0, self.xVboData.size)
- gl.glUseProgram(0)
-
# error bars ##################################################################
@@ -959,9 +981,9 @@ class _ErrorBars(object):
self._lines = GLLines2D(
None, None, color=color, drawMode=gl.GL_LINES, offset=offset)
- self._xErrPoints = _Points2D(
+ self._xErrPoints = Points2D(
None, None, color=color, marker=V_LINE, offset=offset)
- self._yErrPoints = _Points2D(
+ self._yErrPoints = Points2D(
None, None, color=color, marker=H_LINE, offset=offset)
def _buildVertices(self):
@@ -1117,6 +1139,7 @@ class GLPlotCurve2D(GLPlotItem):
baseline=None,
isYLog=False):
super().__init__()
+ self._ratio = None
self.colorData = colorData
# Compute x bounds
@@ -1192,7 +1215,7 @@ class GLPlotCurve2D(GLPlotItem):
self.lines.dashPeriod = lineDashPeriod
self.lines.offset = self.offset
- self.points = _Points2D()
+ self.points = Points2D()
self.points.marker = marker
self.points.color = markerColor
self.points.size = markerSize
@@ -1228,14 +1251,14 @@ class GLPlotCurve2D(GLPlotItem):
def init(cls):
"""OpenGL context initialization"""
GLLines2D.init()
- _Points2D.init()
+ Points2D.init()
def prepare(self):
"""Rendering preparation: build indices and bounding box vertices"""
if self.xVboData is None:
xAttrib, yAttrib, cAttrib, dAttrib = None, None, None, None
if self.lineStyle in (DASHED, DASHDOT, DOTTED):
- dists = distancesFromArrays(self.xData, self.yData)
+ dists = distancesFromArrays(self.xData, self.yData, self._ratio)
if self.colorData is None:
xAttrib, yAttrib, dAttrib = vertexBuffer(
(self.xData, self.yData, dists))
@@ -1262,6 +1285,17 @@ class GLPlotCurve2D(GLPlotItem):
:param RenderContext context: Rendering information
"""
+ if self.lineStyle in (DASHED, DASHDOT, DOTTED):
+ visibleRanges = context.plotFrame.transformedDataRanges
+ xLimits = visibleRanges.x
+ yLimits = visibleRanges.y if self.yaxis == 'left' else visibleRanges.y2
+ width, height = context.plotFrame.plotSize
+ ratio = (height * (xLimits[1] - xLimits[0])) / (width * (yLimits[1] - yLimits[0]))
+ if self._ratio is None or abs(1. - ratio/self._ratio) > 0.05: # Tolerate 5% difference
+ # Rebuild curve buffers to update distances
+ self._ratio = ratio
+ self.discard()
+
self.prepare()
if self.fill is not None:
self.fill.render(context)
diff --git a/src/silx/gui/plot/backends/glutils/GLPlotFrame.py b/src/silx/gui/plot/backends/glutils/GLPlotFrame.py
index 1fccb02..e5fabf2 100644
--- a/src/silx/gui/plot/backends/glutils/GLPlotFrame.py
+++ b/src/silx/gui/plot/backends/glutils/GLPlotFrame.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2014-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +38,8 @@ import datetime as dt
import math
import weakref
import logging
+import numbers
+from typing import Optional, Union
from collections import namedtuple
import numpy
@@ -358,8 +359,12 @@ class PlotAxis(object):
yield ((xPixel, yPixel), dataPos, text)
else:
# Time series
- dtMin = dt.datetime.fromtimestamp(dataMin, tz=self.timeZone)
- dtMax = dt.datetime.fromtimestamp(dataMax, tz=self.timeZone)
+ try:
+ dtMin = dt.datetime.fromtimestamp(dataMin, tz=self.timeZone)
+ dtMax = dt.datetime.fromtimestamp(dataMax, tz=self.timeZone)
+ except ValueError:
+ _logger.warning("Data range cannot be displayed with time axis")
+ return # Range is out of bound of the datetime
tickDateTimes, spacing, unit = calcTicksAdaptive(
dtMin, dtMax, nbPixels, tickDensity)
@@ -984,6 +989,26 @@ class GLPlotFrame2D(GLPlotFrame):
return self._transformedDataY2ProjMat
+ @staticmethod
+ def __applyLog(
+ data: Union[float, numpy.ndarray],
+ isLog: bool
+ ) -> Optional[Union[float, numpy.ndarray]]:
+ """Apply log to data filtering out """
+ if not isLog:
+ return data
+
+ if isinstance(data, numbers.Real):
+ return None if data < FLOAT32_MINPOS else math.log10(data)
+
+ isBelowMin = data < FLOAT32_MINPOS
+ if numpy.any(isBelowMin):
+ data = numpy.array(data, copy=True, dtype=numpy.float64)
+ data[isBelowMin] = numpy.nan
+
+ with numpy.errstate(divide='ignore'):
+ return numpy.log10(data)
+
def dataToPixel(self, x, y, axis='left'):
"""Convert data coordinate to widget pixel coordinate.
"""
@@ -991,19 +1016,13 @@ class GLPlotFrame2D(GLPlotFrame):
trBounds = self.transformedDataRanges
- if self.xAxis.isLog:
- if x < FLOAT32_MINPOS:
- return None
- xDataTr = math.log10(x)
- else:
- xDataTr = x
+ xDataTr = self.__applyLog(x, self.xAxis.isLog)
+ if xDataTr is None:
+ return None
- if self.yAxis.isLog:
- if y < FLOAT32_MINPOS:
- return None
- yDataTr = math.log10(y)
- else:
- yDataTr = y
+ yDataTr = self.__applyLog(y, self.yAxis.isLog)
+ if yDataTr is None:
+ return None
# Non-orthogonal axes
if self.baseVectors != self.DEFAULT_BASE_VECTORS:
@@ -1015,20 +1034,23 @@ class GLPlotFrame2D(GLPlotFrame):
plotWidth, plotHeight = self.plotSize
- xPixel = int(self.margins.left +
- plotWidth * (xDataTr - trBounds.x[0]) /
- (trBounds.x[1] - trBounds.x[0]))
+ xPixel = (self.margins.left +
+ plotWidth * (xDataTr - trBounds.x[0]) /
+ (trBounds.x[1] - trBounds.x[0]))
usedAxis = trBounds.y if axis == "left" else trBounds.y2
yOffset = (plotHeight * (yDataTr - usedAxis[0]) /
(usedAxis[1] - usedAxis[0]))
if self.isYAxisInverted:
- yPixel = int(self.margins.top + yOffset)
+ yPixel = self.margins.top + yOffset
else:
- yPixel = int(self.size[1] - self.margins.bottom - yOffset)
+ yPixel = self.size[1] - self.margins.bottom - yOffset
- return xPixel, yPixel
+ return (
+ int(xPixel) if isinstance(xPixel, numbers.Real) else xPixel.astype(numpy.int64),
+ int(yPixel) if isinstance(yPixel, numbers.Real) else yPixel.astype(numpy.int64),
+ )
def pixelToData(self, x, y, axis="left"):
"""Convert pixel position to data coordinates.
diff --git a/src/silx/gui/plot/backends/glutils/GLPlotImage.py b/src/silx/gui/plot/backends/glutils/GLPlotImage.py
index 3ad94b9..8353911 100644
--- a/src/silx/gui/plot/backends/glutils/GLPlotImage.py
+++ b/src/silx/gui/plot/backends/glutils/GLPlotImage.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2021 European Synchrotron Radiation Facility
@@ -159,6 +158,7 @@ class GLPlotColormap(_GLPlotData2D):
}
uniform sampler2D data;
+ uniform float data_scale;
uniform sampler2D cmap_texture;
uniform int cmap_normalization;
uniform float cmap_parameter;
@@ -174,35 +174,35 @@ class GLPlotColormap(_GLPlotData2D):
const float oneOverLog10 = 0.43429448190325176;
void main(void) {
- float data = texture2D(data, textureCoords()).r;
- float value = data;
+ float raw_data = texture2D(data, textureCoords()).r * data_scale;
+ float value = 0.;
if (cmap_normalization == 1) { /*Logarithm mapping*/
- if (value > 0.) {
+ if (raw_data > 0.) {
value = clamp(cmap_oneOverRange *
- (oneOverLog10 * log(value) - cmap_min),
+ (oneOverLog10 * log(raw_data) - cmap_min),
0., 1.);
} else {
value = 0.;
}
} else if (cmap_normalization == 2) { /*Square root mapping*/
- if (value >= 0.) {
- value = clamp(cmap_oneOverRange * (sqrt(value) - cmap_min),
+ if (raw_data >= 0.) {
+ value = clamp(cmap_oneOverRange * (sqrt(raw_data) - cmap_min),
0., 1.);
} else {
value = 0.;
}
} else if (cmap_normalization == 3) { /*Gamma correction mapping*/
value = pow(
- clamp(cmap_oneOverRange * (value - cmap_min), 0., 1.),
+ clamp(cmap_oneOverRange * (raw_data - cmap_min), 0., 1.),
cmap_parameter);
} else if (cmap_normalization == 4) { /* arcsinh mapping */
/* asinh = log(x + sqrt(x*x + 1) for compatibility with GLSL 1.20 */
- value = clamp(cmap_oneOverRange * (log(value + sqrt(value*value + 1.0)) - cmap_min), 0., 1.);
+ value = clamp(cmap_oneOverRange * (log(raw_data + sqrt(raw_data*raw_data + 1.0)) - cmap_min), 0., 1.);
} else { /*Linear mapping and fallback*/
- value = clamp(cmap_oneOverRange * (value - cmap_min), 0., 1.);
+ value = clamp(cmap_oneOverRange * (raw_data - cmap_min), 0., 1.);
}
- if (isnan(data)) {
+ if (isnan(raw_data)) {
gl_FragColor = nancolor;
} else {
gl_FragColor = texture2D(cmap_texture, vec2(value, 0.5));
@@ -355,9 +355,10 @@ class GLPlotColormap(_GLPlotData2D):
if self.data.dtype in (numpy.uint16, numpy.uint8):
# Using unsigned int as normalized integer in OpenGL
- # So normalize range
- maxInt = float(numpy.iinfo(self.data.dtype).max)
- dataMin, dataMax = dataMin / maxInt, dataMax / maxInt
+ # So revert normalization in the shader
+ dataScale = float(numpy.iinfo(self.data.dtype).max)
+ else:
+ dataScale = 1.
if self.normalization == 'log':
dataMin = math.log10(dataMin)
@@ -378,6 +379,7 @@ class GLPlotColormap(_GLPlotData2D):
else: # Linear and fallback
normID = 0
+ gl.glUniform1f(prog.uniforms['data_scale'], dataScale)
gl.glUniform1i(prog.uniforms['cmap_texture'],
self._cmap_texture.texUnit)
gl.glUniform1i(prog.uniforms['cmap_normalization'], normID)
diff --git a/src/silx/gui/plot/backends/glutils/GLPlotItem.py b/src/silx/gui/plot/backends/glutils/GLPlotItem.py
index ae13091..58f5f41 100644
--- a/src/silx/gui/plot/backends/glutils/GLPlotItem.py
+++ b/src/silx/gui/plot/backends/glutils/GLPlotItem.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2020-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2020-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -40,13 +39,14 @@ class RenderContext:
:param float dpi: Number of device pixels per inch
"""
- def __init__(self, matrix=None, isXLog=False, isYLog=False, dpi=96.):
+ def __init__(self, matrix=None, isXLog=False, isYLog=False, dpi=96., plotFrame=None):
self.matrix = matrix
"""Current transformation matrix"""
self.__isXLog = isXLog
self.__isYLog = isYLog
self.__dpi = dpi
+ self.__plotFrame = plotFrame
@property
def isXLog(self):
@@ -63,6 +63,11 @@ class RenderContext:
"""Number of device pixels per inch"""
return self.__dpi
+ @property
+ def plotFrame(self):
+ """Current PlotFrame"""
+ return self.__plotFrame
+
class GLPlotItem:
"""Base class for primitives used in the PlotWidget OpenGL backend"""
diff --git a/src/silx/gui/plot/backends/glutils/GLPlotTriangles.py b/src/silx/gui/plot/backends/glutils/GLPlotTriangles.py
index fbe9e02..a67afd9 100644
--- a/src/silx/gui/plot/backends/glutils/GLPlotTriangles.py
+++ b/src/silx/gui/plot/backends/glutils/GLPlotTriangles.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/backends/glutils/GLSupport.py b/src/silx/gui/plot/backends/glutils/GLSupport.py
index da6dffa..f5357e2 100644
--- a/src/silx/gui/plot/backends/glutils/GLSupport.py
+++ b/src/silx/gui/plot/backends/glutils/GLSupport.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/backends/glutils/GLText.py b/src/silx/gui/plot/backends/glutils/GLText.py
index d6ae6fa..4862bff 100644
--- a/src/silx/gui/plot/backends/glutils/GLText.py
+++ b/src/silx/gui/plot/backends/glutils/GLText.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
@@ -241,7 +240,7 @@ class Text2D(object):
return vertices
def render(self, matrix):
- if not self.text:
+ if not self.text.strip():
return
prog = self._program
diff --git a/src/silx/gui/plot/backends/glutils/GLTexture.py b/src/silx/gui/plot/backends/glutils/GLTexture.py
index 37fbdd0..caca111 100644
--- a/src/silx/gui/plot/backends/glutils/GLTexture.py
+++ b/src/silx/gui/plot/backends/glutils/GLTexture.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/backends/glutils/PlotImageFile.py b/src/silx/gui/plot/backends/glutils/PlotImageFile.py
index 5fb6853..75ee50b 100644
--- a/src/silx/gui/plot/backends/glutils/PlotImageFile.py
+++ b/src/silx/gui/plot/backends/glutils/PlotImageFile.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/backends/glutils/__init__.py b/src/silx/gui/plot/backends/glutils/__init__.py
index f87d7c1..bc15b78 100644
--- a/src/silx/gui/plot/backends/glutils/__init__.py
+++ b/src/silx/gui/plot/backends/glutils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/__init__.py b/src/silx/gui/plot/items/__init__.py
index 0fe29c2..6e26c64 100644
--- a/src/silx/gui/plot/items/__init__.py
+++ b/src/silx/gui/plot/items/__init__.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -42,7 +41,7 @@ from .curve import Curve, CurveStyle # noqa
from .histogram import Histogram # noqa
from .image import ImageBase, ImageData, ImageDataBase, ImageRgba, ImageStack, MaskImageData # noqa
from .image_aggregated import ImageDataAggregated # noqa
-from .shape import Shape, BoundingRect, XAxisExtent, YAxisExtent # noqa
+from .shape import Line, Shape, BoundingRect, XAxisExtent, YAxisExtent # noqa
from .scatter import Scatter # noqa
from .marker import MarkerBase, Marker, XMarker, YMarker # noqa
from .axis import Axis, XAxis, YAxis, YRightAxis
diff --git a/src/silx/gui/plot/items/_arc_roi.py b/src/silx/gui/plot/items/_arc_roi.py
index 23416ec..40711b7 100644
--- a/src/silx/gui/plot/items/_arc_roi.py
+++ b/src/silx/gui/plot/items/_arc_roi.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2018-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -635,7 +634,9 @@ class ArcROI(HandleBasedROI, items.LineMixIn, InteractionModeMixIn):
innerRadius = geometry.radius - geometry.weight * 0.5
outerRadius = geometry.radius + geometry.weight * 0.5
- delta = 0.1 if geometry.endAngle >= geometry.startAngle else -0.1
+ sign = numpy.sign(geometry.endAngle - geometry.startAngle)
+ delta = min(0.1, abs(geometry.startAngle - geometry.endAngle) / 100) * sign
+
if geometry.startAngle == geometry.endAngle:
# Degenerated, it's a line (single radius)
angle = geometry.startAngle
@@ -654,7 +655,6 @@ class ArcROI(HandleBasedROI, items.LineMixIn, InteractionModeMixIn):
points = []
points.append(geometry.center)
points.append(geometry.startPoint)
- delta = 0.1 if geometry.endAngle >= geometry.startAngle else -0.1
for angle in angles:
direction = numpy.array([numpy.cos(angle), numpy.sin(angle)])
points.append(geometry.center + direction * outerRadius)
diff --git a/src/silx/gui/plot/items/_band_roi.py b/src/silx/gui/plot/items/_band_roi.py
new file mode 100644
index 0000000..a60a177
--- /dev/null
+++ b/src/silx/gui/plot/items/_band_roi.py
@@ -0,0 +1,370 @@
+# /*##########################################################################
+#
+# Copyright (c) 2022 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""Rectangular ROI that can be rotated"""
+
+import functools
+import logging
+from typing import Iterable, List, NamedTuple, Optional, Sequence, Tuple
+import numpy
+
+from ... import qt, utils
+from .. import items
+from ...colors import rgba
+from silx.image.shapes import Polygon
+from ....utils.proxy import docstring
+from ._roi_base import _RegionOfInterestBase
+from ._roi_base import HandleBasedROI
+from ._roi_base import InteractionModeMixIn
+from ._roi_base import RoiInteractionMode
+
+
+logger = logging.getLogger(__name__)
+
+
+class Point(NamedTuple):
+ x: float
+ y: float
+
+
+class BandGeometry(NamedTuple):
+ begin: Point
+ end: Point
+ width: float
+
+ @staticmethod
+ def create(
+ begin: Sequence[float] = (0.0, 0.0),
+ end: Sequence[float] = (0.0, 0.0),
+ width: Optional[float] = None,
+ ):
+ begin = Point(float(begin[0]), float(begin[1]))
+ end = Point(float(end[0]), float(end[1]))
+ if width is None:
+ width = 0.1 * numpy.linalg.norm(numpy.array(end) - begin)
+ return BandGeometry(begin, end, max(0.0, float(width)))
+
+ @property
+ @functools.lru_cache()
+ def normal(self) -> Point:
+ vector = numpy.array(self.end) - self.begin
+ length = numpy.linalg.norm(vector)
+ if length == 0:
+ return Point(0.0, 0.0)
+ return Point(-vector[1] / length, vector[0] / length)
+
+ @property
+ @functools.lru_cache()
+ def center(self) -> Point:
+ return Point(*(0.5 * (numpy.array(self.begin) + self.end)))
+
+ @property
+ @functools.lru_cache()
+ def corners(self) -> Tuple[Point, Point, Point, Point]:
+ """Returns a 4-uple of (x,y) position in float"""
+ offset = 0.5 * self.width * numpy.array(self.normal)
+ return tuple(
+ map(
+ lambda p: Point(*p),
+ (
+ self.begin - offset,
+ self.begin + offset,
+ self.end + offset,
+ self.end - offset,
+ ),
+ )
+ )
+
+ @property
+ @functools.lru_cache()
+ def slope(self) -> float:
+ """Slope of the line (begin, end), infinity for a vertical line"""
+ if self.begin.x == self.end.x:
+ return float('inf')
+ return (self.end.y - self.begin.y) / (self.end.x - self.begin.x)
+
+ @property
+ @functools.lru_cache()
+ def intercept(self) -> float:
+ """Intercept of the line (begin, end) or value of x for vertical line"""
+ if self.begin.x == self.end.x:
+ return self.begin.x
+ return self.begin.y - self.slope * self.begin.x
+
+ @property
+ @functools.lru_cache()
+ def edgesIntercept(self) -> Tuple[float, float]:
+ """Intercepts of lines describing band edges"""
+ offset = 0.5 * self.width * numpy.array(self.normal)
+ if self.begin.x == self.end.x:
+ return self.begin.x - offset[0], self.begin.x + offset[0]
+ return (
+ self.begin.y - offset[1] - self.slope * (self.begin.x - offset[0]),
+ self.begin.y + offset[1] - self.slope * (self.begin.x + offset[0]),
+ )
+
+ def contains(self, position: Sequence[float]) -> bool:
+ return Polygon(self.corners).is_inside(*position)
+
+
+class BandROI(HandleBasedROI, items.LineMixIn, InteractionModeMixIn):
+ """A ROI identifying a line in a 2D plot.
+
+ This ROI provides 1 anchor for each boundary of the line, plus an center
+ in the center to translate the full ROI.
+ """
+
+ ICON = "add-shape-rotated-rectangle"
+ NAME = "band ROI"
+ SHORT_NAME = "band"
+ """Metadata for this kind of ROI"""
+
+ _plotShape = "line"
+ """Plot shape which is used for the first interaction"""
+
+ BoundedMode = RoiInteractionMode("Bounded", "Band is bounded on both sides")
+ """Interaction mode for a rectangular band ROI"""
+
+ UnboundedMode = RoiInteractionMode("Unbounded", "Band is unbounded on both sides")
+ """Interaction mode for unlimited band ROI """
+
+ def __init__(self, parent=None):
+ HandleBasedROI.__init__(self, parent=parent)
+ items.LineMixIn.__init__(self)
+ self.__availableInteractionModes = set((self.BoundedMode, self.UnboundedMode))
+ InteractionModeMixIn.__init__(self)
+
+ self.__handleBegin = self.addHandle()
+ self.__handleEnd = self.addHandle()
+ self.__handleCenter = self.addTranslateHandle()
+ self.__handleLabel = self.addLabelHandle()
+ self.__handleWidthUp = self.addHandle()
+ self.__handleWidthUp._setConstraint(self.__handleWidthUpConstraint)
+ self.__handleWidthUp.setSymbol("d")
+ self.__handleWidthDown = self.addHandle()
+ self.__handleWidthDown._setConstraint(self.__handleWidthDownConstraint)
+ self.__handleWidthDown.setSymbol("d")
+
+ self.__geometry = BandGeometry.create()
+
+ self.__lineUp = items.Line()
+ self.__lineUp.setVisible(False)
+ self.__lineMiddle = items.Line()
+ self.__lineMiddle.setLineWidth(1)
+ self.__lineMiddle.setVisible(False)
+ self.__lineDown = items.Line()
+ self.__lineDown.setVisible(False)
+
+ self.__shape = items.Shape("polygon")
+ self.__shape.setPoints(self.__geometry.corners)
+ self.__shape.setFill(False)
+
+ for item in (self.__lineUp, self.__lineMiddle, self.__lineDown, self.__shape):
+ item.setColor(rgba(self.getColor()))
+ item.setOverlay(True)
+ item.setLineStyle(self.getLineStyle())
+ if item != self.__lineMiddle:
+ item.setLineWidth(self.getLineWidth())
+ self.addItem(item)
+
+ self._initInteractionMode(self.BoundedMode)
+ self._interactiveModeUpdated(self.BoundedMode)
+
+ def availableInteractionModes(self) -> List[RoiInteractionMode]:
+ """Returns the list of available interaction modes"""
+ return list(self.__availableInteractionModes)
+
+ def setAvailableInteractionModes(self, modes: Iterable[RoiInteractionMode]) -> None:
+ """Allows to restrict interaction modes of the ROI.
+
+ :param modes: Subset of BandROI interaction modes:
+ :attr:`BoundedMode` and :attr:`UnboundedMode`.
+ """
+ modes = set(modes)
+ if not modes <= set((self.BoundedMode, self.UnboundedMode)):
+ raise ValueError("Unsupported interaction modes")
+ self.__availableInteractionModes = set(modes)
+ if self.getInteractionMode() not in self.__availableInteractionModes:
+ self.setInteractionMode(self.availableInteractionModes()[0])
+
+ def _interactiveModeUpdated(self, modeId: RoiInteractionMode):
+ """Set the interaction mode."""
+ if modeId is self.BoundedMode:
+ self.__lineDown.setVisible(False)
+ self.__lineMiddle.setVisible(False)
+ self.__lineUp.setVisible(False)
+ self.__shape.setVisible(True)
+ elif modeId is self.UnboundedMode:
+ self.__lineDown.setVisible(True)
+ self.__lineMiddle.setVisible(True)
+ self.__lineUp.setVisible(True)
+ self.__shape.setVisible(False)
+ else:
+ raise RuntimeError("Unsupported interactive mode")
+
+ def _updated(self, event=None, checkVisibility=True):
+ if event == items.ItemChangedType.VISIBLE:
+ if self.isVisible():
+ self._interactiveModeUpdated(self.getInteractionMode())
+ else:
+ self.__lineDown.setVisible(False)
+ self.__lineMiddle.setVisible(False)
+ self.__lineUp.setVisible(False)
+ self.__shape.setVisible(False)
+ super()._updated(event, checkVisibility)
+
+ def _updatedStyle(self, event, style):
+ super()._updatedStyle(event, style)
+ for item in (self.__lineUp, self.__lineMiddle, self.__lineDown, self.__shape):
+ item.setColor(style.getColor())
+ item.setLineStyle(style.getLineStyle())
+ if item != self.__lineMiddle:
+ item.setLineWidth(style.getLineWidth())
+
+ def setFirstShapePoints(self, points):
+ assert len(points) == 2
+ self.setGeometry(*points)
+
+ def _updateText(self, text):
+ self.__handleLabel.setText(text)
+
+ def getGeometry(self) -> BandGeometry:
+ """Returns the geometric description of the ROI"""
+ return self.__geometry
+
+ def setGeometry(
+ self,
+ begin: Sequence[float],
+ end: Sequence[float],
+ width: Optional[float] = None,
+ ):
+ """Set the geometry of the ROI
+
+ :param begin: Starting point as (x, y)
+ :paran end: Closing point as (x, y)
+ :param width: Width of the ROI
+ """
+ geometry = BandGeometry.create(begin, end, width)
+ if self.__geometry == geometry:
+ return
+
+ self.__geometry = geometry
+
+ with utils.blockSignals(self.__handleBegin):
+ self.__handleBegin.setPosition(*geometry.begin)
+ with utils.blockSignals(self.__handleEnd):
+ self.__handleEnd.setPosition(*geometry.end)
+ with utils.blockSignals(self.__handleCenter):
+ self.__handleCenter.setPosition(*geometry.center)
+ with utils.blockSignals(self.__handleLabel):
+ lowerCorner = geometry.corners[numpy.array(geometry.corners)[:, 1].argmin()]
+ self.__handleLabel.setPosition(*lowerCorner)
+
+ delta = 0.5 * geometry.width * numpy.array(geometry.normal)
+ with utils.blockSignals(self.__handleWidthUp):
+ self.__handleWidthUp.setPosition(*(geometry.center + delta))
+ with utils.blockSignals(self.__handleWidthDown):
+ self.__handleWidthDown.setPosition(*(geometry.center - delta))
+
+ self.__lineDown.setSlope(geometry.slope)
+ self.__lineDown.setIntercept(geometry.edgesIntercept[0])
+ self.__lineMiddle.setSlope(geometry.slope)
+ self.__lineMiddle.setIntercept(geometry.intercept)
+ self.__lineUp.setSlope(geometry.slope)
+ self.__lineUp.setIntercept(geometry.edgesIntercept[1])
+ self.__shape.setPoints(geometry.corners)
+ self.sigRegionChanged.emit()
+
+ def __updateGeometry(
+ self,
+ begin: Optional[Sequence[float]] = None,
+ end: Optional[Sequence[float]] = None,
+ width: Optional[float] = None,
+ ):
+ geometry = self.getGeometry()
+ self.setGeometry(
+ geometry.begin if begin is None else begin,
+ geometry.end if end is None else end,
+ geometry.width if width is None else width,
+ )
+
+ @staticmethod
+ def __snap(point: Tuple[float, float], fixed: Tuple[float, float]) -> Tuple[float, float]:
+ """Snap point so that vector [point, fixed] snap to direction 0, 45 or 90 degrees
+
+ :return: the snapped point position.
+ """
+ vector = point[0] - fixed[0], point[1] - fixed[1]
+ angle = numpy.arctan2(vector[1], vector[0])
+ snapAngle = numpy.pi/4 * numpy.round(angle / (numpy.pi/4))
+ length = numpy.linalg.norm(vector)
+ return (
+ fixed[0] + length * numpy.cos(snapAngle),
+ fixed[1] + length * numpy.sin(snapAngle)
+ )
+
+ def handleDragUpdated(self, handle, origin, previous, current):
+ geometry = self.getGeometry()
+ if handle is self.__handleBegin:
+ if qt.QApplication.keyboardModifiers() & qt.Qt.ShiftModifier:
+ self.__updateGeometry(begin=self.__snap(current, geometry.end))
+ return
+ self.__updateGeometry(begin=current)
+ return
+ if handle is self.__handleEnd:
+ if qt.QApplication.keyboardModifiers() & qt.Qt.ShiftModifier:
+ self.__updateGeometry(end=self.__snap(current, geometry.begin))
+ return
+ self.__updateGeometry(end=current)
+ return
+ if handle is self.__handleCenter:
+ delta = current - previous
+ self.__updateGeometry(geometry.begin + delta, geometry.end + delta)
+ return
+ if handle in (self.__handleWidthUp, self.__handleWidthDown):
+ offset = numpy.dot(geometry.normal, current - previous)
+ if handle is self.__handleWidthDown:
+ offset *= -1
+ self.__updateGeometry(
+ geometry.begin,
+ geometry.end,
+ geometry.width + 2 * offset,
+ )
+
+ def __handleWidthUpConstraint(self, x: float, y: float) -> Tuple[float, float]:
+ geometry = self.getGeometry()
+ offset = max(0, numpy.dot(geometry.normal, numpy.array((x, y)) - geometry.center))
+ return tuple(geometry.center + offset * numpy.array(geometry.normal))
+
+ def __handleWidthDownConstraint(self, x: float, y: float) -> Tuple[float, float]:
+ geometry = self.getGeometry()
+ offset = max(0, -numpy.dot(geometry.normal, numpy.array((x, y)) - geometry.center))
+ return tuple(geometry.center - offset * numpy.array(geometry.normal))
+
+ @docstring(_RegionOfInterestBase)
+ def contains(self, position):
+ return self.getGeometry().contains(position)
+
+ def __str__(self):
+ begin, end, width = self.getGeometry()
+ return f"{self.__class__.__name__}(begin=({begin[0]:g}, {begin[1]:g}), end=({end[0]:g}, {end[1]:g}), width={width:g})"
diff --git a/src/silx/gui/plot/items/_pick.py b/src/silx/gui/plot/items/_pick.py
index 8c8e781..631a30a 100644
--- a/src/silx/gui/plot/items/_pick.py
+++ b/src/silx/gui/plot/items/_pick.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/_roi_base.py b/src/silx/gui/plot/items/_roi_base.py
index 3eb6cf4..765a538 100644
--- a/src/silx/gui/plot/items/_roi_base.py
+++ b/src/silx/gui/plot/items/_roi_base.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/axis.py b/src/silx/gui/plot/items/axis.py
index c73323e..fa3f6d7 100644
--- a/src/silx/gui/plot/items/axis.py
+++ b/src/silx/gui/plot/items/axis.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -480,26 +479,10 @@ class YRightAxis(Axis):
"""
Axis.__init__(self, plot)
self.__mainAxis = mainAxis
-
- @property
- def sigInvertedChanged(self):
- """Signal emitted when axis orientation has changed"""
- return self.__mainAxis.sigInvertedChanged
-
- @property
- def sigScaleChanged(self):
- """Signal emitted when axis scale has changed"""
- return self.__mainAxis.sigScaleChanged
-
- @property
- def _sigLogarithmicChanged(self):
- """Signal emitted when axis scale has changed to or from logarithmic"""
- return self.__mainAxis._sigLogarithmicChanged
-
- @property
- def sigAutoScaleChanged(self):
- """Signal emitted when axis autoscale has changed"""
- return self.__mainAxis.sigAutoScaleChanged
+ self.__mainAxis.sigInvertedChanged.connect(self.sigInvertedChanged.emit)
+ self.__mainAxis.sigScaleChanged.connect(self.sigScaleChanged.emit)
+ self.__mainAxis._sigLogarithmicChanged.connect(self._sigLogarithmicChanged.emit)
+ self.__mainAxis.sigAutoScaleChanged.connect(self.sigAutoScaleChanged.emit)
def _internalSetCurrentLabel(self, label):
self._getBackend().setGraphYLabel(label, axis='right')
diff --git a/src/silx/gui/plot/items/complex.py b/src/silx/gui/plot/items/complex.py
index abb64ad..82d821f 100644
--- a/src/silx/gui/plot/items/complex.py
+++ b/src/silx/gui/plot/items/complex.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides the :class:`ImageComplexData` of the :class:`Plot`.
"""
-from __future__ import absolute_import
-
__authors__ = ["Vincent Favre-Nicolin", "T. Vincent"]
__license__ = "MIT"
__date__ = "14/06/2018"
diff --git a/src/silx/gui/plot/items/core.py b/src/silx/gui/plot/items/core.py
index fa3b8cf..074c168 100644
--- a/src/silx/gui/plot/items/core.py
+++ b/src/silx/gui/plot/items/core.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -37,8 +36,7 @@ except ImportError: # Python2 support
from copy import deepcopy
import logging
import enum
-from typing import Optional, Tuple
-import warnings
+from typing import Optional, Tuple, Union
import weakref
import numpy
@@ -244,6 +242,8 @@ class Item(qt.QObject):
# When visibility has changed, always mark as dirty
self._updated(ItemChangedType.VISIBLE,
checkVisibility=False)
+ if visible:
+ self._visibleBoundsChanged()
def isOverlay(self):
"""Return true if item is drawn as an overlay.
@@ -492,7 +492,8 @@ class DataItem(Item):
:param bool checkVisibility:
"""
if not checkVisibility or self.isVisible():
- self._visibleBoundsChanged()
+ if self.isVisible():
+ self._visibleBoundsChanged()
# TODO hackish data range implementation
plot = self.getPlot()
@@ -1479,6 +1480,31 @@ class PointsBase(DataItem, SymbolMixIn, AlphaMixIn):
return x, y, xerror, yerror
+ @staticmethod
+ def __minMaxDataWithError(
+ data: numpy.ndarray,
+ error: Optional[Union[float, numpy.ndarray]],
+ positiveOnly: bool
+ ) -> Tuple[float]:
+ if error is None:
+ min_, max_ = min_max(data, finite=True)
+ return min_, max_
+
+ # float, 1D or 2D array
+ dataMinusError = data - numpy.atleast_2d(error)[0]
+ dataMinusError = dataMinusError[numpy.isfinite(dataMinusError)]
+ if positiveOnly:
+ dataMinusError = dataMinusError[dataMinusError > 0]
+ min_ = numpy.nan if dataMinusError.size == 0 else numpy.min(dataMinusError)
+
+ dataPlusError = data + numpy.atleast_2d(error)[-1]
+ dataPlusError = dataPlusError[numpy.isfinite(dataPlusError)]
+ if positiveOnly:
+ dataPlusError = dataPlusError[dataPlusError > 0]
+ max_ = numpy.nan if dataPlusError.size == 0 else numpy.max(dataPlusError)
+
+ return min_, max_
+
def _getBounds(self):
if self.getXData(copy=False).size == 0: # Empty data
return None
@@ -1491,7 +1517,6 @@ class PointsBase(DataItem, SymbolMixIn, AlphaMixIn):
xPositive = False
yPositive = False
- # TODO bounds do not take error bars into account
if (xPositive, yPositive) not in self._boundsCache:
# use the getData class method because instance method can be
# overloaded to return additional arrays
@@ -1500,12 +1525,13 @@ class PointsBase(DataItem, SymbolMixIn, AlphaMixIn):
# hack to avoid duplicating caching mechanism in Scatter
# (happens when cached data is used, caching done using
# Scatter._logFilterData)
- x, y, _xerror, _yerror = data[0], data[1], data[3], data[4]
+ x, y, xerror, yerror = data[0], data[1], data[3], data[4]
else:
- x, y, _xerror, _yerror = data
+ x, y, xerror, yerror = data
+
+ xmin, xmax = self.__minMaxDataWithError(x, xerror, xPositive)
+ ymin, ymax = self.__minMaxDataWithError(y, yerror, yPositive)
- xmin, xmax = min_max(x, finite=True)
- ymin, ymax = min_max(y, finite=True)
self._boundsCache[(xPositive, yPositive)] = tuple([
(bound if bound is not None else numpy.nan)
for bound in (xmin, xmax, ymin, ymax)])
@@ -1600,8 +1626,8 @@ class PointsBase(DataItem, SymbolMixIn, AlphaMixIn):
:type xerror: A float, or a numpy.ndarray of float32.
If it is an array, it can either be a 1D array of
same length as the data or a 2D array with 2 rows
- of same length as the data: row 0 for positive errors,
- row 1 for negative errors.
+ of same length as the data: row 0 for lower errors,
+ row 1 for upper errors.
:param yerror: Values with the uncertainties on the y values.
:type yerror: A float, or a numpy.ndarray of float32. See xerror.
:param bool copy: True make a copy of the data (default),
diff --git a/src/silx/gui/plot/items/curve.py b/src/silx/gui/plot/items/curve.py
index 7cbe26e..93e4719 100644
--- a/src/silx/gui/plot/items/curve.py
+++ b/src/silx/gui/plot/items/curve.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/histogram.py b/src/silx/gui/plot/items/histogram.py
index 16bbefa..007f0c7 100644
--- a/src/silx/gui/plot/items/histogram.py
+++ b/src/silx/gui/plot/items/histogram.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/image.py b/src/silx/gui/plot/items/image.py
index 5cc719b..eaee05a 100644
--- a/src/silx/gui/plot/items/image.py
+++ b/src/silx/gui/plot/items/image.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/image_aggregated.py b/src/silx/gui/plot/items/image_aggregated.py
index 75fdd59..ffd41b2 100644
--- a/src/silx/gui/plot/items/image_aggregated.py
+++ b/src/silx/gui/plot/items/image_aggregated.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/marker.py b/src/silx/gui/plot/items/marker.py
index 50d070c..7596eb0 100755
--- a/src/silx/gui/plot/items/marker.py
+++ b/src/silx/gui/plot/items/marker.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/items/roi.py b/src/silx/gui/plot/items/roi.py
index 38a1424..559e7e0 100644
--- a/src/silx/gui/plot/items/roi.py
+++ b/src/silx/gui/plot/items/roi.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
+# Copyright (c) 2018-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -50,6 +49,7 @@ from ._roi_base import _RegionOfInterestBase
from ._roi_base import RegionOfInterest
from ._roi_base import HandleBasedROI
from ._arc_roi import ArcROI # noqa
+from ._band_roi import BandROI # noqa
from ._roi_base import InteractionModeMixIn # noqa
from ._roi_base import RoiInteractionMode # noqa
diff --git a/src/silx/gui/plot/items/scatter.py b/src/silx/gui/plot/items/scatter.py
index fdc66f7..96fb311 100644
--- a/src/silx/gui/plot/items/scatter.py
+++ b/src/silx/gui/plot/items/scatter.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -25,9 +24,6 @@
"""This module provides the :class:`Scatter` item of the :class:`Plot`.
"""
-from __future__ import division
-
-
__authors__ = ["T. Vincent", "P. Knobel"]
__license__ = "MIT"
__date__ = "29/03/2017"
@@ -950,8 +946,8 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
:type xerror: A float, or a numpy.ndarray of float32.
If it is an array, it can either be a 1D array of
same length as the data or a 2D array with 2 rows
- of same length as the data: row 0 for positive errors,
- row 1 for negative errors.
+ of same length as the data: row 0 for lower errors,
+ row 1 for upper errors.
:param yerror: Values with the uncertainties on the y values
:type yerror: A float, or a numpy.ndarray of float32. See xerror.
:param alpha: Values with the transparency (between 0 and 1)
diff --git a/src/silx/gui/plot/items/shape.py b/src/silx/gui/plot/items/shape.py
index 00ac5f5..dc35864 100644
--- a/src/silx/gui/plot/items/shape.py
+++ b/src/silx/gui/plot/items/shape.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,17 +34,78 @@ import logging
import numpy
from ... import colors
+from ..utils.intersections import lines_intersection
from .core import (
Item, DataItem,
- ColorMixIn, FillMixIn, ItemChangedType, LineMixIn, YAxisMixIn)
+ AlphaMixIn, ColorMixIn, FillMixIn, ItemChangedType, ItemMixInBase, LineMixIn, YAxisMixIn)
_logger = logging.getLogger(__name__)
+class _OverlayItem(Item):
+ """Item with settable overlay"""
+
+ def __init__(self):
+ self.__overlay = False
+ Item.__init__(self)
+
+ def isOverlay(self) -> bool:
+ """Return true if shape is drawn as an overlay"""
+ return self.__overlay
+
+ def setOverlay(self, overlay: bool):
+ """Set the overlay state of the shape
+
+ :param overlay: True to make it an overlay
+ """
+ overlay = bool(overlay)
+ if overlay != self.__overlay:
+ self.__overlay = overlay
+ self._updated(ItemChangedType.OVERLAY)
+
+
+class _TwoColorsLineMixIn(LineMixIn):
+ """Mix-in class for items with a background color for dashes"""
+
+ def __init__(self):
+ LineMixIn.__init__(self)
+ self.__backgroundColor = None
+
+ def getLineBgColor(self):
+ """Returns the RGBA background color of dash line
+
+ :rtype: 4-tuple of float in [0, 1] or array of colors
+ """
+ return self.__backgroundColor
+
+ def setLineBgColor(self, color, copy: bool=True):
+ """Set dash line background color
+
+ :param color: color(s) to be used
+ :type color: str ("#RRGGBB") or (npoints, 4) unsigned byte array or
+ one of the predefined color names defined in colors.py
+ :param copy: True (Default) to get a copy,
+ False to use internal representation (do not modify!)
+ """
+ if color is not None:
+ if isinstance(color, str):
+ color = colors.rgba(color)
+ else:
+ color = numpy.array(color, copy=copy)
+ # TODO more checks + improve color array support
+ if color.ndim == 1: # Single RGBA color
+ color = colors.rgba(color)
+ else: # Array of colors
+ assert color.ndim == 2
+
+ self.__backgroundColor = color
+ self._updated(ItemChangedType.LINE_BG_COLOR)
+
+
# TODO probably make one class for each kind of shape
# TODO check fill:polygon/polyline + fill = duplicated
-class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
+class Shape(_OverlayItem, ColorMixIn, FillMixIn, _TwoColorsLineMixIn):
"""Description of a shape item
:param str type_: The type of shape in:
@@ -53,16 +113,13 @@ class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
"""
def __init__(self, type_):
- Item.__init__(self)
+ _OverlayItem.__init__(self)
ColorMixIn.__init__(self)
FillMixIn.__init__(self)
- LineMixIn.__init__(self)
- self._overlay = False
+ _TwoColorsLineMixIn.__init__(self)
assert type_ in ('hline', 'polygon', 'rectangle', 'vline', 'polylines')
self._type = type_
self._points = ()
- self._lineBgColor = None
-
self._handle = None
def _addBackendRenderer(self, backend):
@@ -79,23 +136,6 @@ class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
linewidth=self.getLineWidth(),
linebgcolor=self.getLineBgColor())
- def isOverlay(self):
- """Return true if shape is drawn as an overlay
-
- :rtype: bool
- """
- return self._overlay
-
- def setOverlay(self, overlay):
- """Set the overlay state of the shape
-
- :param bool overlay: True to make it an overlay
- """
- overlay = bool(overlay)
- if overlay != self._overlay:
- self._overlay = overlay
- self._updated(ItemChangedType.OVERLAY)
-
def getType(self):
"""Returns the type of shape to draw.
@@ -126,34 +166,6 @@ class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
self._points = numpy.array(points, copy=copy)
self._updated(ItemChangedType.DATA)
- def getLineBgColor(self):
- """Returns the RGBA color of the item
- :rtype: 4-tuple of float in [0, 1] or array of colors
- """
- return self._lineBgColor
-
- def setLineBgColor(self, color, copy=True):
- """Set item color
- :param color: color(s) to be used
- :type color: str ("#RRGGBB") or (npoints, 4) unsigned byte array or
- one of the predefined color names defined in colors.py
- :param bool copy: True (Default) to get a copy,
- False to use internal representation (do not modify!)
- """
- if color is not None:
- if isinstance(color, str):
- color = colors.rgba(color)
- else:
- color = numpy.array(color, copy=copy)
- # TODO more checks + improve color array support
- if color.ndim == 1: # Single RGBA color
- color = colors.rgba(color)
- else: # Array of colors
- assert color.ndim == 2
-
- self._lineBgColor = color
- self._updated(ItemChangedType.LINE_BG_COLOR)
-
class BoundingRect(DataItem, YAxisMixIn):
"""An invisible shape which enforce the plot view to display the defined
@@ -285,3 +297,108 @@ class YAxisExtent(_BaseExtent, YAxisMixIn):
def __init__(self):
_BaseExtent.__init__(self, axis='y')
YAxisMixIn.__init__(self)
+
+
+class Line(_OverlayItem, AlphaMixIn, ColorMixIn, _TwoColorsLineMixIn):
+ """Description of a infinite line item as y = slope * x + interecpt
+
+ Warning: If slope is not finite, then the line is x = intercept.
+ """
+
+ def __init__(self, slope: float=0, intercept: float=0):
+ assert numpy.isfinite(intercept)
+
+ _OverlayItem.__init__(self)
+ AlphaMixIn.__init__(self)
+ ColorMixIn.__init__(self)
+ _TwoColorsLineMixIn.__init__(self)
+ self.__slope = float(slope)
+ self.__intercept = float(intercept)
+ self.__coordinates = None
+ self._setVisibleBoundsTracking(True)
+
+ def __updatePoints(self):
+ if not self.isVisible():
+ return
+
+ plot = self.getPlot()
+ if plot is None or not plot.isVisible():
+ return
+
+ xmin, xmax = plot.getXAxis().getLimits()
+ ymin, ymax = plot.getYAxis().getLimits()
+
+ slope = self.getSlope()
+ intercept = self.getIntercept()
+
+ if not numpy.isfinite(slope):
+ if not xmin <= intercept <= xmax:
+ coordinates = None
+ else:
+ coordinates = (intercept, intercept), (ymin, ymax)
+ else:
+ ycoords = slope * xmin + intercept, slope * xmax + intercept
+
+ if min(ycoords) < ymax and max(ycoords) > ymin:
+ coordinates = (xmin, xmax), ycoords
+ else:
+ coordinates = None
+
+ if coordinates != self.__coordinates:
+ self.__coordinates = coordinates
+ self._updated()
+
+ def _visibleBoundsChanged(self, *args) -> None:
+ """Override method to benefit from bounds tracking"""
+ self.__updatePoints()
+ return super()._visibleBoundsChanged(*args)
+
+ def setSlope(self, slope: float):
+ slope = float(slope)
+ if slope != self.__slope:
+ self.__slope = slope
+ self.__updatePoints()
+ self._updated(ItemChangedType.DATA)
+
+ def getSlope(self) -> float:
+ return self.__slope
+
+ def setIntercept(self, intercept: float):
+ intercept = float(intercept)
+ assert numpy.isfinite(intercept)
+ if intercept != self.__intercept:
+ self.__intercept = intercept
+ self.__updatePoints()
+ self._updated(ItemChangedType.DATA)
+
+ def getIntercept(self) -> float:
+ return self.__intercept
+
+ def setSlopeInterceptFromPoints(self, point0, point1):
+ """Set slope and intercept from 2 (x, y) points"""
+ x0, y0 = point0
+ x1, y1 = point1
+ if x0 == x1: # Special case: vertical line
+ self.setSlope(float("inf"))
+ self.setIntercept(x0)
+ return
+
+ slope = (y1 - y0) / (x1 - x0)
+ self.setSlope(slope)
+ self.setIntercept(y0 - x0 * slope)
+
+ def _addBackendRenderer(self, backend):
+ """Update backend renderer"""
+ if self.__coordinates is None:
+ return None
+
+ return backend.addShape(
+ *self.__coordinates,
+ shape='polylines',
+ color=self.getColor(),
+ fill=False,
+ overlay=self.isOverlay(),
+ linestyle=self.getLineStyle(),
+ linewidth=self.getLineWidth(),
+ linebgcolor=self.getLineBgColor(),
+ )
diff --git a/src/silx/gui/plot/matplotlib/Colormap.py b/src/silx/gui/plot/matplotlib/Colormap.py
index dc432b2..1131df8 100644
--- a/src/silx/gui/plot/matplotlib/Colormap.py
+++ b/src/silx/gui/plot/matplotlib/Colormap.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017-2020 European Synchrotron Radiation Facility
#
diff --git a/src/silx/gui/plot/matplotlib/__init__.py b/src/silx/gui/plot/matplotlib/__init__.py
index e787240..155ffd4 100644
--- a/src/silx/gui/plot/matplotlib/__init__.py
+++ b/src/silx/gui/plot/matplotlib/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/setup.py b/src/silx/gui/plot/setup.py
deleted file mode 100644
index e0b2c91..0000000
--- a/src/silx/gui/plot/setup.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "29/06/2017"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('plot', parent_package, top_path)
- config.add_subpackage('_utils')
- config.add_subpackage('utils')
- config.add_subpackage('matplotlib')
- config.add_subpackage('stats')
- config.add_subpackage('backends')
- config.add_subpackage('backends.glutils')
- config.add_subpackage('items')
- config.add_subpackage('test')
- config.add_subpackage('tools')
- config.add_subpackage('tools.profile')
- config.add_subpackage('tools.test')
- config.add_subpackage('actions')
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/gui/plot/stats/__init__.py b/src/silx/gui/plot/stats/__init__.py
index 04a5327..dfaa865 100644
--- a/src/silx/gui/plot/stats/__init__.py
+++ b/src/silx/gui/plot/stats/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/stats/stats.py b/src/silx/gui/plot/stats/stats.py
index a81f7bb..d266d5c 100644
--- a/src/silx/gui/plot/stats/stats.py
+++ b/src/silx/gui/plot/stats/stats.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -871,7 +870,7 @@ class StatCOM(StatBase):
values = numpy.ma.array(context.values, mask=context.mask, dtype=numpy.float64)
sum_ = numpy.sum(values)
- if sum_ == 0.:
+ if sum_ == 0. or numpy.ma.is_masked(sum_):
return (numpy.nan,) * len(context.axes)
if context.isStructuredData():
diff --git a/src/silx/gui/plot/stats/statshandler.py b/src/silx/gui/plot/stats/statshandler.py
index 17578d8..1531ba2 100644
--- a/src/silx/gui/plot/stats/statshandler.py
+++ b/src/silx/gui/plot/stats/statshandler.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -32,6 +31,9 @@ __date__ = "05/06/2018"
import logging
+import numbers
+
+import numpy
from silx.gui import qt
from silx.gui.plot import stats as statsmdl
@@ -72,11 +74,14 @@ class StatFormatter(object):
self.tabWidgetItemClass = qItemClass
def format(self, val):
- if self.formatter is None or val is None:
- return str(val)
- else:
+ if val is None or numpy.ma.is_masked(val):
+ return "--"
+
+ if self.formatter is not None and isinstance(val, numbers.Number):
return self.formatter.format(val)
+ return str(val)
+
class StatsHandler(object):
"""
diff --git a/src/silx/gui/plot/test/__init__.py b/src/silx/gui/plot/test/__init__.py
index 3ad225d..78821ec 100644
--- a/src/silx/gui/plot/test/__init__.py
+++ b/src/silx/gui/plot/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testAlphaSlider.py b/src/silx/gui/plot/test/testAlphaSlider.py
index ca57bf5..8641da7 100644
--- a/src/silx/gui/plot/test/testAlphaSlider.py
+++ b/src/silx/gui/plot/test/testAlphaSlider.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testColorBar.py b/src/silx/gui/plot/test/testColorBar.py
index 3dc8ff1..199726b 100644
--- a/src/silx/gui/plot/test/testColorBar.py
+++ b/src/silx/gui/plot/test/testColorBar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testCompareImages.py b/src/silx/gui/plot/test/testCompareImages.py
index cf54b99..9b5065d 100644
--- a/src/silx/gui/plot/test/testCompareImages.py
+++ b/src/silx/gui/plot/test/testCompareImages.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testComplexImageView.py b/src/silx/gui/plot/test/testComplexImageView.py
index 46025b9..c26df25 100644
--- a/src/silx/gui/plot/test/testComplexImageView.py
+++ b/src/silx/gui/plot/test/testComplexImageView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testCurvesROIWidget.py b/src/silx/gui/plot/test/testCurvesROIWidget.py
index d7dfafd..32ac057 100644
--- a/src/silx/gui/plot/test/testCurvesROIWidget.py
+++ b/src/silx/gui/plot/test/testCurvesROIWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -348,6 +347,8 @@ class TestRoiWidgetSignals(TestCaseQt):
"""Test Signals emitted by the RoiWidgetSignals"""
def setUp(self):
+ super().setUp()
+
self.plot = Plot1D()
x = range(20)
y = range(20)
@@ -368,8 +369,15 @@ class TestRoiWidgetSignals(TestCaseQt):
self.qWaitForWindowExposed(self.curves_roi_widget)
def tearDown(self):
- self.plot = None
- self.curves_roi_widget = None
+ self.plot.setAttribute(qt.Qt.WA_DeleteOnClose)
+ self.plot.close()
+ del self.plot
+
+ self.curves_roi_widget.setAttribute(qt.Qt.WA_DeleteOnClose)
+ self.curves_roi_widget.close()
+ del self.curves_roi_widget
+
+ super().tearDown()
def testSigROISignalAddRmRois(self):
"""Test SigROISignal when adding and removing ROIS"""
diff --git a/src/silx/gui/plot/test/testImageStack.py b/src/silx/gui/plot/test/testImageStack.py
index 5c44691..702f0fe 100644
--- a/src/silx/gui/plot/test/testImageStack.py
+++ b/src/silx/gui/plot/test/testImageStack.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testImageView.py b/src/silx/gui/plot/test/testImageView.py
index 7c1355f..9fb6a5d 100644
--- a/src/silx/gui/plot/test/testImageView.py
+++ b/src/silx/gui/plot/test/testImageView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testInteraction.py b/src/silx/gui/plot/test/testInteraction.py
index d136b21..459b132 100644
--- a/src/silx/gui/plot/test/testInteraction.py
+++ b/src/silx/gui/plot/test/testInteraction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testItem.py b/src/silx/gui/plot/test/testItem.py
index 0b15dc3..7b4f636 100644
--- a/src/silx/gui/plot/test/testItem.py
+++ b/src/silx/gui/plot/test/testItem.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testLegendSelector.py b/src/silx/gui/plot/test/testLegendSelector.py
index c40875d..3a596ac 100644
--- a/src/silx/gui/plot/test/testLegendSelector.py
+++ b/src/silx/gui/plot/test/testLegendSelector.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testLimitConstraints.py b/src/silx/gui/plot/test/testLimitConstraints.py
index 0bd8e50..04a53e1 100644
--- a/src/silx/gui/plot/test/testLimitConstraints.py
+++ b/src/silx/gui/plot/test/testLimitConstraints.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testMaskToolsWidget.py b/src/silx/gui/plot/test/testMaskToolsWidget.py
index 522ca51..5f36ec2 100644
--- a/src/silx/gui/plot/test/testMaskToolsWidget.py
+++ b/src/silx/gui/plot/test/testMaskToolsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testPixelIntensityHistoAction.py b/src/silx/gui/plot/test/testPixelIntensityHistoAction.py
index 14a467d..43d7588 100644
--- a/src/silx/gui/plot/test/testPixelIntensityHistoAction.py
+++ b/src/silx/gui/plot/test/testPixelIntensityHistoAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testPlotActions.py b/src/silx/gui/plot/test/testPlotActions.py
index f38e05b..4006ab9 100644
--- a/src/silx/gui/plot/test/testPlotActions.py
+++ b/src/silx/gui/plot/test/testPlotActions.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testPlotInteraction.py b/src/silx/gui/plot/test/testPlotInteraction.py
index fba364e..17aad97 100644
--- a/src/silx/gui/plot/test/testPlotInteraction.py
+++ b/src/silx/gui/plot/test/testPlotInteraction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016=2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testPlotWidget.py b/src/silx/gui/plot/test/testPlotWidget.py
index f6e108d..19a34a9 100755
--- a/src/silx/gui/plot/test/testPlotWidget.py
+++ b/src/silx/gui/plot/test/testPlotWidget.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -1651,6 +1650,26 @@ class TestPlotCurveLog(PlotWidgetTestCase, ParametricTestCase):
self.qapp.processEvents()
+ if xError is None:
+ dataMin, dataMax = numpy.min(self.xData), numpy.max(self.xData)
+ else:
+ xMinusError = self.xData - numpy.atleast_2d(xError)[0]
+ dataMin = numpy.min(xMinusError[xMinusError > 0])
+ xPlusError = self.xData + numpy.atleast_2d(xError)[-1]
+ dataMax = numpy.max(xPlusError[xPlusError > 0])
+ plotMin, plotMax = self.plot.getXAxis().getLimits()
+ assert numpy.allclose((dataMin, dataMax), (plotMin, plotMax))
+
+ if yError is None:
+ dataMin, dataMax = numpy.min(self.yData), numpy.max(self.yData)
+ else:
+ yMinusError = self.yData - numpy.atleast_2d(yError)[0]
+ dataMin = numpy.min(yMinusError[yMinusError > 0])
+ yPlusError = self.yData + numpy.atleast_2d(yError)[-1]
+ dataMax = numpy.max(yPlusError[yPlusError > 0])
+ plotMin, plotMax = self.plot.getYAxis().getLimits()
+ assert numpy.allclose((dataMin, dataMax), (plotMin, plotMax))
+
self.plot.clear()
self.plot.resetZoom()
self.qapp.processEvents()
diff --git a/src/silx/gui/plot/test/testPlotWidgetNoBackend.py b/src/silx/gui/plot/test/testPlotWidgetNoBackend.py
index 4914929..787d5a8 100644
--- a/src/silx/gui/plot/test/testPlotWidgetNoBackend.py
+++ b/src/silx/gui/plot/test/testPlotWidgetNoBackend.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testPlotWindow.py b/src/silx/gui/plot/test/testPlotWindow.py
index 9e1497f..8e3f1df 100644
--- a/src/silx/gui/plot/test/testPlotWindow.py
+++ b/src/silx/gui/plot/test/testPlotWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testRoiStatsWidget.py b/src/silx/gui/plot/test/testRoiStatsWidget.py
index eb29267..2c1c6b3 100644
--- a/src/silx/gui/plot/test/testRoiStatsWidget.py
+++ b/src/silx/gui/plot/test/testRoiStatsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testSaveAction.py b/src/silx/gui/plot/test/testSaveAction.py
index 9280fb6..d5a06c6 100644
--- a/src/silx/gui/plot/test/testSaveAction.py
+++ b/src/silx/gui/plot/test/testSaveAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testScatterMaskToolsWidget.py b/src/silx/gui/plot/test/testScatterMaskToolsWidget.py
index 447ee58..68375b0 100644
--- a/src/silx/gui/plot/test/testScatterMaskToolsWidget.py
+++ b/src/silx/gui/plot/test/testScatterMaskToolsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testScatterView.py b/src/silx/gui/plot/test/testScatterView.py
index d11d4d8..692612d 100644
--- a/src/silx/gui/plot/test/testScatterView.py
+++ b/src/silx/gui/plot/test/testScatterView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testStackView.py b/src/silx/gui/plot/test/testStackView.py
index 0d18113..aba8678 100644
--- a/src/silx/gui/plot/test/testStackView.py
+++ b/src/silx/gui/plot/test/testStackView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testStats.py b/src/silx/gui/plot/test/testStats.py
index 0a792a4..c5d5181 100644
--- a/src/silx/gui/plot/test/testStats.py
+++ b/src/silx/gui/plot/test/testStats.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/testUtilsAxis.py b/src/silx/gui/plot/test/testUtilsAxis.py
index dd4a689..879ec73 100644
--- a/src/silx/gui/plot/test/testUtilsAxis.py
+++ b/src/silx/gui/plot/test/testUtilsAxis.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/test/utils.py b/src/silx/gui/plot/test/utils.py
index 64fca56..faa40bb 100644
--- a/src/silx/gui/plot/test/utils.py
+++ b/src/silx/gui/plot/test/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/CurveLegendsWidget.py b/src/silx/gui/plot/tools/CurveLegendsWidget.py
index 4a517dd..c9b0101 100644
--- a/src/silx/gui/plot/tools/CurveLegendsWidget.py
+++ b/src/silx/gui/plot/tools/CurveLegendsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a widget to display :class:`PlotWidget` curve legends.
"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "20/07/2018"
diff --git a/src/silx/gui/plot/tools/LimitsToolBar.py b/src/silx/gui/plot/tools/LimitsToolBar.py
index fc192a6..d7f4bf5 100644
--- a/src/silx/gui/plot/tools/LimitsToolBar.py
+++ b/src/silx/gui/plot/tools/LimitsToolBar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -25,9 +24,6 @@
"""A toolbar to display and edit limits of a PlotWidget
"""
-
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "16/10/2017"
diff --git a/src/silx/gui/plot/tools/PositionInfo.py b/src/silx/gui/plot/tools/PositionInfo.py
index 8b95fbc..cb16b80 100644
--- a/src/silx/gui/plot/tools/PositionInfo.py
+++ b/src/silx/gui/plot/tools/PositionInfo.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -27,8 +26,6 @@
It can be configured to provide more information.
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "16/10/2017"
@@ -239,7 +236,7 @@ class PositionInfo(qt.QWidget):
ratio = qt.QGuiApplication.primaryScreen().devicePixelRatio()
# Baseline squared distance threshold
- distInPixels = (self.SNAP_THRESHOLD_DIST * ratio)**2
+ sqDistInPixels = (self.SNAP_THRESHOLD_DIST * ratio)**2
for item in selectedItems:
if (snappingMode & self.SNAPPING_SYMBOLS_ONLY and (
@@ -263,33 +260,36 @@ class PositionInfo(qt.QWidget):
break
else: # Curve, Scatter
- xArray = item.getXData(copy=False)
- yArray = item.getYData(copy=False)
- closestIndex = numpy.argmin(
- pow(xArray - x, 2) + pow(yArray - y, 2))
-
- xClosest = xArray[closestIndex]
- yClosest = yArray[closestIndex]
+ result = item.pick(xPixel, yPixel)
+ if result is None:
+ continue
+ indices = result.getIndices(copy=False)
+ if indices is None:
+ continue
if isinstance(item, items.YAxisMixIn):
axis = item.getYAxis()
else:
axis = 'left'
- closestInPixels = plot.dataToPixel(
- xClosest, yClosest, axis=axis)
- if closestInPixels is not None:
- curveDistInPixels = (
- (closestInPixels[0] - xPixel)**2 +
- (closestInPixels[1] - yPixel)**2)
-
- if curveDistInPixels <= distInPixels:
- # Update label style sheet
- styleSheet = "color: rgb(0, 0, 0);"
+ xArray = item.getXData(copy=False)[indices]
+ yArray = item.getYData(copy=False)[indices]
+ pixelPositions = plot.dataToPixel(xArray, yArray, axis=axis)
+ if pixelPositions is None:
+ continue
+ sqDistances = (pixelPositions[0] - xPixel)**2 + (pixelPositions[1] - yPixel)**2
+ if not numpy.any(numpy.isfinite(sqDistances)):
+ continue
+ closestIndex = numpy.nanargmin(sqDistances)
+ closestSqDistInPixels = sqDistances[closestIndex]
+
+ if closestSqDistInPixels <= sqDistInPixels:
+ # Update label style sheet
+ styleSheet = "color: rgb(0, 0, 0);"
- # if close enough, snap to data point coord
- xData, yData = xClosest, yClosest
- distInPixels = curveDistInPixels
+ # if close enough, snap to data point coord
+ xData, yData = xArray[closestIndex], yArray[closestIndex]
+ sqDistInPixels = closestSqDistInPixels
for label, name, func in self._fields:
label.setStyleSheet(styleSheet)
diff --git a/src/silx/gui/plot/tools/RadarView.py b/src/silx/gui/plot/tools/RadarView.py
index 7076835..886f37e 100644
--- a/src/silx/gui/plot/tools/RadarView.py
+++ b/src/silx/gui/plot/tools/RadarView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/__init__.py b/src/silx/gui/plot/tools/__init__.py
index 09f468c..5b6b74c 100644
--- a/src/silx/gui/plot/tools/__init__.py
+++ b/src/silx/gui/plot/tools/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py b/src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py
index 44187ef..09f90b7 100644
--- a/src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py
+++ b/src/silx/gui/plot/tools/profile/ScatterProfileToolBar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/profile/__init__.py b/src/silx/gui/plot/tools/profile/__init__.py
index d91191e..a72b5d2 100644
--- a/src/silx/gui/plot/tools/profile/__init__.py
+++ b/src/silx/gui/plot/tools/profile/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/profile/core.py b/src/silx/gui/plot/tools/profile/core.py
index 200f5cf..5d4a674 100644
--- a/src/silx/gui/plot/tools/profile/core.py
+++ b/src/silx/gui/plot/tools/profile/core.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/profile/editors.py b/src/silx/gui/plot/tools/profile/editors.py
index 80e0452..1d6f198 100644
--- a/src/silx/gui/plot/tools/profile/editors.py
+++ b/src/silx/gui/plot/tools/profile/editors.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
@@ -252,7 +251,10 @@ class ProfileRoiEditorAction(qt.QWidgetAction):
return
layout = widget.layout()
if previousEditor is not None:
- previousEditor.sigDataCommited.disconnect(self._editorDataCommited)
+ try:
+ previousEditor.sigDataCommited.disconnect(self._editorDataCommited)
+ except (RuntimeError, TypeError):
+ pass
layout.removeWidget(previousEditor)
previousEditor.deleteLater()
if editor is not None:
diff --git a/src/silx/gui/plot/tools/profile/manager.py b/src/silx/gui/plot/tools/profile/manager.py
index 4a22bc0..58c1c86 100644
--- a/src/silx/gui/plot/tools/profile/manager.py
+++ b/src/silx/gui/plot/tools/profile/manager.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -180,6 +179,8 @@ class ProfileWindow(qt.QMainWindow):
plot.setDataMargins(yMinMargin=0.1, yMaxMargin=0.1)
plot.setGraphYLabel('Profile')
plot.setGraphXLabel('')
+ positionInfo = plot.getPositionInfoWidget()
+ positionInfo.setSnappingMode(positionInfo.SNAPPING_CURVE)
return plot
def createPlot2D(self, parent, backend):
diff --git a/src/silx/gui/plot/tools/profile/rois.py b/src/silx/gui/plot/tools/profile/rois.py
index 9eef622..042aff1 100644
--- a/src/silx/gui/plot/tools/profile/rois.py
+++ b/src/silx/gui/plot/tools/profile/rois.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -945,13 +944,19 @@ class _DefaultScatterProfileSliceRoiMixIn(core.ProfileRoiMixIn):
if major_axis:
# slice in the middle of the scatter
- start = max_grid_second // 2 * max_grid_first
- vslice = axis[start:start + max_grid_second]
+ actual_size_grid_second = len(axis) // max_grid_first
+ start = actual_size_grid_second // 2 * max_grid_first
+ vslice = axis[start:start + max_grid_first]
+ if len(vslice) == 0:
+ return None
index = argnearest(vslice, position)
slicing = slice(index, None, max_grid_first)
else:
# slice in the middle of the scatter
- vslice = axis[max_grid_second // 2::max_grid_second]
+ actual_size_grid_second = len(axis) // max_grid_first
+ vslice = axis[actual_size_grid_second // 2::max_grid_second]
+ if len(vslice) == 0:
+ return None
index = argnearest(vslice, position)
start = index * max_grid_second
slicing = slice(start, start + max_grid_second)
@@ -1086,11 +1091,14 @@ class _DefaultImageStackProfileRoiMixIn(_DefaultImageProfileRoiMixIn):
coords, profile, profileName, xLabel = createProfile2(currentData)
+ profileManager = self.getProfileManager()
+ plot = profileManager.getPlotWidget()
+
data = core.ImageProfileData(
coords=coords,
profile=profile,
- title=profileName,
- xLabel=xLabel,
+ title=_relabelAxes(plot, profileName),
+ xLabel=_relabelAxes(plot, xLabel),
yLabel="Profile",
colormap=colormap,
)
diff --git a/src/silx/gui/plot/tools/profile/toolbar.py b/src/silx/gui/plot/tools/profile/toolbar.py
index 4a9a195..12a734a 100644
--- a/src/silx/gui/plot/tools/profile/toolbar.py
+++ b/src/silx/gui/plot/tools/profile/toolbar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/roi.py b/src/silx/gui/plot/tools/roi.py
index e4be6a7..1da692c 100644
--- a/src/silx/gui/plot/tools/roi.py
+++ b/src/silx/gui/plot/tools/roi.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2018-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -381,6 +380,7 @@ class RegionOfInterestManager(qt.QObject):
roi_items.VerticalLineROI,
roi_items.ArcROI,
roi_items.HorizontalRangeROI,
+ roi_items.BandROI,
)
def __init__(self, parent):
diff --git a/src/silx/gui/plot/tools/test/__init__.py b/src/silx/gui/plot/tools/test/__init__.py
index aa4a601..2e682d7 100644
--- a/src/silx/gui/plot/tools/test/__init__.py
+++ b/src/silx/gui/plot/tools/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/test/testCurveLegendsWidget.py b/src/silx/gui/plot/tools/test/testCurveLegendsWidget.py
index 37af10e..657d328 100644
--- a/src/silx/gui/plot/tools/test/testCurveLegendsWidget.py
+++ b/src/silx/gui/plot/tools/test/testCurveLegendsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/test/testProfile.py b/src/silx/gui/plot/tools/test/testProfile.py
index 829f49e..ad40e67 100644
--- a/src/silx/gui/plot/tools/test/testProfile.py
+++ b/src/silx/gui/plot/tools/test/testProfile.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/test/testROI.py b/src/silx/gui/plot/tools/test/testROI.py
index 21697d1..6ce1553 100644
--- a/src/silx/gui/plot/tools/test/testROI.py
+++ b/src/silx/gui/plot/tools/test/testROI.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
@@ -268,6 +267,12 @@ class TestRoiItems(TestCaseQt):
self.assertAlmostEqual(item.getMax(), vmax)
self.assertAlmostEqual(item.getCenter(), 2)
+ def testBand_getToSetGeometry(self):
+ """Test that we can use getGeometry as input to setGeometry"""
+ item = roi_items.BandROI()
+ item.setFirstShapePoints(numpy.array([[5, 10], [50, 100]]))
+ item.setGeometry(*item.getGeometry())
+
class TestRegionOfInterestManager(TestCaseQt, ParametricTestCase):
"""Tests for RegionOfInterestManager class"""
@@ -577,7 +582,7 @@ class TestRegionOfInterestManager(TestCaseQt, ParametricTestCase):
manager.addRoi(item)
self.qapp.processEvents()
- # Drag the center
+ # Drag the center
widget = self.plot.getWidgetHandle()
mx, my = self.plot.dataToPixel(*center)
self.mouseMove(widget, pos=(mx, my))
@@ -680,3 +685,56 @@ class TestRegionOfInterestManager(TestCaseQt, ParametricTestCase):
manager.clear()
self.qapp.processEvents()
+
+ def testBandRoiSwitchMode(self):
+ """Make sure we can switch mode by clicking on the ROI"""
+ xlimit = self.plot.getXAxis().getLimits()
+ ylimit = self.plot.getYAxis().getLimits()
+ xcenter = 0.5 * (xlimit[0] + xlimit[1])
+ ycenter = 0.5 * (ylimit[0] + ylimit[1])
+
+ # Create the line
+ manager = roi.RegionOfInterestManager(self.plot)
+ item = roi_items.BandROI()
+ item.setGeometry(
+ (xlimit[0], ycenter),
+ (xlimit[1], ycenter),
+ 20,
+ )
+ item.setEditable(True)
+ item.setSelectable(True)
+ manager.addRoi(item)
+ self.qapp.processEvents()
+
+ # Initial state
+ assert item.getInteractionMode() is roi_items.BandROI.BoundedMode
+ self.qWait(500)
+
+ # Click on the center
+ widget = self.plot.getWidgetHandle()
+ mx, my = self.plot.dataToPixel(xcenter, ycenter)
+
+ # Select the ROI
+ self.mouseMove(widget, pos=(mx, my))
+ self.mouseClick(widget, qt.Qt.LeftButton, pos=(mx, my))
+ self.qWait(500)
+ assert item.getInteractionMode() is roi_items.BandROI.BoundedMode
+
+ # Change the mode
+ self.mouseMove(widget, pos=(mx, my))
+ self.mouseClick(widget, qt.Qt.LeftButton, pos=(mx, my))
+ self.qWait(500)
+ assert item.getInteractionMode() is roi_items.BandROI.UnboundedMode
+
+ # Set available modes that exclude the current one
+ item.setAvailableInteractionModes([roi_items.BandROI.BoundedMode])
+ assert item.getInteractionMode() is roi_items.BandROI.BoundedMode
+
+ # Clicking does not change the mode since there is only one
+ self.mouseMove(widget, pos=(mx, my))
+ self.mouseClick(widget, qt.Qt.LeftButton, pos=(mx, my))
+ self.qWait(500)
+ assert item.getInteractionMode() is roi_items.BandROI.BoundedMode
+
+ manager.clear()
+ self.qapp.processEvents()
diff --git a/src/silx/gui/plot/tools/test/testScatterProfileToolBar.py b/src/silx/gui/plot/tools/test/testScatterProfileToolBar.py
index 582a276..9b9caa1 100644
--- a/src/silx/gui/plot/tools/test/testScatterProfileToolBar.py
+++ b/src/silx/gui/plot/tools/test/testScatterProfileToolBar.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/test/testTools.py b/src/silx/gui/plot/tools/test/testTools.py
index 846f641..507b922 100644
--- a/src/silx/gui/plot/tools/test/testTools.py
+++ b/src/silx/gui/plot/tools/test/testTools.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/tools/toolbars.py b/src/silx/gui/plot/tools/toolbars.py
index 3df7d06..bb89942 100644
--- a/src/silx/gui/plot/tools/toolbars.py
+++ b/src/silx/gui/plot/tools/toolbars.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/utils/__init__.py b/src/silx/gui/plot/utils/__init__.py
index 3187f6b..61e45b4 100644
--- a/src/silx/gui/plot/utils/__init__.py
+++ b/src/silx/gui/plot/utils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/utils/axis.py b/src/silx/gui/plot/utils/axis.py
index 5cf8ad9..419a71c 100644
--- a/src/silx/gui/plot/utils/axis.py
+++ b/src/silx/gui/plot/utils/axis.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot/utils/intersections.py b/src/silx/gui/plot/utils/intersections.py
index 53f2546..4f6ed23 100644
--- a/src/silx/gui/plot/utils/intersections.py
+++ b/src/silx/gui/plot/utils/intersections.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/ParamTreeView.py b/src/silx/gui/plot3d/ParamTreeView.py
index 2593860..b648251 100644
--- a/src/silx/gui/plot3d/ParamTreeView.py
+++ b/src/silx/gui/plot3d/ParamTreeView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -33,8 +32,6 @@ This module contains:
:class:`Vector4DEditor`, :class:`IntSliderEditor`, :class:`BooleanEditor`
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "05/12/2017"
diff --git a/src/silx/gui/plot3d/Plot3DWidget.py b/src/silx/gui/plot3d/Plot3DWidget.py
index a90d34c..09e06a2 100644
--- a/src/silx/gui/plot3d/Plot3DWidget.py
+++ b/src/silx/gui/plot3d/Plot3DWidget.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides a Qt widget embedding an OpenGL scene."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
@@ -125,7 +122,7 @@ class Plot3DWidget(glu.OpenGLWidget):
LINEAR = 'linear'
"""Linear fog through the whole scene"""
- def __init__(self, parent=None, f=qt.Qt.WindowFlags()):
+ def __init__(self, parent=None, f=qt.Qt.Widget):
self._firstRender = True
super(Plot3DWidget, self).__init__(
@@ -380,10 +377,7 @@ class Plot3DWidget(glu.OpenGLWidget):
return convertArrayToQImage(image)
def wheelEvent(self, event):
- if qt.BINDING == "PySide6":
- x, y = event.position().x(), event.position().y()
- else:
- x, y = event.x(), event.y()
+ x, y = qt.getMouseEventPosition(event)
xpixel = x * self.getDevicePixelRatio()
ypixel = y * self.getDevicePixelRatio()
angle = event.angleDelta().y() / 8.
@@ -431,11 +425,16 @@ class Plot3DWidget(glu.OpenGLWidget):
super(Plot3DWidget, self).keyReleaseEvent(event)
# Mouse events #
- _MOUSE_BTNS = {1: 'left', 2: 'right', 4: 'middle'}
+ _MOUSE_BTNS = {
+ qt.Qt.LeftButton: 'left',
+ qt.Qt.RightButton: 'right',
+ qt.Qt.MiddleButton: 'middle',
+ }
def mousePressEvent(self, event):
- xpixel = event.x() * self.getDevicePixelRatio()
- ypixel = event.y() * self.getDevicePixelRatio()
+ x, y = qt.getMouseEventPosition(event)
+ xpixel = x * self.getDevicePixelRatio()
+ ypixel = y * self.getDevicePixelRatio()
btn = self._MOUSE_BTNS[event.button()]
event.accept()
@@ -444,8 +443,9 @@ class Plot3DWidget(glu.OpenGLWidget):
self.eventHandler.handleEvent('press', xpixel, ypixel, btn)
def mouseMoveEvent(self, event):
- xpixel = event.x() * self.getDevicePixelRatio()
- ypixel = event.y() * self.getDevicePixelRatio()
+ x, y = qt.getMouseEventPosition(event)
+ xpixel = x * self.getDevicePixelRatio()
+ ypixel = y * self.getDevicePixelRatio()
event.accept()
if self.eventHandler is not None and self.isValid():
@@ -453,8 +453,9 @@ class Plot3DWidget(glu.OpenGLWidget):
self.eventHandler.handleEvent('move', xpixel, ypixel)
def mouseReleaseEvent(self, event):
- xpixel = event.x() * self.getDevicePixelRatio()
- ypixel = event.y() * self.getDevicePixelRatio()
+ x, y = qt.getMouseEventPosition(event)
+ xpixel = x * self.getDevicePixelRatio()
+ ypixel = y * self.getDevicePixelRatio()
btn = self._MOUSE_BTNS[event.button()]
event.accept()
diff --git a/src/silx/gui/plot3d/Plot3DWindow.py b/src/silx/gui/plot3d/Plot3DWindow.py
index 470b966..882f4cd 100644
--- a/src/silx/gui/plot3d/Plot3DWindow.py
+++ b/src/silx/gui/plot3d/Plot3DWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a QMainWindow with a 3D scene and associated toolbar.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "26/01/2017"
diff --git a/src/silx/gui/plot3d/SFViewParamTree.py b/src/silx/gui/plot3d/SFViewParamTree.py
index b269a6a..cc78cec 100644
--- a/src/silx/gui/plot3d/SFViewParamTree.py
+++ b/src/silx/gui/plot3d/SFViewParamTree.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
@@ -26,8 +25,6 @@
This module provides a tree widget to set/view parameters of a ScalarFieldView.
"""
-from __future__ import absolute_import
-
__authors__ = ["D. N."]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/ScalarFieldView.py b/src/silx/gui/plot3d/ScalarFieldView.py
index b2bb254..0633221 100644
--- a/src/silx/gui/plot3d/ScalarFieldView.py
+++ b/src/silx/gui/plot3d/ScalarFieldView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
@@ -28,8 +27,6 @@ It supports iso-surfaces, a cutting plane and the definition of
a region of interest.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "14/06/2018"
diff --git a/src/silx/gui/plot3d/SceneWidget.py b/src/silx/gui/plot3d/SceneWidget.py
index 883f5e7..910820c 100644
--- a/src/silx/gui/plot3d/SceneWidget.py
+++ b/src/silx/gui/plot3d/SceneWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides a widget to view data sets in 3D."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/SceneWindow.py b/src/silx/gui/plot3d/SceneWindow.py
index 052a4dc..d88cfa9 100644
--- a/src/silx/gui/plot3d/SceneWindow.py
+++ b/src/silx/gui/plot3d/SceneWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a QMainWindow with a 3D SceneWidget and toolbars.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "29/11/2017"
diff --git a/src/silx/gui/plot3d/__init__.py b/src/silx/gui/plot3d/__init__.py
index af74613..e0cb688 100644
--- a/src/silx/gui/plot3d/__init__.py
+++ b/src/silx/gui/plot3d/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
@@ -27,7 +26,6 @@ This package provides widgets displaying 3D content based on OpenGL.
It depends on PyOpenGL and PyQtx.QtOpenGL or PyQt>=5.4.
"""
-from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
diff --git a/src/silx/gui/plot3d/_model/__init__.py b/src/silx/gui/plot3d/_model/__init__.py
index 4b16e32..fd8eafb 100644
--- a/src/silx/gui/plot3d/_model/__init__.py
+++ b/src/silx/gui/plot3d/_model/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -26,8 +25,6 @@
This package provides :class:`SceneWidget` content and parameters model.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "11/01/2018"
diff --git a/src/silx/gui/plot3d/_model/core.py b/src/silx/gui/plot3d/_model/core.py
index e8e0820..30d45ec 100644
--- a/src/silx/gui/plot3d/_model/core.py
+++ b/src/silx/gui/plot3d/_model/core.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -26,8 +25,6 @@
This module provides base classes to implement models for 3D scene content.
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "11/01/2018"
diff --git a/src/silx/gui/plot3d/_model/items.py b/src/silx/gui/plot3d/_model/items.py
index 492f44b..c6bf69a 100644
--- a/src/silx/gui/plot3d/_model/items.py
+++ b/src/silx/gui/plot3d/_model/items.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -26,8 +25,6 @@
This module provides base classes to implement models for 3D scene content
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/_model/model.py b/src/silx/gui/plot3d/_model/model.py
index 186838f..5276878 100644
--- a/src/silx/gui/plot3d/_model/model.py
+++ b/src/silx/gui/plot3d/_model/model.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -26,8 +25,6 @@
This module provides the :class:`SceneWidget` content and parameters model.
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "11/01/2018"
diff --git a/src/silx/gui/plot3d/actions/Plot3DAction.py b/src/silx/gui/plot3d/actions/Plot3DAction.py
index 94b9572..a2ee93c 100644
--- a/src/silx/gui/plot3d/actions/Plot3DAction.py
+++ b/src/silx/gui/plot3d/actions/Plot3DAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Base class for QAction attached to a Plot3DWidget."""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "06/09/2017"
diff --git a/src/silx/gui/plot3d/actions/__init__.py b/src/silx/gui/plot3d/actions/__init__.py
index 26243cf..e6c7312 100644
--- a/src/silx/gui/plot3d/actions/__init__.py
+++ b/src/silx/gui/plot3d/actions/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/actions/io.py b/src/silx/gui/plot3d/actions/io.py
index 25f4ade..f8a1d86 100644
--- a/src/silx/gui/plot3d/actions/io.py
+++ b/src/silx/gui/plot3d/actions/io.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -27,8 +26,6 @@
It provides QAction to copy, save (snapshot and video), print a Plot3DWidget.
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "06/09/2017"
diff --git a/src/silx/gui/plot3d/actions/mode.py b/src/silx/gui/plot3d/actions/mode.py
index b9cd7c8..179fe05 100644
--- a/src/silx/gui/plot3d/actions/mode.py
+++ b/src/silx/gui/plot3d/actions/mode.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -28,8 +27,6 @@ It provides QAction to rotate or pan a Plot3DWidget
as well as toggle a picking mode.
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "06/09/2017"
diff --git a/src/silx/gui/plot3d/actions/viewpoint.py b/src/silx/gui/plot3d/actions/viewpoint.py
index d764c40..c3d640e 100644
--- a/src/silx/gui/plot3d/actions/viewpoint.py
+++ b/src/silx/gui/plot3d/actions/viewpoint.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -27,8 +26,6 @@
It provides QAction to rotate or pan a Plot3DWidget.
"""
-from __future__ import absolute_import, division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "03/10/2017"
diff --git a/src/silx/gui/plot3d/items/__init__.py b/src/silx/gui/plot3d/items/__init__.py
index e7c4af1..3d22103 100644
--- a/src/silx/gui/plot3d/items/__init__.py
+++ b/src/silx/gui/plot3d/items/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This package provides classes that describes :class:`.SceneWidget` content.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/11/2017"
diff --git a/src/silx/gui/plot3d/items/_pick.py b/src/silx/gui/plot3d/items/_pick.py
index 0d6a495..49e1a5b 100644
--- a/src/silx/gui/plot3d/items/_pick.py
+++ b/src/silx/gui/plot3d/items/_pick.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides classes supporting item picking.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/09/2018"
diff --git a/src/silx/gui/plot3d/items/clipplane.py b/src/silx/gui/plot3d/items/clipplane.py
index 3e819d0..83a3c0e 100644
--- a/src/silx/gui/plot3d/items/clipplane.py
+++ b/src/silx/gui/plot3d/items/clipplane.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a scene clip plane class.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/11/2017"
diff --git a/src/silx/gui/plot3d/items/core.py b/src/silx/gui/plot3d/items/core.py
index 0388ce7..5fbe62c 100644
--- a/src/silx/gui/plot3d/items/core.py
+++ b/src/silx/gui/plot3d/items/core.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides the base class for items of the :class:`.SceneWidget`.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/11/2017"
diff --git a/src/silx/gui/plot3d/items/image.py b/src/silx/gui/plot3d/items/image.py
index 5a50459..669e97d 100644
--- a/src/silx/gui/plot3d/items/image.py
+++ b/src/silx/gui/plot3d/items/image.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides 2D data and RGB(A) image item class.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/11/2017"
diff --git a/src/silx/gui/plot3d/items/mesh.py b/src/silx/gui/plot3d/items/mesh.py
index 4e19939..dc1df3e 100644
--- a/src/silx/gui/plot3d/items/mesh.py
+++ b/src/silx/gui/plot3d/items/mesh.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides regular mesh item class.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/07/2018"
diff --git a/src/silx/gui/plot3d/items/mixins.py b/src/silx/gui/plot3d/items/mixins.py
index f512365..45b569d 100644
--- a/src/silx/gui/plot3d/items/mixins.py
+++ b/src/silx/gui/plot3d/items/mixins.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/items/scatter.py b/src/silx/gui/plot3d/items/scatter.py
index 24abaa5..c93db88 100644
--- a/src/silx/gui/plot3d/items/scatter.py
+++ b/src/silx/gui/plot3d/items/scatter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides 2D and 3D scatter data item class.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/11/2017"
diff --git a/src/silx/gui/plot3d/items/volume.py b/src/silx/gui/plot3d/items/volume.py
index f80fea2..b3007fa 100644
--- a/src/silx/gui/plot3d/items/volume.py
+++ b/src/silx/gui/plot3d/items/volume.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides 3D array item class and its sub-items.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/scene/__init__.py b/src/silx/gui/plot3d/scene/__init__.py
index 9671725..9f7c470 100644
--- a/src/silx/gui/plot3d/scene/__init__.py
+++ b/src/silx/gui/plot3d/scene/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/scene/axes.py b/src/silx/gui/plot3d/scene/axes.py
index e35e5e1..9f6ac6c 100644
--- a/src/silx/gui/plot3d/scene/axes.py
+++ b/src/silx/gui/plot3d/scene/axes.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Primitive displaying a text field in the scene."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/10/2016"
diff --git a/src/silx/gui/plot3d/scene/camera.py b/src/silx/gui/plot3d/scene/camera.py
index 90de7ed..a6bc642 100644
--- a/src/silx/gui/plot3d/scene/camera.py
+++ b/src/silx/gui/plot3d/scene/camera.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides classes to handle a perspective projection in 3D."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "25/07/2016"
diff --git a/src/silx/gui/plot3d/scene/core.py b/src/silx/gui/plot3d/scene/core.py
index 43838fe..c32a2c1 100644
--- a/src/silx/gui/plot3d/scene/core.py
+++ b/src/silx/gui/plot3d/scene/core.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
@@ -32,8 +31,6 @@ Nodes with children are provided with :class:`PrivateGroup` and
Leaf rendering nodes should inherit from :class:`Elem`.
"""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "25/07/2016"
diff --git a/src/silx/gui/plot3d/scene/cutplane.py b/src/silx/gui/plot3d/scene/cutplane.py
index 88147df..bfd578f 100644
--- a/src/silx/gui/plot3d/scene/cutplane.py
+++ b/src/silx/gui/plot3d/scene/cutplane.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""A cut plane in a 3D texture: hackish implementation...
"""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "11/01/2018"
diff --git a/src/silx/gui/plot3d/scene/event.py b/src/silx/gui/plot3d/scene/event.py
index 98f8f8b..637eddf 100644
--- a/src/silx/gui/plot3d/scene/event.py
+++ b/src/silx/gui/plot3d/scene/event.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides a simple generic notification system."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/07/2018"
diff --git a/src/silx/gui/plot3d/scene/function.py b/src/silx/gui/plot3d/scene/function.py
index 2deb785..3d0a62f 100644
--- a/src/silx/gui/plot3d/scene/function.py
+++ b/src/silx/gui/plot3d/scene/function.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides functions to add to shaders."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/07/2018"
diff --git a/src/silx/gui/plot3d/scene/interaction.py b/src/silx/gui/plot3d/scene/interaction.py
index 14a54dc..91fab23 100644
--- a/src/silx/gui/plot3d/scene/interaction.py
+++ b/src/silx/gui/plot3d/scene/interaction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides interaction to plug on the scene graph."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "25/07/2016"
diff --git a/src/silx/gui/plot3d/scene/primitives.py b/src/silx/gui/plot3d/scene/primitives.py
index 7f35c3c..6d3c4ff 100644
--- a/src/silx/gui/plot3d/scene/primitives.py
+++ b/src/silx/gui/plot3d/scene/primitives.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
@@ -23,8 +22,6 @@
#
# ###########################################################################*/
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/scene/test/__init__.py b/src/silx/gui/plot3d/scene/test/__init__.py
index 3bb978e..4bdcc18 100644
--- a/src/silx/gui/plot3d/scene/test/__init__.py
+++ b/src/silx/gui/plot3d/scene/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/scene/test/test_transform.py b/src/silx/gui/plot3d/scene/test/test_transform.py
index 69e991b..2998c65 100644
--- a/src/silx/gui/plot3d/scene/test/test_transform.py
+++ b/src/silx/gui/plot3d/scene/test/test_transform.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
@@ -23,8 +22,6 @@
#
# ###########################################################################*/
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "05/01/2017"
diff --git a/src/silx/gui/plot3d/scene/test/test_utils.py b/src/silx/gui/plot3d/scene/test/test_utils.py
index 65d0ce0..a9ba6bc 100644
--- a/src/silx/gui/plot3d/scene/test/test_utils.py
+++ b/src/silx/gui/plot3d/scene/test/test_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
@@ -23,8 +22,6 @@
#
# ###########################################################################*/
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"
diff --git a/src/silx/gui/plot3d/scene/text.py b/src/silx/gui/plot3d/scene/text.py
index bacc2e6..3c4e692 100644
--- a/src/silx/gui/plot3d/scene/text.py
+++ b/src/silx/gui/plot3d/scene/text.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Primitive displaying a text field in the scene."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/scene/transform.py b/src/silx/gui/plot3d/scene/transform.py
index 43b739b..5c2cbb3 100644
--- a/src/silx/gui/plot3d/scene/transform.py
+++ b/src/silx/gui/plot3d/scene/transform.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides 4x4 matrix operation and classes to handle them."""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "25/07/2016"
diff --git a/src/silx/gui/plot3d/scene/utils.py b/src/silx/gui/plot3d/scene/utils.py
index c6cd129..48fc2f5 100644
--- a/src/silx/gui/plot3d/scene/utils.py
+++ b/src/silx/gui/plot3d/scene/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
@@ -27,8 +26,6 @@ This module provides functions to generate indices, to check intersection
and to handle planes.
"""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "25/07/2016"
diff --git a/src/silx/gui/plot3d/scene/viewport.py b/src/silx/gui/plot3d/scene/viewport.py
index 6de640e..bff77e2 100644
--- a/src/silx/gui/plot3d/scene/viewport.py
+++ b/src/silx/gui/plot3d/scene/viewport.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
@@ -29,8 +28,6 @@ The attribute :attr:`scene` is the root group of the scene tree.
:class:`RenderContext` handles the current state during rendering.
"""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/scene/window.py b/src/silx/gui/plot3d/scene/window.py
index b92c404..c8f4cee 100644
--- a/src/silx/gui/plot3d/scene/window.py
+++ b/src/silx/gui/plot3d/scene/window.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
@@ -32,8 +31,6 @@ The :class:`Context` and :class:`ContextGL2` represent the operating system
OpenGL context and handle OpenGL resources.
"""
-from __future__ import absolute_import, division, unicode_literals
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "10/01/2017"
diff --git a/src/silx/gui/plot3d/setup.py b/src/silx/gui/plot3d/setup.py
deleted file mode 100644
index 59c0230..0000000
--- a/src/silx/gui/plot3d/setup.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "25/07/2016"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('plot3d', parent_package, top_path)
- config.add_subpackage('_model')
- config.add_subpackage('actions')
- config.add_subpackage('items')
- config.add_subpackage('scene')
- config.add_subpackage('scene.test')
- config.add_subpackage('tools')
- config.add_subpackage('tools.test')
- config.add_subpackage('test')
- config.add_subpackage('utils')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/gui/plot3d/test/__init__.py b/src/silx/gui/plot3d/test/__init__.py
index 83491ad..f8afa83 100644
--- a/src/silx/gui/plot3d/test/__init__.py
+++ b/src/silx/gui/plot3d/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/test/testGL.py b/src/silx/gui/plot3d/test/testGL.py
index a7309a9..d1d53ef 100644
--- a/src/silx/gui/plot3d/test/testGL.py
+++ b/src/silx/gui/plot3d/test/testGL.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
@@ -29,7 +28,7 @@ __date__ = "10/08/2017"
import logging
-import unittest
+import pytest
from silx.gui._glutils import gl, OpenGLWidget
from silx.gui.utils.testutils import TestCaseQt
@@ -39,6 +38,7 @@ from silx.gui import qt
_logger = logging.getLogger(__name__)
+@pytest.mark.usefixtures("use_opengl")
class TestOpenGL(TestCaseQt):
"""Tests of OpenGL widget."""
diff --git a/src/silx/gui/plot3d/test/testScalarFieldView.py b/src/silx/gui/plot3d/test/testScalarFieldView.py
index e6535fc..1e06e3f 100644
--- a/src/silx/gui/plot3d/test/testScalarFieldView.py
+++ b/src/silx/gui/plot3d/test/testScalarFieldView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
@@ -29,7 +28,7 @@ __date__ = "17/01/2018"
import logging
-import unittest
+import pytest
import numpy
@@ -44,6 +43,7 @@ from silx.gui.plot3d.SFViewParamTree import TreeView
_logger = logging.getLogger(__name__)
+@pytest.mark.usefixtures("use_opengl")
class TestScalarFieldView(TestCaseQt, ParametricTestCase):
"""Tests of ScalarFieldView widget."""
diff --git a/src/silx/gui/plot3d/test/testSceneWidget.py b/src/silx/gui/plot3d/test/testSceneWidget.py
index fc96781..e7f3b3f 100644
--- a/src/silx/gui/plot3d/test/testSceneWidget.py
+++ b/src/silx/gui/plot3d/test/testSceneWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -28,7 +27,7 @@ __license__ = "MIT"
__date__ = "06/03/2019"
-import unittest
+import pytest
import numpy
@@ -39,6 +38,7 @@ from silx.gui import qt
from silx.gui.plot3d.SceneWidget import SceneWidget
+@pytest.mark.usefixtures("use_opengl")
class TestSceneWidget(TestCaseQt, ParametricTestCase):
"""Tests SceneWidget picking feature"""
diff --git a/src/silx/gui/plot3d/test/testSceneWidgetPicking.py b/src/silx/gui/plot3d/test/testSceneWidgetPicking.py
index d4d8db7..c0ad3b0 100644
--- a/src/silx/gui/plot3d/test/testSceneWidgetPicking.py
+++ b/src/silx/gui/plot3d/test/testSceneWidgetPicking.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
@@ -28,7 +27,7 @@ __license__ = "MIT"
__date__ = "03/10/2018"
-import unittest
+import pytest
import numpy
@@ -39,6 +38,7 @@ from silx.gui import qt
from silx.gui.plot3d.SceneWidget import SceneWidget, items
+@pytest.mark.usefixtures("use_opengl")
class TestSceneWidgetPicking(TestCaseQt, ParametricTestCase):
"""Tests SceneWidget picking feature"""
diff --git a/src/silx/gui/plot3d/test/testSceneWindow.py b/src/silx/gui/plot3d/test/testSceneWindow.py
index 6b61335..09e097c 100644
--- a/src/silx/gui/plot3d/test/testSceneWindow.py
+++ b/src/silx/gui/plot3d/test/testSceneWindow.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019-2021 European Synchrotron Radiation Facility
@@ -28,7 +27,7 @@ __license__ = "MIT"
__date__ = "22/03/2019"
-import unittest
+import pytest
import numpy
@@ -39,6 +38,8 @@ from silx.gui import qt
from silx.gui.plot3d.SceneWindow import SceneWindow
from silx.gui.plot3d.items import HeightMapData, HeightMapRGBA
+
+@pytest.mark.usefixtures("use_opengl")
class TestSceneWindow(TestCaseQt, ParametricTestCase):
"""Tests SceneWidget picking feature"""
diff --git a/src/silx/gui/plot3d/test/testStatsWidget.py b/src/silx/gui/plot3d/test/testStatsWidget.py
index d452eb5..e1411bf 100644
--- a/src/silx/gui/plot3d/test/testStatsWidget.py
+++ b/src/silx/gui/plot3d/test/testStatsWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -28,7 +27,7 @@ __license__ = "MIT"
__date__ = "25/01/2019"
-import unittest
+import pytest
import numpy
@@ -43,6 +42,7 @@ from silx.gui.plot3d.ScalarFieldView import ScalarFieldView
from silx.gui.plot3d.SceneWidget import SceneWidget, items
+@pytest.mark.usefixtures("use_opengl")
class TestSceneWidget(TestCaseQt, ParametricTestCase):
"""Tests StatsWidget combined with SceneWidget"""
diff --git a/src/silx/gui/plot3d/tools/GroupPropertiesWidget.py b/src/silx/gui/plot3d/tools/GroupPropertiesWidget.py
index 146c2cd..922df3a 100644
--- a/src/silx/gui/plot3d/tools/GroupPropertiesWidget.py
+++ b/src/silx/gui/plot3d/tools/GroupPropertiesWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
""":class:`GroupPropertiesWidget` allows to reset properties in a GroupItem."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "24/04/2018"
diff --git a/src/silx/gui/plot3d/tools/PositionInfoWidget.py b/src/silx/gui/plot3d/tools/PositionInfoWidget.py
index 99d6356..1998533 100644
--- a/src/silx/gui/plot3d/tools/PositionInfoWidget.py
+++ b/src/silx/gui/plot3d/tools/PositionInfoWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a widget that displays data values of a SceneWidget.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/10/2018"
diff --git a/src/silx/gui/plot3d/tools/ViewpointTools.py b/src/silx/gui/plot3d/tools/ViewpointTools.py
index 0607382..ab26c96 100644
--- a/src/silx/gui/plot3d/tools/ViewpointTools.py
+++ b/src/silx/gui/plot3d/tools/ViewpointTools.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""This module provides a toolbar to control Plot3DWidget viewpoint."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "08/09/2017"
diff --git a/src/silx/gui/plot3d/tools/__init__.py b/src/silx/gui/plot3d/tools/__init__.py
index c8b8d21..5e2c76c 100644
--- a/src/silx/gui/plot3d/tools/__init__.py
+++ b/src/silx/gui/plot3d/tools/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/tools/test/__init__.py b/src/silx/gui/plot3d/tools/test/__init__.py
index 86741ed..a6032b9 100644
--- a/src/silx/gui/plot3d/tools/test/__init__.py
+++ b/src/silx/gui/plot3d/tools/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py b/src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py
index 17fb3db..e988817 100644
--- a/src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py
+++ b/src/silx/gui/plot3d/tools/test/testPositionInfoWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/tools/toolbars.py b/src/silx/gui/plot3d/tools/toolbars.py
index d4f32db..c89f6c6 100644
--- a/src/silx/gui/plot3d/tools/toolbars.py
+++ b/src/silx/gui/plot3d/tools/toolbars.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -37,8 +36,6 @@ It provides the following toolbars:
- Print
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "06/09/2017"
diff --git a/src/silx/gui/plot3d/utils/__init__.py b/src/silx/gui/plot3d/utils/__init__.py
index 99d3e08..3cf3825 100644
--- a/src/silx/gui/plot3d/utils/__init__.py
+++ b/src/silx/gui/plot3d/utils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/plot3d/utils/mng.py b/src/silx/gui/plot3d/utils/mng.py
index 8049a2f..52f619f 100644
--- a/src/silx/gui/plot3d/utils/mng.py
+++ b/src/silx/gui/plot3d/utils/mng.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
@@ -28,8 +27,6 @@ It only supports RGB888 images of the same shape stored as
MNG-VLC (very low complexity) format.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "15/12/2016"
diff --git a/src/silx/gui/printer.py b/src/silx/gui/printer.py
index 761fa0f..c0af97f 100644
--- a/src/silx/gui/printer.py
+++ b/src/silx/gui/printer.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a singleton QPrinter used by default by silx widgets.
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/03/2018"
diff --git a/src/silx/gui/qt/__init__.py b/src/silx/gui/qt/__init__.py
index 915c89b..bc75041 100644
--- a/src/silx/gui/qt/__init__.py
+++ b/src/silx/gui/qt/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -25,11 +24,12 @@
"""Common wrapper over Python Qt bindings:
- `PyQt5 <http://pyqt.sourceforge.net/Docs/PyQt5/>`_
-- `PySide2 <https://pypi.org/project/PySide2/>`_
- `PySide6 <https://pypi.org/project/PySide6/>`_
+- `PySide2 <https://pypi.org/project/PySide2/>`_
+- `PyQt6 <https://pypi.org/project/PyQt6/>`_
If a Qt binding is already loaded, it will use it, otherwise the different
-Qt bindings are tried in this order: PyQt5, PySide2, PySide6.
+Qt bindings are tried in this order: PyQt5, PySide6, PySide2, PyQt6.
The name of the loaded Qt binding is stored in the BINDING variable.
diff --git a/src/silx/gui/qt/_pyqt6.py b/src/silx/gui/qt/_pyqt6.py
new file mode 100644
index 0000000..15b49bb
--- /dev/null
+++ b/src/silx/gui/qt/_pyqt6.py
@@ -0,0 +1,64 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2021 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""PyQt6 backward compatibility patching"""
+
+__authors__ = ["Thomas VINCENT"]
+__license__ = "MIT"
+__date__ = "02/09/2021"
+
+import enum
+import logging
+
+import PyQt6.sip
+from PyQt6.QtCore import Qt
+
+
+_logger = logging.getLogger(__name__)
+
+
+def patch_enums(*modules):
+ """Patch PyQt6 modules to provide backward compatibility of enum values
+
+ :param modules: Modules to patch (e.g., PyQt6.QtCore).
+ """
+ for module in modules:
+ for clsName in dir(module):
+ cls = getattr(module, clsName, None)
+ if isinstance(cls, PyQt6.sip.wrappertype) and clsName.startswith('Q'):
+ for qenumName in dir(cls):
+ if qenumName[0].isupper():
+ qenum = getattr(cls, qenumName, None)
+ if isinstance(qenum, enum.EnumMeta):
+ if qenum is getattr(cls.__mro__[1], qenumName, None):
+ continue # Only handle it once
+ for item in qenum:
+ # Special cases to avoid overrides and mimic PySide6
+ if clsName == 'QColorSpace' and qenumName in (
+ 'Primaries', 'TransferFunction'):
+ break
+ if qenumName in ('DeviceType', 'PointerType'):
+ break
+
+ setattr(cls, item.name, item)
diff --git a/src/silx/gui/qt/_pyside_dynamic.py b/src/silx/gui/qt/_pyside_dynamic.py
index a841eae..80520ac 100644
--- a/src/silx/gui/qt/_pyside_dynamic.py
+++ b/src/silx/gui/qt/_pyside_dynamic.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# Taken from: https://gist.github.com/cpbotha/1b42a20c8f3eb9bb7cb8
# Plus: https://github.com/spyder-ide/qtpy/commit/001a862c401d757feb63025f88dbb4601d353c84
diff --git a/src/silx/gui/qt/_qt.py b/src/silx/gui/qt/_qt.py
index f62f4c8..b92fce2 100644
--- a/src/silx/gui/qt/_qt.py
+++ b/src/silx/gui/qt/_qt.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,22 +25,23 @@
__authors__ = ["V.A. Sole"]
__license__ = "MIT"
-__date__ = "23/05/2018"
+__date__ = "12/01/2022"
import logging
import sys
import traceback
+from silx.utils import deprecation
_logger = logging.getLogger(__name__)
BINDING = None
-"""The name of the Qt binding in use: PyQt5, PySide2, PySide6."""
+"""The name of the Qt binding in use: PyQt5, PySide2, PySide6, PyQt6."""
QtBinding = None # noqa
-"""The Qt binding module in use: PyQt5, PySide2, PySide6."""
+"""The Qt binding module in use: PyQt5, PySide2, PySide6, PyQt6."""
HAS_SVG = False
"""True if Qt provides support for Scalable Vector Graphics (QtSVG)."""
@@ -50,7 +50,7 @@ HAS_OPENGL = False
"""True if Qt provides support for OpenGL (QtOpenGL)."""
# First check for an already loaded wrapper
-for _binding in ('PySide2', 'PyQt5', 'PySide6'):
+for _binding in ('PySide2', 'PyQt5', 'PySide6', 'PyQt6'):
if _binding + '.QtCore' in sys.modules:
BINDING = _binding
break
@@ -61,27 +61,40 @@ else: # Then try Qt bindings
if 'PyQt5' in sys.modules:
del sys.modules["PyQt5"]
try:
- import PySide2.QtCore # noqa
+ import PySide6.QtCore # noqa
except ImportError:
- if 'PySide2' in sys.modules:
- del sys.modules["PySide2"]
+ if 'PySide6' in sys.modules:
+ del sys.modules["PySide6"]
try:
- import PySide6.QtCore # noqa
+ import PySide2.QtCore # noqa
except ImportError:
- if 'PySide6' in sys.modules:
- del sys.modules["PySide6"]
- raise ImportError(
- 'No Qt wrapper found. Install PyQt5, PySide2, PySide6.')
+ if 'PySide2' in sys.modules:
+ del sys.modules["PySide2"]
+ try:
+ import PyQt6.QtCore # noqa
+ except ImportError:
+ if 'PyQt6' in sys.modules:
+ del sys.modules["PyQt6"]
+
+ raise ImportError(
+ 'No Qt wrapper found. Install PyQt5, PySide2, PySide6, PyQt6.')
+ else:
+ BINDING = 'PyQt6'
else:
- BINDING = 'PySide6'
+ BINDING = 'PySide2'
else:
- BINDING = 'PySide2'
+ BINDING = 'PySide6'
else:
BINDING = 'PyQt5'
if BINDING == 'PyQt5':
_logger.debug('Using PyQt5 bindings')
+ from PyQt5 import QtCore
+ if sys.version_info >= (3, 10) and QtCore.PYQT_VERSION < 0x50e02:
+ raise RuntimeError(
+ "PyQt5 v%s is not supported, please upgrade it." % QtCore.PYQT_VERSION_STR
+ )
import PyQt5 as QtBinding # noqa
@@ -121,7 +134,12 @@ if BINDING == 'PyQt5':
elif BINDING == 'PySide2':
- _logger.debug('Using PySide2 bindings')
+ deprecation.deprecated_warning(
+ type_="Qt Binding",
+ name="PySide2",
+ replacement="PySide6",
+ since_version="1.1",
+ )
import PySide2 as QtBinding # noqa
@@ -156,7 +174,7 @@ elif BINDING == 'PySide2':
return super().exec_(*args, **kwargs)
# QtWidgets
- class QApplication(_ExecMixIn, QApplication): pass
+ QApplication.exec = QApplication.exec_
class QColorDialog(_ExecMixIn, QColorDialog): pass
class QDialog(_ExecMixIn, QDialog): pass
class QErrorMessage(_ExecMixIn, QErrorMessage): pass
@@ -189,7 +207,7 @@ elif BINDING == 'PySide6':
from PySide6.QtOpenGL import * # noqa
from PySide6.QtOpenGLWidgets import QOpenGLWidget # noqa
except ImportError:
- _logger.info("PySide6.QtOpenGL not available")
+ _logger.info("PySide6's QtOpenGL or QtOpenGLWidgets not available")
HAS_OPENGL = False
else:
HAS_OPENGL = True
@@ -204,8 +222,63 @@ elif BINDING == 'PySide6':
pyqtSignal = Signal
+
+elif BINDING == 'PyQt6':
+ _logger.debug('Using PyQt6 bindings')
+
+ # Monkey-patch module to expose enum values for compatibility
+ # All Qt modules loaded here should be patched.
+ from . import _pyqt6
+ from PyQt6 import QtCore
+ if QtCore.PYQT_VERSION < int("0x60300", 16):
+ raise RuntimeError(
+ "PyQt6 v%s is not supported, please upgrade it." % QtCore.PYQT_VERSION_STR
+ )
+
+ from PyQt6 import QtGui, QtWidgets, QtPrintSupport, QtOpenGL, QtSvg
+ from PyQt6 import QtTest as _QtTest
+ _pyqt6.patch_enums(
+ QtCore, QtGui, QtWidgets, QtPrintSupport, QtOpenGL, QtSvg, _QtTest)
+
+ import PyQt6 as QtBinding # noqa
+
+ from PyQt6.QtCore import * # noqa
+ from PyQt6.QtGui import * # noqa
+ from PyQt6.QtWidgets import * # noqa
+ from PyQt6.QtPrintSupport import * # noqa
+
+ try:
+ from PyQt6.QtOpenGL import * # noqa
+ from PyQt6.QtOpenGLWidgets import QOpenGLWidget # noqa
+ except ImportError:
+ _logger.info("PyQt6's QtOpenGL or QtOpenGLWidgets not available")
+ HAS_OPENGL = False
+ else:
+ HAS_OPENGL = True
+
+ try:
+ from PyQt6.QtSvg import * # noqa
+ except ImportError:
+ _logger.info("PyQt6.QtSvg not available")
+ HAS_SVG = False
+ else:
+ HAS_SVG = True
+
+ from PyQt6.uic import loadUi # noqa
+
+ Signal = pyqtSignal
+
+ Property = pyqtProperty
+
+ Slot = pyqtSlot
+
+ # Disable PyQt6 cooperative multi-inheritance since other bindings do not provide it.
+ # See https://www.riverbankcomputing.com/static/Docs/PyQt6/multiinheritance.html?highlight=inheritance
+ class _Foo(object): pass
+ class QObject(QObject, _Foo): pass
+
else:
- raise ImportError('No Qt wrapper found. Install PyQt5, PySide2 or PySide6')
+ raise ImportError('No Qt wrapper found. Install PyQt5, PySide2, PySide6 or PyQt6')
# provide a exception handler but not implement it by default
diff --git a/src/silx/gui/qt/_utils.py b/src/silx/gui/qt/_utils.py
index 5dced95..fb2b8ce 100644
--- a/src/silx/gui/qt/_utils.py
+++ b/src/silx/gui/qt/_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -33,6 +32,19 @@ __date__ = "30/11/2016"
from . import _qt
+def getMouseEventPosition(event):
+ """Qt5/Qt6 compatibility wrapper to access QMouseEvent position
+
+ :param QMouseEvent event:
+ :returns: (x, y) as a tuple of float
+ """
+ if _qt.BINDING in ("PyQt5", "PySide2"):
+ return float(event.x()), float(event.y())
+ # Qt6
+ position = event.position()
+ return position.x(), position.y()
+
+
def supportedImageFormats():
"""Return a set of string of file format extensions supported by the
Qt runtime."""
diff --git a/src/silx/gui/qt/inspect.py b/src/silx/gui/qt/inspect.py
index b9a0d1d..c7fe32a 100644
--- a/src/silx/gui/qt/inspect.py
+++ b/src/silx/gui/qt/inspect.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -69,6 +68,21 @@ elif qt.BINDING == 'PySide2':
elif qt.BINDING == 'PySide6':
from shiboken6 import isValid, createdByPython, ownedByPython # noqa
+elif qt.BINDING == 'PyQt6':
+ from PyQt6.sip import isdeleted as _isdeleted # noqa
+ from PyQt6.sip import ispycreated as createdByPython # noqa
+ from PyQt6.sip import ispyowned as ownedByPython # noqa
+
+ def isValid(obj):
+ """Returns True if underlying C++ object is valid.
+
+ :param QObject obj:
+ :rtype: bool
+ """
+ return not _isdeleted(obj)
+
+
+
else:
raise ImportError("Unsupported Qt binding %s" % qt.BINDING)
diff --git a/src/silx/gui/setup.py b/src/silx/gui/setup.py
deleted file mode 100644
index 04a2bac..0000000
--- a/src/silx/gui/setup.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "28/11/2017"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('gui', parent_package, top_path)
- config.add_subpackage('_glutils')
- config.add_subpackage('qt')
- config.add_subpackage('plot')
- config.add_subpackage('fit')
- config.add_subpackage('hdf5')
- config.add_subpackage('widgets')
- config.add_subpackage('test')
- config.add_subpackage('plot3d')
- config.add_subpackage('data')
- config.add_subpackage('dialog')
- config.add_subpackage('utils')
- config.add_subpackage('utils.glutils')
- config.add_subpackage('utils.test')
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/gui/test/__init__.py b/src/silx/gui/test/__init__.py
index 00d6216..d9e06fc 100644
--- a/src/silx/gui/test/__init__.py
+++ b/src/silx/gui/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/test/test_colors.py b/src/silx/gui/test/test_colors.py
index fa87d7d..b0e6139 100755
--- a/src/silx/gui/test/test_colors.py
+++ b/src/silx/gui/test/test_colors.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides the Colormap object
"""
-from __future__ import absolute_import
-
__authors__ = ["H.Payno"]
__license__ = "MIT"
__date__ = "09/11/2018"
diff --git a/src/silx/gui/test/test_console.py b/src/silx/gui/test/test_console.py
index 21f3564..f636287 100644
--- a/src/silx/gui/test/test_console.py
+++ b/src/silx/gui/test/test_console.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Basic tests for IPython console widget"""
-from __future__ import print_function
-
__authors__ = ["P. Knobel"]
__license__ = "MIT"
__date__ = "05/12/2016"
diff --git a/src/silx/gui/test/test_icons.py b/src/silx/gui/test/test_icons.py
index 154adf6..59c7e00 100644
--- a/src/silx/gui/test/test_icons.py
+++ b/src/silx/gui/test/test_icons.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/test/test_qt.py b/src/silx/gui/test/test_qt.py
index 8554744..692d7f7 100644
--- a/src/silx/gui/test/test_qt.py
+++ b/src/silx/gui/test/test_qt.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/test/utils.py b/src/silx/gui/test/utils.py
index db4c0ee..1cfee67 100644
--- a/src/silx/gui/test/utils.py
+++ b/src/silx/gui/test/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Color conversion function, color dictionary and colormap tools."""
-from __future__ import absolute_import
-
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "05/10/2018"
diff --git a/src/silx/gui/utils/__init__.py b/src/silx/gui/utils/__init__.py
index 726ad74..4fae646 100755
--- a/src/silx/gui/utils/__init__.py
+++ b/src/silx/gui/utils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/utils/concurrent.py b/src/silx/gui/utils/concurrent.py
index c27374f..242e804 100644
--- a/src/silx/gui/utils/concurrent.py
+++ b/src/silx/gui/utils/concurrent.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module allows to run a function in Qt main thread from another thread
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "09/03/2018"
diff --git a/src/silx/gui/utils/glutils/__init__.py b/src/silx/gui/utils/glutils/__init__.py
index 20e611e..2651402 100644
--- a/src/silx/gui/utils/glutils/__init__.py
+++ b/src/silx/gui/utils/glutils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020-2021 European Synchrotron Radiation Facility
@@ -52,14 +51,15 @@ class _isOpenGLAvailableResult:
return '<_isOpenGLAvailableResult: %s, "%s">' % (self.status, self.error)
-def _runtimeOpenGLCheck(version):
+def _runtimeOpenGLCheck(version, shareOpenGLContexts):
"""Run OpenGL check in a subprocess.
This is done by starting a subprocess that displays a Qt OpenGL widget.
:param List[int] version:
The minimal required OpenGL version as a 2-tuple (major, minor).
- Default: (2, 1)
+ :param bool shareOpenGLContexts:
+ True to test the `QApplication` with `AA_ShareOpenGLContexts`.
:return: An error string that is empty if no error occured
:rtype: str
"""
@@ -69,10 +69,10 @@ def _runtimeOpenGLCheck(version):
[os.path.abspath(p) for p in sys.path])
try:
- error = subprocess.check_output(
- [sys.executable, '-s', '-S', __file__, major, minor],
- env=env,
- timeout=2)
+ cmd = [sys.executable, '-s', '-S', __file__, major, minor]
+ if shareOpenGLContexts:
+ cmd.append("--shareOpenGLContexts")
+ error = subprocess.check_output(cmd, env=env, timeout=2)
except subprocess.TimeoutExpired:
status = False
error = "Qt OpenGL widget hang"
@@ -90,7 +90,7 @@ def _runtimeOpenGLCheck(version):
_runtimeCheckCache = {} # Cache runtime check results: {version: result}
-def isOpenGLAvailable(version=(2, 1), runtimeCheck=True):
+def isOpenGLAvailable(version=(2, 1), runtimeCheck=True, shareOpenGLContexts=False):
"""Check if OpenGL is available through Qt and actually working.
After some basic tests, this is done by starting a subprocess that
@@ -99,8 +99,12 @@ def isOpenGLAvailable(version=(2, 1), runtimeCheck=True):
:param List[int] version:
The minimal required OpenGL version as a 2-tuple (major, minor).
Default: (2, 1)
+ :param bool shareOpenGLContexts:
+ True to test the `QApplication` with `AA_ShareOpenGLContexts`.
+ This only can be checked with `runtimeCheck` enabled.
+ Default is false.
:param bool runtimeCheck:
- True (default) to run the test creating a Qt OpenGL widgt in a subprocess,
+ True (default) to run the test creating a Qt OpenGL widget in a subprocess,
False to avoid this check.
:return: A result object that evaluates to True if successful and
which has a `status` boolean attribute (True if successful) and
@@ -131,12 +135,13 @@ def isOpenGLAvailable(version=(2, 1), runtimeCheck=True):
result = _isOpenGLAvailableResult(error == '', error)
+ keyCache = version, shareOpenGLContexts
if result: # No error so far, runtime check
- if version in _runtimeCheckCache: # Use cache
- result = _runtimeCheckCache[version]
+ if keyCache in _runtimeCheckCache: # Use cache
+ result = _runtimeCheckCache[keyCache]
elif runtimeCheck: # Run test in subprocess
- result = _runtimeOpenGLCheck(version)
- _runtimeCheckCache[version] = result
+ result = _runtimeOpenGLCheck(version, shareOpenGLContexts)
+ _runtimeCheckCache[keyCache] = result
return result
@@ -178,9 +183,12 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('major')
parser.add_argument('minor')
+ parser.add_argument('--shareOpenGLContexts', action="store_true")
args = parser.parse_args(args=sys.argv[1:])
+ if args.shareOpenGLContexts:
+ qt.QCoreApplication.setAttribute(qt.Qt.AA_ShareOpenGLContexts)
app = qt.QApplication([])
window = qt.QMainWindow(flags=
qt.Qt.Popup |
diff --git a/src/silx/gui/utils/image.py b/src/silx/gui/utils/image.py
index 96f50ab..1757e3e 100644
--- a/src/silx/gui/utils/image.py
+++ b/src/silx/gui/utils/image.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,9 +27,6 @@
- :func:`convertQImageToArray`
"""
-from __future__ import division
-
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "04/09/2018"
@@ -118,6 +114,8 @@ def convertQImageToArray(image):
ptr = image.bits()
if qt.BINDING == 'PyQt5':
ptr.setsize(image.byteCount())
+ elif qt.BINDING == 'PyQt6':
+ ptr.setsize(image.sizeInBytes())
elif qt.BINDING in ('PySide2', 'PySide6'):
ptr = ptr.tobytes()
else:
diff --git a/src/silx/gui/utils/matplotlib.py b/src/silx/gui/utils/matplotlib.py
index 90257f8..277a303 100644
--- a/src/silx/gui/utils/matplotlib.py
+++ b/src/silx/gui/utils/matplotlib.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,8 +22,6 @@
#
# ###########################################################################*/
-from __future__ import absolute_import
-
"""This module initializes matplotlib and sets-up the backend to use.
It MUST be imported prior to any other import of matplotlib.
@@ -38,27 +35,116 @@ __license__ = "MIT"
__date__ = "02/05/2018"
+import io
from pkg_resources import parse_version
import matplotlib
+import numpy
from .. import qt
+def rasterMathText(text, font, size=-1, weight=-1, italic=False, devicePixelRatio=1.0):
+ """Raster text using matplotlib supporting latex-like math syntax.
+
+ It supports multiple lines.
+
+ :param str text: The text to raster
+ :param font: Font name or QFont to use
+ :type font: str or :class:`QFont`
+ :param int size:
+ Font size in points
+ Used only if font is given as name.
+ :param int weight:
+ Font weight in [0, 99], see QFont.Weight.
+ Used only if font is given as name.
+ :param bool italic:
+ True for italic font (default: False).
+ Used only if font is given as name.
+ :param float devicePixelRatio:
+ The current ratio between device and device-independent pixel
+ (default: 1.0)
+ :return: Corresponding image in gray scale and baseline offset from top
+ :rtype: (HxW numpy.ndarray of uint8, int)
+ """
+ # Implementation adapted from:
+ # https://github.com/matplotlib/matplotlib/blob/d624571a19aec7c7d4a24123643288fc27db17e7/lib/matplotlib/mathtext.py#L264
+
+ # Lazy import to avoid imports before setting matplotlib's rcParams
+ from matplotlib.font_manager import FontProperties
+ from matplotlib.mathtext import MathTextParser
+ from matplotlib import figure
+
+ dpi = 96 # default
+ qapp = qt.QApplication.instance()
+ if qapp:
+ screen = qapp.primaryScreen()
+ if screen:
+ dpi = screen.logicalDotsPerInchY()
+
+ # Make sure dpi is even, it causes issues with array reshape otherwise
+ dpi = ((dpi * devicePixelRatio) // 2) * 2
+
+ stripped_text = text.strip("\n")
+
+ parser = MathTextParser("path")
+ width, height, depth, _, _ = parser.parse(stripped_text, dpi=dpi)
+ width *= 2
+ height *= 2 * (stripped_text.count("\n") + 1)
+
+ if not isinstance(font, qt.QFont):
+ font = qt.QFont(font, size, weight, italic)
+ prop = FontProperties(
+ family=font.family(),
+ style="italic" if font.italic() else "normal",
+ weight=10 * font.weight(),
+ size=font.pointSize(),
+ )
+
+ fig = figure.Figure(figsize=(width / dpi, height / dpi))
+ fig.text(0, depth / height, stripped_text, fontproperties=prop)
+ with io.BytesIO() as buffer:
+ fig.savefig(buffer, dpi=dpi, format="raw")
+ buffer.seek(0)
+ image = numpy.frombuffer(buffer.read(), dtype=numpy.uint8).reshape(
+ int(height), int(width), 4
+ )
+
+ # RGB to inverted R channel
+ array = 255 - image[:, :, 0]
+
+ # Remove leading and trailing empty columns/rows but one on each side
+ filled_rows = numpy.nonzero(numpy.sum(array, axis=1))[0]
+ filled_columns = numpy.nonzero(numpy.sum(array, axis=0))[0]
+ if len(filled_rows) == 0 or len(filled_columns) == 0:
+ return array, image.shape[0] - 1
+
+ clipped_array = numpy.ascontiguousarray(
+ array[
+ max(0, filled_rows[0] - 1) : filled_rows[-1] + 2,
+ max(0, filled_columns[0] - 1) : filled_columns[-1] + 2,
+ ]
+ )
+
+ return clipped_array, image.shape[0] - 1 # baseline not available
+
+
def _matplotlib_use(backend, force):
"""Wrapper of `matplotlib.use` to set-up backend.
- It adds extra initialization for PySide2 with matplotlib < 2.2.
+ It adds extra initialization for PySide2 with matplotlib < 2.2.
"""
# This is kept for compatibility with matplotlib < 2.2
- if (parse_version(matplotlib.__version__) < parse_version('2.2') and
- qt.BINDING == 'PySide2'):
- matplotlib.rcParams['backend.qt5'] = 'PySide2'
+ if (
+ parse_version(matplotlib.__version__) < parse_version("2.2")
+ and qt.BINDING == "PySide2"
+ ):
+ matplotlib.rcParams["backend.qt5"] = "PySide2"
matplotlib.use(backend, force=force)
-if qt.BINDING in ('PySide6', 'PyQt5', 'PySide2'):
- _matplotlib_use('Qt5Agg', force=False)
+if qt.BINDING in ("PySide6", "PyQt6", "PyQt5", "PySide2"):
+ _matplotlib_use("Qt5Agg", force=False)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg # noqa
else:
diff --git a/src/silx/gui/utils/projecturl.py b/src/silx/gui/utils/projecturl.py
index 0832c2e..116017e 100644
--- a/src/silx/gui/utils/projecturl.py
+++ b/src/silx/gui/utils/projecturl.py
@@ -1,4 +1,3 @@
-# coding: utf-8
#
# Project: Azimuthal integration
# https://github.com/silx-kit/silx
@@ -23,8 +22,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-from __future__ import absolute_import, print_function, division
-
"""Provide convenient URL for silx-kit projects."""
__author__ = "Valentin Valls"
diff --git a/src/silx/gui/utils/qtutils.py b/src/silx/gui/utils/qtutils.py
index 9682913..d686a48 100755
--- a/src/silx/gui/utils/qtutils.py
+++ b/src/silx/gui/utils/qtutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/utils/signal.py b/src/silx/gui/utils/signal.py
index 359f5cc..cd376a9 100644
--- a/src/silx/gui/utils/signal.py
+++ b/src/silx/gui/utils/signal.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2012 University of North Carolina at Chapel Hill, Luke Campagnola
diff --git a/src/silx/gui/utils/test/__init__.py b/src/silx/gui/utils/test/__init__.py
index 15cd186..7a8edb9 100755
--- a/src/silx/gui/utils/test/__init__.py
+++ b/src/silx/gui/utils/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/utils/test/test.py b/src/silx/gui/utils/test/test.py
index 0208d64..42bf5a2 100644
--- a/src/silx/gui/utils/test/test.py
+++ b/src/silx/gui/utils/test/test.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019-2021 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Test of functions available in silx.gui.utils module."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/gui/utils/test/test_async.py b/src/silx/gui/utils/test/test_async.py
index 7304ca9..1fd8509 100644
--- a/src/silx/gui/utils/test/test_async.py
+++ b/src/silx/gui/utils/test/test_async.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Test of async module."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "09/03/2018"
diff --git a/src/silx/gui/utils/test/test_glutils.py b/src/silx/gui/utils/test/test_glutils.py
index 7c9831b..4921f16 100644
--- a/src/silx/gui/utils/test/test_glutils.py
+++ b/src/silx/gui/utils/test/test_glutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
@@ -30,26 +29,24 @@ __date__ = "15/01/2020"
import logging
-import unittest
+import pytest
+
from silx.gui.utils.glutils import isOpenGLAvailable
_logger = logging.getLogger(__name__)
-class TestIsOpenGLAvailable(unittest.TestCase):
- """Test isOpenGLAvailable"""
-
- def test(self):
- for version in ((2, 1), (2, 1), (1000, 1)):
- with self.subTest(version=version):
- result = isOpenGLAvailable(version=version)
- _logger.info("isOpenGLAvailable returned: %s", str(result))
- if version[0] == 1000:
- self.assertFalse(result)
- if not result:
- self.assertFalse(result.status)
- self.assertTrue(len(result.error) > 0)
- else:
- self.assertTrue(result.status)
- self.assertTrue(len(result.error) == 0)
+@pytest.mark.parametrize("params", (((2, 1), False), ((2, 1), False), ((1000, 1), False), ((2, 1), True)))
+def testOpenGLAvailable(params):
+ version, shareOpenGLContexts = params
+ result = isOpenGLAvailable(version=version, shareOpenGLContexts=shareOpenGLContexts)
+ _logger.info("isOpenGLAvailable returned: %s", str(result))
+ if version[0] == 1000:
+ assert not result
+ if not result:
+ assert not result.status
+ assert len(result.error) > 0
+ else:
+ assert result.status
+ assert len(result.error) == 0
diff --git a/src/silx/gui/utils/test/test_image.py b/src/silx/gui/utils/test/test_image.py
index 62316b0..07bc396 100644
--- a/src/silx/gui/utils/test/test_image.py
+++ b/src/silx/gui/utils/test/test_image.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/utils/test/test_qtutils.py b/src/silx/gui/utils/test/test_qtutils.py
index c00280b..c5ff2d2 100755
--- a/src/silx/gui/utils/test/test_qtutils.py
+++ b/src/silx/gui/utils/test/test_qtutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Test of functions available in silx.gui.utils module."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/gui/utils/test/test_testutils.py b/src/silx/gui/utils/test/test_testutils.py
index 07294a7..e8a0123 100644
--- a/src/silx/gui/utils/test/test_testutils.py
+++ b/src/silx/gui/utils/test/test_testutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/utils/testutils.py b/src/silx/gui/utils/testutils.py
index 40c8237..1ec9b0b 100644
--- a/src/silx/gui/utils/testutils.py
+++ b/src/silx/gui/utils/testutils.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -26,7 +25,7 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "05/10/2018"
+__date__ = "22/07/2022"
import gc
@@ -49,6 +48,8 @@ elif qt.BINDING == 'PyQt5':
from PyQt5.QtTest import QTest
elif qt.BINDING == 'PySide6':
from PySide6.QtTest import QTest
+elif qt.BINDING == 'PyQt6':
+ from PyQt6.QtTest import QTest
else:
raise ImportError('Unsupported Qt bindings')
@@ -140,10 +141,14 @@ class TestCaseQt(unittest.TestCase):
def _currentTestSucceeded(self):
if hasattr(self, '_outcome'):
- # For Python >= 3.4
- result = self.defaultTestResult() # these 2 methods have no side effects
- if hasattr(self._outcome, 'errors'):
- self._feedErrorsToResult(result, self._outcome.errors)
+ if hasattr(self, '_feedErrorsToResult'):
+ # For Python 3.4 -3.10
+ result = self.defaultTestResult() # these 2 methods have no side effects
+ if hasattr(self._outcome, 'errors'):
+ self._feedErrorsToResult(result, self._outcome.errors)
+ else:
+ # Python 3.11+
+ result = self._outcome.result
else:
# For Python < 3.4
result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups)
@@ -155,11 +160,11 @@ class TestCaseQt(unittest.TestCase):
def _checkForUnreleasedWidgets(self):
"""Test fixture checking that no more widgets exists."""
- gc.collect()
-
if self.__previousWidgets is None:
return # Do not test for leaking widgets with PySide2
+ gc.collect()
+
widgets = [widget for widget in self.qapp.allWidgets()
if (widget not in self.__previousWidgets and
_inspect.createdByPython(widget))]
@@ -253,7 +258,7 @@ class TestCaseQt(unittest.TestCase):
See QTest.mouseClick for details.
"""
if modifier is None:
- modifier = qt.Qt.KeyboardModifiers()
+ modifier = self.qapp.keyboardModifiers()
pos = qt.QPoint(int(pos[0]), int(pos[1])) if pos is not None else qt.QPoint()
QTest.mouseClick(widget, button, modifier, pos, delay)
self.qWait(20)
@@ -264,7 +269,7 @@ class TestCaseQt(unittest.TestCase):
See QTest.mouseDClick for details.
"""
if modifier is None:
- modifier = qt.Qt.KeyboardModifiers()
+ modifier = self.qapp.keyboardModifiers()
pos = qt.QPoint(int(pos[0]), int(pos[1])) if pos is not None else qt.QPoint()
QTest.mouseDClick(widget, button, modifier, pos, delay)
self.qWait(20)
@@ -284,7 +289,7 @@ class TestCaseQt(unittest.TestCase):
See QTest.mousePress for details.
"""
if modifier is None:
- modifier = qt.Qt.KeyboardModifiers()
+ modifier = self.qapp.keyboardModifiers()
pos = qt.QPoint(int(pos[0]), int(pos[1])) if pos is not None else qt.QPoint()
QTest.mousePress(widget, button, modifier, pos, delay)
self.qWait(20)
@@ -295,7 +300,7 @@ class TestCaseQt(unittest.TestCase):
See QTest.mouseRelease for details.
"""
if modifier is None:
- modifier = qt.Qt.KeyboardModifiers()
+ modifier = self.qapp.keyboardModifiers()
pos = qt.QPoint(int(pos[0]), int(pos[1])) if pos is not None else qt.QPoint()
QTest.mouseRelease(widget, button, modifier, pos, delay)
self.qWait(20)
@@ -486,7 +491,7 @@ def getQToolButtonFromAction(action):
:param QAction action: The QAction from which to get QToolButton.
:return: A QToolButton associated to action or None.
"""
- if qt.BINDING == "PySide6":
+ if qt.BINDING in ("PySide6", "PyQt6"):
widgets = action.associatedObjects()
else:
widgets = action.associatedWidgets()
diff --git a/src/silx/gui/widgets/BoxLayoutDockWidget.py b/src/silx/gui/widgets/BoxLayoutDockWidget.py
index 3d2b853..aa45153 100644
--- a/src/silx/gui/widgets/BoxLayoutDockWidget.py
+++ b/src/silx/gui/widgets/BoxLayoutDockWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/ColormapNameComboBox.py b/src/silx/gui/widgets/ColormapNameComboBox.py
index fa8faf1..388b032 100644
--- a/src/silx/gui/widgets/ColormapNameComboBox.py
+++ b/src/silx/gui/widgets/ColormapNameComboBox.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""A QComboBox to display prefered colormaps
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent", "H. Payno"]
__license__ = "MIT"
__date__ = "27/11/2018"
diff --git a/src/silx/gui/widgets/ElidedLabel.py b/src/silx/gui/widgets/ElidedLabel.py
index 7c6dfb5..3760ec0 100644
--- a/src/silx/gui/widgets/ElidedLabel.py
+++ b/src/silx/gui/widgets/ElidedLabel.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -28,17 +27,18 @@
__license__ = "MIT"
__date__ = "07/12/2018"
+from ...utils.deprecation import deprecated
from silx.gui import qt
class ElidedLabel(qt.QLabel):
- """QLabel with an edile property.
+ """QLabel with an elide property.
- By default if the text is too big, it is elided on the right.
+ By default if the text is too long, it is elided on the right.
This mode can be changed with :func:`setElideMode`.
- In case the text is elided, the full content is displayed as part of the
+ In this case the text is elided, the full content is displayed as part of the
tool tip. This behavior can be disabled with :func:`setTextAsToolTip`.
"""
@@ -83,25 +83,41 @@ class ElidedLabel(qt.QLabel):
else:
qt.QLabel.setToolTip(self, self.__toolTip)
- # Properties
+ # Inherited properties
+
+ def text(self):
+ """Returns the text defined by the user.
+
+ It can be different from the one really displayed, depending on the
+ `elideMode` defined for this widget.
+ """
+ return self.__text
+
+ @deprecated(replacement='text', since_version='1.1.0')
+ def getText(self):
+ return self.text()
def setText(self, text):
self.__text = text
self.__updateText()
- def getText(self):
- return self.__text
+ def toolTip(self):
+ """Returns the tooltip defined by the user.
- text = qt.Property(str, getText, setText)
+ It can be different from the one really displayed, if `textAsToolTip` was
+ set to true.
+ """
+ return self.__toolTip
+
+ @deprecated(replacement='toolTip', since_version='1.1.0')
+ def getToolTip(self):
+ return self.toolTip()
def setToolTip(self, toolTip):
self.__toolTip = toolTip
self.__updateToolTip()
- def getToolTip(self):
- return self.__toolTip
-
- toolTip = qt.Property(str, getToolTip, setToolTip)
+ # New properties
def setElideMode(self, elideMode):
"""Set the elide mode.
@@ -118,7 +134,7 @@ class ElidedLabel(qt.QLabel):
"""
return self.__elideMode
- elideMode = qt.Property(qt.Qt.TextElideMode, getToolTip, setToolTip)
+ elideMode = qt.Property(qt.Qt.TextElideMode, getElideMode, setElideMode)
def setTextAsToolTip(self, enabled):
"""Enable displaying text as part of the tooltip if it is elided.
diff --git a/src/silx/gui/widgets/FloatEdit.py b/src/silx/gui/widgets/FloatEdit.py
index 08ed67d..61f518f 100644
--- a/src/silx/gui/widgets/FloatEdit.py
+++ b/src/silx/gui/widgets/FloatEdit.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""Module contains a float editor
"""
-from __future__ import division
-
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
__date__ = "02/10/2017"
diff --git a/src/silx/gui/widgets/FlowLayout.py b/src/silx/gui/widgets/FlowLayout.py
index 3c4c9dd..917aa09 100644
--- a/src/silx/gui/widgets/FlowLayout.py
+++ b/src/silx/gui/widgets/FlowLayout.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
"""This module provides a flow layout for QWidget: :class:`FlowLayout`.
"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "20/07/2018"
diff --git a/src/silx/gui/widgets/FormGridLayout.py b/src/silx/gui/widgets/FormGridLayout.py
new file mode 100644
index 0000000..6068d30
--- /dev/null
+++ b/src/silx/gui/widgets/FormGridLayout.py
@@ -0,0 +1,74 @@
+# /*##########################################################################
+#
+# Copyright (c) 2022 European Synchrotron Radiation Facility
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# ###########################################################################*/
+"""This module provides a form layout for QWidget: :class:`FormGridLayout`.
+"""
+
+__authors__ = ["V. Valls"]
+__license__ = "MIT"
+__date__ = "29/09/2022"
+
+
+import typing
+from .. import qt
+
+
+class FormGridLayout(qt.QGridLayout):
+ """A layout with the API of :class:`qt.QFormLayout` based on a :class:`qt.QGridLayout`.
+
+ This allow a bit more flexibility, like allow vertical expanding
+ of the rows.
+ """
+ def __init__(self, parent):
+ super(FormGridLayout, self).__init__(parent)
+ self.__cursor = 0
+
+ def _addCell(self, something, row, column, rowSpan=1, columnSpan=1):
+ if isinstance(something, qt.QLayout):
+ self.addLayout(something, row, column, rowSpan, columnSpan)
+ else:
+ if isinstance(something, str):
+ something = qt.QLabel(something)
+ self.addWidget(something, row, column, rowSpan, columnSpan)
+
+ def addRow(self, label: typing.Union[str, qt.QWidget, qt.QLayout], field: typing.Union[None, qt.QWidget, qt.QLayout] = None):
+ """
+ Adds a new row to the bottom of this form layout.
+
+ If field is defined, the given label and field are added.
+
+ Else, the label is a widget and spans both columns.
+ """
+ if field is None:
+ self._addCell(label, self.__cursor, 0, 1, 2)
+ else:
+ self._addCell(label, self.__cursor, 0)
+ self._addCell(field, self.__cursor, 1)
+ self.__cursor += 1
+
+ def addItem(self, item: qt.QLayoutItem):
+ """
+ Adds a new layout item to the bottom of this form layout.
+ """
+ super(FormGridLayout, self).addItem(item)
+ self.__cursor += 1
diff --git a/src/silx/gui/widgets/FrameBrowser.py b/src/silx/gui/widgets/FrameBrowser.py
index 671991f..17a9148 100644
--- a/src/silx/gui/widgets/FrameBrowser.py
+++ b/src/silx/gui/widgets/FrameBrowser.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/HierarchicalTableView.py b/src/silx/gui/widgets/HierarchicalTableView.py
index 3ccf4c7..6e6329b 100644
--- a/src/silx/gui/widgets/HierarchicalTableView.py
+++ b/src/silx/gui/widgets/HierarchicalTableView.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/LegendIconWidget.py b/src/silx/gui/widgets/LegendIconWidget.py
index 1c95e41..d0d2f5c 100755
--- a/src/silx/gui/widgets/LegendIconWidget.py
+++ b/src/silx/gui/widgets/LegendIconWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/MedianFilterDialog.py b/src/silx/gui/widgets/MedianFilterDialog.py
index dd4a00d..982736c 100644
--- a/src/silx/gui/widgets/MedianFilterDialog.py
+++ b/src/silx/gui/widgets/MedianFilterDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/MultiModeAction.py b/src/silx/gui/widgets/MultiModeAction.py
index 502275d..b40d285 100644
--- a/src/silx/gui/widgets/MultiModeAction.py
+++ b/src/silx/gui/widgets/MultiModeAction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/PeriodicTable.py b/src/silx/gui/widgets/PeriodicTable.py
index 6fed109..1fc3bab 100644
--- a/src/silx/gui/widgets/PeriodicTable.py
+++ b/src/silx/gui/widgets/PeriodicTable.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/PrintGeometryDialog.py b/src/silx/gui/widgets/PrintGeometryDialog.py
index 98ff8d1..db905fb 100644
--- a/src/silx/gui/widgets/PrintGeometryDialog.py
+++ b/src/silx/gui/widgets/PrintGeometryDialog.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/PrintPreview.py b/src/silx/gui/widgets/PrintPreview.py
index 53e0a1f..dd6af1f 100644
--- a/src/silx/gui/widgets/PrintPreview.py
+++ b/src/silx/gui/widgets/PrintPreview.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/RangeSlider.py b/src/silx/gui/widgets/RangeSlider.py
index 61b73fc..4db0470 100644
--- a/src/silx/gui/widgets/RangeSlider.py
+++ b/src/silx/gui/widgets/RangeSlider.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
@@ -27,7 +26,6 @@
.. image:: img/RangeSlider.png
:align: center
"""
-from __future__ import absolute_import, division
__authors__ = ["D. Naudet", "T. Vincent"]
__license__ = "MIT"
diff --git a/src/silx/gui/widgets/TableWidget.py b/src/silx/gui/widgets/TableWidget.py
index 50eb9e2..9bada5e 100644
--- a/src/silx/gui/widgets/TableWidget.py
+++ b/src/silx/gui/widgets/TableWidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/ThreadPoolPushButton.py b/src/silx/gui/widgets/ThreadPoolPushButton.py
index 949b6ef..8a1d428 100644
--- a/src/silx/gui/widgets/ThreadPoolPushButton.py
+++ b/src/silx/gui/widgets/ThreadPoolPushButton.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/WaitingPushButton.py b/src/silx/gui/widgets/WaitingPushButton.py
index 443dc9a..8bd9ea0 100644
--- a/src/silx/gui/widgets/WaitingPushButton.py
+++ b/src/silx/gui/widgets/WaitingPushButton.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/__init__.py b/src/silx/gui/widgets/__init__.py
index 9d0299d..cab7ef6 100644
--- a/src/silx/gui/widgets/__init__.py
+++ b/src/silx/gui/widgets/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/setup.py b/src/silx/gui/widgets/setup.py
deleted file mode 100644
index e96ac8d..0000000
--- a/src/silx/gui/widgets/setup.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "11/10/2016"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('widgets', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/gui/widgets/test/__init__.py b/src/silx/gui/widgets/test/__init__.py
index 243dbc7..03af6f2 100644
--- a/src/silx/gui/widgets/test/__init__.py
+++ b/src/silx/gui/widgets/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_boxlayoutdockwidget.py b/src/silx/gui/widgets/test/test_boxlayoutdockwidget.py
index 5df8df9..dd0ddf4 100644
--- a/src/silx/gui/widgets/test/test_boxlayoutdockwidget.py
+++ b/src/silx/gui/widgets/test/test_boxlayoutdockwidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_elidedlabel.py b/src/silx/gui/widgets/test/test_elidedlabel.py
index 693e43c..d7e2cdc 100644
--- a/src/silx/gui/widgets/test/test_elidedlabel.py
+++ b/src/silx/gui/widgets/test/test_elidedlabel.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2020 European Synchrotron Radiation Facility
+# Copyright (c) 2020-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -27,8 +26,6 @@
__license__ = "MIT"
__date__ = "08/06/2020"
-import unittest
-
from silx.gui import qt
from silx.gui.widgets.ElidedLabel import ElidedLabel
from silx.gui.utils import testutils
@@ -47,11 +44,18 @@ class TestElidedLabel(testutils.TestCaseQt):
del self.label
self.qapp.processEvents()
+ def testQLabelApi(self):
+ """Test overrided API from QLabel"""
+ self.label.setText("a")
+ assert self.label.text() == "a"
+ self.label.setToolTip("b")
+ assert self.label.toolTip() == "b"
+
def testElidedValue(self):
"""Test elided text"""
raw = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"
self.label.setText(raw)
- self.label.setFixedWidth(30)
+ self.label.setFixedWidth(40)
displayedText = qt.QLabel.text(self.label)
self.assertNotEqual(raw, displayedText)
self.assertIn("…", displayedText)
@@ -98,3 +102,21 @@ class TestElidedLabel(testutils.TestCaseQt):
displayedTooltip = qt.QLabel.toolTip(self.label)
self.assertNotIn(raw1, displayedTooltip)
self.assertIn(raw2, displayedTooltip)
+
+ def testTooltip(self):
+ """Test tooltip when elided"""
+ self.label.setToolTip("Fooo")
+ assert self.label.toolTip() == "Fooo"
+ displayedTooltip = qt.QLabel.toolTip(self.label)
+ assert displayedTooltip == "Fooo"
+
+ def testElidedTextAndTooltip(self):
+ """Test tooltip when elided"""
+ raw1 = "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"
+ self.label.setText(raw1)
+ self.label.setFixedWidth(30)
+ self.label.setToolTip("Fooo")
+ displayedTooltip = qt.QLabel.toolTip(self.label)
+ assert self.label.toolTip() == "Fooo"
+ assert "Fooo" in displayedTooltip
+ assert raw1 in displayedTooltip
diff --git a/src/silx/gui/widgets/test/test_flowlayout.py b/src/silx/gui/widgets/test/test_flowlayout.py
index 85d7cfe..07f6697 100644
--- a/src/silx/gui/widgets/test/test_flowlayout.py
+++ b/src/silx/gui/widgets/test/test_flowlayout.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_framebrowser.py b/src/silx/gui/widgets/test/test_framebrowser.py
index 8233622..7fa621b 100644
--- a/src/silx/gui/widgets/test/test_framebrowser.py
+++ b/src/silx/gui/widgets/test/test_framebrowser.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_hierarchicaltableview.py b/src/silx/gui/widgets/test/test_hierarchicaltableview.py
index 302086a..8f6a2a0 100644
--- a/src/silx/gui/widgets/test/test_hierarchicaltableview.py
+++ b/src/silx/gui/widgets/test/test_hierarchicaltableview.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_legendiconwidget.py b/src/silx/gui/widgets/test/test_legendiconwidget.py
index fe320f6..cfebc62 100644
--- a/src/silx/gui/widgets/test/test_legendiconwidget.py
+++ b/src/silx/gui/widgets/test/test_legendiconwidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2020 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_periodictable.py b/src/silx/gui/widgets/test/test_periodictable.py
index de9e1af..f687e36 100644
--- a/src/silx/gui/widgets/test/test_periodictable.py
+++ b/src/silx/gui/widgets/test/test_periodictable.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_printpreview.py b/src/silx/gui/widgets/test/test_printpreview.py
index 8602666..b703d63 100644
--- a/src/silx/gui/widgets/test/test_printpreview.py
+++ b/src/silx/gui/widgets/test/test_printpreview.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_rangeslider.py b/src/silx/gui/widgets/test/test_rangeslider.py
index f829857..6ed50af 100644
--- a/src/silx/gui/widgets/test/test_rangeslider.py
+++ b/src/silx/gui/widgets/test/test_rangeslider.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_tablewidget.py b/src/silx/gui/widgets/test/test_tablewidget.py
index 09122ca..9b1e53f 100644
--- a/src/silx/gui/widgets/test/test_tablewidget.py
+++ b/src/silx/gui/widgets/test/test_tablewidget.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/gui/widgets/test/test_threadpoolpushbutton.py b/src/silx/gui/widgets/test/test_threadpoolpushbutton.py
index 3808be0..a3eca33 100644
--- a/src/silx/gui/widgets/test/test_threadpoolpushbutton.py
+++ b/src/silx/gui/widgets/test/test_threadpoolpushbutton.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/image/__init__.py b/src/silx/image/__init__.py
index 12bf320..72bd116 100644
--- a/src/silx/image/__init__.py
+++ b/src/silx/image/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/_boundingbox.py b/src/silx/image/_boundingbox.py
index 1c086b1..c016471 100644
--- a/src/silx/image/_boundingbox.py
+++ b/src/silx/image/_boundingbox.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/image/backprojection.py b/src/silx/image/backprojection.py
index 63f99ca..b208d3e 100644
--- a/src/silx/image/backprojection.py
+++ b/src/silx/image/backprojection.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/bilinear.pyx b/src/silx/image/bilinear.pyx
index 14547f8..31ba354 100644
--- a/src/silx/image/bilinear.pyx
+++ b/src/silx/image/bilinear.pyx
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#cython: embedsignature=True, language_level=3
## This is for optimisation
#cython: boundscheck=False, wraparound=False, cdivision=True, initializedcheck=False,
diff --git a/src/silx/image/marchingsquares/__init__.py b/src/silx/image/marchingsquares/__init__.py
index a47a7f6..1c6f15e 100644
--- a/src/silx/image/marchingsquares/__init__.py
+++ b/src/silx/image/marchingsquares/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/marchingsquares/_mergeimpl.pyx b/src/silx/image/marchingsquares/_mergeimpl.pyx
index 5a7a3b5..ce4786f 100644
--- a/src/silx/image/marchingsquares/_mergeimpl.pyx
+++ b/src/silx/image/marchingsquares/_mergeimpl.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018-2020 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/marchingsquares/_skimage.py b/src/silx/image/marchingsquares/_skimage.py
index d49eeb0..7fa97d5 100644
--- a/src/silx/image/marchingsquares/_skimage.py
+++ b/src/silx/image/marchingsquares/_skimage.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/marchingsquares/setup.py b/src/silx/image/marchingsquares/setup.py
deleted file mode 100644
index 95998ab..0000000
--- a/src/silx/image/marchingsquares/setup.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "23/04/2018"
-
-import os
-import numpy
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('marchingsquares', parent_package, top_path)
- config.add_subpackage('test')
-
- silx_include = os.path.join(top_path, "src", "silx", "utils", "include")
- config.add_extension('_mergeimpl',
- sources=['_mergeimpl.pyx'],
- include_dirs=[numpy.get_include(), silx_include],
- language='c++',
- extra_link_args=['-fopenmp'],
- extra_compile_args=['-fopenmp'])
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/image/marchingsquares/test/__init__.py b/src/silx/image/marchingsquares/test/__init__.py
index 776bb73..0e66f61 100644
--- a/src/silx/image/marchingsquares/test/__init__.py
+++ b/src/silx/image/marchingsquares/test/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/image/marchingsquares/test/test_funcapi.py b/src/silx/image/marchingsquares/test/test_funcapi.py
index d1be584..e9d2d7d 100644
--- a/src/silx/image/marchingsquares/test/test_funcapi.py
+++ b/src/silx/image/marchingsquares/test/test_funcapi.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/image/marchingsquares/test/test_mergeimpl.py b/src/silx/image/marchingsquares/test/test_mergeimpl.py
index 07b94b5..bfa1263 100644
--- a/src/silx/image/marchingsquares/test/test_mergeimpl.py
+++ b/src/silx/image/marchingsquares/test/test_mergeimpl.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/image/medianfilter.py b/src/silx/image/medianfilter.py
index 857f73d..1938357 100644
--- a/src/silx/image/medianfilter.py
+++ b/src/silx/image/medianfilter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/phantomgenerator.py b/src/silx/image/phantomgenerator.py
index 10b249b..1893368 100644
--- a/src/silx/image/phantomgenerator.py
+++ b/src/silx/image/phantomgenerator.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/image/projection.py b/src/silx/image/projection.py
index 5c76c35..0b58323 100644
--- a/src/silx/image/projection.py
+++ b/src/silx/image/projection.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/reconstruction.py b/src/silx/image/reconstruction.py
index 875b66b..2ed95c0 100644
--- a/src/silx/image/reconstruction.py
+++ b/src/silx/image/reconstruction.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/setup.py b/src/silx/image/setup.py
deleted file mode 100644
index 69d5b1b..0000000
--- a/src/silx/image/setup.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["J. Kieffer"]
-__license__ = "MIT"
-__date__ = "05/04/2018"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('image', parent_package, top_path)
- config.add_subpackage('test')
- config.add_extension('bilinear',
- sources=["bilinear.pyx"],
- language='c')
- config.add_extension('shapes',
- sources=["shapes.pyx"],
- language='c')
- config.add_subpackage('marchingsquares')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/image/shapes.pyx b/src/silx/image/shapes.pyx
index 9284811..26065e1 100644
--- a/src/silx/image/shapes.pyx
+++ b/src/silx/image/shapes.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/image/sift.py b/src/silx/image/sift.py
index cb1e6bd..57599cd 100644
--- a/src/silx/image/sift.py
+++ b/src/silx/image/sift.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/test/__init__.py b/src/silx/image/test/__init__.py
index 40b11a1..3ebbb32 100644
--- a/src/silx/image/test/__init__.py
+++ b/src/silx/image/test/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/image/test/test_bb.py b/src/silx/image/test/test_bb.py
index 7427273..19f5f39 100644
--- a/src/silx/image/test/test_bb.py
+++ b/src/silx/image/test/test_bb.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/image/test/test_bilinear.py b/src/silx/image/test/test_bilinear.py
index 20ceb58..d0abe64 100644
--- a/src/silx/image/test/test_bilinear.py
+++ b/src/silx/image/test/test_bilinear.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx (originally pyFAI)
# https://github.com/silx-kit/silx
diff --git a/src/silx/image/test/test_medianfilter.py b/src/silx/image/test/test_medianfilter.py
index d3386a4..3215d69 100644
--- a/src/silx/image/test/test_medianfilter.py
+++ b/src/silx/image/test/test_medianfilter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/image/test/test_shapes.py b/src/silx/image/test/test_shapes.py
index 63abc00..1adc112 100644
--- a/src/silx/image/test/test_shapes.py
+++ b/src/silx/image/test/test_shapes.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/image/test/test_tomography.py b/src/silx/image/test/test_tomography.py
index f391a72..e697cbc 100644
--- a/src/silx/image/test/test_tomography.py
+++ b/src/silx/image/test/test_tomography.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/image/tomography.py b/src/silx/image/tomography.py
index 53855c1..d64afde 100644
--- a/src/silx/image/tomography.py
+++ b/src/silx/image/tomography.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/image/utils.py b/src/silx/image/utils.py
index 996d010..2659112 100644
--- a/src/silx/image/utils.py
+++ b/src/silx/image/utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# /*##########################################################################
# Copyright (C) 2019 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/__init__.py b/src/silx/io/__init__.py
index b43d290..2ff6cad 100644
--- a/src/silx/io/__init__.py
+++ b/src/silx/io/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/io/commonh5.py b/src/silx/io/commonh5.py
index af4274f..25744b4 100644
--- a/src/silx/io/commonh5.py
+++ b/src/silx/io/commonh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/convert.py b/src/silx/io/convert.py
index ba9a254..a4c5dc3 100644
--- a/src/silx/io/convert.py
+++ b/src/silx/io/convert.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/dictdump.py b/src/silx/io/dictdump.py
index a24de42..d1bf8c4 100644
--- a/src/silx/io/dictdump.py
+++ b/src/silx/io/dictdump.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -31,8 +30,11 @@ import json
import logging
import numpy
import os.path
-import sys
import h5py
+try:
+ import pint
+except ImportError:
+ pint = None
from .configdict import ConfigDict
from .utils import is_group
@@ -65,6 +67,8 @@ def _prepare_hdf5_write_value(array_like):
``numpy.array()`` (`str`, `list`, `numpy.ndarray`…)
:return: ``numpy.ndarray`` ready to be written as an HDF5 dataset
"""
+ if pint is not None and isinstance(array_like, pint.quantity.Quantity):
+ return numpy.array(array_like.magnitude)
array = numpy.asarray(array_like)
if numpy.issubdtype(array.dtype, numpy.bytes_):
return numpy.array(array_like, dtype=vlen_bytes)
@@ -294,6 +298,7 @@ def dicttoh5(treedict, h5file, h5path='/',
del h5f[h5path]
h5f.create_group(h5path)
else:
+ logger.info(f'Cannot overwrite {h5f.file.filename}::{h5f[h5path].name} with update_mode="{update_mode}"')
return
else:
h5f.create_group(h5path)
@@ -330,6 +335,7 @@ def dicttoh5(treedict, h5file, h5path='/',
else:
# HDF5 dataset
if exists and not change_allowed:
+ logger.info(f'Cannot modify dataset {h5f.file.filename}::{h5f[h5name].name} with update_mode="{update_mode}"')
continue
data = _prepare_hdf5_write_value(value)
@@ -343,6 +349,7 @@ def dicttoh5(treedict, h5file, h5path='/',
# Delete the existing dataset
if update_mode != "replace":
if not is_dataset(h5f[h5name]):
+ logger.info(f'Cannot overwrite {h5f.file.filename}::{h5f[h5name].name} with update_mode="{update_mode}"')
continue
attrs_backup = dict(h5f[h5name].attrs)
del h5f[h5name]
@@ -381,6 +388,7 @@ def dicttoh5(treedict, h5file, h5path='/',
else:
# Add/modify HDF5 attribute
if exists and not change_allowed:
+ logger.info(f'Cannot modify attribute {h5f.file.filename}::{h5f[h5name].name}@{attr_name} with update_mode="{update_mode}"')
continue
data = _prepare_hdf5_write_value(value)
h5a[attr_name] = data
@@ -452,6 +460,7 @@ def nexus_to_h5_dict(
value = h5py.SoftLink(first)
elif is_link(value):
key = key[1:]
+
if isinstance(value, Mapping):
# HDF5 group
key_has_nx_class = add_nx_class and _has_nx_class(treedict, key)
@@ -460,9 +469,15 @@ def nexus_to_h5_dict(
parents=parents+(key,),
add_nx_class=add_nx_class,
has_nx_class=key_has_nx_class)
+
+ elif pint is not None and isinstance(value, pint.quantity.Quantity):
+ copy[key] = value.magnitude
+ copy[(key, "units")] = f"{value.units:~C}"
+
else:
# HDF5 dataset or link
copy[key] = value
+
if add_nx_class and not has_nx_class:
_ensure_nx_class(copy, parents)
return copy
diff --git a/src/silx/io/fabioh5.py b/src/silx/io/fabioh5.py
index af9b29a..c5ef964 100755
--- a/src/silx/io/fabioh5.py
+++ b/src/silx/io/fabioh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/fioh5.py b/src/silx/io/fioh5.py
index 75fe587..0a86bbf 100644
--- a/src/silx/io/fioh5.py
+++ b/src/silx/io/fioh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2021 Timo Fuchs
#
diff --git a/src/silx/io/h5py_utils.py b/src/silx/io/h5py_utils.py
index fb04152..139bff3 100644
--- a/src/silx/io/h5py_utils.py
+++ b/src/silx/io/h5py_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/nxdata/__init__.py b/src/silx/io/nxdata/__init__.py
index 5bfa442..51efc68 100644
--- a/src/silx/io/nxdata/__init__.py
+++ b/src/silx/io/nxdata/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/io/nxdata/_utils.py b/src/silx/io/nxdata/_utils.py
index 12318f1..3aa3846 100644
--- a/src/silx/io/nxdata/_utils.py
+++ b/src/silx/io/nxdata/_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/io/nxdata/parse.py b/src/silx/io/nxdata/parse.py
index d00f65b..0c9d7e7 100644
--- a/src/silx/io/nxdata/parse.py
+++ b/src/silx/io/nxdata/parse.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -42,6 +41,8 @@ Other public functions:
"""
import json
+from typing import Optional
+
import numpy
from silx.io.utils import is_group, is_file, is_dataset, h5py_read_dataset
@@ -684,8 +685,6 @@ class NXdata(object):
return self.group[errors_name]
# case of uncertainties dataset name provided in @uncertainties
uncertainties_names = get_attr_as_unicode(self.group, "uncertainties")
- if uncertainties_names is None:
- uncertainties_names = get_attr_as_unicode(self.signal, "uncertainties")
if isinstance(uncertainties_names, str):
uncertainties_names = [uncertainties_names]
if uncertainties_names is not None:
@@ -720,15 +719,18 @@ class NXdata(object):
if not self.is_valid:
raise InvalidNXdataError("Unable to parse invalid NXdata")
- # case of signal
- signal_errors = self.signal_dataset_name + "_errors"
- if "errors" in self.group and is_dataset(self.group["errors"]):
- errors = "errors"
- elif signal_errors in self.group and is_dataset(self.group[signal_errors]):
- errors = signal_errors
- else:
- return None
- return self.group[errors]
+ dataset_names = [
+ # From NXData:
+ "errors",
+ # Not Nexus (VARIABLE_errors is only for axes), but supported anyway
+ self.signal_dataset_name + "_errors",
+ ]
+ for name in dataset_names:
+ entity = self.group.get(name)
+ if entity is not None and is_dataset(entity):
+ return entity
+
+ return None
@property
def plot_style(self):
@@ -970,35 +972,42 @@ def is_NXroot_with_default_NXdata(group, validate=True):
validate=validate)
-def get_default(group, validate=True):
- """Return a :class:`NXdata` object corresponding to the default NXdata group
- in the group specified as parameter.
+def _get_default(
+ group,
+ validate: bool,
+ traversed: list,
+) -> Optional[NXdata]:
+ if not is_group(group):
+ raise TypeError("Provided parameter is not a h5py-like group")
- This function can find the NXdata if the group is already a NXdata, or
- if it is a NXentry defining a default NXdata, or if it is a NXroot
- defining such a default valid NXentry.
+ if get_attr_as_unicode(group, "NX_class") == "NXdata":
+ nxdata = NXdata(group, validate=validate)
+ return nxdata if nxdata.is_valid else None
- Return None if no valid NXdata could be found.
+ default_name = get_attr_as_unicode(group, "default")
+ if default_name is None:
+ return None
- :param group: h5py-like group following the Nexus specification
- (NXdata, NXentry or NXroot).
- :param bool validate: Set this to False if you are sure that group
- is valid NXdata (i.e. :func:`silx.io.nxdata.is_valid_nxdata(group)`
- returns True). Parameter provided for optimisation purposes.
- :return: :class:`NXdata` object or None
- :raise TypeError: if group is not a h5py-like group
- """
- if not is_group(group):
- raise TypeError("Provided parameter is not a h5py-like group")
+ default_entity = group.get(default_name)
+ if default_entity is None or default_entity in traversed:
+ return None
- if is_NXroot_with_default_NXdata(group, validate=validate):
- default_entry = group[group.attrs["default"]]
- default_data = default_entry[default_entry.attrs["default"]]
- elif is_group_with_default_NXdata(group, validate=validate):
- default_data = group[group.attrs["default"]]
- elif not validate or is_valid_nxdata(group):
- default_data = group
- else:
+ try:
+ return _get_default(default_entity, validate, traversed + [default_entity])
+ except TypeError:
return None
- return NXdata(default_data, validate=False)
+
+def get_default(group, validate: bool=True) -> Optional[NXdata]:
+ """Find the default :class:`NXdata` group in given group.
+
+ `@default` attributes are recursively followed until finding a group with
+ NX_class="NXdata".
+ Return None if no valid NXdata group could be found.
+
+ :param group: h5py-like group to look for @default NXdata.
+ In cas it is a NXdata group, it is returned.
+ :param validate: False to disable checking the returned NXdata group.
+ :raise TypeError: if group is not a h5py-like group
+ """
+ return _get_default(group, validate, [])
diff --git a/src/silx/io/nxdata/write.py b/src/silx/io/nxdata/write.py
index 9e84240..5dfe1df 100644
--- a/src/silx/io/nxdata/write.py
+++ b/src/silx/io/nxdata/write.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/io/octaveh5.py b/src/silx/io/octaveh5.py
index 84fa726..67fb1e2 100644
--- a/src/silx/io/octaveh5.py
+++ b/src/silx/io/octaveh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/rawh5.py b/src/silx/io/rawh5.py
index ceabbdb..31b554d 100644
--- a/src/silx/io/rawh5.py
+++ b/src/silx/io/rawh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/setup.py b/src/silx/io/setup.py
deleted file mode 100644
index 9cafa17..0000000
--- a/src/silx/io/setup.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# coding: ascii
-#
-# JK: Numpy.distutils which imports this does not handle utf-8 in version<1.12
-#
-# /*##########################################################################
-#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-
-__authors__ = ["P. Knobel", "V.A. Sole"]
-__license__ = "MIT"
-__date__ = "03/10/2016"
-
-import os
-import sys
-
-from numpy.distutils.misc_util import Configuration
-
-
-# Locale and platform management
-SPECFILE_USE_GNU_SOURCE = os.getenv("SPECFILE_USE_GNU_SOURCE")
-if SPECFILE_USE_GNU_SOURCE is None:
- SPECFILE_USE_GNU_SOURCE = 0
- if sys.platform.lower().startswith("linux"):
- warn = ("silx.io.specfile WARNING:",
- "A cleaner locale independent implementation",
- "may be achieved setting SPECFILE_USE_GNU_SOURCE to 1",
- "For instance running this script as:",
- "SPECFILE_USE_GNU_SOURCE=1 python setup.py build")
- print(os.linesep.join(warn))
-else:
- SPECFILE_USE_GNU_SOURCE = int(SPECFILE_USE_GNU_SOURCE)
-
-if sys.platform == "win32":
- define_macros = [('WIN32', None), ('SPECFILE_POSIX', None)]
-elif os.name.lower().startswith('posix'):
- define_macros = [('SPECFILE_POSIX', None)]
- # the best choice is to have _GNU_SOURCE defined
- # as a compilation flag because that allows the
- # use of strtod_l
- if SPECFILE_USE_GNU_SOURCE:
- define_macros = [('_GNU_SOURCE', 1)]
-else:
- define_macros = []
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('io', parent_package, top_path)
- config.add_subpackage('test')
- config.add_subpackage('nxdata')
-
- srcfiles = ['sfheader', 'sfinit', 'sflists', 'sfdata', 'sfindex',
- 'sflabel', 'sfmca', 'sftools', 'locale_management']
- sources = [os.path.join('specfile', 'src', ffile + '.c') for ffile in srcfiles]
- sources.append('specfile.pyx')
-
- config.add_extension('specfile',
- sources=sources,
- define_macros=define_macros,
- include_dirs=[os.path.join('specfile', 'include')],
- language='c')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/io/specfile.pyx b/src/silx/io/specfile.pyx
index cb9e1a5..dde6d82 100644
--- a/src/silx/io/specfile.pyx
+++ b/src/silx/io/specfile.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/specfile/include/SpecFileCython.h b/src/silx/io/specfile/include/SpecFileCython.h
index 3225e13..77e9168 100644
--- a/src/silx/io/specfile/include/SpecFileCython.h
+++ b/src/silx/io/specfile/include/SpecFileCython.h
@@ -1,5 +1,4 @@
#/*##########################################################################
-# coding: utf-8
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/src/silx/io/specfile/src/sflabel.c b/src/silx/io/specfile/src/sflabel.c
index 61cbb3f..29e8f57 100644
--- a/src/silx/io/specfile/src/sflabel.c
+++ b/src/silx/io/specfile/src/sflabel.c
@@ -1,5 +1,5 @@
# /*##########################################################################
-# Copyright (C) 1995-2019 European Synchrotron Radiation Facility
+# Copyright (C) 1995-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -87,6 +87,10 @@ DllExport double SfMotorPosByName( SpecFile *sf, long index, char *name,
DllExport long SfAllMotorPos ( SpecFile *sf, long index, double **pos,
int *error );
+
+#define BUFFER_SIZE 256
+#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
+
/*********************************************************************
* Function: char *SfLabel( sf, index, column, error )
@@ -180,7 +184,7 @@ SfLabel( SpecFile *sf, long index, long column, int *error )
DllExport long
SfAllLabels( SpecFile *sf, long index, char ***labels, int *error )
{
- static char tmplab[40];
+ static char tmplab[BUFFER_SIZE];
char **labarr;
char *onelabel;
@@ -243,7 +247,7 @@ SfAllLabels( SpecFile *sf, long index, char ***labels, int *error )
for (i=0;ptr < buf + strlen(buf) -1;ptr++,i++) {
if (*ptr==' ' && *(ptr+1) == ' ') { /* two spaces delimits one label */
- tmplab[i] = '\0';
+ tmplab[MIN(i, BUFFER_SIZE-1)] = '\0';
labarr = (char **)realloc( labarr, (no_labels+1) * sizeof(char *));
onelabel = (char *) malloc (i+2);
@@ -253,7 +257,7 @@ SfAllLabels( SpecFile *sf, long index, char ***labels, int *error )
no_labels++;
i=-1;
for(;*(ptr+1) == ' ' && ptr < buf+strlen(buf)-1;ptr++);
- } else {
+ } else if (i < BUFFER_SIZE) {
tmplab[i] = *ptr;
}
}
@@ -318,7 +322,7 @@ SfAllMotors( SpecFile *sf, long index, char ***names, int *error )
char **motarr;
char *onemot;
- static char tmpmot[40];
+ static char tmpmot[BUFFER_SIZE];
char *ptr;
@@ -368,7 +372,7 @@ SfAllMotors( SpecFile *sf, long index, char ***names, int *error )
for(ptr=thisline;*ptr == ' ';ptr++);
for (i=0;ptr < endline -2;ptr++,i++) {
if (*ptr==' ' && *(ptr+1) == ' ') {
- tmpmot[i] = '\0';
+ tmpmot[MIN(i, BUFFER_SIZE-1)] = '\0';
motarr = (char **)realloc( motarr, (motct+1) * sizeof(char *));
onemot = (char *) malloc (i+2);
@@ -378,7 +382,7 @@ SfAllMotors( SpecFile *sf, long index, char ***names, int *error )
motct++;
i=-1;
for(;*(ptr+1) == ' ' && ptr < endline -1;ptr++);
- } else {
+ } else if (i < BUFFER_SIZE) {
tmpmot[i] = *ptr;
}
}
diff --git a/src/silx/io/specfile/src/sfmca.c b/src/silx/io/specfile/src/sfmca.c
index ad13bae..246837e 100644
--- a/src/silx/io/specfile/src/sfmca.c
+++ b/src/silx/io/specfile/src/sfmca.c
@@ -298,6 +298,11 @@ SfGetMca( SpecFile *sf, long index, long number, double **retdata, int *error )
val = PyMcaAtof(strval);
data[vals] = val;
vals++;
+ } else if (i>0) {
+ strval[i] = '\0';
+ val = PyMcaAtof(strval);
+ data[vals] = val;
+ vals++;
}
#ifndef _GNU_SOURCE
#ifdef PYMCA_POSIX
diff --git a/src/silx/io/specfile_wrapper.pxd b/src/silx/io/specfile_wrapper.pxd
index 6770f7e..df629f7 100644
--- a/src/silx/io/specfile_wrapper.pxd
+++ b/src/silx/io/specfile_wrapper.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/specfilewrapper.py b/src/silx/io/specfilewrapper.py
index 01e185c..d8ee90b 100644
--- a/src/silx/io/specfilewrapper.py
+++ b/src/silx/io/specfilewrapper.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*#########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/spech5.py b/src/silx/io/spech5.py
index df2021c..05ce9f0 100644
--- a/src/silx/io/spech5.py
+++ b/src/silx/io/spech5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/spectoh5.py b/src/silx/io/spectoh5.py
index fb3b739..0f4f1c5 100644
--- a/src/silx/io/spectoh5.py
+++ b/src/silx/io/spectoh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/__init__.py b/src/silx/io/test/__init__.py
index 244d090..3c723bb 100644
--- a/src/silx/io/test/__init__.py
+++ b/src/silx/io/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_commonh5.py b/src/silx/io/test/test_commonh5.py
index 27f6e8c..d554d27 100644
--- a/src/silx/io/test/test_commonh5.py
+++ b/src/silx/io/test/test_commonh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_dictdump.py b/src/silx/io/test/test_dictdump.py
index 4cafa9b..e31d7a8 100644
--- a/src/silx/io/test/test_dictdump.py
+++ b/src/silx/io/test/test_dictdump.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -27,15 +26,21 @@ __authors__ = ["P. Knobel"]
__license__ = "MIT"
__date__ = "17/01/2018"
-from collections import OrderedDict
-import numpy
+
+from collections import defaultdict, OrderedDict
+from copy import deepcopy
+from io import BytesIO
import os
import tempfile
import unittest
-import h5py
-from copy import deepcopy
-from collections import defaultdict
+import h5py
+import numpy
+try:
+ import pint
+except ImportError:
+ pint = None
+import pytest
from silx.utils.testutils import LoggingValidator
@@ -48,6 +53,13 @@ from ..utils import is_link
from ..utils import h5py_read_dataset
+@pytest.fixture
+def tmp_h5py_file():
+ with BytesIO() as buffer:
+ with h5py.File(buffer, mode="w") as h5file:
+ yield h5file
+
+
def tree():
"""Tree data structure as a recursive nested dictionary"""
return defaultdict(tree)
@@ -512,6 +524,22 @@ class TestDictToH5(H5DictTestCase):
assert_append("replace")
+@pytest.mark.skipif(pint is None, reason="Require pint")
+def test_dicttoh5_pint(tmp_h5py_file):
+ ureg = pint.UnitRegistry()
+ treedict = {
+ "array_mm": pint.Quantity([1, 2, 3], ureg.mm),
+ "value_kg": 3 * ureg.kg,
+ }
+
+ dicttoh5(treedict, tmp_h5py_file)
+
+ result = h5todict(tmp_h5py_file)
+ assert set(treedict.keys()) == set(result.keys())
+ for key, value in treedict.items():
+ assert numpy.array_equal(result[key], value.magnitude)
+
+
class TestH5ToDict(H5DictTestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
@@ -800,6 +828,22 @@ class TestDictToNx(H5DictTestCase):
assert_append("replace", add_nx_class=True)
+@pytest.mark.skipif(pint is None, reason="Require pint")
+def test_dicttonx_pint(tmp_h5py_file):
+ ureg = pint.UnitRegistry()
+ treedict = {
+ "array_mm": pint.Quantity([1, 2, 3], ureg.mm),
+ "value_kg": 3 * ureg.kg,
+ }
+
+ dictdump.dicttonx(treedict, tmp_h5py_file)
+
+ result = dictdump.nxtodict(tmp_h5py_file)
+ for key, value in treedict.items():
+ assert numpy.array_equal(result[key], value.magnitude)
+ assert result[f"{key}@units"] == f"{value.units:~C}"
+
+
class TestNxToDict(H5DictTestCase):
def setUp(self):
self.tempdir = tempfile.mkdtemp()
diff --git a/src/silx/io/test/test_fabioh5.py b/src/silx/io/test/test_fabioh5.py
index c410024..fdeb1c3 100755
--- a/src/silx/io/test/test_fabioh5.py
+++ b/src/silx/io/test/test_fabioh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_fioh5.py b/src/silx/io/test/test_fioh5.py
index 8ffb4ad..18200c9 100644
--- a/src/silx/io/test/test_fioh5.py
+++ b/src/silx/io/test/test_fioh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2021 Timo Fuchs
#
diff --git a/src/silx/io/test/test_h5py_utils.py b/src/silx/io/test/test_h5py_utils.py
index ea46eca..0d10a78 100644
--- a/src/silx/io/test/test_h5py_utils.py
+++ b/src/silx/io/test/test_h5py_utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
@@ -449,3 +448,35 @@ class TestH5pyUtils(unittest.TestCase):
f.write("0")
with self.assertRaises(RetryTimeoutError):
top_level_names_test(txtfilename, filename, **kw)
+
+ @subtests
+ def test_retry_generator(self):
+ filename = self._new_filename()
+ ncausefailure = 3
+ faildelay = 0.1
+ sufficient_timeout = ncausefailure * (faildelay + 10)
+ insufficient_timeout = ncausefailure * faildelay * 0.5
+
+ @h5py_utils.retry()
+ def iter_data(filename, name, start_index=0):
+ nonlocal failcounter
+ if start_index <= 0:
+ with h5py_utils.File(filename) as h5file:
+ yield h5file[name][()]
+ if failcounter < ncausefailure:
+ time.sleep(faildelay)
+ failcounter += 1
+ raise RetryError
+ if start_index <= 1:
+ with h5py_utils.File(filename) as h5file:
+ yield not h5file[name][()]
+
+ failcounter = 0
+ kw = {"retry_timeout": sufficient_timeout}
+ data = list(iter_data(filename, "/check", **kw))
+ self.assertEqual(data, [True, False])
+
+ failcounter = 0
+ kw = {"retry_timeout": insufficient_timeout}
+ with self.assertRaises(RetryTimeoutError):
+ list(iter_data(filename, "/check", **kw))
diff --git a/src/silx/io/test/test_nxdata.py b/src/silx/io/test/test_nxdata.py
index 9025d6d..52a2b8a 100644
--- a/src/silx/io/test/test_nxdata.py
+++ b/src/silx/io/test/test_nxdata.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -30,10 +29,13 @@ __date__ = "24/03/2020"
import tempfile
import unittest
+
import h5py
import numpy
+import pytest
from .. import nxdata
+from ..dictdump import dicttoh5
text_dtype = h5py.special_dtype(vlen=str)
@@ -561,3 +563,144 @@ class TestSaveNXdata(unittest.TestCase):
self.assertTrue(numpy.array_equal(nxd.axes[0],
a0))
h5f.close()
+
+
+class TestGetDefault:
+ """Test silx.io.nxdata.get_default function"""
+
+ @pytest.fixture
+ def hdf5_file(self, tmp_path):
+ with h5py.File(tmp_path / "test_file.h5", "w") as h5f:
+ yield h5f
+
+ def testDirectPath(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "/nxentry/nxprocess/nxdata",
+ "nxentry": {
+ "nxprocess": {
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxprocess/nxdata"
+
+ def testAbsolutePath(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "/nxentry",
+ "nxentry": {
+ ("", "default"): "/nxentry/nxprocess/nxdata",
+ "nxprocess": {
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxprocess/nxdata"
+
+ def testRelativePath(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "nxentry",
+ "nxentry": {
+ ("", "default"): "nxdata",
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxdata"
+
+ def testRelativePathSubdir(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "nxentry",
+ "nxentry": {
+ ("", "default"): "nxprocess/nxdata",
+ "nxprocess": {
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxprocess/nxdata"
+
+ def testRecursiveAbsolutePath(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "/nxentry",
+ "nxentry": {
+ ("", "default"): "/nxentry/nxprocess",
+ "nxprocess": {
+ ("", "default"): "/nxentry/nxprocess/nxdata",
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxprocess/nxdata"
+
+ def testRecursiveRelativePath(self, hdf5_file):
+ dicttoh5(
+ {
+ ("", "default"): "nxentry",
+ "nxentry": {
+ ("", "default"): "nxprocess",
+ "nxprocess": {
+ ("", "default"): "nxdata",
+ "nxdata": {
+ ("", "NX_class"): "NXdata",
+ ("", "signal"): "data",
+ "data": (1, 2, 3),
+ }
+ }
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert isinstance(default, nxdata.NXdata)
+ assert default.group.name == "/nxentry/nxprocess/nxdata"
+
+ def testLoop(self, hdf5_file):
+ """Infinite loop of @default"""
+ dicttoh5(
+ {
+ ("", "default"): "/nxentry",
+ "nxentry": {
+ ("", "default"): "/nxentry",
+ }
+ },
+ hdf5_file)
+ default = nxdata.get_default(hdf5_file)
+ assert default is None
diff --git a/src/silx/io/test/test_octaveh5.py b/src/silx/io/test/test_octaveh5.py
index 1c3b3e0..19b8ad6 100644
--- a/src/silx/io/test/test_octaveh5.py
+++ b/src/silx/io/test/test_octaveh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_rawh5.py b/src/silx/io/test/test_rawh5.py
index 236484d..947be0f 100644
--- a/src/silx/io/test/test_rawh5.py
+++ b/src/silx/io/test/test_rawh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/io/test/test_specfile.py b/src/silx/io/test/test_specfile.py
index 44cb08c..748e31c 100644
--- a/src/silx/io/test/test_specfile.py
+++ b/src/silx/io/test/test_specfile.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_specfilewrapper.py b/src/silx/io/test/test_specfilewrapper.py
index a1ba5f4..7d2ce60 100644
--- a/src/silx/io/test/test_specfilewrapper.py
+++ b/src/silx/io/test/test_specfilewrapper.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_spech5.py b/src/silx/io/test/test_spech5.py
index 1e67961..456a538 100644
--- a/src/silx/io/test/test_spech5.py
+++ b/src/silx/io/test/test_spech5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_spectoh5.py b/src/silx/io/test/test_spectoh5.py
index 66bf8d6..5465ece 100644
--- a/src/silx/io/test/test_spectoh5.py
+++ b/src/silx/io/test/test_spectoh5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2019 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_url.py b/src/silx/io/test/test_url.py
index 7346391..8cbfb34 100644
--- a/src/silx/io/test/test_url.py
+++ b/src/silx/io/test/test_url.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/test/test_utils.py b/src/silx/io/test/test_utils.py
index cc34100..b9fc3ab 100644
--- a/src/silx/io/test/test_utils.py
+++ b/src/silx/io/test/test_utils.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -30,7 +29,6 @@ import re
import shutil
import tempfile
import unittest
-import sys
from .. import utils
from ..._version import calc_hexversion
@@ -40,6 +38,7 @@ import h5py
from ..utils import h5ls
from silx.io import commonh5
+
import fabio
__authors__ = ["P. Knobel"]
@@ -921,3 +920,33 @@ def test_visitall_commonh5():
soft_link = visited_items["/group/soft_link"]
assert isinstance(soft_link, commonh5.SoftLink)
assert soft_link.path == "/group/dataset"
+
+
+def test_match_hdf5(tmp_path):
+ """Test match function with HDF5 file"""
+ with h5py.File(tmp_path / "test_match.h5", "w") as h5f:
+ h5f.create_group("entry_0000/group")
+ h5f["entry_0000/data"] = 0
+ h5f.create_group("entry_0001/group")
+ h5f["entry_0001/data"] = 1
+ h5f.create_group("entry_0002")
+ h5f["entry_0003"] = 3
+
+ result = list(utils.match(h5f, "/entry_*/*"))
+
+ assert sorted(result) == ['entry_0000/data', 'entry_0000/group', 'entry_0001/data', 'entry_0001/group']
+
+
+def test_match_commonh5():
+ """Test match function with commonh5 objects"""
+ with commonh5.File("filename.file", mode="w") as fobj:
+ fobj.create_group("entry_0000/group")
+ fobj["entry_0000/data"] = 0
+ fobj.create_group("entry_0001/group")
+ fobj["entry_0001/data"] = 1
+ fobj.create_group("entry_0002")
+ fobj["entry_0003"] = 3
+
+ result = list(utils.match(fobj, "/entry_*/*"))
+
+ assert sorted(result) == ['entry_0000/data', 'entry_0000/group', 'entry_0001/data', 'entry_0001/group']
diff --git a/src/silx/io/test/test_write_to_h5.py b/src/silx/io/test/test_write_to_h5.py
index 06149c9..fe855e1 100644
--- a/src/silx/io/test/test_write_to_h5.py
+++ b/src/silx/io/test/test_write_to_h5.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/io/url.py b/src/silx/io/url.py
index a3c49e6..71b3103 100644
--- a/src/silx/io/url.py
+++ b/src/silx/io/url.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/io/utils.py b/src/silx/io/utils.py
index 642c6fb..0588138 100644
--- a/src/silx/io/utils.py
+++ b/src/silx/io/utils.py
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -28,11 +27,13 @@ __license__ = "MIT"
__date__ = "03/12/2020"
import enum
+import fnmatch
import os.path
import sys
import time
import logging
import collections
+from typing import Generator
import urllib.parse
import numpy
@@ -538,6 +539,7 @@ class _MainNode(Proxy):
def __init__(self, h5_node, h5_file):
super(_MainNode, self).__init__(h5_node)
+ self.__node = h5_node
self.__file = h5_file
self.__class = get_h5_class(h5_node)
@@ -823,6 +825,24 @@ def visitall(item):
yield from _visitall(item, '')
+
+def match(group, path_pattern: str) -> Generator[str, None, None]:
+ """Generator of paths inside given h5py-like `group` matching `path_pattern`"""
+ if not is_group(group):
+ raise ValueError(f"Not a h5py-like group: {group}")
+
+ path_parts = path_pattern.strip("/").split("/", 1)
+ for matching_path in fnmatch.filter(group.keys(), path_parts[0]):
+ if len(path_parts) == 1: # No more sub-path, stop recursion
+ yield matching_path
+ continue
+
+ entity = group.get(matching_path)
+ if is_group(entity):
+ for matching_subpath in match(entity, path_parts[1]):
+ yield f"{matching_path}/{matching_subpath}"
+
+
def get_data(url):
"""Returns a numpy data from an URL.
diff --git a/src/silx/math/__init__.py b/src/silx/math/__init__.py
index d8b7d81..e3e0447 100644
--- a/src/silx/math/__init__.py
+++ b/src/silx/math/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/_colormap.pyx b/src/silx/math/_colormap.pyx
index 70857f0..e1409fa 100644
--- a/src/silx/math/_colormap.pyx
+++ b/src/silx/math/_colormap.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/math/calibration.py b/src/silx/math/calibration.py
index 658e2dc..79be585 100644
--- a/src/silx/math/calibration.py
+++ b/src/silx/math/calibration.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/chistogramnd.pyx b/src/silx/math/chistogramnd.pyx
index 8484f35..3a0fa31 100644
--- a/src/silx/math/chistogramnd.pyx
+++ b/src/silx/math/chistogramnd.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
@@ -675,7 +674,7 @@ def chistogramnd(sample,
cdef int _histogramnd_double_double_double(double[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -706,7 +705,7 @@ cdef int _histogramnd_double_double_double(double[:] sample,
cdef int _histogramnd_double_float_double(double[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -737,7 +736,7 @@ cdef int _histogramnd_double_float_double(double[:] sample,
cdef int _histogramnd_double_int32_t_double(double[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -773,7 +772,7 @@ cdef int _histogramnd_double_int32_t_double(double[:] sample,
cdef int _histogramnd_float_double_double(float[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -804,7 +803,7 @@ cdef int _histogramnd_float_double_double(float[:] sample,
cdef int _histogramnd_float_float_double(float[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -835,7 +834,7 @@ cdef int _histogramnd_float_float_double(float[:] sample,
cdef int _histogramnd_float_int32_t_double(float[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -871,7 +870,7 @@ cdef int _histogramnd_float_int32_t_double(float[:] sample,
cdef int _histogramnd_int32_t_double_double(cnumpy.int32_t[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -902,7 +901,7 @@ cdef int _histogramnd_int32_t_double_double(cnumpy.int32_t[:] sample,
cdef int _histogramnd_int32_t_float_double(cnumpy.int32_t[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -933,7 +932,7 @@ cdef int _histogramnd_int32_t_float_double(cnumpy.int32_t[:] sample,
cdef int _histogramnd_int32_t_int32_t_double(cnumpy.int32_t[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -969,7 +968,7 @@ cdef int _histogramnd_int32_t_int32_t_double(cnumpy.int32_t[:] sample,
cdef int _histogramnd_double_double_float(double[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1000,7 +999,7 @@ cdef int _histogramnd_double_double_float(double[:] sample,
cdef int _histogramnd_double_float_float(double[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1031,7 +1030,7 @@ cdef int _histogramnd_double_float_float(double[:] sample,
cdef int _histogramnd_double_int32_t_float(double[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1067,7 +1066,7 @@ cdef int _histogramnd_double_int32_t_float(double[:] sample,
cdef int _histogramnd_float_double_float(float[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1098,7 +1097,7 @@ cdef int _histogramnd_float_double_float(float[:] sample,
cdef int _histogramnd_float_float_float(float[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1129,7 +1128,7 @@ cdef int _histogramnd_float_float_float(float[:] sample,
cdef int _histogramnd_float_int32_t_float(float[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1165,7 +1164,7 @@ cdef int _histogramnd_float_int32_t_float(float[:] sample,
cdef int _histogramnd_int32_t_double_float(cnumpy.int32_t[:] sample,
double[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1196,7 +1195,7 @@ cdef int _histogramnd_int32_t_double_float(cnumpy.int32_t[:] sample,
cdef int _histogramnd_int32_t_float_float(cnumpy.int32_t[:] sample,
float[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
@@ -1227,7 +1226,7 @@ cdef int _histogramnd_int32_t_float_float(cnumpy.int32_t[:] sample,
cdef int _histogramnd_int32_t_int32_t_float(cnumpy.int32_t[:] sample,
cnumpy.int32_t[:] weights,
int n_dims,
- int n_elem,
+ size_t n_elem,
double[:] histo_range,
int[:] n_bins,
cnumpy.uint32_t[:] histo,
diff --git a/src/silx/math/chistogramnd_lut.pyx b/src/silx/math/chistogramnd_lut.pyx
index 3a3f05e..eed583a 100644
--- a/src/silx/math/chistogramnd_lut.pyx
+++ b/src/silx/math/chistogramnd_lut.pyx
@@ -1,6 +1,5 @@
-# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -44,6 +43,7 @@ ctypedef fused cumul_t:
cnumpy.int64_t
ctypedef fused weights_t:
+ cnumpy.uint16_t
cnumpy.float64_t
cnumpy.float32_t
cnumpy.int32_t
@@ -108,7 +108,7 @@ def histogramnd_get_lut(sample,
if histo_range.shape == (2,):
pass
elif histo_range.shape == (1, 2):
- histo_range.reshape(-1)
+ histo_range = histo_range.reshape(-1)
else:
err_histo_range = True
elif n_dims != 1 and histo_range.shape != (n_dims, 2):
@@ -333,7 +333,7 @@ def _histogramnd_from_lut_fused(weights_t[:] i_weights,
lut_t[:] i_lut,
cnumpy.uint32_t[:] o_histo,
cumul_t[:] o_weighted_histo,
- int i_n_elems,
+ size_t i_n_elems,
bint i_filt_min_weights,
weights_t i_weight_min,
bint i_filt_max_weights,
@@ -360,7 +360,7 @@ def _histogramnd_from_lut_fused(weights_t[:] i_weights,
@cython.cdivision(True)
def _histogramnd_get_lut_fused(sample_t[:] i_sample,
int i_n_dims,
- int i_n_elems,
+ size_t i_n_elems,
double[:] i_histo_range,
int[:] i_n_bins,
lut_t[:] o_lut,
diff --git a/src/silx/math/colormap.py b/src/silx/math/colormap.py
index 43b8949..8c05b63 100644
--- a/src/silx/math/colormap.py
+++ b/src/silx/math/colormap.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/math/combo.pyx b/src/silx/math/combo.pyx
index e24edda..07197c6 100644
--- a/src/silx/math/combo.pyx
+++ b/src/silx/math/combo.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fft/__init__.py b/src/silx/math/fft/__init__.py
index ea12cd6..6966a60 100644
--- a/src/silx/math/fft/__init__.py
+++ b/src/silx/math/fft/__init__.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
__authors__ = ["P. Paleo"]
__license__ = "MIT"
diff --git a/src/silx/math/fft/basefft.py b/src/silx/math/fft/basefft.py
index 854ca37..c608fde 100644
--- a/src/silx/math/fft/basefft.py
+++ b/src/silx/math/fft/basefft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fft/clfft.py b/src/silx/math/fft/clfft.py
index dad8ec1..2e41e47 100644
--- a/src/silx/math/fft/clfft.py
+++ b/src/silx/math/fft/clfft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
@@ -74,7 +73,7 @@ class CLFFT(BaseFFT):
if not(__have_clfft__) or not(__have_clfft__):
raise ImportError("Please install pyopencl and gpyfft >= %s to use the OpenCL back-end" % __required_gpyfft_version__)
- super(CLFFT, self).__init__(
+ super().__init__(
shape=shape,
dtype=dtype,
template=template,
diff --git a/src/silx/math/fft/cufft.py b/src/silx/math/fft/cufft.py
index 848f3e6..4bc7806 100644
--- a/src/silx/math/fft/cufft.py
+++ b/src/silx/math/fft/cufft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
@@ -61,7 +60,7 @@ class CUFFT(BaseFFT):
if not(__have_cufft__) or not(__have_cufft__):
raise ImportError("Please install pycuda and scikit-cuda to use the CUDA back-end")
- super(CUFFT, self).__init__(
+ super().__init__(
shape=shape,
dtype=dtype,
template=template,
diff --git a/src/silx/math/fft/fft.py b/src/silx/math/fft/fft.py
index eb0d73b..23de0cb 100644
--- a/src/silx/math/fft/fft.py
+++ b/src/silx/math/fft/fft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
@@ -24,9 +23,7 @@
#
# ###########################################################################*/
from .fftw import FFTW
-from .clfft import CLFFT
from .npfft import NPFFT
-from .cufft import CUFFT
def FFT(
@@ -64,27 +61,33 @@ def FFT(
:param str normalize:
Whether to normalize FFT and IFFT. Possible values are:
* "rescale": in this case, Fourier data is divided by "N"
- before IFFT, so that (FFT(data)) = data
+ before IFFT, so that IFFT(FFT(data)) = data.
+ This corresponds to numpy norm=None i.e norm="backward".
* "ortho": in this case, FFT and IFFT are adjoint of eachother,
the transform is unitary. Both FFT and IFFT are scaled with 1/sqrt(N).
* "none": no normalizatio is done : IFFT(FFT(data)) = data*N
:param str backend:
FFT Backend to use. Value can be "numpy", "fftw", "opencl", "cuda".
"""
- backends = {
- "numpy": NPFFT,
- "np": NPFFT,
- "fftw": FFTW,
- "opencl": CLFFT,
- "clfft": CLFFT,
- "cuda": CUFFT,
- "cufft": CUFFT,
- }
-
+ backends = ["numpy", "fftw", "opencl", "cuda"]
backend = backend.lower()
- if backend not in backends:
+ if backend in ["numpy", "np"]:
+ fft_cls = NPFFT
+ elif backend == "fftw":
+ fft_cls = FFTW
+ elif backend in ["opencl", "clfft"]:
+ # Late import for creating context only if needed
+ from .clfft import CLFFT
+
+ fft_cls = CLFFT
+ elif backend in ["cuda", "cufft"]:
+ # Late import for creating context only if needed
+ from .cufft import CUFFT
+
+ fft_cls = CUFFT
+ else:
raise ValueError("Unknown backend %s, available are %s" % (backend, backends))
- F = backends[backend](
+ F = fft_cls(
shape=shape,
dtype=dtype,
template=template,
diff --git a/src/silx/math/fft/fftw.py b/src/silx/math/fft/fftw.py
index ff6966c..797543b 100644
--- a/src/silx/math/fft/fftw.py
+++ b/src/silx/math/fft/fftw.py
@@ -1,8 +1,7 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2018-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -23,11 +22,18 @@
# THE SOFTWARE.
#
# ###########################################################################*/
-import numpy as np
+import os
+from sys import executable as sys_executable
+from socket import gethostname
+from tempfile import gettempdir
+from pathlib import Path
+import numpy as np
from .basefft import BaseFFT, check_version
+
try:
import pyfftw
+
__have_fftw__ = True
except ImportError:
__have_fftw__ = False
@@ -53,6 +59,7 @@ class FFTW(BaseFFT):
:param int num_threads:
Number of threads for computing FFT.
"""
+
def __init__(
self,
shape=None,
@@ -64,9 +71,12 @@ class FFTW(BaseFFT):
check_alignment=False,
num_threads=1,
):
- if not(__have_fftw__):
- raise ImportError("Please install pyfftw >= %s to use the FFTW back-end" % __required_pyfftw_version__)
- super(FFTW, self).__init__(
+ if not (__have_fftw__):
+ raise ImportError(
+ "Please install pyfftw >= %s to use the FFTW back-end"
+ % __required_pyfftw_version__
+ )
+ super().__init__(
shape=shape,
dtype=dtype,
template=template,
@@ -87,17 +97,55 @@ class FFTW(BaseFFT):
"data_out": self.data_out,
}
+ # About normalization with norm="none", issues about pyfftw version :
+ # --------------- pyfftw 0.12 ---------------
+ # FFT :
+ # normalise_idft --> 1
+ # not normalise_idft --> 1
+ # IFFT :
+ # normalise_idft --> 1 / N
+ # not normalise_idft --> 1
+ # --------------- pyfftw 0.13 ---------------
+ # FFT :
+ # normalise_idft --> 1
+ # not normalise_idft --> 1 / N (this normalization is incorrect, doc says contrary)
+ # IFFT :
+ # normalise_idft --> 1 / N
+ # not normalise_idft --> 1
+
+ # Solution :
+ # select 'normalise_idft' for FFT and 'not normalise_idft' for IFFT
+ # => behavior is the same in both version :)
+
def set_fftw_flags(self):
- self.fftw_flags = ('FFTW_MEASURE', ) # TODO
- self.fftw_planning_timelimit = None # TODO
+ self.fftw_flags = ("FFTW_MEASURE",) # TODO
+ self.fftw_planning_timelimit = None # TODO
+
+ # To skip normalization on norm="none", we should
+ # flip 'normalise_idft' to normalize no-where (see comments up):
+ #
+ # and :
+ # ortho (orthogonal normalization)
+ # ortho = True : forward -> 1/sqrt(N), backward -> 1/sqrt(N)
+
self.fftw_norm_modes = {
- "rescale": {"ortho": False, "normalize": True},
- "ortho": {"ortho": True, "normalize": False},
- "none": {"ortho": False, "normalize": False},
+ "rescale": (
+ {"ortho": False, "normalise_idft": True}, # fft
+ {"ortho": False, "normalise_idft": True}, # ifft
+ ),
+ "ortho": (
+ {"ortho": True, "normalise_idft": False}, # fft
+ {"ortho": True, "normalise_idft": False}, # ifft
+ ),
+ "none": (
+ {"ortho": False, "normalise_idft": True}, # fft
+ {"ortho": False, "normalise_idft": False}, # ifft
+ ),
}
if self.normalize not in self.fftw_norm_modes:
- raise ValueError("Unknown normalization mode %s. Possible values are %s" %
- (self.normalize, self.fftw_norm_modes.keys())
+ raise ValueError(
+ "Unknown normalization mode %s. Possible values are %s"
+ % (self.normalize, self.fftw_norm_modes.keys())
)
self.fftw_norm_mode = self.fftw_norm_modes[self.normalize]
@@ -106,12 +154,12 @@ class FFTW(BaseFFT):
def check_array(self, array, shape, dtype, copy=True):
if array.shape != shape:
- raise ValueError("Invalid data shape: expected %s, got %s" %
- (shape, array.shape)
+ raise ValueError(
+ "Invalid data shape: expected %s, got %s" % (shape, array.shape)
)
if array.dtype != dtype:
- raise ValueError("Invalid data type: expected %s, got %s" %
- (dtype, array.dtype)
+ raise ValueError(
+ "Invalid data type: expected %s, got %s" % (dtype, array.dtype)
)
def set_data(self, self_array, array, shape, dtype, copy=True, name=None):
@@ -133,7 +181,7 @@ class FFTW(BaseFFT):
if id(self.refs[name]) == id(array):
# nothing to do: fft is performed on self.data_in or self.data_out
arr_to_use = self.refs[name]
- if self.check_alignment and not(pyfftw.is_byte_aligned(array)):
+ if self.check_alignment and not (pyfftw.is_byte_aligned(array)):
# If the array is not properly aligned,
# create a temp. array copy it to self.data_in or self.data_out
self_array[:] = array[:]
@@ -151,13 +199,10 @@ class FFTW(BaseFFT):
self.data_in,
self.data_out,
axes=self.axes,
- direction='FFTW_FORWARD',
+ direction="FFTW_FORWARD",
flags=self.fftw_flags,
threads=self.num_threads,
planning_timelimit=self.fftw_planning_timelimit,
- # the following seems to be taken into account only when using __call__
- ortho=self.fftw_norm_mode["ortho"],
- normalise_idft=self.fftw_norm_mode["normalize"],
)
def compute_inverse_plan(self):
@@ -165,13 +210,10 @@ class FFTW(BaseFFT):
self.data_out,
self.data_in,
axes=self.axes,
- direction='FFTW_BACKWARD',
+ direction="FFTW_BACKWARD",
flags=self.fftw_flags,
threads=self.num_threads,
planning_timelimit=self.fftw_planning_timelimit,
- # the following seem to be taken into account only when using __call__
- ortho=self.fftw_norm_mode["ortho"],
- normalise_idft=self.fftw_norm_mode["normalize"],
)
def fft(self, array, output=None):
@@ -187,8 +229,9 @@ class FFTW(BaseFFT):
data_out = self.set_output_data(output, copy=False)
self.plan_forward.update_arrays(data_in, data_out)
# execute.__call__ does both update_arrays() and normalization
- self.plan_forward(
- ortho=self.fftw_norm_mode["ortho"],
+ self.plan_forward( # [0] --> fft
+ ortho=self.fftw_norm_mode[0]["ortho"],
+ normalise_idft=self.fftw_norm_mode[0]["normalise_idft"],
)
self.plan_forward.update_arrays(self.refs["data_in"], self.refs["data_out"])
return data_out
@@ -204,11 +247,119 @@ class FFTW(BaseFFT):
"""
data_in = self.set_output_data(array, copy=False)
data_out = self.set_input_data(output, copy=False)
- self.plan_inverse.update_arrays(data_in, data_out)
+ self.plan_inverse.update_arrays(
+ data_in, data_out
+ ) # TODO why in/out when it is out/in everywhere else in the function
# execute.__call__ does both update_arrays() and normalization
- self.plan_inverse(
- ortho=self.fftw_norm_mode["ortho"],
- normalise_idft=self.fftw_norm_mode["normalize"]
+ self.plan_inverse( # [1] --> ifft
+ ortho=self.fftw_norm_mode[1]["ortho"],
+ normalise_idft=self.fftw_norm_mode[1]["normalise_idft"],
)
self.plan_inverse.update_arrays(self.refs["data_out"], self.refs["data_in"])
return data_out
+
+
+
+def get_wisdom_metadata():
+ """
+ Get metadata on the current platform.
+ FFTW wisdom works with varying performance depending on whether the plans are re-used
+ on the same machine/architecture/etc.
+ For more information: https://www.fftw.org/fftw3_doc/Caveats-in-Using-Wisdom.html
+ """
+ return {
+ # "venv"
+ "executable": sys_executable,
+ # encapsulates sys.platform, platform.machine(), platform.architecture(), platform.libc_ver(), ...
+ "hostname": gethostname(),
+ "available_threads": len(os.sched_getaffinity(0)),
+ }
+
+
+def export_wisdom(fname, on_existing="overwrite"):
+ """
+ Export the current FFTW wisdom to a file.
+
+ :param str fname:
+ Path to the file where the wisdom is to be exported
+ :param str on_existing:
+ What do do when the target file already exists.
+ Possible options are:
+ - raise: raise an error and exit
+ - overwrite: overwrite the file with the current wisdom
+ - append: Import the already existing wisdom, and dump the newly combined wisdom to this file
+ """
+ if os.path.isfile(fname):
+ if on_existing == "raise":
+ raise ValueError("File already exists: %s" % fname)
+ if on_existing == "append":
+ import_wisdom(fname, on_mismatch="ignore") # ?
+ current_wisdom = pyfftw.export_wisdom()
+ res = get_wisdom_metadata()
+ for i, w in enumerate(current_wisdom):
+ res[str(i)] = np.array(w)
+ np.savez_compressed(fname, **res)
+
+
+def import_wisdom(fname, match=["hostname"], on_mismatch="warn"):
+ """
+ Import FFTW wisdom for a .npz file.
+
+ :param str fname:
+ Path to the .npz file containing FFTW wisdom
+ :param list match:
+ List of elements that must match when importing wisdom.
+ If match=["hostname"] (default), this class will only load wisdom that was saved
+ on the current machine, and discard everything else.
+ If match=["hostname", "executable"], wisdom will only be loaded if the file was
+ created on the same machine and by the same python executable.
+ :param str on_mismatch:
+ What to do when the file wisdom does not match the current platform.
+ Available options:
+ - "raise": raise an error (crash)
+ - "warn": print a warning, don't crash
+ - "ignore": do nothing
+ """
+ def handle_mismatch(item, loaded_value, current_value):
+ msg = "Platform configuration mismatch: %s: currently have '%s', loaded '%s'" % (item, current_value, loaded_value)
+ if on_mismatch == "raise":
+ raise ValueError(msg)
+ if on_mismatch == "warn":
+ print(msg)
+
+ wis_metadata = get_wisdom_metadata()
+ loaded_wisdom = np.load(fname)
+ for metadata_name in match:
+ if metadata_name not in wis_metadata:
+ raise ValueError(
+ "Cannot match metadata '%s'. Available are: %s" % (match, str(wis_metadata.keys()))
+ )
+ if loaded_wisdom[metadata_name] != wis_metadata[metadata_name]:
+ handle_mismatch(metadata_name, loaded_wisdom[metadata_name], wis_metadata[metadata_name])
+ return
+ w = tuple(loaded_wisdom[k][()] for k in loaded_wisdom.keys() if k not in wis_metadata.keys())
+ pyfftw.import_wisdom(w)
+
+
+def get_wisdom_file(directory=None, name_template="fftw_wisdom_{whoami}_{hostname}.npz", create_dirs=True):
+ """
+ Get a file path for storing FFTW wisdom.
+
+ :param str directory:
+ Directory where the file is created. By default, files are written in a temporary directory.
+ :param str name_template:
+ File name pattern. The following patterns can be used:
+ - {whoami}: current username
+ - {hostname}: machine name
+ :param bool create_dirs:
+ Whether to create (possibly nested) directories if needed.
+ """
+ directory = directory or gettempdir()
+ file_basename = name_template.format(
+ whoami=os.getlogin(),
+ hostname=gethostname()
+ )
+ out_file = os.path.join(directory, file_basename)
+ if create_dirs:
+ Path(os.path.dirname(out_file)).mkdir(parents=True, exist_ok=True)
+ return out_file
diff --git a/src/silx/math/fft/npfft.py b/src/silx/math/fft/npfft.py
index 20351de..fc7d1c9 100644
--- a/src/silx/math/fft/npfft.py
+++ b/src/silx/math/fft/npfft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
@@ -24,6 +23,8 @@
#
# ###########################################################################*/
import numpy as np
+import warnings
+from pkg_resources import parse_version
from .basefft import BaseFFT
@@ -33,6 +34,7 @@ class NPFFT(BaseFFT):
Please see FFT class for parameters help.
"""
+
def __init__(
self,
shape=None,
@@ -42,7 +44,7 @@ class NPFFT(BaseFFT):
axes=None,
normalize="rescale",
):
- super(NPFFT, self).__init__(
+ super().__init__(
shape=shape,
dtype=dtype,
template=template,
@@ -55,13 +57,34 @@ class NPFFT(BaseFFT):
if template is not None and np.isrealobj(template):
self.real_transform = True
# For numpy functions.
- # TODO Issue warning if user wants ifft(fft(data)) = N*data ?
- if normalize != "ortho":
- self.normalize = None
+
+ self.set_fft_norm()
self.set_fft_functions()
- #~ self.allocate_arrays() # not needed for this backend
self.compute_plans()
+ def set_fft_norm(self):
+ # backward, forward indicates the direction in which the
+ # normalisation is done. default is "backward"
+
+ # rescale is default norm with numpy, no need of keywords
+ # if normalize == "rescale": # normalisation 1/N on ifft
+ self.numpy_args_fft = {}
+ self.numpy_args_ifft = {}
+
+ if self.normalize == "ortho": # normalization 1/sqrt(N) on both fft & ifft
+ self.numpy_args_fft = {"norm": "ortho"}
+ self.numpy_args_ifft = {"norm": "ortho"}
+
+ elif self.normalize == "none": # no normalisation on both fft & ifft
+ if parse_version(np.version.version) < parse_version("1.20"):
+ # "backward" & "forward" keywords were introduced in 1.20 and we support numpy >= 1.8
+ warnings.warn(
+ "Numpy version %s does not allow to non-normalization. Effective normalization will be 'rescale'"
+ % (np.version.version)
+ ) # default 'rescale' normalization
+ else:
+ self.numpy_args_fft = {"norm": "backward"}
+ self.numpy_args_ifft = {"norm": "forward"}
def set_fft_functions(self):
# (fwd, inv) = _fft_functions[is_real][ndim]
@@ -75,34 +98,33 @@ class NPFFT(BaseFFT):
1: (np.fft.fft, np.fft.ifft),
2: (np.fft.fft2, np.fft.ifft2),
3: (np.fft.fftn, np.fft.ifftn),
- }
+ },
}
-
def _allocate(self, shape, dtype):
- return np.zeros(self.queue, shape, dtype=dtype)
-
+ return np.zeros(shape, dtype=dtype)
def compute_plans(self):
ndim = len(self.shape)
funcs = self._fft_functions[self.real_transform][np.minimum(ndim, 3)]
- if np.version.version[:4] in ["1.8.", "1.9."]:
- # norm keyword was introduced in 1.10 and we support numpy >= 1.8
- self.numpy_args = {}
- else:
- self.numpy_args = {"norm": self.normalize}
+
+ # Set norm
+ # self.numpy_args_fft & self.numpy_args_ifft already set in set_fft_norm
+
# Batched transform
if (self.user_axes is not None) and len(self.user_axes) < ndim:
- funcs = self._fft_functions[self.real_transform][np.minimum(ndim-1, 3)]
- self.numpy_args["axes"] = self.user_axes
+ funcs = self._fft_functions[self.real_transform][np.minimum(ndim - 1, 3)]
+ self.numpy_args_fft["axes"] = self.user_axes
+ self.numpy_args_ifft["axes"] = self.user_axes
# Special case of batched 1D transform on 2D data
if ndim == 2:
assert len(self.user_axes) == 1
- self.numpy_args["axis"] = self.user_axes[0]
- self.numpy_args.pop("axes")
+ self.numpy_args_fft["axis"] = self.user_axes[0]
+ self.numpy_args_fft.pop("axes")
+ self.numpy_args_ifft["axis"] = self.user_axes[0]
+ self.numpy_args_ifft.pop("axes")
self.numpy_funcs = funcs
-
def fft(self, array):
"""
Perform a (forward) Fast Fourier Transform.
@@ -110,8 +132,7 @@ class NPFFT(BaseFFT):
:param numpy.ndarray array:
Input data. Must be consistent with the current context.
"""
- return self.numpy_funcs[0](array, **self.numpy_args)
-
+ return self.numpy_funcs[0](array, **self.numpy_args_fft)
def ifft(self, array):
"""
@@ -120,5 +141,4 @@ class NPFFT(BaseFFT):
:param numpy.ndarray array:
Input data. Must be consistent with the current context.
"""
- return self.numpy_funcs[1](array, **self.numpy_args)
-
+ return self.numpy_funcs[1](array, **self.numpy_args_ifft)
diff --git a/src/silx/math/fft/setup.py b/src/silx/math/fft/setup.py
deleted file mode 100644
index 76bb864..0000000
--- a/src/silx/math/fft/setup.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["P. Naudet"]
-__license__ = "MIT"
-__date__ = "12/12/2018"
-
-import numpy
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('fft', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/math/fft/test/__init__.py b/src/silx/math/fft/test/__init__.py
index ad9836c..d076ee3 100644
--- a/src/silx/math/fft/test/__init__.py
+++ b/src/silx/math/fft/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2019 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fft/test/test_fft.py b/src/silx/math/fft/test/test_fft.py
index 19becb8..b696317 100644
--- a/src/silx/math/fft/test/test_fft.py
+++ b/src/silx/math/fft/test/test_fft.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -25,10 +24,13 @@
# ###########################################################################*/
"""Test of the FFT module"""
+from os import path
+import logging
import numpy as np
import unittest
-import logging
+from pkg_resources import parse_version
import pytest
+from tempfile import TemporaryDirectory
try:
from scipy.misc import ascent
__have_scipy = True
@@ -38,11 +40,43 @@ from silx.utils.testutils import ParametricTestCase
from silx.math.fft.fft import FFT
from silx.math.fft.clfft import __have_clfft__
from silx.math.fft.cufft import __have_cufft__
-from silx.math.fft.fftw import __have_fftw__
+from silx.math.fft.fftw import __have_fftw__, import_wisdom, export_wisdom, get_wisdom_file
+if __have_cufft__:
+ import atexit
+ import pycuda.driver as cuda
+ from pycuda.tools import clear_context_caches
-logger = logging.getLogger(__name__)
+def get_cuda_context(device_id=None, cleanup_at_exit=True):
+ """
+ Create or get a CUDA context.
+ """
+ current_ctx = cuda.Context.get_current()
+ # If a context already exists, use this one
+ # TODO what if the device used is different from device_id ?
+ if current_ctx is not None:
+ return current_ctx
+ # Otherwise create a new context
+ cuda.init()
+
+ if device_id is None:
+ device_id = 0
+ # Use the Context obtained by retaining the device's primary context,
+ # which is the one used by the CUDA runtime API (ex. scikit-cuda).
+ # Unlike Context.make_context(), the newly-created context is not made current.
+ context = cuda.Device(device_id).retain_primary_context()
+ context.push()
+ # Register a clean-up function at exit
+ def _finish_up(context):
+ if context is not None:
+ context.pop()
+ context = None
+ clear_context_caches()
+ if cleanup_at_exit:
+ atexit.register(_finish_up, context)
+ return context
+logger = logging.getLogger(__name__)
class TransformInfos(object):
def __init__(self):
@@ -113,7 +147,7 @@ class TestFFT(ParametricTestCase):
@unittest.skipIf(not __have_cufft__,
"cuda back-end requires pycuda and scikit-cuda")
def test_cuda(self):
- import pycuda.autoinit
+ get_cuda_context()
# Error is higher when using cuda. fast_math mode ?
self.tol[np.dtype("float32")] *= 2
@@ -196,6 +230,90 @@ class TestFFT(ParametricTestCase):
)
+ # Test normalizations. silx FFT has three normalization modes:
+ # - "rescale" (default). FFT is unscaled, IFFT is scaled by 1/N.
+ # This corresponds to numpy normalize=None i.e normalize="backward"
+ # - "ortho": FFT/IFFT are both scaled with 1/sqrt(N) so that FFT is unitary.
+ # - "none": Neither FFT nor IFFT are not scaled, so IFFT(FFT(array)) = N*array
+
+ norms_backends_support = {
+ "numpy": {
+ "supported_normalizations": ["rescale", "ortho", "none"],
+ },
+ "fftw": {
+ "supported_normalizations": ["rescale", "ortho", "none"],
+ },
+ "opencl": {
+ "supported_normalizations": ["rescale"],
+ },
+ "cuda": {
+ "supported_normalizations": ["rescale", "none"],
+ }
+ }
+
+ @staticmethod
+ def _compute_numpy_normalized_fft(data, axes, silx_normalization_mode):
+ if silx_normalization_mode in ["rescale", "none"]:
+ return np.fft.rfftn(data, axes=axes, norm=None)
+ elif silx_normalization_mode == "ortho":
+ return np.fft.rfftn(data, axes=axes, norm="ortho")
+ else:
+ raise ValueError("Unknown normalization mode %s" % silx_normalization_mode)
+
+ @staticmethod
+ def _compute_numpy_normalized_ifft(data, axes, silx_normalization_mode):
+ if silx_normalization_mode == "rescale":
+ return np.fft.irfftn(data, axes=axes, norm=None)
+ elif silx_normalization_mode == "ortho":
+ return np.fft.irfftn(data, axes=axes, norm="ortho")
+ elif silx_normalization_mode == "none":
+ res = np.fft.irfftn(data, axes=axes, norm=None)
+ # This assumes a FFT on all the axes, won't work on batched FFT
+ N = res.size
+ return res * N
+ else:
+ raise ValueError("Unknown normalization mode %s" % silx_normalization_mode)
+
+ @unittest.skipIf(not __have_fftw__, "fftw back-end requires pyfftw")
+ def test_norms_fftw(self):
+ return self._test_norms_with_backend("fftw")
+
+ @unittest.skipIf(
+ parse_version(np.version.version) <= parse_version("1.19.5"),
+ "normalization does not work for numpy <= 1.19.5"
+ )
+ def test_norms_numpy(self):
+ return self._test_norms_with_backend("numpy")
+
+ @unittest.skipIf(not __have_clfft__, "opencl back-end requires pyopencl and gpyfft")
+ def test_norms_opencl(self):
+ from silx.opencl.common import ocl
+ if ocl is not None:
+ return self._test_norms_with_backend("opencl")
+
+ @unittest.skipIf(not __have_cufft__, "cuda back-end requires pycuda and scikit-cuda")
+ def test_norms_cuda(self):
+ get_cuda_context()
+ return self._test_norms_with_backend("cuda")
+
+ def _test_norms_with_backend(self, backend_name):
+ backend_params = self.norms_backends_support[backend_name]
+
+ data = self.test_data.data
+ tol = self.tol[np.dtype(data.dtype)]
+
+ for norm in backend_params["supported_normalizations"]:
+ fft = FFT(template=data, backend=backend_name, normalize=norm)
+ res = fft.fft(data)
+ ref = self._compute_numpy_normalized_fft(data, fft.axes, norm)
+ assert np.allclose(res, ref, atol=tol, rtol=tol), "Something wrong with %s norm=%s" % (backend_name, norm)
+
+ res2 = fft.ifft(res)
+ ref2 = self._compute_numpy_normalized_ifft(ref, fft.axes, norm)
+ # unscaled IFFT yields very large values. Use a relatively high "atol"
+ assert np.allclose(res2, ref2, atol=res2.max()/1e6), "Something wrong with I%s norm=%s" % (backend_name, norm)
+
+
@unittest.skipUnless(__have_scipy, "scipy is missing")
class TestNumpyFFT(ParametricTestCase):
"""
@@ -255,3 +373,23 @@ class TestNumpyFFT(ParametricTestCase):
res2 = F.ifft(res)
ref2 = np_ifft(ref)
self.assertTrue(np.allclose(res2, ref2))
+
+
+@pytest.mark.skipif(not(__have_fftw__), reason="Need fftw/pyfftw for this test")
+def test_fftw_wisdom():
+ """
+ Test FFTW wisdom import/export mechanism
+ """
+
+ assert path.isdir(path.dirname(get_wisdom_file())) # Default: tempdir.gettempdir()
+
+ with TemporaryDirectory(prefix="test_fftw_wisdom") as dname:
+ subdir = path.join(dname, "subdir")
+ get_wisdom_file(directory=subdir, create_dirs=False)
+ assert not(path.isdir(subdir))
+ fname = get_wisdom_file(directory=subdir, create_dirs=True)
+ assert path.isdir(subdir)
+ export_wisdom(fname)
+ assert path.isfile(fname)
+ import_wisdom(fname)
+
diff --git a/src/silx/math/fit/__init__.py b/src/silx/math/fit/__init__.py
index 29e6a9e..7dd6d32 100644
--- a/src/silx/math/fit/__init__.py
+++ b/src/silx/math/fit/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/bgtheories.py b/src/silx/math/fit/bgtheories.py
index 631c43e..d0f4987 100644
--- a/src/silx/math/fit/bgtheories.py
+++ b/src/silx/math/fit/bgtheories.py
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
#
# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fit/filters.pyx b/src/silx/math/fit/filters.pyx
index da1f6f5..054d129 100644
--- a/src/silx/math/fit/filters.pyx
+++ b/src/silx/math/fit/filters.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/filters_wrapper.pxd b/src/silx/math/fit/filters_wrapper.pxd
index e4f7c72..e09de32 100644
--- a/src/silx/math/fit/filters_wrapper.pxd
+++ b/src/silx/math/fit/filters_wrapper.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/fitmanager.py b/src/silx/math/fit/fitmanager.py
index 226e047..cbb1e34 100644
--- a/src/silx/math/fit/fitmanager.py
+++ b/src/silx/math/fit/fitmanager.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*#########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fit/fittheories.py b/src/silx/math/fit/fittheories.py
index 5461416..76f2478 100644
--- a/src/silx/math/fit/fittheories.py
+++ b/src/silx/math/fit/fittheories.py
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
#
# Copyright (c) 2004-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fit/fittheory.py b/src/silx/math/fit/fittheory.py
index fa42e6b..ab3ae43 100644
--- a/src/silx/math/fit/fittheory.py
+++ b/src/silx/math/fit/fittheory.py
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
#
# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fit/functions.pyx b/src/silx/math/fit/functions.pyx
index 1f78563..a69086c 100644
--- a/src/silx/math/fit/functions.pyx
+++ b/src/silx/math/fit/functions.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/functions_wrapper.pxd b/src/silx/math/fit/functions_wrapper.pxd
index 780116c..38de94a 100644
--- a/src/silx/math/fit/functions_wrapper.pxd
+++ b/src/silx/math/fit/functions_wrapper.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/leastsq.py b/src/silx/math/fit/leastsq.py
index 3df1a35..e49977f 100644
--- a/src/silx/math/fit/leastsq.py
+++ b/src/silx/math/fit/leastsq.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
diff --git a/src/silx/math/fit/peaks.pyx b/src/silx/math/fit/peaks.pyx
index a4fce89..cc705a5 100644
--- a/src/silx/math/fit/peaks.pyx
+++ b/src/silx/math/fit/peaks.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
@@ -65,6 +64,7 @@ def peak_search(y, fwhm, sensitivity=3.5,
if ``relevance_info`` is ``False``.
Else, sequence of ``(peak_index, peak_relevance)`` tuples (one tuple
per peak).
+ WARNING: Peak indices are returned as float64.
:raise: ``IndexError`` if the number of peaks is too large to fit in the
output array.
"""
diff --git a/src/silx/math/fit/peaks_wrapper.pxd b/src/silx/math/fit/peaks_wrapper.pxd
index 4c77dc6..0ae1910 100644
--- a/src/silx/math/fit/peaks_wrapper.pxd
+++ b/src/silx/math/fit/peaks_wrapper.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
#/*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/setup.py b/src/silx/math/fit/setup.py
deleted file mode 100644
index 649387f..0000000
--- a/src/silx/math/fit/setup.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-
-__authors__ = ["P. Knobel"]
-__license__ = "MIT"
-__date__ = "22/06/2016"
-
-
-import os.path
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('fit', parent_package, top_path)
- config.add_subpackage('test')
-
- # =====================================
- # fit functions
- # =====================================
- fun_src = [os.path.join('functions', "src", "funs.c"),
- "functions.pyx"]
- fun_inc = [os.path.join('functions', 'include')]
-
- config.add_extension('functions',
- sources=fun_src,
- include_dirs=fun_inc,
- language='c')
-
- # =====================================
- # fit filters
- # =====================================
- filt_src = [os.path.join('filters', "src", srcf)
- for srcf in ["smoothnd.c", "snip1d.c",
- "snip2d.c", "snip3d.c", "strip.c"]]
- filt_src.append("filters.pyx")
- filt_inc = [os.path.join('filters', 'include')]
-
- config.add_extension('filters',
- sources=filt_src,
- include_dirs=filt_inc,
- language='c')
-
- # =====================================
- # peaks
- # =====================================
- peaks_src = [os.path.join('peaks', "src", "peaks.c"),
- "peaks.pyx"]
- peaks_inc = [os.path.join('peaks', 'include')]
-
- config.add_extension('peaks',
- sources=peaks_src,
- include_dirs=peaks_inc,
- language='c')
- # =====================================
- # =====================================
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/math/fit/test/__init__.py b/src/silx/math/fit/test/__init__.py
index 745efe3..bfc51f5 100644
--- a/src/silx/math/fit/test/__init__.py
+++ b/src/silx/math/fit/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_bgtheories.py b/src/silx/math/fit/test/test_bgtheories.py
index 6620d38..40f0831 100644
--- a/src/silx/math/fit/test/test_bgtheories.py
+++ b/src/silx/math/fit/test/test_bgtheories.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_filters.py b/src/silx/math/fit/test/test_filters.py
index 8314bdc..5b8b070 100644
--- a/src/silx/math/fit/test/test_filters.py
+++ b/src/silx/math/fit/test/test_filters.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_fit.py b/src/silx/math/fit/test/test_fit.py
index 00f04e2..39a04f9 100644
--- a/src/silx/math/fit/test/test_fit.py
+++ b/src/silx/math/fit/test/test_fit.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_fitmanager.py b/src/silx/math/fit/test/test_fitmanager.py
index 4ab56a5..cc35ccf 100644
--- a/src/silx/math/fit/test/test_fitmanager.py
+++ b/src/silx/math/fit/test/test_fitmanager.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_functions.py b/src/silx/math/fit/test/test_functions.py
index 7e3ff63..71cce8b 100644
--- a/src/silx/math/fit/test/test_functions.py
+++ b/src/silx/math/fit/test/test_functions.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/fit/test/test_peaks.py b/src/silx/math/fit/test/test_peaks.py
index 495c70d..23e4061 100644
--- a/src/silx/math/fit/test/test_peaks.py
+++ b/src/silx/math/fit/test/test_peaks.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/histogram.py b/src/silx/math/histogram.py
index af9ee68..e00daa9 100644
--- a/src/silx/math/histogram.py
+++ b/src/silx/math/histogram.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/histogramnd/include/histogramnd_c.h b/src/silx/math/histogramnd/include/histogramnd_c.h
index abe464f..25293b9 100644
--- a/src/silx/math/histogramnd/include/histogramnd_c.h
+++ b/src/silx/math/histogramnd/include/histogramnd_c.h
@@ -31,10 +31,10 @@
#else
#include <inttypes.h>
#endif
-
+#include <stddef.h>
#include "templates.h"
-/** Allowed flag values for the i_opt_flags arguments.
+/** Allowed flag values for the i_opt_flags arguments.
*/
typedef enum {
HISTO_NONE = 0, /**< No options. */
@@ -43,7 +43,7 @@ typedef enum {
HISTO_LAST_BIN_CLOSED = 1<<2 /**< Last bin is closed. */
} histo_opt_type;
-/** Return codees for the histogramnd function.
+/** Return codees for the histogramnd function.
*/
typedef enum {
HISTO_OK = 0, /**< No error. */
@@ -58,7 +58,7 @@ typedef enum {
int histogramnd_double_double_double(double *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -67,11 +67,11 @@ int histogramnd_double_double_double(double *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_double_float_double(double *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -80,11 +80,11 @@ int histogramnd_double_float_double(double *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_double_int32_t_double(double *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -93,7 +93,7 @@ int histogramnd_double_int32_t_double(double *i_sample,
int i_opt_flags,
int32_t i_weight_min,
int32_t i_weight_max);
-
+
/*=====================
* float sample, double cumul
* ====================
@@ -101,7 +101,7 @@ int histogramnd_double_int32_t_double(double *i_sample,
int histogramnd_float_double_double(float *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -110,11 +110,11 @@ int histogramnd_float_double_double(float *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_float_float_double(float *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -123,11 +123,11 @@ int histogramnd_float_float_double(float *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_float_int32_t_double(float *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -144,7 +144,7 @@ int histogramnd_float_int32_t_double(float *i_sample,
int histogramnd_int32_t_double_double(int32_t *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -153,11 +153,11 @@ int histogramnd_int32_t_double_double(int32_t *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_int32_t_float_double(int32_t *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -166,11 +166,11 @@ int histogramnd_int32_t_float_double(int32_t *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_int32_t_int32_t_double(int32_t *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -179,7 +179,7 @@ int histogramnd_int32_t_int32_t_double(int32_t *i_sample,
int i_opt_flags,
int32_t i_weight_min,
int32_t i_weight_max);
-
+
/*=====================
* double sample, float cumul
* ====================
@@ -188,7 +188,7 @@ int histogramnd_int32_t_int32_t_double(int32_t *i_sample,
int histogramnd_double_double_float(double *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -197,11 +197,11 @@ int histogramnd_double_double_float(double *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_double_float_float(double *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -210,11 +210,11 @@ int histogramnd_double_float_float(double *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_double_int32_t_float(double *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -223,7 +223,7 @@ int histogramnd_double_int32_t_float(double *i_sample,
int i_opt_flags,
int32_t i_weight_min,
int32_t i_weight_max);
-
+
/*=====================
* float sample, float cumul
* ====================
@@ -231,7 +231,7 @@ int histogramnd_double_int32_t_float(double *i_sample,
int histogramnd_float_double_float(float *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -240,11 +240,11 @@ int histogramnd_float_double_float(float *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_float_float_float(float *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -253,11 +253,11 @@ int histogramnd_float_float_float(float *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_float_int32_t_float(float *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -274,7 +274,7 @@ int histogramnd_float_int32_t_float(float *i_sample,
int histogramnd_int32_t_double_float(int32_t *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -283,11 +283,11 @@ int histogramnd_int32_t_double_float(int32_t *i_sample,
int i_opt_flags,
double i_weight_min,
double i_weight_max);
-
+
int histogramnd_int32_t_float_float(int32_t *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -296,11 +296,11 @@ int histogramnd_int32_t_float_float(int32_t *i_sample,
int i_opt_flags,
float i_weight_min,
float i_weight_max);
-
+
int histogramnd_int32_t_int32_t_float(int32_t *i_sample,
int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
uint32_t *o_histo,
@@ -309,5 +309,5 @@ int histogramnd_int32_t_int32_t_float(int32_t *i_sample,
int i_opt_flags,
int32_t i_weight_min,
int32_t i_weight_max);
-
+
#endif /* #define HISTOGRAMND_C_H */
diff --git a/src/silx/math/histogramnd/src/histogramnd_template.c b/src/silx/math/histogramnd/src/histogramnd_template.c
index 0276bb4..e446b74 100644
--- a/src/silx/math/histogramnd/src/histogramnd_template.c
+++ b/src/silx/math/histogramnd/src/histogramnd_template.c
@@ -36,7 +36,7 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
(HISTO_SAMPLE_T *i_sample,
HISTO_WEIGHT_T *i_weights,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bins,
uint32_t *o_histo,
@@ -48,43 +48,43 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
{
/* some counters */
int i = 0, j = 0;
- long elem_idx = 0;
-
+ size_t elem_idx = 0;
+
HISTO_WEIGHT_T * weight_ptr = 0;
HISTO_SAMPLE_T elem_coord = 0.;
-
+
/* computed bin index (i_sample -> grid) */
long bin_idx = 0;
-
+
double * g_min = 0;
double * g_max = 0;
double * range = 0;
-
+
/* ================================
* Parsing options, if any.
* ================================
*/
-
+
int filt_min_weight = 0;
int filt_max_weight = 0;
int last_bin_closed = 0;
-
+
/* Testing the option flags */
if(i_opt_flags & HISTO_WEIGHT_MIN)
{
filt_min_weight = 1;
}
-
+
if(i_opt_flags & HISTO_WEIGHT_MAX)
{
filt_max_weight = 1;
}
-
+
if(i_opt_flags & HISTO_LAST_BIN_CLOSED)
{
last_bin_closed = 1;
}
-
+
/* storing the min & max bin coordinates in their own arrays because
* i_bin_ranges = [[min0, max0], [min1, max1], ...]
* (mostly for the sake of clarity)
@@ -94,7 +94,7 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
g_max = (double *) malloc(i_n_dim * sizeof(double));
/* range used to convert from i_coords to bin indices in the grid */
range = (double *) malloc(i_n_dim * sizeof(double));
-
+
if(!g_min || !g_max || !range)
{
free(g_min);
@@ -102,14 +102,14 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
free(range);
return HISTO_ERR_ALLOC;
}
-
+
j = 0;
for(i=0; i<i_n_dim; i++)
{
g_min[i] = i_bin_ranges[i*2];
g_max[i] = i_bin_ranges[i*2+1];
range[i] = g_max[i]-g_min[i];
-
+
for(bin_idx=0; bin_idx<i_n_bins[i]; j++, bin_idx++)
{
o_bin_edges[j] = g_min[i] +
@@ -117,9 +117,9 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
}
o_bin_edges[j++] = g_max[i];
}
-
+
weight_ptr = i_weights;
-
+
if(!i_weights)
{
/* if weights are not provided there no point in trying to filter them
@@ -127,7 +127,7 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
*/
filt_min_weight = 0;
filt_max_weight = 0;
-
+
/* If the weights array is not provided then there is no point
* updating the weighted histogram, only the bin counts (o_histo)
* will be filled.
@@ -135,9 +135,9 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
*/
o_cumul = 0;
}
-
+
/* tried to use pointers instead of indices here, but it didn't
- * seem any faster (probably because the compiler
+ * seem any faster (probably because the compiler
* optimizes stuff anyway),
* so i'm keeping the "indices" version, for the sake of clarity
*/
@@ -159,11 +159,11 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
}
bin_idx = 0;
-
+
for(i=0; i<i_n_dim; i++)
{
elem_coord = i_sample[elem_idx+i];
-
+
/* =====================
* Element is rejected if any of the following is NOT true :
* 1. coordinate is >= than the minimum value
@@ -176,7 +176,7 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
bin_idx = -1;
break;
}
-
+
/* Here we make the assumption that most of the time
* there will be more coordinates inside the grid interval
* (one test)
@@ -193,7 +193,7 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
* i_n_bins[i]
* );
*/
-
+
/* Not using floor to speed up things.
* We don't (?) need all the error checking provided by
* the built-in floor().
@@ -221,33 +221,33 @@ int TEMPLATE(histogramnd, HISTO_SAMPLE_T, HISTO_WEIGHT_T, HISTO_CUMUL_T)
break;
}
} /* if(elem_coord<g_max[i]) */
-
+
} /* for(i=0; i<i_n_dim; i++) */
-
+
/* element is out of the grid */
if(bin_idx==-1)
{
continue;
}
-
+
if(o_histo)
{
o_histo[bin_idx] += 1;
}
if(o_cumul)
{
- /* not testing the pointer since o_cumul is null if
- * i_weights is null.
+ /* not testing the pointer since o_cumul is null if
+ * i_weights is null.
*/
o_cumul[bin_idx] += (HISTO_CUMUL_T) *weight_ptr;
}
-
+
} /* for(elem_idx=0; elem_idx<i_n_elem*i_n_dim; elem_idx+=i_n_dim) */
-
+
free(g_min);
free(g_max);
free(range);
-
+
/* For now just returning 0 (OK) since all the checks are done in
* python. This might change later if people want to call this
* function directly from C (might have to implement error codes).
diff --git a/src/silx/math/histogramnd_c.pxd b/src/silx/math/histogramnd_c.pxd
index 35db529..54a3daf 100644
--- a/src/silx/math/histogramnd_c.pxd
+++ b/src/silx/math/histogramnd_c.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
@@ -47,7 +46,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_double_double(double *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -60,7 +59,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_float_double(double *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -73,7 +72,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_int32_t_double(double *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -90,7 +89,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_double_double(float *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -103,7 +102,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_float_double(float *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -116,7 +115,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_int32_t_double(float *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -133,7 +132,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_double_double(cnumpy.int32_t *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -146,7 +145,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_float_double(cnumpy.int32_t *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -159,7 +158,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_int32_t_double(cnumpy.int32_t *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -176,7 +175,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_double_float(double *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -189,7 +188,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_float_float(double *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -202,7 +201,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_double_int32_t_float(double *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -219,7 +218,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_double_float(float *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -232,7 +231,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_float_float(float *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -245,7 +244,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_float_int32_t_float(float *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -262,7 +261,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_double_float(cnumpy.int32_t *i_sample,
double *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -275,7 +274,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_float_float(cnumpy.int32_t *i_sample,
float *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
@@ -288,7 +287,7 @@ cdef extern from "histogramnd_c.h":
int histogramnd_int32_t_int32_t_float(cnumpy.int32_t *i_sample,
cnumpy.int32_t *i_weigths,
int i_n_dim,
- int i_n_elem,
+ size_t i_n_elem,
double *i_bin_ranges,
int *i_n_bin,
cnumpy.uint32_t *o_histo,
diff --git a/src/silx/math/interpolate.pyx b/src/silx/math/interpolate.pyx
index c79224a..948cf9a 100644
--- a/src/silx/math/interpolate.pyx
+++ b/src/silx/math/interpolate.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
diff --git a/src/silx/math/marchingcubes.pyx b/src/silx/math/marchingcubes.pyx
index 0409691..78b76c4 100644
--- a/src/silx/math/marchingcubes.pyx
+++ b/src/silx/math/marchingcubes.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/math_compatibility.pxd b/src/silx/math/math_compatibility.pxd
index ddaa550..98fd21d 100644
--- a/src/silx/math/math_compatibility.pxd
+++ b/src/silx/math/math_compatibility.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/mc.pxd b/src/silx/math/mc.pxd
index b1c81e7..6270e21 100644
--- a/src/silx/math/mc.pxd
+++ b/src/silx/math/mc.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
diff --git a/src/silx/math/medianfilter/__init__.py b/src/silx/math/medianfilter/__init__.py
index 2b05f06..5c199e3 100644
--- a/src/silx/math/medianfilter/__init__.py
+++ b/src/silx/math/medianfilter/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/medianfilter/median_filter.pxd b/src/silx/math/medianfilter/median_filter.pxd
index 2fc0283..b302388 100644
--- a/src/silx/math/medianfilter/median_filter.pxd
+++ b/src/silx/math/medianfilter/median_filter.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/medianfilter/medianfilter.pyx b/src/silx/math/medianfilter/medianfilter.pyx
index fe05a78..f4b7c51 100644
--- a/src/silx/math/medianfilter/medianfilter.pyx
+++ b/src/silx/math/medianfilter/medianfilter.pyx
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/math/medianfilter/setup.py b/src/silx/math/medianfilter/setup.py
deleted file mode 100644
index d228357..0000000
--- a/src/silx/math/medianfilter/setup.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["D. Naudet"]
-__license__ = "MIT"
-__date__ = "02/05/2017"
-
-
-import numpy
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('medianfilter', parent_package, top_path)
- config.add_subpackage('test')
-
- # =====================================
- # median filter
- # =====================================
- medfilt_src = ['medianfilter.pyx']
- medfilt_inc = ['include', numpy.get_include()]
- extra_link_args = ['-fopenmp']
- extra_compile_args = ['-fopenmp']
- config.add_extension('medianfilter',
- sources=medfilt_src,
- include_dirs=[medfilt_inc],
- language='c++',
- extra_link_args=extra_link_args,
- extra_compile_args=extra_compile_args)
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration) \ No newline at end of file
diff --git a/src/silx/math/medianfilter/test/__init__.py b/src/silx/math/medianfilter/test/__init__.py
index 71f8e95..8bcf19a 100644
--- a/src/silx/math/medianfilter/test/__init__.py
+++ b/src/silx/math/medianfilter/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/medianfilter/test/benchmark.py b/src/silx/math/medianfilter/test/benchmark.py
index 81e893e..ebe4ac4 100644
--- a/src/silx/math/medianfilter/test/benchmark.py
+++ b/src/silx/math/medianfilter/test/benchmark.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2017-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/medianfilter/test/test_medianfilter.py b/src/silx/math/medianfilter/test/test_medianfilter.py
index a4e3021..15ee92e 100644
--- a/src/silx/math/medianfilter/test/test_medianfilter.py
+++ b/src/silx/math/medianfilter/test/test_medianfilter.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# ##########################################################################
# Copyright (C) 2017-2018 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/setup.py b/src/silx/math/setup.py
deleted file mode 100644
index 1c30e6e..0000000
--- a/src/silx/math/setup.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ############################################################################*/
-
-__authors__ = ["D. Naudet"]
-__license__ = "MIT"
-__date__ = "27/03/2017"
-
-import os.path
-
-import numpy
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('math', parent_package, top_path)
- config.add_subpackage('test')
- config.add_subpackage('fit')
- config.add_subpackage('medianfilter')
- config.add_subpackage('fft')
-
- # =====================================
- # histogramnd
- # =====================================
- histo_src = [os.path.join('histogramnd', 'src', 'histogramnd_c.c'),
- 'chistogramnd.pyx']
- histo_inc = [os.path.join('histogramnd', 'include'),
- numpy.get_include()]
-
- config.add_extension('chistogramnd',
- sources=histo_src,
- include_dirs=histo_inc,
- language='c')
-
- # =====================================
- # histogramnd_lut
- # =====================================
- config.add_extension('chistogramnd_lut',
- sources=['chistogramnd_lut.pyx'],
- include_dirs=histo_inc,
- language='c')
- # =====================================
- # marching cubes
- # =====================================
- mc_src = [os.path.join('marchingcubes', 'mc_lut.cpp'),
- 'marchingcubes.pyx']
- config.add_extension('marchingcubes',
- sources=mc_src,
- include_dirs=['marchingcubes', numpy.get_include()],
- language='c++')
-
- # min/max
- config.add_extension('combo',
- sources=['combo.pyx'],
- include_dirs=['include'],
- language='c')
-
- config.add_extension('_colormap',
- sources=["_colormap.pyx"],
- language='c',
- include_dirs=['include', numpy.get_include()],
- extra_link_args=['-fopenmp'],
- extra_compile_args=['-fopenmp'])
-
- config.add_extension('interpolate',
- sources=["interpolate.pyx"],
- language='c',
- include_dirs=['include', numpy.get_include()],
- extra_link_args=['-fopenmp'],
- extra_compile_args=['-fopenmp'])
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/math/test/__init__.py b/src/silx/math/test/__init__.py
index ad9836c..d076ee3 100644
--- a/src/silx/math/test/__init__.py
+++ b/src/silx/math/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2019 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/test/benchmark_combo.py b/src/silx/math/test/benchmark_combo.py
index c12f590..484bc93 100644
--- a/src/silx/math/test/benchmark_combo.py
+++ b/src/silx/math/test/benchmark_combo.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
@@ -23,8 +22,6 @@
# ############################################################################*/
"""Benchmarks of the combo module"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"
diff --git a/src/silx/math/test/histo_benchmarks.py b/src/silx/math/test/histo_benchmarks.py
index 7d3216d..6cc5507 100644
--- a/src/silx/math/test/histo_benchmarks.py
+++ b/src/silx/math/test/histo_benchmarks.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/test/test_HistogramndLut_nominal.py b/src/silx/math/test/test_HistogramndLut_nominal.py
index 52e003c..907a592 100644
--- a/src/silx/math/test/test_HistogramndLut_nominal.py
+++ b/src/silx/math/test/test_HistogramndLut_nominal.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2019 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/test/test_calibration.py b/src/silx/math/test/test_calibration.py
index 7158293..1c961be 100644
--- a/src/silx/math/test/test_calibration.py
+++ b/src/silx/math/test/test_calibration.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2018 European Synchrotron Radiation Facility
#
@@ -23,8 +22,6 @@
# ############################################################################*/
"""Tests of the calibration module"""
-from __future__ import division
-
__authors__ = ["P. Knobel"]
__license__ = "MIT"
__date__ = "14/05/2018"
diff --git a/src/silx/math/test/test_colormap.py b/src/silx/math/test/test_colormap.py
index 0b0ec59..144ee5f 100644
--- a/src/silx/math/test/test_colormap.py
+++ b/src/silx/math/test/test_colormap.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ############################################################################*/
"""Test for colormap mapping implementation"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "16/05/2018"
diff --git a/src/silx/math/test/test_combo.py b/src/silx/math/test/test_combo.py
index 9a96923..eed0625 100644
--- a/src/silx/math/test/test_combo.py
+++ b/src/silx/math/test/test_combo.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
#
@@ -23,8 +22,6 @@
# ############################################################################*/
"""Tests of the combo module"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"
diff --git a/src/silx/math/test/test_histogramnd_error.py b/src/silx/math/test/test_histogramnd_error.py
index 22304cb..d01cab9 100644
--- a/src/silx/math/test/test_histogramnd_error.py
+++ b/src/silx/math/test/test_histogramnd_error.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/test/test_histogramnd_nominal.py b/src/silx/math/test/test_histogramnd_nominal.py
index 031a772..9a8c3c3 100644
--- a/src/silx/math/test/test_histogramnd_nominal.py
+++ b/src/silx/math/test/test_histogramnd_nominal.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/math/test/test_histogramnd_vs_np.py b/src/silx/math/test/test_histogramnd_vs_np.py
index d6a8d19..d1fb8be 100644
--- a/src/silx/math/test/test_histogramnd_vs_np.py
+++ b/src/silx/math/test/test_histogramnd_vs_np.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
@@ -26,8 +25,10 @@ Tests for the histogramnd function.
Results are compared to numpy's histogramdd.
"""
+import os
import unittest
import operator
+import pytest
import numpy as np
@@ -609,6 +610,40 @@ class _TestHistogramnd(unittest.TestCase):
result_np_w_1[0].sum(dtype=np.float64)),
msg=self.state_msg)
+ @pytest.mark.usefixtures("use_large_memory")
+ def test_histo_big_array(self):
+ """
+ Test histogram on arrays with more than 2**31-1 samples.
+ """
+ if self.sample.ndim > 1:
+ self.skipTest("Test only many samples along one dimension")
+ if self.sample.dtype.itemsize > 4:
+ self.skipTest("Test only many samples for itemsize < 4")
+ n_repeat = (2**31 + 10) // self.sample.size
+ sample = np.repeat(self.sample, n_repeat)
+ n_bins = int(1e6)
+ result_c = histogramnd(
+ sample,
+ self.histo_range,
+ n_bins,
+ last_bin_closed=True
+ )
+ result_np = np.histogramdd(
+ sample,
+ n_bins,
+ range=self.histo_range
+ )
+ for i_edges, edges in enumerate(result_c[2]):
+ self.assertTrue(
+ np.allclose(
+ edges,
+ result_np[1][i_edges]
+ ),
+ msg='{0}. Testing bin_edges for dim {1}.'''.format(self.state_msg, i_edges+1)
+ )
+
+
+
class _TestHistogramnd_1d(_TestHistogramnd):
"""
diff --git a/src/silx/math/test/test_interpolate.py b/src/silx/math/test/test_interpolate.py
index 146449d..cff8bd9 100644
--- a/src/silx/math/test/test_interpolate.py
+++ b/src/silx/math/test/test_interpolate.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
diff --git a/src/silx/math/test/test_marchingcubes.py b/src/silx/math/test/test_marchingcubes.py
index 5e2b193..7c60414 100644
--- a/src/silx/math/test/test_marchingcubes.py
+++ b/src/silx/math/test/test_marchingcubes.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016 European Synchrotron Radiation Facility
#
@@ -23,8 +22,6 @@
# ############################################################################*/
"""Tests of the marchingcubes module"""
-from __future__ import division
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "17/01/2018"
diff --git a/src/silx/opencl/__init__.py b/src/silx/opencl/__init__.py
index fbd1f88..466ffaf 100644
--- a/src/silx/opencl/__init__.py
+++ b/src/silx/opencl/__init__.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: S I L X project
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/backprojection.py b/src/silx/opencl/backprojection.py
index 65a9836..9f747c1 100644
--- a/src/silx/opencl/backprojection.py
+++ b/src/silx/opencl/backprojection.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for (filtered) backprojection on the GPU"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["A. Mirone, P. Paleo"]
__license__ = "MIT"
__date__ = "25/01/2019"
diff --git a/src/silx/opencl/codec/byte_offset.py b/src/silx/opencl/codec/byte_offset.py
index 9a52427..e497a73 100644
--- a/src/silx/opencl/codec/byte_offset.py
+++ b/src/silx/opencl/codec/byte_offset.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: Sift implementation in Python + OpenCL
# https://github.com/silx-kit/silx
@@ -31,8 +30,6 @@
This module provides a class for CBF byte offset compression/decompression.
"""
-from __future__ import division, print_function, with_statement
-
__authors__ = ["Jérôme Kieffer"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
diff --git a/src/silx/opencl/codec/setup.py b/src/silx/opencl/codec/setup.py
deleted file mode 100644
index 4a5c1e5..0000000
--- a/src/silx/opencl/codec/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# coding: utf-8
-#
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-
-from __future__ import division
-
-__contact__ = "jerome.kieffer@esrf.eu"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__authors__ = ["J. Kieffer"]
-__date__ = "13/10/2017"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('codec', parent_package, top_path)
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/opencl/codec/test/__init__.py b/src/silx/opencl/codec/test/__init__.py
index 325c2c7..45065f8 100644
--- a/src/silx/opencl/codec/test/__init__.py
+++ b/src/silx/opencl/codec/test/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/codec/test/test_byte_offset.py b/src/silx/opencl/codec/test/test_byte_offset.py
index 4b2d5a3..9ed53bc 100644
--- a/src/silx/opencl/codec/test/test_byte_offset.py
+++ b/src/silx/opencl/codec/test/test_byte_offset.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: Byte-offset decompression in OpenCL
# https://github.com/silx-kit/silx
@@ -31,8 +30,6 @@
Test suite for byte-offset decompression
"""
-from __future__ import division, print_function
-
__authors__ = ["Jérôme Kieffer"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
diff --git a/src/silx/opencl/common.py b/src/silx/opencl/common.py
index 60849d6..cf51406 100644
--- a/src/silx/opencl/common.py
+++ b/src/silx/opencl/common.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: S I L X project
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/convolution.py b/src/silx/opencl/convolution.py
index 15ef931..481e8fb 100644
--- a/src/silx/opencl/convolution.py
+++ b/src/silx/opencl/convolution.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for convolution on CPU/GPU."""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["P. Paleo"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/opencl/image.py b/src/silx/opencl/image.py
index 65e2d5e..6a4a854 100644
--- a/src/silx/opencl/image.py
+++ b/src/silx/opencl/image.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
@@ -28,8 +27,6 @@
"""A general purpose library for manipulating 2D images in 1 or 3 colors
"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__author__ = "Jerome Kieffer"
__license__ = "MIT"
diff --git a/src/silx/opencl/linalg.py b/src/silx/opencl/linalg.py
index a64122a..77d826b 100644
--- a/src/silx/opencl/linalg.py
+++ b/src/silx/opencl/linalg.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for basic linear algebra in OpenCL"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["P. Paleo"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/opencl/medfilt.py b/src/silx/opencl/medfilt.py
index d4e425b..ae63eb2 100644
--- a/src/silx/opencl/medfilt.py
+++ b/src/silx/opencl/medfilt.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: Azimuthal integration
# https://github.com/silx-kit/pyFAI
@@ -31,8 +30,6 @@ The target is to mimic the signature of scipy.signal.medfilt and scipy.medfilt2
The first implementation targets 2D implementation where this operation is costly (~10s/2kx2k image)
"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__author__ = "Jerome Kieffer"
__license__ = "MIT"
diff --git a/src/silx/opencl/processing.py b/src/silx/opencl/processing.py
index 8b81f7f..c223354 100644
--- a/src/silx/opencl/processing.py
+++ b/src/silx/opencl/processing.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: S I L X project
# https://github.com/silx-kit/silx
@@ -38,7 +37,7 @@ __author__ = "Jerome Kieffer"
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "02/03/2021"
+__date__ = "06/10/2022"
__status__ = "stable"
import sys
@@ -53,7 +52,8 @@ from .utils import concatenate_cl_kernel
import platform
BufferDescription = namedtuple("BufferDescription", ["name", "size", "dtype", "flags"])
-EventDescription = namedtuple("EventDescription", ["name", "event"])
+EventDescription = namedtuple("EventDescription", ["name", "event"]) # Deprecated, please use ProfileDescription
+ProfileDescription = namedtuple("ProfileDescription", ["name", "start", "stop"])
logger = logging.getLogger(__name__)
@@ -286,6 +286,7 @@ class OpenclProcessing(object):
self.kernels = None
self.program = None
+# Methods about Profiling
def set_profiling(self, value=True):
"""Switch On/Off the profiling flag of the command queue to allow debugging
@@ -309,37 +310,42 @@ class OpenclProcessing(object):
"""
Add an OpenCL event to the events lists, if profiling is enabled.
- :param event: silx.opencl.processing.EventDescription.
+ :param event: pyopencl.NanyEvent.
:param desc: event description
"""
if self.profile:
- self.events.append(EventDescription(desc, event))
-
- def allocate_texture(self, shape, hostbuf=None, support_1D=False):
- return allocate_texture(self.ctx, shape, hostbuf=hostbuf, support_1D=support_1D)
+ try:
+ profile = event.profile
+ self.events.append(ProfileDescription(desc, profile.start, profile.end))
+ except Exception:
+ # Probably the driver does not support profiling
+ pass
- def transfer_to_texture(self, arr, tex_ref):
+ def profile_multi(self, event_lists):
"""
- Transfer an array to a texture.
+ Extract profiling info from several OpenCL event, if profiling is enabled.
- :param arr: Input array. Can be a numpy array or a pyopencl array.
- :param tex_ref: texture reference (pyopencl._cl.Image).
+ :param event_lists: list of ("desc", pyopencl.NanyEvent).
"""
- copy_args = [self.queue, tex_ref, arr]
- shp = arr.shape
- ndim = arr.ndim
- if ndim == 1:
- # pyopencl and OpenCL < 1.2 do not support image1d_t
- # force 2D with one row in this case
- # ~ ndim = 2
- shp = (1,) + shp
- copy_kwargs = {"origin":(0,) * ndim, "region": shp[::-1]}
- if not(isinstance(arr, numpy.ndarray)): # assuming pyopencl.array.Array
- # D->D copy
- copy_args[2] = arr.data
- copy_kwargs["offset"] = 0
- ev = pyopencl.enqueue_copy(*copy_args, **copy_kwargs)
- self.profile_add(ev, "Transfer to texture")
+ if self.profile:
+ for event_desc in event_lists:
+ if isinstance(event_desc, ProfileDescription):
+ self.events.append(event_desc)
+ else:
+ if isinstance(event_desc, EventDescription) or "__len__" in dir(e) and len(e) == 2:
+ desc, event = event_desc
+ else:
+ desc = "?"
+ event = event_desc
+ try:
+ profile = event.profile
+ start = profile.start
+ end = profile.end
+ except Exception:
+ # probably an unfinished job ... use old-style.
+ self.events.append(event_desc)
+ else:
+ self.events.append(ProfileDescription(desc, start, end))
def log_profile(self, stats=False):
"""If we are in profiling mode, prints out all timing for every single OpenCL call
@@ -359,20 +365,29 @@ class OpenclProcessing(object):
if self.profile:
for e in self.events:
- if "__len__" in dir(e) and len(e) >= 2:
+ if isinstance(e, ProfileDescription):
+ name = e[0]
+ t0 = e[1]
+ t1 = e[2]
+ elif isinstance(e, EventDescription) or "__len__" in dir(e) and len(e) == 2:
name = e[0]
pr = e[1].profile
t0 = pr.start
t1 = pr.end
- et = 1e-6 * (t1 - t0)
- total_time += et
- if stats is None:
- out.append(f"{name:>50} : {et:.3f}ms")
+ else:
+ name = "?"
+ t0 = e.profile.start
+ t1 = e.profile.end
+
+ et = 1e-6 * (t1 - t0)
+ total_time += et
+ if stats is None:
+ out.append(f"{name:>50} : {et:.3f}ms")
+ else:
+ if name in stats:
+ stats[name].append(et)
else:
- if name in stats:
- stats[name].append(et)
- else:
- stats[name] = [et]
+ stats[name] = [et]
if stats is not None:
for k, v in stats.items():
n = numpy.array(v)
@@ -390,6 +405,33 @@ class OpenclProcessing(object):
with self.sem:
self.events = []
+# Methods about textures
+ def allocate_texture(self, shape, hostbuf=None, support_1D=False):
+ return allocate_texture(self.ctx, shape, hostbuf=hostbuf, support_1D=support_1D)
+
+ def transfer_to_texture(self, arr, tex_ref):
+ """
+ Transfer an array to a texture.
+
+ :param arr: Input array. Can be a numpy array or a pyopencl array.
+ :param tex_ref: texture reference (pyopencl._cl.Image).
+ """
+ copy_args = [self.queue, tex_ref, arr]
+ shp = arr.shape
+ ndim = arr.ndim
+ if ndim == 1:
+ # pyopencl and OpenCL < 1.2 do not support image1d_t
+ # force 2D with one row in this case
+ # ~ ndim = 2
+ shp = (1,) + shp
+ copy_kwargs = {"origin":(0,) * ndim, "region": shp[::-1]}
+ if not(isinstance(arr, numpy.ndarray)): # assuming pyopencl.array.Array
+ # D->D copy
+ copy_args[2] = arr.data
+ copy_kwargs["offset"] = 0
+ ev = pyopencl.enqueue_copy(*copy_args, **copy_kwargs)
+ self.profile_add(ev, "Transfer to texture")
+
@property
def x87_volatile_option(self):
# this is running 32 bits OpenCL woth POCL
diff --git a/src/silx/opencl/projection.py b/src/silx/opencl/projection.py
index c02faf6..a02e28b 100644
--- a/src/silx/opencl/projection.py
+++ b/src/silx/opencl/projection.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2020 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for tomographic projector on the GPU"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["A. Mirone, P. Paleo"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/opencl/reconstruction.py b/src/silx/opencl/reconstruction.py
index 2c84aee..c85fd42 100644
--- a/src/silx/opencl/reconstruction.py
+++ b/src/silx/opencl/reconstruction.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for tomographic reconstruction algorithms"""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["P. Paleo"]
__license__ = "MIT"
__date__ = "01/08/2019"
diff --git a/src/silx/opencl/setup.py b/src/silx/opencl/setup.py
deleted file mode 100644
index 10fb1be..0000000
--- a/src/silx/opencl/setup.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# coding: utf-8
-#
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-
-from __future__ import division
-
-__contact__ = "jerome.kieffer@esrf.eu"
-__license__ = "MIT"
-__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__authors__ = ["J. Kieffer"]
-__date__ = "16/10/2017"
-
-import os.path
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('opencl', parent_package, top_path)
- path = os.path.dirname(os.path.abspath(__file__))
- if os.path.exists(os.path.join(path, 'sift')):
- config.add_subpackage('sift')
- config.add_subpackage('codec')
- config.add_subpackage('test')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/opencl/sinofilter.py b/src/silx/opencl/sinofilter.py
index d608744..890267e 100644
--- a/src/silx/opencl/sinofilter.py
+++ b/src/silx/opencl/sinofilter.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for sinogram filtering on CPU/GPU."""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["P. Paleo"]
__license__ = "MIT"
__date__ = "07/06/2019"
diff --git a/src/silx/opencl/sparse.py b/src/silx/opencl/sparse.py
index 514589a..709e3c7 100644
--- a/src/silx/opencl/sparse.py
+++ b/src/silx/opencl/sparse.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Module for data sparsification on CPU/GPU."""
-from __future__ import absolute_import, print_function, with_statement, division
-
__authors__ = ["P. Paleo"]
__license__ = "MIT"
__date__ = "07/06/2019"
diff --git a/src/silx/opencl/statistics.py b/src/silx/opencl/statistics.py
index a96ee33..9197dd1 100644
--- a/src/silx/opencl/statistics.py
+++ b/src/silx/opencl/statistics.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: SILX
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/test/__init__.py b/src/silx/opencl/test/__init__.py
index 92cda4a..b1ecf1b 100644
--- a/src/silx/opencl/test/__init__.py
+++ b/src/silx/opencl/test/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
#
# Project: silx
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/test/test_addition.py b/src/silx/opencl/test/test_addition.py
index 3b668bf..d6cf1ac 100644
--- a/src/silx/opencl/test/test_addition.py
+++ b/src/silx/opencl/test/test_addition.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: Sift implementation in Python + OpenCL
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/test/test_array_utils.py b/src/silx/opencl/test/test_array_utils.py
index 325a6c3..125d323 100644
--- a/src/silx/opencl/test/test_array_utils.py
+++ b/src/silx/opencl/test/test_array_utils.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Test of the OpenCL array_utils"""
-from __future__ import division, print_function
-
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
diff --git a/src/silx/opencl/test/test_backprojection.py b/src/silx/opencl/test/test_backprojection.py
index 96d56fa..501cf2f 100644
--- a/src/silx/opencl/test/test_backprojection.py
+++ b/src/silx/opencl/test/test_backprojection.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Test of the filtered backprojection module"""
-from __future__ import division, print_function
-
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
diff --git a/src/silx/opencl/test/test_convolution.py b/src/silx/opencl/test/test_convolution.py
index 6a2759d..e38a36a 100644
--- a/src/silx/opencl/test/test_convolution.py
+++ b/src/silx/opencl/test/test_convolution.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -28,8 +27,6 @@
Test of the Convolution class.
"""
-from __future__ import division, print_function
-
__authors__ = ["Pierre Paleo"]
__contact__ = "pierre.paleo@esrf.fr"
__license__ = "MIT"
diff --git a/src/silx/opencl/test/test_doubleword.py b/src/silx/opencl/test/test_doubleword.py
index a33cf5a..8ab594d 100644
--- a/src/silx/opencl/test/test_doubleword.py
+++ b/src/silx/opencl/test/test_doubleword.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
#
# Project: The silx project
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/test/test_image.py b/src/silx/opencl/test/test_image.py
index 73c771b..4ea8960 100644
--- a/src/silx/opencl/test/test_image.py
+++ b/src/silx/opencl/test/test_image.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: image manipulation in OpenCL
# https://github.com/silx-kit/silx
@@ -29,8 +28,6 @@
Simple test of image manipulation
"""
-from __future__ import division, print_function
-
__authors__ = ["Jérôme Kieffer"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
diff --git a/src/silx/opencl/test/test_kahan.py b/src/silx/opencl/test/test_kahan.py
index 9e4a1e3..62ed047 100644
--- a/src/silx/opencl/test/test_kahan.py
+++ b/src/silx/opencl/test/test_kahan.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
#
# Project: OpenCL numerical library
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/test/test_linalg.py b/src/silx/opencl/test/test_linalg.py
index a997a36..da99480 100644
--- a/src/silx/opencl/test/test_linalg.py
+++ b/src/silx/opencl/test/test_linalg.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Test of the linalg module"""
-from __future__ import division, print_function
-
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
diff --git a/src/silx/opencl/test/test_medfilt.py b/src/silx/opencl/test/test_medfilt.py
index 339e0f2..e657d0d 100644
--- a/src/silx/opencl/test/test_medfilt.py
+++ b/src/silx/opencl/test/test_medfilt.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: Median filter of images + OpenCL
# https://github.com/silx-kit/silx
@@ -29,8 +28,6 @@
Simple test of the median filter
"""
-from __future__ import division, print_function
-
__authors__ = ["Jérôme Kieffer"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
diff --git a/src/silx/opencl/test/test_projection.py b/src/silx/opencl/test/test_projection.py
index 13db5f4..d093e4b 100644
--- a/src/silx/opencl/test/test_projection.py
+++ b/src/silx/opencl/test/test_projection.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
@@ -25,8 +24,6 @@
# ###########################################################################*/
"""Test of the forward projection module"""
-from __future__ import division, print_function
-
__authors__ = ["Pierre paleo"]
__license__ = "MIT"
__copyright__ = "2013-2017 European Synchrotron Radiation Facility, Grenoble, France"
diff --git a/src/silx/opencl/test/test_sparse.py b/src/silx/opencl/test/test_sparse.py
index 1d26b36..62a1399 100644
--- a/src/silx/opencl/test/test_sparse.py
+++ b/src/silx/opencl/test/test_sparse.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/opencl/test/test_stats.py b/src/silx/opencl/test/test_stats.py
index 859271d..f8ab1a7 100644
--- a/src/silx/opencl/test/test_stats.py
+++ b/src/silx/opencl/test/test_stats.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# -*- coding: utf-8 -*-
#
# Project: Sift implementation in Python + OpenCL
# https://github.com/silx-kit/silx
diff --git a/src/silx/opencl/utils.py b/src/silx/opencl/utils.py
index 575e018..cc9f62d 100644
--- a/src/silx/opencl/utils.py
+++ b/src/silx/opencl/utils.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# /*##########################################################################
# Copyright (C) 2017 European Synchrotron Radiation Facility
#
@@ -26,8 +25,6 @@ Project: Sift implementation in Python + OpenCL
https://github.com/silx-kit/silx
"""
-from __future__ import division
-
__authors__ = ["Jérôme Kieffer", "Pierre Paleo"]
__contact__ = "jerome.kieffer@esrf.eu"
__license__ = "MIT"
diff --git a/src/silx/resources/__init__.py b/src/silx/resources/__init__.py
index 5346f48..b53f15b 100644
--- a/src/silx/resources/__init__.py
+++ b/src/silx/resources/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/resources/gui/icons/add-shape-rotated-rectangle.png b/src/silx/resources/gui/icons/add-shape-rotated-rectangle.png
new file mode 100644
index 0000000..d07efe5
--- /dev/null
+++ b/src/silx/resources/gui/icons/add-shape-rotated-rectangle.png
Binary files differ
diff --git a/src/silx/resources/gui/icons/add-shape-rotated-rectangle.svg b/src/silx/resources/gui/icons/add-shape-rotated-rectangle.svg
new file mode 100644
index 0000000..5f308e0
--- /dev/null
+++ b/src/silx/resources/gui/icons/add-shape-rotated-rectangle.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><rect transform="rotate(37.949)" x="11.714" y="-3.8806" width="21.14" height="12.56" fill="none" stroke="#f7941e" stroke-miterlimit="10" stroke-width="3"/><g transform="translate(.25293 13.263)" fill="#00a651" stroke="#00a651" stroke-miterlimit="10"><rect x="24.483" y="7.225" width="1.239" height="8.379"/><rect x="20.913" y="10.796" width="8.38" height="1.237"/></g></svg>
diff --git a/src/silx/resources/gui/icons/scale-auto.png b/src/silx/resources/gui/icons/scale-auto.png
new file mode 100644
index 0000000..35c68b4
--- /dev/null
+++ b/src/silx/resources/gui/icons/scale-auto.png
Binary files differ
diff --git a/src/silx/resources/gui/icons/scale-auto.svg b/src/silx/resources/gui/icons/scale-auto.svg
new file mode 100644
index 0000000..573e16e
--- /dev/null
+++ b/src/silx/resources/gui/icons/scale-auto.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg id="svg8" version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata id="metadata14"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g id="text841" transform="matrix(.60674 0 0 1.2718 .00017519 3.6533)" stroke-width=".42868" aria-label="AUTO"><path id="path1407" d="m10.2 13.672h-5.0403l-0.7954 2.2774h-3.2402l4.6301-12.5h3.843l4.6301 12.5h-3.2402zm-4.2366-2.3192h3.4244l-1.708-4.9734z"/><path id="path1409" d="m14.846 3.4493h3.2235v7.4935q0 1.5489 0.50236 2.2188 0.51073 0.66144 1.6578 0.66144 1.1554 0 1.6578-0.66144 0.51073-0.66981 0.51073-2.2188v-7.4935h3.2235v7.4935q0 2.6541-1.3313 3.9519t-4.0607 1.2978q-2.7211 0-4.0524-1.2978t-1.3313-3.9519z"/><path id="path1411" d="m26.793 3.4493h11.521v2.4364h-4.1445v10.064h-3.2235v-10.064h-4.1528z"/><path id="path1413" d="m45.186 5.5592q-1.4736 0-2.2857 1.0884-0.81215 1.0884-0.81215 3.0644 0 1.9676 0.81215 3.056t2.2857 1.0884q1.482 0 2.2941-1.0884 0.81215-1.0884 0.81215-3.056 0-1.9759-0.81215-3.0644-0.81215-1.0884-2.2941-1.0884zm0-2.336q3.0142 0 4.7222 1.7248t1.708 4.764q0 3.0309-1.708 4.7557t-4.7222 1.7248q-3.0058 0-4.7222-1.7248-1.708-1.7248-1.708-4.7557 0-3.0393 1.708-4.764 1.7164-1.7248 4.7222-1.7248z"/></g></svg>
diff --git a/src/silx/resources/gui/icons/scale-fixed.png b/src/silx/resources/gui/icons/scale-fixed.png
new file mode 100644
index 0000000..9e765c2
--- /dev/null
+++ b/src/silx/resources/gui/icons/scale-fixed.png
Binary files differ
diff --git a/src/silx/resources/gui/icons/scale-fixed.svg b/src/silx/resources/gui/icons/scale-fixed.svg
new file mode 100644
index 0000000..93fd99a
--- /dev/null
+++ b/src/silx/resources/gui/icons/scale-fixed.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg id="svg8" version="1.1" viewBox="0 0 32 32" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata id="metadata14"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g id="text841-0" transform="matrix(.60674 0 0 1.2718 .00017519 3.6533)" fill="#4d4d4d" stroke-width=".42868" aria-label="AUTO"><path id="path1407" d="m10.2 13.672h-5.0403l-0.7954 2.2774h-3.2402l4.6301-12.5h3.843l4.6301 12.5h-3.2402zm-4.2366-2.3192h3.4244l-1.708-4.9734z"/><path id="path1409" d="m14.846 3.4493h3.2235v7.4935q0 1.5489 0.50236 2.2188 0.51073 0.66144 1.6578 0.66144 1.1554 0 1.6578-0.66144 0.51073-0.66981 0.51073-2.2188v-7.4935h3.2235v7.4935q0 2.6541-1.3313 3.9519t-4.0607 1.2978q-2.7211 0-4.0524-1.2978t-1.3313-3.9519z"/><path id="path1411" d="m26.793 3.4493h11.521v2.4364h-4.1445v10.064h-3.2235v-10.064h-4.1528z"/><path id="path1413" d="m45.186 5.5592q-1.4736 0-2.2857 1.0884-0.81215 1.0884-0.81215 3.0644 0 1.9676 0.81215 3.056t2.2857 1.0884q1.482 0 2.2941-1.0884 0.81215-1.0884 0.81215-3.056 0-1.9759-0.81215-3.0644-0.81215-1.0884-2.2941-1.0884zm0-2.336q3.0142 0 4.7222 1.7248t1.708 4.764q0 3.0309-1.708 4.7557t-4.7222 1.7248q-3.0058 0-4.7222-1.7248-1.708-1.7248-1.708-4.7557 0-3.0393 1.708-4.764 1.7164-1.7248 4.7222-1.7248z"/></g><path id="rect846" transform="rotate(15.647)" d="m3.5335 9.776h32.378v2.6316h-32.378z" fill="#4d4d4d"/></svg>
diff --git a/src/silx/setup.py b/src/silx/setup.py
deleted file mode 100644
index 5e2bd0d..0000000
--- a/src/silx/setup.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "26/07/2018"
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('silx', parent_package, top_path)
- config.add_subpackage('gui')
- config.add_subpackage('io')
- config.add_subpackage('math')
- config.add_subpackage('image')
- config.add_subpackage('opencl')
- config.add_subpackage('resources')
- config.add_subpackage('sx')
- config.add_subpackage('test')
- config.add_subpackage('third_party')
- config.add_subpackage('utils')
- config.add_subpackage('app')
- config.add_subpackage("examples", "../../examples")
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/sx/__init__.py b/src/silx/sx/__init__.py
index 97a3460..8922989 100644
--- a/src/silx/sx/__init__.py
+++ b/src/silx/sx/__init__.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -88,7 +87,7 @@ def enable_gui():
global qt, _qapp
- if _IS_NOTEBOOK:
+ if _get_ipython is not None and _get_ipython() is not None:
_get_ipython().enable_pylab(gui='qt', import_all=False)
from silx.gui import qt
diff --git a/src/silx/sx/_plot.py b/src/silx/sx/_plot.py
index b44c042..155adba 100644
--- a/src/silx/sx/_plot.py
+++ b/src/silx/sx/_plot.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/sx/_plot3d.py b/src/silx/sx/_plot3d.py
index 444d9e0..c6833ac 100644
--- a/src/silx/sx/_plot3d.py
+++ b/src/silx/sx/_plot3d.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/test/__init__.py b/src/silx/test/__init__.py
index d9d3e42..31a892a 100644
--- a/src/silx/test/__init__.py
+++ b/src/silx/test/__init__.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -49,5 +48,5 @@ def run_tests(module: str='silx', verbosity: int=0, args=()):
str(verbosity),
'-o python_files=["test/test*.py","test/Test*.py"]',
'-o python_classes=["Test"]',
- '-o python_functions=["Test"]',
+ '-o python_functions=["test"]',
] + list(args))
diff --git a/src/silx/test/test_resources.py b/src/silx/test/test_resources.py
index 4030271..3344da0 100644
--- a/src/silx/test/test_resources.py
+++ b/src/silx/test/test_resources.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/test/test_sx.py b/src/silx/test/test_sx.py
index 9836285..1107964 100644
--- a/src/silx/test/test_sx.py
+++ b/src/silx/test/test_sx.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/test/test_version.py b/src/silx/test/test_version.py
index 80084f9..c138d84 100644
--- a/src/silx/test/test_version.py
+++ b/src/silx/test/test_version.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2016 European Synchrotron Radiation Facility
diff --git a/src/silx/test/utils.py b/src/silx/test/utils.py
index 0c2d5bf..5178e4b 100644
--- a/src/silx/test/utils.py
+++ b/src/silx/test/utils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/third_party/__init__.py b/src/silx/third_party/__init__.py
index 156563c..529ae3f 100644
--- a/src/silx/third_party/__init__.py
+++ b/src/silx/third_party/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/third_party/scipy_spatial.py b/src/silx/third_party/scipy_spatial.py
index 9885154..13069b3 100644
--- a/src/silx/third_party/scipy_spatial.py
+++ b/src/silx/third_party/scipy_spatial.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2017 European Synchrotron Radiation Facility
@@ -35,8 +34,6 @@ It should be used like that:
"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "07/11/2017"
diff --git a/src/silx/third_party/setup.py b/src/silx/third_party/setup.py
deleted file mode 100644
index 47686ea..0000000
--- a/src/silx/third_party/setup.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# coding: ascii
-#
-# JK: Numpy.distutils which imports this does not handle utf-8 in version<1.12
-#
-# /*##########################################################################
-#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-
-__authors__ = ["Valentin Valls"]
-__license__ = "MIT"
-__date__ = "23/04/2018"
-
-import os
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('third_party', parent_package, top_path)
- # includes _local only if it is available
- local_path = os.path.join(top_path, "src", "silx", "third_party", "_local")
- if os.path.exists(local_path):
- config.add_subpackage('_local')
- config.add_subpackage('_local.scipy_spatial')
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
- setup(configuration=configuration)
diff --git a/src/silx/utils/ExternalResources.py b/src/silx/utils/ExternalResources.py
index b79d6ff..429314e 100644
--- a/src/silx/utils/ExternalResources.py
+++ b/src/silx/utils/ExternalResources.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -27,7 +26,7 @@
__authors__ = ["Thomas Vincent", "J. Kieffer"]
__license__ = "MIT"
-__date__ = "08/03/2019"
+__date__ = "21/12/2021"
import os
@@ -38,7 +37,8 @@ import tempfile
import unittest
import urllib.request
import urllib.error
-
+import hashlib
+from collections import OrderedDict
logger = logging.getLogger(__name__)
@@ -68,10 +68,10 @@ class ExternalResources(object):
self.project = project
self._initialized = False
self.sem = threading.Semaphore()
-
+ self.hash = hashlib.sha256
self.env_key = env_key or (self.project.upper() + "_TESTDATA")
self.url_base = url_base
- self.all_data = set()
+ self.all_data = {}
self.timeout = timeout
self._data_home = None
@@ -104,6 +104,21 @@ class ExternalResources(object):
self._data_home = data_home
return data_home
+ def get_hash(self, filename=None, data=None):
+ "Calculate and return the hash of a file or a bunch of data"
+ if data is None and filename is None:
+ return
+ h = self.hash()
+ if filename is not None:
+ fullfilename = os.path.join(self.data_home, filename)
+ if os.path.exists(fullfilename):
+ with open(fullfilename, "rb") as fd:
+ data = fd.read()
+ else:
+ raise RuntimeError(f"Filename {fullfilename} does not exist !")
+ h.update(data)
+ return h.hexdigest()
+
def _initialize_data(self):
"""Initialize for downloading test data"""
if not self._initialized:
@@ -112,7 +127,13 @@ class ExternalResources(object):
self.testdata = os.path.join(self.data_home, "all_testdata.json")
if os.path.exists(self.testdata):
with open(self.testdata) as f:
- self.all_data = set(json.load(f))
+ jdata = json.load(f)
+ if isinstance(jdata, dict):
+ self.all_data = jdata
+ else:
+ #recalculate the hash only if the data was stored as a list
+ self.all_data = {k: self.get_hash(k) for k in jdata}
+ self.save_json()
self._initialized = True
def clean_up(self):
@@ -160,7 +181,7 @@ class ExternalResources(object):
os.makedirs(os.path.dirname(fullfilename))
try:
- with open(fullfilename, "wb") as outfile:
+ with open(fullfilename, mode="wb") as outfile:
outfile.write(data)
except IOError:
raise IOError("unable to write downloaded \
@@ -173,19 +194,32 @@ class ExternalResources(object):
This even works under windows !
Otherwise please try to download the images manually from
%s/%s""" % (filename, self.url_base, filename))
+ else:
+ self.all_data[filename] = self.get_hash(data=data)
+ self.save_json()
- if filename not in self.all_data:
- self.all_data.add(filename)
- image_list = list(self.all_data)
- image_list.sort()
- try:
- with open(self.testdata, "w") as fp:
- json.dump(image_list, fp, indent=4)
- except IOError:
- logger.debug("Unable to save JSON list")
-
+ else:
+ h = self.hash()
+ with open(fullfilename, mode="rb") as fd:
+ h.update(fd.read())
+ if h.hexdigest() != self.all_data[filename]:
+ logger.warning(f"Detected corruped file {fullfilename}")
+ self.all_data.pop(filename)
+ os.unlink(fullfilename)
+ return self.getfile(filename)
+
return fullfilename
+ def save_json(self):
+ image_list = list(self.all_data.keys())
+ image_list.sort()
+ dico = OrderedDict([(i, self.all_data[i]) for i in image_list])
+ try:
+ with open(self.testdata, "w") as fp:
+ json.dump(dico, fp, indent=4)
+ except IOError:
+ logger.info("Unable to save JSON dict")
+
def getdir(self, dirname):
"""Downloads the requested tarball from the server
https://www.silx.org/pub/silx/
@@ -227,14 +261,8 @@ class ExternalResources(object):
if not self._initialized:
self._initialize_data()
if filename not in self.all_data:
- self.all_data.add(filename)
- image_list = list(self.all_data)
- image_list.sort()
- try:
- with open(self.testdata, "w") as fp:
- json.dump(image_list, fp, indent=4)
- except IOError:
- logger.debug("Unable to save JSON list")
+ self.all_data[filename] = self.get_hash(filename)
+ seld.save_json()
baseimage = os.path.basename(filename)
logger.info("UtilsTest.getimage('%s')" % baseimage)
@@ -313,7 +341,7 @@ class ExternalResources(object):
if not self._initialized:
self._initialize_data()
if not imgs:
- imgs = self.all_data
+ imgs = self.all_data.keys()
res = []
for fn in imgs:
logger.info("Downloading from silx.org: %s", fn)
diff --git a/src/silx/utils/__init__.py b/src/silx/utils/__init__.py
index f803a5f..6505e84 100644
--- a/src/silx/utils/__init__.py
+++ b/src/silx/utils/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/_have_openmp.pxd b/src/silx/utils/_have_openmp.pxd
index 89a385c..7302956 100644
--- a/src/silx/utils/_have_openmp.pxd
+++ b/src/silx/utils/_have_openmp.pxd
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/array_like.py b/src/silx/utils/array_like.py
index 0cf4857..d9c7b73 100644
--- a/src/silx/utils/array_like.py
+++ b/src/silx/utils/array_like.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -47,8 +46,6 @@ Functions:
"""
-from __future__ import absolute_import, print_function, division
-
import sys
import numpy
diff --git a/src/silx/utils/debug.py b/src/silx/utils/debug.py
index 3d50fc9..ec361ac 100644
--- a/src/silx/utils/debug.py
+++ b/src/silx/utils/debug.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/deprecation.py b/src/silx/utils/deprecation.py
index 7b19ee5..81d7ed1 100644
--- a/src/silx/utils/deprecation.py
+++ b/src/silx/utils/deprecation.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Bunch of useful decorators"""
-from __future__ import absolute_import, print_function, division
-
__authors__ = ["Jerome Kieffer", "H. Payno", "P. Knobel"]
__license__ = "MIT"
__date__ = "26/02/2018"
diff --git a/src/silx/utils/enum.py b/src/silx/utils/enum.py
index fece575..176d429 100644
--- a/src/silx/utils/enum.py
+++ b/src/silx/utils/enum.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""An :class:`.Enum` class with additional features."""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "29/04/2019"
diff --git a/src/silx/utils/exceptions.py b/src/silx/utils/exceptions.py
index addba89..d7e5533 100644
--- a/src/silx/utils/exceptions.py
+++ b/src/silx/utils/exceptions.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/files.py b/src/silx/utils/files.py
index 1982c0d..ab8d417 100644
--- a/src/silx/utils/files.py
+++ b/src/silx/utils/files.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/html.py b/src/silx/utils/html.py
index 9b39b95..654c780 100644
--- a/src/silx/utils/html.py
+++ b/src/silx/utils/html.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/launcher.py b/src/silx/utils/launcher.py
index c46256a..20752b3 100644
--- a/src/silx/utils/launcher.py
+++ b/src/silx/utils/launcher.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/number.py b/src/silx/utils/number.py
index f852a39..72106e7 100755
--- a/src/silx/utils/number.py
+++ b/src/silx/utils/number.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/property.py b/src/silx/utils/property.py
index 10d5d98..029f28e 100644
--- a/src/silx/utils/property.py
+++ b/src/silx/utils/property.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Bunch of useful decorators"""
-from __future__ import absolute_import, print_function, division
-
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "22/02/2018"
diff --git a/src/silx/utils/proxy.py b/src/silx/utils/proxy.py
index d8821c2..7801b4b 100644
--- a/src/silx/utils/proxy.py
+++ b/src/silx/utils/proxy.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Module containing proxy objects"""
-from __future__ import absolute_import, print_function, division
-
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "02/10/2017"
diff --git a/src/silx/utils/retry.py b/src/silx/utils/retry.py
index adc43bc..804bcb6 100644
--- a/src/silx/utils/retry.py
+++ b/src/silx/utils/retry.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
@@ -32,6 +31,7 @@ __date__ = "05/02/2020"
import time
+import inspect
from functools import wraps
from contextlib import contextmanager
import multiprocessing
@@ -58,13 +58,13 @@ def _default_retry_on_error(e):
@contextmanager
-def _handle_exception(options):
+def _handle_exception(retry_state):
try:
yield
except BaseException as e:
- retry_on_error = options.get("retry_on_error")
+ retry_on_error = retry_state.get("retry_on_error")
if retry_on_error is not None and retry_on_error(e):
- options["exception"] = e
+ retry_state["exception"] = e
else:
raise
@@ -79,15 +79,19 @@ def _retry_loop(retry_timeout=None, retry_period=None, retry_on_error=None):
eligible for retry
"""
has_timeout = retry_timeout is not None
- options = {"exception": None, "retry_on_error": retry_on_error}
if has_timeout:
t0 = time.time()
+ else:
+ t0 = None
+ retry_state = {"t0": t0, "exception": None, "retry_on_error": retry_on_error}
while True:
- yield options
+ yield retry_state
if retry_period is not None:
time.sleep(retry_period)
if has_timeout and (time.time() - t0) > retry_timeout:
- raise RetryTimeoutError from options.get("exception")
+ err_msg = "%s seconds" % retry_timeout
+ cause = retry_state.get("exception")
+ raise RetryTimeoutError(err_msg) from cause
def retry(
@@ -99,6 +103,9 @@ def retry(
The decorator arguments can be overriden by using them when calling the
decorated method.
+ Generator functions are required to have a `start_index` argument which allows
+ the method to start iterating from the last failure when called on retry.
+
:param num retry_timeout:
:param num retry_period: sleep before retry
:param callable or None retry_on_error: checks whether an exception is
@@ -109,18 +116,53 @@ def retry(
retry_period = RETRY_PERIOD
def decorator(method):
- @wraps(method)
- def wrapper(*args, **kw):
- _retry_timeout = kw.pop("retry_timeout", retry_timeout)
- _retry_period = kw.pop("retry_period", retry_period)
- _retry_on_error = kw.pop("retry_on_error", retry_on_error)
- for options in _retry_loop(
- retry_timeout=_retry_timeout,
- retry_period=_retry_period,
- retry_on_error=_retry_on_error,
- ):
- with _handle_exception(options):
- return method(*args, **kw)
+ if inspect.isgeneratorfunction(method):
+ if "start_index" not in inspect.signature(method).parameters:
+ raise TypeError(
+ "The generator function '%s' needs a `start_index` named argument because it is wrapped with the `retry` decorator."
+ % method.__name__
+ )
+
+ @wraps(method)
+ def wrapper(*args, **kw):
+ _retry_timeout = kw.pop("retry_timeout", retry_timeout)
+ _retry_period = kw.pop("retry_period", retry_period)
+ _retry_on_error = kw.pop("retry_on_error", retry_on_error)
+ start_index = kw.pop("start_index", 0)
+ if start_index is None:
+ start_index = 0
+ for retry_state in _retry_loop(
+ retry_timeout=_retry_timeout,
+ retry_period=_retry_period,
+ retry_on_error=_retry_on_error,
+ ):
+ with _handle_exception(retry_state):
+ oretry_on_error = retry_state["retry_on_error"]
+ for result in method(*args, start_index=start_index, **kw):
+ start_index += 1
+ retry_state["retry_on_error"] = None
+ # any exception here will NOT cause a retry
+ yield result
+ # restart the retry loop
+ if retry_state["t0"] is not None:
+ retry_state["t0"] = time.time()
+ retry_state["retry_on_error"] = oretry_on_error
+ return
+
+ else:
+
+ @wraps(method)
+ def wrapper(*args, **kw):
+ _retry_timeout = kw.pop("retry_timeout", retry_timeout)
+ _retry_period = kw.pop("retry_period", retry_period)
+ _retry_on_error = kw.pop("retry_on_error", retry_on_error)
+ for retry_state in _retry_loop(
+ retry_timeout=_retry_timeout,
+ retry_period=_retry_period,
+ retry_on_error=_retry_on_error,
+ ):
+ with _handle_exception(retry_state):
+ return method(*args, **kw)
return wrapper
@@ -151,18 +193,18 @@ def retry_contextmanager(
_retry_timeout = kw.pop("retry_timeout", retry_timeout)
_retry_period = kw.pop("retry_period", retry_period)
_retry_on_error = kw.pop("retry_on_error", retry_on_error)
- for options in _retry_loop(
+ for retry_state in _retry_loop(
retry_timeout=_retry_timeout,
retry_period=_retry_period,
retry_on_error=_retry_on_error,
):
- with _handle_exception(options):
- gen = method(*args, **kw)
- result = next(gen)
- options["retry_on_error"] = None
+ with _handle_exception(retry_state):
+ ctx = method(*args, **kw)
+ result = next(ctx)
+ retry_state["retry_on_error"] = None
yield result
try:
- next(gen)
+ next(ctx)
except StopIteration:
return
else:
@@ -238,10 +280,10 @@ def retry_in_subprocess(
p, queue = start_subprocess()
try:
- for options in _retry_loop(
+ for retry_state in _retry_loop(
retry_timeout=_retry_timeout, retry_on_error=_retry_on_error
):
- with _handle_exception(options):
+ with _handle_exception(retry_state):
if not p.is_alive():
p, queue = start_subprocess()
try:
diff --git a/src/silx/utils/setup.py b/src/silx/utils/setup.py
deleted file mode 100644
index 1f3e09a..0000000
--- a/src/silx/utils/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-__authors__ = ["V. Valls"]
-__license__ = "MIT"
-__date__ = "24/08/2016"
-
-
-from numpy.distutils.misc_util import Configuration
-
-
-def configuration(parent_package='', top_path=None):
- config = Configuration('utils', parent_package, top_path)
- config.add_subpackage('test')
-
- return config
-
-
-if __name__ == "__main__":
- from numpy.distutils.core import setup
-
- setup(configuration=configuration)
diff --git a/src/silx/utils/test/__init__.py b/src/silx/utils/test/__init__.py
index 14fd940..88135c3 100755
--- a/src/silx/utils/test/__init__.py
+++ b/src/silx/utils/test/__init__.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_array_like.py b/src/silx/utils/test/test_array_like.py
index a0b4b7b..309b9ff 100644
--- a/src/silx/utils/test/test_array_like.py
+++ b/src/silx/utils/test/test_array_like.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_debug.py b/src/silx/utils/test/test_debug.py
index 09f4b01..6b7b5d6 100644
--- a/src/silx/utils/test/test_debug.py
+++ b/src/silx/utils/test/test_debug.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_deprecation.py b/src/silx/utils/test/test_deprecation.py
index d52cb26..798221a 100644
--- a/src/silx/utils/test/test_deprecation.py
+++ b/src/silx/utils/test/test_deprecation.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_enum.py b/src/silx/utils/test/test_enum.py
index 808304a..df6b266 100644
--- a/src/silx/utils/test/test_enum.py
+++ b/src/silx/utils/test/test_enum.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2019 European Synchrotron Radiation Facility
@@ -24,8 +23,6 @@
# ###########################################################################*/
"""Tests of Enum class with extra class methods"""
-from __future__ import absolute_import
-
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "29/04/2019"
diff --git a/src/silx/utils/test/test_external_resources.py b/src/silx/utils/test/test_external_resources.py
index 1fedda3..6279460 100644
--- a/src/silx/utils/test/test_external_resources.py
+++ b/src/silx/utils/test/test_external_resources.py
@@ -1,7 +1,6 @@
-# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
+# Copyright (c) 2016-2022 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -59,7 +58,7 @@ class TestExternalResources(unittest.TestCase):
raise unittest.SkipTest("Network or silx website not available")
def setUp(self):
- self.resources = ExternalResources("toto", "http://www.silx.org/pub/silx/")
+ self.resources = ExternalResources("toto%d" % os.getpid(), "http://www.silx.org/pub/silx/")
def tearDown(self):
if self.resources.data_home:
diff --git a/src/silx/utils/test/test_launcher.py b/src/silx/utils/test/test_launcher.py
index 9e9024c..3261df5 100644
--- a/src/silx/utils/test/test_launcher.py
+++ b/src/silx/utils/test/test_launcher.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_launcher_command.py b/src/silx/utils/test/test_launcher_command.py
index ccf4601..ff9f336 100644
--- a/src/silx/utils/test/test_launcher_command.py
+++ b/src/silx/utils/test/test_launcher_command.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_number.py b/src/silx/utils/test/test_number.py
index 3eb8e91..8c6d1a2 100644
--- a/src/silx/utils/test/test_number.py
+++ b/src/silx/utils/test/test_number.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2021 European Synchrotron Radiation Facility
#
diff --git a/src/silx/utils/test/test_proxy.py b/src/silx/utils/test/test_proxy.py
index e165267..7af4d1f 100644
--- a/src/silx/utils/test/test_proxy.py
+++ b/src/silx/utils/test/test_proxy.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_retry.py b/src/silx/utils/test/test_retry.py
index 39bfdcf..7e06e65 100644
--- a/src/silx/utils/test/test_retry.py
+++ b/src/silx/utils/test/test_retry.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
#
@@ -167,3 +166,47 @@ class TestRetry(unittest.TestCase):
f.write("0")
with self.assertRaises(retry.RetryTimeoutError):
_wsubmain(self.ctr_file, **kw)
+
+ def test_retry_generator(self):
+ ncausefailure = 3
+ faildelay = 0.1
+ sufficient_timeout = ncausefailure * (faildelay + 10)
+ insufficient_timeout = ncausefailure * faildelay * 0.5
+
+ @retry.retry()
+ def method(check, kwcheck=None, start_index=0):
+ if start_index <= 0:
+ yield 0
+ assert check
+ assert kwcheck
+ nonlocal failcounter
+ if failcounter < ncausefailure:
+ time.sleep(faildelay)
+ failcounter += 1
+ if start_index <= 1:
+ yield 1
+ raise retry.RetryError
+ else:
+ if start_index <= 1:
+ yield 1
+ if start_index <= 2:
+ yield 2
+
+ failcounter = 0
+ kw = {"kwcheck": True, "retry_timeout": sufficient_timeout}
+ self.assertEqual(list(method(True, **kw)), [0, 1, 2])
+
+ failcounter = 0
+ kw = {
+ "kwcheck": True,
+ "retry_timeout": insufficient_timeout,
+ }
+ with self.assertRaises(retry.RetryTimeoutError):
+ list(method(True, **kw))
+
+ def test_retry_wrong_generator(self):
+ with self.assertRaises(TypeError):
+
+ @retry.retry()
+ def method():
+ yield from range(3)
diff --git a/src/silx/utils/test/test_testutils.py b/src/silx/utils/test/test_testutils.py
index 4f07c4e..a0624b1 100755
--- a/src/silx/utils/test/test_testutils.py
+++ b/src/silx/utils/test/test_testutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/test/test_weakref.py b/src/silx/utils/test/test_weakref.py
index 06f3adf..4e3bf21 100644
--- a/src/silx/utils/test/test_weakref.py
+++ b/src/silx/utils/test/test_weakref.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/testutils.py b/src/silx/utils/testutils.py
index 4177e33..b331829 100755
--- a/src/silx/utils/testutils.py
+++ b/src/silx/utils/testutils.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2021 European Synchrotron Radiation Facility
diff --git a/src/silx/utils/weakref.py b/src/silx/utils/weakref.py
index 06646e8..62a9232 100644
--- a/src/silx/utils/weakref.py
+++ b/src/silx/utils/weakref.py
@@ -1,4 +1,3 @@
-# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
@@ -25,7 +24,6 @@
"""Weakref utils for compatibility between Python 2 and Python 3 or for
extended features.
"""
-from __future__ import absolute_import
__authors__ = ["V. Valls"]
__license__ = "MIT"