summaryrefslogtreecommitdiff
path: root/silx
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>2019-12-23 13:45:09 +0100
committerPicca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>2019-12-23 13:45:09 +0100
commit5d647cf9a6159afd2933da594b9c79ad93d3cd9b (patch)
tree2571025a602f68fc8933b01104dc712d41f84034 /silx
parent654a6ac93513c3cc1ef97cacd782ff674c6f4559 (diff)
New upstream version 0.12.0~b0+dfsg
Diffstat (limited to 'silx')
-rw-r--r--silx/app/view/Viewer.py4
-rw-r--r--silx/gui/_glutils/OpenGLWidget.py11
-rwxr-xr-x[-rw-r--r--]silx/gui/colors.py27
-rw-r--r--silx/gui/data/DataViewer.py53
-rw-r--r--silx/gui/data/DataViews.py3
-rw-r--r--silx/gui/data/NumpyAxesSelector.py236
-rw-r--r--silx/gui/data/test/test_numpyaxesselector.py4
-rw-r--r--silx/gui/dialog/ColormapDialog.py125
-rwxr-xr-x[-rw-r--r--]silx/gui/hdf5/Hdf5Item.py152
-rwxr-xr-x[-rw-r--r--]silx/gui/hdf5/test/test_hdf5.py4
-rw-r--r--silx/gui/plot/ColorBar.py2
-rw-r--r--silx/gui/plot/CurvesROIWidget.py59
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/LegendSelector.py207
-rw-r--r--silx/gui/plot/PlotInteraction.py208
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/PlotWidget.py177
-rw-r--r--silx/gui/plot/PlotWindow.py49
-rw-r--r--silx/gui/plot/ScatterMaskToolsWidget.py7
-rw-r--r--silx/gui/plot/ScatterView.py45
-rw-r--r--silx/gui/plot/StackView.py32
-rw-r--r--silx/gui/plot/StatsWidget.py7
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/actions/control.py2
-rw-r--r--silx/gui/plot/actions/fit.py22
-rw-r--r--silx/gui/plot/actions/histogram.py1
-rw-r--r--silx/gui/plot/actions/io.py42
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/backends/BackendBase.py87
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/backends/BackendMatplotlib.py496
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/backends/BackendOpenGL.py990
-rw-r--r--silx/gui/plot/backends/glutils/GLPlotCurve.py165
-rw-r--r--silx/gui/plot/backends/glutils/GLPlotImage.py4
-rw-r--r--silx/gui/plot/backends/glutils/GLPlotTriangles.py9
-rw-r--r--silx/gui/plot/items/__init__.py4
-rw-r--r--silx/gui/plot/items/_pick.py70
-rw-r--r--silx/gui/plot/items/complex.py13
-rw-r--r--silx/gui/plot/items/core.py162
-rw-r--r--silx/gui/plot/items/curve.py40
-rw-r--r--silx/gui/plot/items/histogram.py44
-rw-r--r--silx/gui/plot/items/image.py26
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/items/marker.py17
-rw-r--r--silx/gui/plot/items/roi.py200
-rw-r--r--silx/gui/plot/items/scatter.py429
-rw-r--r--silx/gui/plot/items/shape.py64
-rwxr-xr-x[-rw-r--r--]silx/gui/plot/test/testPlotWidget.py218
-rw-r--r--silx/gui/plot/test/testStats.py5
-rw-r--r--silx/gui/plot/tools/PositionInfo.py2
-rw-r--r--silx/gui/plot/tools/profile/_BaseProfileToolBar.py4
-rw-r--r--silx/gui/plot/tools/roi.py22
-rw-r--r--silx/gui/plot3d/_model/items.py96
-rw-r--r--silx/gui/plot3d/items/_pick.py39
-rw-r--r--silx/gui/plot3d/items/scatter.py3
-rw-r--r--silx/gui/plot3d/items/volume.py151
-rw-r--r--silx/gui/plot3d/scene/primitives.py9
-rw-r--r--silx/gui/plot3d/tools/PositionInfoWidget.py2
-rw-r--r--silx/gui/qt/_utils.py15
-rwxr-xr-x[-rw-r--r--]silx/gui/test/test_colors.py39
-rwxr-xr-x[-rw-r--r--]silx/gui/utils/__init__.py32
-rwxr-xr-xsilx/gui/utils/qtutils.py170
-rwxr-xr-x[-rw-r--r--]silx/gui/utils/test/__init__.py12
-rw-r--r--silx/gui/utils/test/test.py76
-rwxr-xr-xsilx/gui/utils/test/test_qtutils.py75
-rw-r--r--silx/gui/utils/test/test_testutils.py55
-rw-r--r--silx/gui/utils/testutils.py3
-rw-r--r--silx/gui/widgets/ColormapNameComboBox.py166
-rw-r--r--silx/gui/widgets/FrameBrowser.py2
-rwxr-xr-xsilx/gui/widgets/LegendIconWidget.py513
-rw-r--r--silx/gui/widgets/RangeSlider.py4
-rw-r--r--silx/image/bilinear.c24879
-rw-r--r--silx/image/marchingsquares/_mergeimpl.cpp33603
-rw-r--r--silx/image/shapes.c25400
-rw-r--r--silx/image/shapes.pyx2
-rw-r--r--silx/image/utils.py53
-rw-r--r--silx/io/dictdump.py16
-rwxr-xr-x[-rw-r--r--]silx/io/fabioh5.py22
-rw-r--r--silx/io/specfile.c38340
-rw-r--r--silx/io/specfile/src/sflabel.c4
-rw-r--r--silx/io/test/test_dictdump.py16
-rwxr-xr-x[-rw-r--r--]silx/io/test/test_fabioh5.py60
-rw-r--r--silx/io/url.py2
-rw-r--r--silx/math/chistogramnd.c34233
-rw-r--r--silx/math/chistogramnd_lut.c57012
-rw-r--r--silx/math/colormap.c49957
-rw-r--r--silx/math/combo.c43092
-rw-r--r--silx/math/fft/basefft.py3
-rw-r--r--silx/math/fft/clfft.py12
-rw-r--r--silx/math/fft/fftw.py72
-rw-r--r--silx/math/fft/test/test_fft.py3
-rw-r--r--silx/math/fit/filters.c24868
-rw-r--r--silx/math/fit/functions.c31679
-rw-r--r--silx/math/fit/peaks.c22459
-rw-r--r--silx/math/interpolate.pyx165
-rw-r--r--silx/math/marchingcubes.cpp26983
-rw-r--r--silx/math/medianfilter/medianfilter.cpp30527
-rw-r--r--silx/math/setup.py9
-rw-r--r--silx/math/test/__init__.py4
-rw-r--r--silx/math/test/test_interpolate.py136
-rw-r--r--silx/opencl/common.py38
-rw-r--r--silx/opencl/convolution.py124
-rw-r--r--silx/opencl/linalg.py8
-rw-r--r--silx/opencl/processing.py11
-rw-r--r--silx/opencl/projection.py11
-rw-r--r--silx/opencl/reconstruction.py33
-rw-r--r--silx/opencl/sinofilter.py21
-rw-r--r--silx/opencl/sparse.py82
-rw-r--r--silx/opencl/test/test_addition.py5
-rw-r--r--silx/opencl/test/test_convolution.py8
-rw-r--r--silx/opencl/test/test_kahan.py8
-rw-r--r--silx/opencl/test/test_linalg.py5
-rw-r--r--silx/opencl/test/test_sparse.py85
-rw-r--r--silx/opencl/utils.py93
-rw-r--r--silx/resources/gui/colormaps/cividis.npybin0 -> 3200 bytes
-rw-r--r--silx/resources/gui/icons/description-description.pngbin0 -> 756 bytes
-rw-r--r--silx/resources/gui/icons/description-description.svg13
-rw-r--r--silx/resources/gui/icons/description-error.pngbin0 -> 952 bytes
-rw-r--r--silx/resources/gui/icons/description-error.svg13
-rw-r--r--silx/resources/gui/icons/description-name.pngbin0 -> 822 bytes
-rw-r--r--silx/resources/gui/icons/description-name.svg13
-rw-r--r--silx/resources/gui/icons/description-program.pngbin0 -> 767 bytes
-rw-r--r--silx/resources/gui/icons/description-program.svg13
-rw-r--r--silx/resources/gui/icons/description-title.pngbin0 -> 707 bytes
-rw-r--r--silx/resources/gui/icons/description-title.svg13
-rw-r--r--silx/resources/gui/icons/description-value.pngbin0 -> 833 bytes
-rw-r--r--silx/resources/gui/icons/description-value.svg13
-rw-r--r--silx/resources/opencl/sparse.cl20
-rw-r--r--silx/sx/_plot.py50
-rw-r--r--silx/utils/files.py6
-rwxr-xr-x[-rw-r--r--]silx/utils/number.py6
-rwxr-xr-x[-rw-r--r--]silx/utils/test/__init__.py2
-rw-r--r--silx/utils/test/test_number.py4
-rwxr-xr-xsilx/utils/test/test_testutils.py96
-rwxr-xr-x[-rw-r--r--]silx/utils/testutils.py73
129 files changed, 5253 insertions, 445237 deletions
diff --git a/silx/app/view/Viewer.py b/silx/app/view/Viewer.py
index d543352..2daa2df 100644
--- a/silx/app/view/Viewer.py
+++ b/silx/app/view/Viewer.py
@@ -134,8 +134,10 @@ class Viewer(qt.QMainWindow):
treeModel = self.__treeview.findHdf5TreeModel()
columns = list(treeModel.COLUMN_IDS)
- columns.remove(treeModel.DESCRIPTION_COLUMN)
+ columns.remove(treeModel.VALUE_COLUMN)
columns.remove(treeModel.NODE_COLUMN)
+ columns.remove(treeModel.DESCRIPTION_COLUMN)
+ columns.insert(1, treeModel.DESCRIPTION_COLUMN)
self.__treeview.header().setSections(columns)
self._iconUpward = icons.getQIcon('plot-yup')
diff --git a/silx/gui/_glutils/OpenGLWidget.py b/silx/gui/_glutils/OpenGLWidget.py
index 7f600a0..c5ece9c 100644
--- a/silx/gui/_glutils/OpenGLWidget.py
+++ b/silx/gui/_glutils/OpenGLWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017 European Synchrotron Radiation Facility
+# Copyright (c) 2017-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
@@ -30,7 +30,7 @@ across Qt<=5.3 QtOpenGL.QGLWidget and QOpenGLWidget.
__authors__ = ["T. Vincent"]
__license__ = "MIT"
-__date__ = "26/07/2017"
+__date__ = "22/11/2019"
import logging
@@ -192,7 +192,12 @@ else:
# Check OpenGL version
if self.getOpenGLVersion() >= self.getRequestedOpenGLVersion():
- version = gl.glGetString(gl.GL_VERSION)
+ try:
+ gl.glGetError() # clear any previous error (if any)
+ version = gl.glGetString(gl.GL_VERSION)
+ except:
+ version = None
+
if version:
self.__isValid = True
else:
diff --git a/silx/gui/colors.py b/silx/gui/colors.py
index aa2958a..365b569 100644..100755
--- a/silx/gui/colors.py
+++ b/silx/gui/colors.py
@@ -97,6 +97,7 @@ _AVAILABLE_LUTS = collections.OrderedDict([
('blue', _LUT_DESCRIPTION('builtin', 'yellow', True)),
('jet', _LUT_DESCRIPTION('matplotlib', 'pink', True)),
('viridis', _LUT_DESCRIPTION('resource', 'pink', True)),
+ ('cividis', _LUT_DESCRIPTION('resource', 'pink', True)),
('magma', _LUT_DESCRIPTION('resource', 'green', True)),
('inferno', _LUT_DESCRIPTION('resource', 'green', True)),
('plasma', _LUT_DESCRIPTION('resource', 'green', True)),
@@ -116,10 +117,11 @@ DEFAULT_MAX_LOG = 10
def rgba(color, colorDict=None):
- """Convert color code '#RRGGBB' and '#RRGGBBAA' to (R, G, B, A)
+ """Convert color code '#RRGGBB' and '#RRGGBBAA' to a tuple (R, G, B, A)
+ of floats.
- It also convert RGB(A) values from uint8 to float in [0, 1] and
- accept a QColor as color argument.
+ It also supports RGB(A) from uint8 in [0, 255], float in [0, 1], and
+ QColor as color argument.
:param str color: The color to convert
:param dict colorDict: A dictionary of color name conversion to color code
@@ -167,8 +169,8 @@ def greyed(color, colorDict=None):
"""Convert color code '#RRGGBB' and '#RRGGBBAA' to a grey color
(R, G, B, A).
- It also convert RGB(A) values from uint8 to float in [0, 1] and
- accept a QColor as color argument.
+ It also supports RGB(A) from uint8 in [0, 255], float in [0, 1], and
+ QColor as color argument.
:param str color: The color to convert
:param dict colorDict: A dictionary of color name conversion to color code
@@ -180,6 +182,19 @@ def greyed(color, colorDict=None):
return g, g, g, a
+def asQColor(color):
+ """Convert color code '#RRGGBB' and '#RRGGBBAA' to a `qt.QColor`.
+
+ It also supports RGB(A) from uint8 in [0, 255], float in [0, 1], and
+ QColor as color argument.
+
+ :param str color: The color to convert
+ :rtype: qt.QColor
+ """
+ color = rgba(color)
+ return qt.QColor.fromRgbF(*color)
+
+
def cursorColorForColormap(colormapName):
"""Get a color suitable for overlay over a colormap.
@@ -386,7 +401,7 @@ class Colormap(qt.QObject):
def setFromColormap(self, other):
"""Set this colormap using information from the `other` colormap.
- :param Colormap other: Colormap to use as reference.
+ :param ~silx.gui.colors.Colormap other: Colormap to use as reference.
"""
if not self.isEditable():
raise NotEditableError('Colormap is not editable')
diff --git a/silx/gui/data/DataViewer.py b/silx/gui/data/DataViewer.py
index b33a931..67db5f9 100644
--- a/silx/gui/data/DataViewer.py
+++ b/silx/gui/data/DataViewer.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -31,8 +31,10 @@ from silx.gui.data import DataViews
from silx.gui.data.DataViews import _normalizeData
import logging
from silx.gui import qt
+from silx.gui.utils import blockSignals
from silx.gui.data.NumpyAxesSelector import NumpyAxesSelector
+
__authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "12/02/2019"
@@ -197,25 +199,38 @@ class DataViewer(qt.QFrame):
"""
Update the numpy-selector according to the needed axis names
"""
- previous = self.__numpySelection.blockSignals(True)
- self.__numpySelection.clear()
- info = self._getInfo()
- axisNames = self.__currentView.axesNames(self.__data, info)
- if info.isArray and info.size != 0 and self.__data is not None and axisNames is not None:
- self.__useAxisSelection = True
- self.__numpySelection.setAxisNames(axisNames)
- self.__numpySelection.setCustomAxis(self.__currentView.customAxisNames())
- data = self.normalizeData(self.__data)
- self.__numpySelection.setData(data)
- if hasattr(data, "shape"):
- isVisible = not (len(axisNames) == 1 and len(data.shape) == 1)
+ with blockSignals(self.__numpySelection):
+ previousPermutation = self.__numpySelection.permutation()
+ previousSelection = self.__numpySelection.selection()
+
+ self.__numpySelection.clear()
+
+ info = self._getInfo()
+ axisNames = self.__currentView.axesNames(self.__data, info)
+ if (info.isArray and info.size != 0 and
+ self.__data is not None and axisNames is not None):
+ self.__useAxisSelection = True
+ self.__numpySelection.setAxisNames(axisNames)
+ self.__numpySelection.setCustomAxis(
+ self.__currentView.customAxisNames())
+ data = self.normalizeData(self.__data)
+ self.__numpySelection.setData(data)
+
+ # Try to restore previous permutation and selection
+ try:
+ self.__numpySelection.setSelection(
+ previousSelection, previousPermutation)
+ except ValueError as e:
+ _logger.error("Not restoring selection because: %s", e)
+
+ if hasattr(data, "shape"):
+ isVisible = not (len(axisNames) == 1 and len(data.shape) == 1)
+ else:
+ isVisible = True
+ self.__axisSelection.setVisible(isVisible)
else:
- isVisible = True
- self.__axisSelection.setVisible(isVisible)
- else:
- self.__useAxisSelection = False
- self.__axisSelection.setVisible(False)
- self.__numpySelection.blockSignals(previous)
+ self.__useAxisSelection = False
+ self.__axisSelection.setVisible(False)
def __updateDataInView(self):
"""
diff --git a/silx/gui/data/DataViews.py b/silx/gui/data/DataViews.py
index 664090d..eb635c4 100644
--- a/silx/gui/data/DataViews.py
+++ b/silx/gui/data/DataViews.py
@@ -1482,7 +1482,8 @@ class _NXdataXYVScatterView(DataView):
data = self.normalizeData(data)
if info.hasNXdata and not info.isInvalidNXdata:
if nxdata.get_default(data, validate=False).is_x_y_value_scatter:
- return 100
+ # It have to be a little more than a NX curve priority
+ return 110
return DataView.UNSUPPORTED
diff --git a/silx/gui/data/NumpyAxesSelector.py b/silx/gui/data/NumpyAxesSelector.py
index 4530aa9..e6da0d4 100644
--- a/silx/gui/data/NumpyAxesSelector.py
+++ b/silx/gui/data/NumpyAxesSelector.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -31,13 +31,18 @@ __authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "29/01/2018"
+import logging
import numpy
import functools
from silx.gui.widgets.FrameBrowser import HorizontalSliderWithBrowser
from silx.gui import qt
+from silx.gui.utils import blockSignals
import silx.utils.weakref
+_logger = logging.getLogger(__name__)
+
+
class _Axis(qt.QWidget):
"""Widget displaying an axis.
@@ -110,6 +115,8 @@ class _Axis(qt.QWidget):
if axisName == "" and self.__axes.count() == 0:
self.__axes.setCurrentIndex(-1)
self.__updateSliderVisibility()
+ return
+
for index in range(self.__axes.count()):
name = self.__axes.itemData(index)
if name == axisName:
@@ -121,7 +128,7 @@ class _Axis(qt.QWidget):
def axisName(self):
"""Returns the selected axis name.
- If no names are selected, an empty string is retruned.
+ If no name is selected, an empty string is returned.
:rtype: str
"""
@@ -136,11 +143,11 @@ class _Axis(qt.QWidget):
:param List[str] axesNames: List of available names
"""
self.__axes.clear()
- previous = self.__axes.blockSignals(True)
- self.__axes.addItem(" ", "")
- for axis in axesNames:
- self.__axes.addItem(axis, axis)
- self.__axes.blockSignals(previous)
+ with blockSignals(self.__axes):
+ self.__axes.addItem(" ", "")
+ for axis in axesNames:
+ self.__axes.addItem(axis, axis)
+
self.__updateSliderVisibility()
def setCustomAxis(self, axesNames):
@@ -168,12 +175,19 @@ class _Axis(qt.QWidget):
self.__slider.setVisible(isVisible)
def value(self):
- """Returns the current selected position in the axis.
+ """Returns the currently selected position in the axis.
:rtype: int
"""
return self.__slider.value()
+ def setValue(self, value):
+ """Set the currently selected position in the axis.
+
+ :param int value:
+ """
+ self.__slider.setValue(value)
+
def __sliderValueChanged(self, value):
"""Called when the selected position in the axis change.
@@ -183,18 +197,14 @@ class _Axis(qt.QWidget):
def setNamedAxisSelectorVisibility(self, visible):
"""Hide or show the named axis combobox.
- If both the selector and the slider are hidden,
- hide the entire widget.
+
+ If both the selector and the slider are hidden, hide the entire widget.
:param visible: boolean
"""
self.__axes.setVisible(visible)
name = self.axisName()
-
- if not visible and name != "":
- self.setVisible(False)
- else:
- self.setVisible(True)
+ self.setVisible(visible or name == "")
class NumpyAxesSelector(qt.QWidget):
@@ -236,7 +246,6 @@ class NumpyAxesSelector(qt.QWidget):
self.__data = None
self.__selectedData = None
- self.__selection = tuple()
self.__axis = []
self.__axisNames = []
self.__customAxisNames = set([])
@@ -268,13 +277,12 @@ class NumpyAxesSelector(qt.QWidget):
if delta < 0:
delta = 0
for index, axis in enumerate(self.__axis):
- previous = axis.blockSignals(True)
- axis.setAxisNames(self.__axisNames)
- if index >= delta and index - delta < len(self.__axisNames):
- axis.setAxisName(self.__axisNames[index - delta])
- else:
- axis.setAxisName("")
- axis.blockSignals(previous)
+ with blockSignals(axis):
+ axis.setAxisNames(self.__axisNames)
+ if index >= delta and index - delta < len(self.__axisNames):
+ axis.setAxisName(self.__axisNames[index - delta])
+ else:
+ axis.setAxisName("")
self.__updateSelectedData()
def setCustomAxis(self, axesNames):
@@ -372,9 +380,8 @@ class NumpyAxesSelector(qt.QWidget):
# If there is no other solution we set the name at the same place
axisChanged = False
availableWidget = axis
- previous = availableWidget.blockSignals(True)
- availableWidget.setAxisName(missingName)
- availableWidget.blockSignals(previous)
+ with blockSignals(availableWidget):
+ availableWidget.setAxisName(missingName)
else:
# there is a duplicated name somewhere
# we swap it with the missing name or with nothing
@@ -387,9 +394,8 @@ class NumpyAxesSelector(qt.QWidget):
break
if missingName is None:
missingName = ""
- previous = dupWidget.blockSignals(True)
- dupWidget.setAxisName(missingName)
- dupWidget.blockSignals(previous)
+ with blockSignals(dupWidget):
+ dupWidget.setAxisName(missingName)
if self.__data is None:
return
@@ -402,70 +408,164 @@ class NumpyAxesSelector(qt.QWidget):
It fires a `selectionChanged` event.
"""
- if self.__data is None:
+ permutation = self.permutation()
+
+ if self.__data is None or permutation is None:
+ # No data or not all the expected axes are there
if self.__selectedData is not None:
self.__selectedData = None
- self.__selection = tuple()
self.selectionChanged.emit()
return
- selection = []
- axisNames = []
- for slider in self.__axis:
- name = slider.axisName()
- if name == "":
- selection.append(slider.value())
- else:
- selection.append(slice(None))
- axisNames.append(name)
- self.__selection = tuple(selection)
# get a view with few fixed dimensions
# with a h5py dataset, it create a copy
# TODO we can reuse the same memory in case of a copy
- view = self.__data[self.__selection]
-
- if set(self.__axisNames) - set(axisNames) != set([]):
- # Not all the expected axis are there
- if self.__selectedData is not None:
- self.__selectedData = None
- self.__selection = tuple()
- self.selectionChanged.emit()
- return
-
- # order axis as expected
- source = []
- destination = []
- order = []
- for index, name in enumerate(self.__axisNames):
- destination.append(index)
- source.append(axisNames.index(name))
- for _, s in sorted(zip(destination, source)):
- order.append(s)
- view = numpy.transpose(view, order)
-
- self.__selectedData = view
+ self.__selectedData = numpy.transpose(self.__data[self.selection()], permutation)
self.selectionChanged.emit()
def data(self):
"""Returns the input data.
- :rtype: numpy.ndarray
+ :rtype: Union[numpy.ndarray,None]
"""
- return self.__data
+ if self.__data is None:
+ return None
+ else:
+ return numpy.array(self.__data, copy=False)
def selectedData(self):
"""Returns the output data.
- :rtype: numpy.ndarray
+ This is equivalent to::
+
+ numpy.transpose(self.data()[self.selection()], self.permutation())
+
+ :rtype: Union[numpy.ndarray,None]
"""
- return self.__selectedData
+ if self.__selectedData is None:
+ return None
+ else:
+ return numpy.array(self.__selectedData, copy=False)
+
+ def permutation(self):
+ """Returns the axes permutation to convert data subset to selected data.
+
+ If permutation cannot be computer, it returns None.
+
+ :rtype: Union[List[int],None]
+ """
+ if self.__data is None:
+ return None
+ else:
+ indices = []
+ for name in self.__axisNames:
+ index = 0
+ for axis in self.__axis:
+ if axis.axisName() == name:
+ indices.append(index)
+ break
+ if axis.axisName() != "":
+ index += 1
+ else:
+ _logger.warning("No axis corresponding to: %s", name)
+ return None
+ return tuple(indices)
def selection(self):
"""Returns the selection tuple used to slice the data.
:rtype: tuple
"""
- return self.__selection
+ if self.__data is None:
+ return tuple()
+ else:
+ return tuple([axis.value() if axis.axisName() == "" else slice(None)
+ for axis in self.__axis])
+
+ def setSelection(self, selection, permutation=None):
+ """Set the selection along each dimension.
+
+ tuple returned by :meth:`selection` can be provided as input,
+ provided that it is for the same the number of axes and
+ the same number of dimensions of the data.
+
+ :param List[Union[int,slice,None]] selection:
+ The selection tuple with as one element for each dimension of the data.
+ If an element is None, then the whole dimension is selected.
+ :param Union[List[int],None] permutation:
+ The data axes indices to transpose.
+ If not given, no permutation is applied
+ :raise ValueError:
+ When the selection does not match current data shape and number of axes.
+ """
+ data_shape = self.__data.shape if self.__data is not None else ()
+
+ # Check selection
+ if len(selection) != len(data_shape):
+ raise ValueError(
+ "Selection length (%d) and data ndim (%d) mismatch" %
+ (len(selection), len(data_shape)))
+
+ # Check selection type
+ selectedDataNDim = 0
+ for element, size in zip(selection, data_shape):
+ if isinstance(element, int):
+ if not 0 <= element < size:
+ raise ValueError(
+ "Selected index (%d) outside data dimension range [0-%d]" %
+ (element, size))
+ elif element is None or element == slice(None):
+ selectedDataNDim += 1
+ else:
+ raise ValueError("Unsupported element in selection: %s" % element)
+
+ ndim = len(self.__axisNames)
+ if selectedDataNDim != ndim:
+ raise ValueError(
+ "Selection dimensions (%d) and number of axes (%d) mismatch" %
+ (selectedDataNDim, ndim))
+
+ # check permutation
+ if permutation is None:
+ permutation = tuple(range(ndim))
+
+ if set(permutation) != set(range(ndim)):
+ raise ValueError(
+ "Error in provided permutation: "
+ "Wrong size, elements out of range or duplicates")
+
+ inversePermutation = numpy.argsort(permutation)
+
+ axisNameChanged = False
+ customValueChanged = []
+ with blockSignals(*self.__axis):
+ index = 0
+ for element, axis in zip(selection, self.__axis):
+ if isinstance(element, int):
+ name = ""
+ else:
+ name = self.__axisNames[inversePermutation[index]]
+ index += 1
+
+ if axis.axisName() != name:
+ axis.setAxisName(name)
+ axisNameChanged = True
+
+ for element, axis in zip(selection, self.__axis):
+ value = element if isinstance(element, int) else 0
+ if axis.value() != value:
+ axis.setValue(value)
+
+ name = axis.axisName()
+ if name in self.__customAxisNames:
+ customValueChanged.append((name, value))
+
+ # Send signals that where disabled
+ if axisNameChanged:
+ self.selectedAxisChanged.emit()
+ for name, value in customValueChanged:
+ self.customAxisChanged.emit(name, value)
+ self.__updateSelectedData()
def setNamedAxesSelectorVisibility(self, visible):
"""Show or hide the combo-boxes allowing to map the plot axes
diff --git a/silx/gui/data/test/test_numpyaxesselector.py b/silx/gui/data/test/test_numpyaxesselector.py
index df11c1a..d37cff7 100644
--- a/silx/gui/data/test/test_numpyaxesselector.py
+++ b/silx/gui/data/test/test_numpyaxesselector.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -76,7 +76,7 @@ class TestNumpyAxesSelector(TestCaseQt):
widget.setAxisNames(["x", "y", "z", "boum"])
widget.setData(data[0])
result = widget.selectedData()
- self.assertEqual(result, None)
+ self.assertIsNone(result)
widget.setData(data)
result = widget.selectedData()
self.assertTrue(numpy.array_equal(result, expectedResult))
diff --git a/silx/gui/dialog/ColormapDialog.py b/silx/gui/dialog/ColormapDialog.py
index 9c956f8..ed15947 100644
--- a/silx/gui/dialog/ColormapDialog.py
+++ b/silx/gui/dialog/ColormapDialog.py
@@ -79,6 +79,7 @@ from silx.gui.widgets.FloatEdit import FloatEdit
import weakref
from silx.math.combo import min_max
from silx.gui import icons
+from silx.gui.widgets.ColormapNameComboBox import ColormapNameComboBox
from silx.math.histogram import Histogramnd
_logger = logging.getLogger(__name__)
@@ -150,128 +151,6 @@ class _BoundaryWidget(qt.QWidget):
self._updateDisplayedText()
-class _ColormapNameCombox(qt.QComboBox):
- def __init__(self, parent=None):
- qt.QComboBox.__init__(self, parent)
- self.__initItems()
-
- LUT_NAME = qt.Qt.UserRole + 1
- LUT_COLORS = qt.Qt.UserRole + 2
-
- def __initItems(self):
- for colormapName in preferredColormaps():
- index = self.count()
- self.addItem(str.title(colormapName))
- self.setItemIcon(index, self.getIconPreview(name=colormapName))
- self.setItemData(index, colormapName, role=self.LUT_NAME)
-
- def getIconPreview(self, name=None, colors=None):
- """Return an icon preview from a LUT name.
-
- This icons are cached into a global structure.
-
- :param str name: Name of the LUT
- :param numpy.ndarray colors: Colors identify the LUT
- :rtype: qt.QIcon
- """
- if name is not None:
- iconKey = name
- else:
- iconKey = tuple(colors)
- icon = _colormapIconPreview.get(iconKey, None)
- if icon is None:
- icon = self.createIconPreview(name, colors)
- _colormapIconPreview[iconKey] = icon
- return icon
-
- def createIconPreview(self, name=None, colors=None):
- """Create and return an icon preview from a LUT name.
-
- This icons are cached into a global structure.
-
- :param str name: Name of the LUT
- :param numpy.ndarray colors: Colors identify the LUT
- :rtype: qt.QIcon
- """
- colormap = Colormap(name)
- size = 32
- if name is not None:
- lut = colormap.getNColors(size)
- else:
- lut = colors
- if len(lut) > size:
- # Down sample
- step = int(len(lut) / size)
- lut = lut[::step]
- elif len(lut) < size:
- # Over sample
- indexes = numpy.arange(size) / float(size) * (len(lut) - 1)
- indexes = indexes.astype("int")
- lut = lut[indexes]
- if lut is None or len(lut) == 0:
- return qt.QIcon()
-
- pixmap = qt.QPixmap(size, size)
- painter = qt.QPainter(pixmap)
- for i in range(size):
- rgb = lut[i]
- r, g, b = rgb[0], rgb[1], rgb[2]
- painter.setPen(qt.QColor(r, g, b))
- painter.drawPoint(qt.QPoint(i, 0))
-
- painter.drawPixmap(0, 1, size, size - 1, pixmap, 0, 0, size, 1)
- painter.end()
-
- return qt.QIcon(pixmap)
-
- def getCurrentName(self):
- return self.itemData(self.currentIndex(), self.LUT_NAME)
-
- def getCurrentColors(self):
- return self.itemData(self.currentIndex(), self.LUT_COLORS)
-
- def findLutName(self, name):
- return self.findData(name, role=self.LUT_NAME)
-
- def findLutColors(self, lut):
- for index in range(self.count()):
- if self.itemData(index, role=self.LUT_NAME) is not None:
- continue
- colors = self.itemData(index, role=self.LUT_COLORS)
- if colors is None:
- continue
- if numpy.array_equal(colors, lut):
- return index
- return -1
-
- def setCurrentLut(self, colormap):
- name = colormap.getName()
- if name is not None:
- self._setCurrentName(name)
- else:
- lut = colormap.getColormapLUT()
- self._setCurrentLut(lut)
-
- def _setCurrentLut(self, lut):
- index = self.findLutColors(lut)
- if index == -1:
- index = self.count()
- self.addItem("Custom")
- self.setItemIcon(index, self.getIconPreview(colors=lut))
- self.setItemData(index, None, role=self.LUT_NAME)
- self.setItemData(index, lut, role=self.LUT_COLORS)
- self.setCurrentIndex(index)
-
- def _setCurrentName(self, name):
- index = self.findLutName(name)
- if index < 0:
- index = self.count()
- self.addItem(str.title(name))
- self.setItemIcon(index, self.getIconPreview(name=name))
- self.setItemData(index, name, role=self.LUT_NAME)
- self.setCurrentIndex(index)
-
-
@enum.unique
class _DataInPlotMode(enum.Enum):
"""Enum for each mode of display of the data in the plot."""
@@ -329,7 +208,7 @@ class ColormapDialog(qt.QDialog):
formLayout.setSpacing(0)
# Colormap row
- self._comboBoxColormap = _ColormapNameCombox(parent=formWidget)
+ self._comboBoxColormap = ColormapNameComboBox(parent=formWidget)
self._comboBoxColormap.currentIndexChanged[int].connect(self._updateLut)
formLayout.addRow('Colormap:', self._comboBoxColormap)
diff --git a/silx/gui/hdf5/Hdf5Item.py b/silx/gui/hdf5/Hdf5Item.py
index 6ea870f..11a08b6 100644..100755
--- a/silx/gui/hdf5/Hdf5Item.py
+++ b/silx/gui/hdf5/Hdf5Item.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -30,6 +30,7 @@ __date__ = "17/01/2019"
import logging
import collections
+import enum
from .. import qt
from .. import icons
@@ -44,6 +45,17 @@ _hdf5Formatter = Hdf5Formatter(textFormatter=_formatter)
# FIXME: The formatter should be an attribute of the Hdf5Model
+class DescriptionType(enum.Enum):
+ """List of available kind of description.
+ """
+ ERROR = "error"
+ DESCRIPTION = "description"
+ TITLE = "title"
+ PROGRAM = "program"
+ NAME = "name"
+ VALUE = "value"
+
+
class Hdf5Item(Hdf5Node):
"""Subclass of :class:`qt.QStandardItem` to represent an HDF5-like
item (dataset, file, group or link) as an element of a HDF5-like
@@ -62,6 +74,7 @@ class Hdf5Item(Hdf5Node):
self.__error = None
self.__text = text
self.__linkClass = linkClass
+ self.__description = None
self.__nx_class = None
Hdf5Node.__init__(self, parent, populateAll=populateAll)
@@ -367,7 +380,20 @@ class Hdf5Item(Hdf5Node):
text = ""
else:
text = self._getFormatter().textFormatter().toString(obj)
- self.__nx_class = text.strip('"')
+ text = text.strip('"')
+ # Check NX_class formatting
+ lower = text.lower()
+ if lower.startswith('nx'):
+ formatedNX_class = 'NX' + lower[2:]
+ if lower == 'nxcansas':
+ formatedNX_class = 'NXcanSAS' # That's the only class with capital letters...
+ if text != formatedNX_class:
+ _logger.error("NX_class: %s is malformed (should be %s)",
+ text,
+ formatedNX_class)
+ text = formatedNX_class
+
+ self.__nx_class = text
return self.__nx_class
def dataName(self, role):
@@ -430,31 +456,131 @@ class Hdf5Item(Hdf5Node):
return self._getFormatter().humanReadableValue(self.obj)
return None
+ _NEXUS_CLASS_TO_VALUE_CHILDREN = {
+ 'NXaperture': (
+ (DescriptionType.DESCRIPTION, 'description'),
+ ),
+ 'NXbeam_stop': (
+ (DescriptionType.DESCRIPTION, 'description'),
+ ),
+ 'NXdetector': (
+ (DescriptionType.NAME, 'local_name'),
+ (DescriptionType.DESCRIPTION, 'description')
+ ),
+ 'NXentry': (
+ (DescriptionType.TITLE, 'title'),
+ ),
+ 'NXenvironment': (
+ (DescriptionType.NAME, 'short_name'),
+ (DescriptionType.NAME, 'name'),
+ (DescriptionType.DESCRIPTION, 'description')
+ ),
+ 'NXinstrument': (
+ (DescriptionType.NAME, 'name'),
+ ),
+ 'NXlog': (
+ (DescriptionType.DESCRIPTION, 'description'),
+ ),
+ 'NXmirror': (
+ (DescriptionType.DESCRIPTION, 'description'),
+ ),
+ 'NXpositioner': (
+ (DescriptionType.NAME, 'name'),
+ ),
+ 'NXprocess': (
+ (DescriptionType.PROGRAM, 'program'),
+ ),
+ 'NXsample': (
+ (DescriptionType.TITLE, 'short_title'),
+ (DescriptionType.NAME, 'name'),
+ (DescriptionType.DESCRIPTION, 'description')
+ ),
+ 'NXsample_component': (
+ (DescriptionType.NAME, 'name'),
+ (DescriptionType.DESCRIPTION, 'description')
+ ),
+ 'NXsensor': (
+ (DescriptionType.NAME, 'short_name'),
+ (DescriptionType.NAME, 'name')
+ ),
+ 'NXsource': (
+ (DescriptionType.NAME, 'name'),
+ ), # or its 'short_name' attribute... This is not supported
+ 'NXsubentry': (
+ (DescriptionType.DESCRIPTION, 'definition'),
+ (DescriptionType.PROGRAM, 'program_name'),
+ (DescriptionType.TITLE, 'title'),
+ ),
+ }
+ """Mapping from NeXus class to child names containing data to use as value"""
+
+ def __computeDataDescription(self):
+ """Compute the data description of this item
+
+ :rtype: Tuple[kind, str]
+ """
+ if self.__isBroken or self.__error is not None:
+ self.obj # lazy loading of the object
+ return DescriptionType.ERROR, self.__error
+
+ if self.h5Class == silx.io.utils.H5Type.DATASET:
+ return DescriptionType.VALUE, self._getFormatter().humanReadableValue(self.obj)
+
+ elif self.isGroupObj() and self.nexusClassName:
+ # For NeXus groups, try to find a title or name
+ # By default, look for a title (most application definitions should have one)
+ defaultSequence = ((DescriptionType.TITLE, 'title'),)
+ sequence = self._NEXUS_CLASS_TO_VALUE_CHILDREN.get(self.nexusClassName, defaultSequence)
+ for kind, child_name in sequence:
+ for index in range(self.childCount()):
+ child = self.child(index)
+ if (isinstance(child, Hdf5Item) and
+ child.h5Class == silx.io.utils.H5Type.DATASET and
+ child.basename == child_name):
+ return kind, self._getFormatter().humanReadableValue(child.obj)
+
+ description = self.obj.attrs.get("desc", None)
+ if description is not None:
+ return DescriptionType.DESCRIPTION, description
+ else:
+ return None, None
+
+ def __getDataDescription(self):
+ """Returns a cached version of the data description
+
+ As the data description have to reach inside the HDF5 tree, the result
+ is cached. A better implementation could be to use a MRU cache, to avoid
+ to allocate too much data.
+
+ :rtype: Tuple[kind, str]
+ """
+ if self.__description is None:
+ self.__description = self.__computeDataDescription()
+ return self.__description
+
def dataDescription(self, role):
"""Data for the description column"""
if role == qt.Qt.DecorationRole:
+ kind, _label = self.__getDataDescription()
+ if kind is not None:
+ icon = icons.getQIcon("description-%s" % kind.value)
+ return icon
return None
if role == qt.Qt.TextAlignmentRole:
return qt.Qt.AlignTop | qt.Qt.AlignLeft
if role == qt.Qt.DisplayRole:
- if self.__isBroken:
- self.obj # lazy loading of the object
- return self.__error
- if "desc" in self.obj.attrs:
- text = self.obj.attrs["desc"]
- else:
- return ""
- return text
+ _kind, label = self.__getDataDescription()
+ return label
if role == qt.Qt.ToolTipRole:
if self.__error is not None:
self.obj # lazy loading of the object
self.__initH5Object()
return self.__error
- if "desc" in self.obj.attrs:
- text = self.obj.attrs["desc"]
+ kind, label = self.__getDataDescription()
+ if label is not None:
+ return "<b>%s</b><br/>%s" % (kind.value.capitalize(), label)
else:
return ""
- return "Description: %s" % text
return None
def dataNode(self, role):
diff --git a/silx/gui/hdf5/test/test_hdf5.py b/silx/gui/hdf5/test/test_hdf5.py
index 0ab4dc4..4bb43ff 100644..100755
--- a/silx/gui/hdf5/test/test_hdf5.py
+++ b/silx/gui/hdf5/test/test_hdf5.py
@@ -313,7 +313,7 @@ class TestHdf5TreeModel(TestCaseQt):
self.assertEqual(displayed[hdf5.Hdf5TreeModel.TYPE_COLUMN, qt.Qt.DisplayRole], "")
self.assertEqual(displayed[hdf5.Hdf5TreeModel.SHAPE_COLUMN, qt.Qt.DisplayRole], "")
self.assertEqual(displayed[hdf5.Hdf5TreeModel.VALUE_COLUMN, qt.Qt.DisplayRole], "")
- self.assertEqual(displayed[hdf5.Hdf5TreeModel.DESCRIPTION_COLUMN, qt.Qt.DisplayRole], "")
+ self.assertEqual(displayed[hdf5.Hdf5TreeModel.DESCRIPTION_COLUMN, qt.Qt.DisplayRole], None)
self.assertEqual(displayed[hdf5.Hdf5TreeModel.NODE_COLUMN, qt.Qt.DisplayRole], "File")
def testGroupData(self):
@@ -345,7 +345,7 @@ class TestHdf5TreeModel(TestCaseQt):
self.assertEqual(displayed[hdf5.Hdf5TreeModel.TYPE_COLUMN, qt.Qt.DisplayRole], value.dtype.name)
self.assertEqual(displayed[hdf5.Hdf5TreeModel.SHAPE_COLUMN, qt.Qt.DisplayRole], "3")
self.assertEqual(displayed[hdf5.Hdf5TreeModel.VALUE_COLUMN, qt.Qt.DisplayRole], "[1 2 3]")
- self.assertEqual(displayed[hdf5.Hdf5TreeModel.DESCRIPTION_COLUMN, qt.Qt.DisplayRole], "")
+ self.assertEqual(displayed[hdf5.Hdf5TreeModel.DESCRIPTION_COLUMN, qt.Qt.DisplayRole], "[1 2 3]")
self.assertEqual(displayed[hdf5.Hdf5TreeModel.NODE_COLUMN, qt.Qt.DisplayRole], "Dataset")
def testDropLastAsFirst(self):
diff --git a/silx/gui/plot/ColorBar.py b/silx/gui/plot/ColorBar.py
index 9798123..fd4fdf8 100644
--- a/silx/gui/plot/ColorBar.py
+++ b/silx/gui/plot/ColorBar.py
@@ -874,7 +874,7 @@ class _TickBar(qt.QWidget):
fm = qt.QFontMetrics(font)
width = 0
for tick in self.ticks:
- width = max(fm.width(form.format(tick)), width)
+ width = max(fm.boundingRect(form.format(tick)).width(), width)
# if the length of the string are too long we are moving to scientific
# display
diff --git a/silx/gui/plot/CurvesROIWidget.py b/silx/gui/plot/CurvesROIWidget.py
index 050b344..4508c60 100644
--- a/silx/gui/plot/CurvesROIWidget.py
+++ b/silx/gui/plot/CurvesROIWidget.py
@@ -42,11 +42,13 @@ import numpy
from silx.io import dictdump
from silx.utils import deprecation
from silx.utils.weakref import WeakMethodProxy
+from silx.utils.proxy import docstring
from .. import icons, qt
-from silx.gui.plot.items.curve import Curve
from silx.math.combo import min_max
import weakref
from silx.gui.widgets.TableWidget import TableWidget
+from . import items
+from .items.roi import _RegionOfInterestBase
_logger = logging.getLogger(__name__)
@@ -66,12 +68,15 @@ class CurvesROIWidget(qt.QWidget):
sigROIWidgetSignal = qt.Signal(object)
"""Signal of ROIs modifications.
- Modification information if given as a dict with an 'event' key
- providing the type of events.
- Type of events:
- - AddROI, DelROI, LoadROI and ResetROI with keys: 'roilist', 'roidict'
- - selectionChanged with keys: 'row', 'col' 'roi', 'key', 'colheader',
- 'rowheader'
+
+ Modification information if given as a dict with an 'event' key
+ providing the type of events.
+
+ Type of events:
+
+ - AddROI, DelROI, LoadROI and ResetROI with keys: 'roilist', 'roidict'
+ - selectionChanged with keys: 'row', 'col' 'roi', 'key', 'colheader',
+ 'rowheader'
"""
sigROISignal = qt.Signal(object)
@@ -1045,12 +1050,12 @@ class ROITable(TableWidget):
_indexNextROI = 0
-class ROI(qt.QObject):
+class ROI(_RegionOfInterestBase):
"""The Region Of Interest is defined by:
- A name
- A type. The type is the label of the x axis. This can be used to apply or
- not some ROI to a curve and do some post processing.
+ not some ROI to a curve and do some post processing.
- The x coordinate of the left limit (fromdata)
- The x coordinate of the right limit (todata)
@@ -1064,17 +1069,22 @@ class ROI(qt.QObject):
"""Signal emitted when the ROI is edited"""
def __init__(self, name, fromdata=None, todata=None, type_=None):
- qt.QObject.__init__(self)
- assert type(name) is str
+ _RegionOfInterestBase.__init__(self, name=name)
global _indexNextROI
self._id = _indexNextROI
_indexNextROI += 1
- self._name = name
self._fromdata = fromdata
self._todata = todata
self._type = type_ or 'Default'
+ self.sigItemChanged.connect(self.__itemChanged)
+
+ def __itemChanged(self, event):
+ """Handle name change"""
+ if event == items.ItemChangedType.NAME:
+ self.sigChanged.emit()
+
def getID(self):
"""
@@ -1098,23 +1108,6 @@ class ROI(qt.QObject):
"""
return self._type
- def setName(self, name):
- """
- Set the name of the :class:`ROI`
-
- :param str name:
- """
- if self._name != name:
- self._name = name
- self.sigChanged.emit()
-
- def getName(self):
- """
-
- :return str: name of the :class:`ROI`
- """
- return self._name
-
def setFrom(self, frm):
"""
@@ -1161,7 +1154,7 @@ class ROI(qt.QObject):
"""
ddict = {
'type': self._type,
- 'name': self._name,
+ 'name': self.getName(),
'from': self._fromdata,
'to': self._todata,
}
@@ -1191,7 +1184,7 @@ class ROI(qt.QObject):
:return: True if the ROI is the `ICR`
"""
- return self._name == 'ICR'
+ return self.getName() == 'ICR'
def computeRawAndNetCounts(self, curve):
"""Compute the Raw and net counts in the ROI for the given curve.
@@ -1208,7 +1201,7 @@ class ROI(qt.QObject):
:param CurveItem curve:
:return tuple: rawCount, netCount
"""
- assert isinstance(curve, Curve) or curve is None
+ assert isinstance(curve, items.Curve) or curve is None
if curve is None:
return None, None
@@ -1251,7 +1244,7 @@ class ROI(qt.QObject):
:param CurveItem curve:
:return tuple: rawArea, netArea
"""
- assert isinstance(curve, Curve) or curve is None
+ assert isinstance(curve, items.Curve) or curve is None
if curve is None:
return None, None
diff --git a/silx/gui/plot/LegendSelector.py b/silx/gui/plot/LegendSelector.py
index b9d0fd3..a9d89db 100644..100755
--- a/silx/gui/plot/LegendSelector.py
+++ b/silx/gui/plot/LegendSelector.py
@@ -38,63 +38,14 @@ import weakref
import numpy
from .. import qt, colors
+from ..widgets.LegendIconWidget import LegendIconWidget
from . import items
_logger = logging.getLogger(__name__)
-# Build all symbols
-# Courtesy of the pyqtgraph project
-Symbols = dict([(name, qt.QPainterPath())
- for name in ['o', 's', 't', 'd', '+', 'x', '.', ',']])
-Symbols['o'].addEllipse(qt.QRectF(.1, .1, .8, .8))
-Symbols['.'].addEllipse(qt.QRectF(.3, .3, .4, .4))
-Symbols[','].addEllipse(qt.QRectF(.4, .4, .2, .2))
-Symbols['s'].addRect(qt.QRectF(.1, .1, .8, .8))
-
-coords = {
- 't': [(0.5, 0.), (.1, .8), (.9, .8)],
- 'd': [(0.1, 0.5), (0.5, 0.), (0.9, 0.5), (0.5, 1.)],
- '+': [(0.0, 0.40), (0.40, 0.40), (0.40, 0.), (0.60, 0.),
- (0.60, 0.40), (1., 0.40), (1., 0.60), (0.60, 0.60),
- (0.60, 1.), (0.40, 1.), (0.40, 0.60), (0., 0.60)],
- 'x': [(0.0, 0.40), (0.40, 0.40), (0.40, 0.), (0.60, 0.),
- (0.60, 0.40), (1., 0.40), (1., 0.60), (0.60, 0.60),
- (0.60, 1.), (0.40, 1.), (0.40, 0.60), (0., 0.60)]
-}
-for s, c in coords.items():
- Symbols[s].moveTo(*c[0])
- for x, y in c[1:]:
- Symbols[s].lineTo(x, y)
- Symbols[s].closeSubpath()
-tr = qt.QTransform()
-tr.rotate(45)
-Symbols['x'].translate(qt.QPointF(-0.5, -0.5))
-Symbols['x'] = tr.map(Symbols['x'])
-Symbols['x'].translate(qt.QPointF(0.5, 0.5))
-
-NoSymbols = (None, 'None', 'none', '', ' ')
-"""List of values resulting in no symbol being displayed for a curve"""
-
-
-LineStyles = {
- None: qt.Qt.NoPen,
- 'None': qt.Qt.NoPen,
- 'none': qt.Qt.NoPen,
- '': qt.Qt.NoPen,
- ' ': qt.Qt.NoPen,
- '-': qt.Qt.SolidLine,
- '--': qt.Qt.DashLine,
- ':': qt.Qt.DotLine,
- '-.': qt.Qt.DashDotLine
-}
-"""Conversion from matplotlib-like linestyle to Qt"""
-
-NoLineStyle = (None, 'None', 'none', '', ' ')
-"""List of style values resulting in no line being displayed for a curve"""
-
-
-class LegendIcon(qt.QWidget):
+
+class LegendIcon(LegendIconWidget):
"""Object displaying a curve linestyle and symbol.
:param QWidget parent: See :class:`QWidget`
@@ -105,35 +56,8 @@ class LegendIcon(qt.QWidget):
def __init__(self, parent=None, curve=None):
super(LegendIcon, self).__init__(parent)
self._curveRef = None
-
- # Visibilities
- self.showLine = True
- self.showSymbol = True
-
- # Line attributes
- self.lineStyle = qt.Qt.NoPen
- self.lineWidth = 1.
- self.lineColor = qt.Qt.green
-
- self.symbol = ''
- # Symbol attributes
- self.symbolStyle = qt.Qt.SolidPattern
- self.symbolColor = qt.Qt.green
- self.symbolOutlineBrush = qt.QBrush(qt.Qt.white)
-
- # Control widget size: sizeHint "is the only acceptable
- # alternative, so the widget can never grow or shrink"
- # (c.f. Qt Doc, enum QSizePolicy::Policy)
- self.setSizePolicy(qt.QSizePolicy.Fixed,
- qt.QSizePolicy.Fixed)
-
self.setCurve(curve)
- def sizeHint(self):
- return qt.QSize(50, 15)
-
- # Synchronize with a curve
-
def getCurve(self):
"""Returns curve associated to this widget
@@ -206,125 +130,6 @@ class LegendIcon(qt.QWidget):
items.ItemChangedType.HIGHLIGHTED_STYLE):
self._update()
- # Modify Symbol
- def setSymbol(self, symbol):
- symbol = str(symbol)
- if symbol not in NoSymbols:
- if symbol not in Symbols:
- raise ValueError("Unknown symbol: <%s>" % symbol)
- self.symbol = symbol
- # self.update() after set...?
- # Does not seem necessary
-
- def setSymbolColor(self, color):
- """
- :param color: determines the symbol color
- :type style: qt.QColor
- """
- self.symbolColor = qt.QColor(color)
-
- # Modify Line
-
- def setLineColor(self, color):
- self.lineColor = qt.QColor(color)
-
- def setLineWidth(self, width):
- self.lineWidth = float(width)
-
- def setLineStyle(self, style):
- """Set the linestyle.
-
- Possible line styles:
-
- - '', ' ', 'None': No line
- - '-': solid
- - '--': dashed
- - ':': dotted
- - '-.': dash and dot
-
- :param str style: The linestyle to use
- """
- if style not in LineStyles:
- raise ValueError('Unknown style: %s', style)
- self.lineStyle = LineStyles[style]
-
- # Paint
-
- def paintEvent(self, event):
- """
- :param event: event
- :type event: QPaintEvent
- """
- painter = qt.QPainter(self)
- self.paint(painter, event.rect(), self.palette())
-
- def paint(self, painter, rect, palette):
- painter.save()
- painter.setRenderHint(qt.QPainter.Antialiasing)
- # Scale painter to the icon height
- # current -> width = 2.5, height = 1.0
- scale = float(self.height())
- ratio = float(self.width()) / scale
- painter.scale(scale,
- scale)
- symbolOffset = qt.QPointF(.5 * (ratio - 1.), 0.)
- # Determine and scale offset
- offset = qt.QPointF(float(rect.left()) / scale, float(rect.top()) / scale)
-
- # Override color when disabled
- if self.isEnabled():
- overrideColor = None
- else:
- overrideColor = palette.color(qt.QPalette.Disabled,
- qt.QPalette.WindowText)
-
- # Draw BG rectangle (for debugging)
- # bottomRight = qt.QPointF(
- # float(rect.right())/scale,
- # float(rect.bottom())/scale)
- # painter.fillRect(qt.QRectF(offset, bottomRight),
- # qt.QBrush(qt.Qt.green))
- llist = []
- if self.showLine:
- linePath = qt.QPainterPath()
- linePath.moveTo(0., 0.5)
- linePath.lineTo(ratio, 0.5)
- # linePath.lineTo(2.5, 0.5)
- lineBrush = qt.QBrush(
- self.lineColor if overrideColor is None else overrideColor)
- linePen = qt.QPen(
- lineBrush,
- (self.lineWidth / self.height()),
- self.lineStyle,
- qt.Qt.FlatCap
- )
- llist.append((linePath, linePen, lineBrush))
- if (self.showSymbol and len(self.symbol) and
- self.symbol not in NoSymbols):
- # PITFALL ahead: Let this be a warning to others
- # symbolPath = Symbols[self.symbol]
- # Copy before translate! Dict is a mutable type
- symbolPath = qt.QPainterPath(Symbols[self.symbol])
- symbolPath.translate(symbolOffset)
- symbolBrush = qt.QBrush(
- self.symbolColor if overrideColor is None else overrideColor,
- self.symbolStyle)
- symbolPen = qt.QPen(
- self.symbolOutlineBrush, # Brush
- 1. / self.height(), # Width
- qt.Qt.SolidLine # Style
- )
- llist.append((symbolPath,
- symbolPen,
- symbolBrush))
- # Draw
- for path, pen, brush in llist:
- path.translate(offset)
- painter.setPen(pen)
- painter.setBrush(brush)
- painter.drawPath(path)
- painter.restore()
-
class LegendModel(qt.QAbstractListModel):
"""Data model of curve legends.
@@ -476,7 +281,7 @@ class LegendModel(qt.QAbstractListModel):
new = []
for (legend, icon) in llist:
linestyle = icon.get('linestyle', None)
- if linestyle in NoLineStyle:
+ if LegendIconWidget.isEmptyLineStyle(linestyle):
# Curve had no line, give it one and hide it
# So when toggle line, it will display a solid line
showLine = False
@@ -485,7 +290,7 @@ class LegendModel(qt.QAbstractListModel):
showLine = True
symbol = icon.get('symbol', None)
- if symbol in NoSymbols:
+ if LegendIconWidget.isEmptySymbol(symbol):
# Curve had no symbol, give it one and hide it
# So when toggle symbol, it will display 'o'
showSymbol = False
@@ -959,7 +764,7 @@ class LegendListContextMenu(qt.QMenu):
}
flag = modelIndex.data(LegendModel.showSymbolRole)
symbol = modelIndex.data(LegendModel.iconSymbolRole)
- visible = not flag or symbol in NoSymbols
+ visible = not flag or LegendIconWidget.isEmptySymbol(symbol)
_logger.debug(
'togglePointsAction -- Symbols visible: %s', str(visible))
diff --git a/silx/gui/plot/PlotInteraction.py b/silx/gui/plot/PlotInteraction.py
index 27abd10..abfcf79 100644
--- a/silx/gui/plot/PlotInteraction.py
+++ b/silx/gui/plot/PlotInteraction.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2014-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
@@ -1079,7 +1079,10 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction):
applyZoomToPlot(self.machine.plot, scaleF, (x, y))
def onMove(self, x, y):
- marker = self.machine.plot._pickMarker(x, y)
+ result = self.machine.plot._pickTopMost(
+ x, y, lambda item: isinstance(item, items.MarkerBase))
+ marker = result.getItem() if result is not None else None
+
if marker is not None:
dataPos = self.machine.plot.pixelToData(x, y)
assert dataPos is not None
@@ -1151,10 +1154,14 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction):
"""
if btn == LEFT_BTN:
- marker = self.plot._pickMarker(
- x, y, lambda m: m.isSelectable())
- if marker is not None:
- xData, yData = marker.getPosition()
+ result = self.plot._pickTopMost(x, y, lambda i: i.isSelectable())
+ if result is None:
+ return None
+
+ item = result.getItem()
+
+ if isinstance(item, items.MarkerBase):
+ xData, yData = item.getPosition()
if xData is None:
xData = [0, 1]
if yData is None:
@@ -1162,58 +1169,44 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction):
eventDict = prepareMarkerSignal('markerClicked',
'left',
- marker.getLegend(),
+ item.getLegend(),
'marker',
- marker.isDraggable(),
- marker.isSelectable(),
+ item.isDraggable(),
+ item.isSelectable(),
(xData, yData),
(x, y), None)
return eventDict
- else:
- picked = self.plot._pickImageOrCurve(
- x, y, lambda item: item.isSelectable())
-
- if picked is None:
- pass
-
- elif picked[0] == 'curve':
- curve = picked[1]
- indices = picked[2]
-
- dataPos = self.plot.pixelToData(x, y)
- assert dataPos is not None
-
- xData = curve.getXData(copy=False)
- yData = curve.getYData(copy=False)
-
- eventDict = prepareCurveSignal('left',
- curve.getLegend(),
- 'curve',
- xData[indices],
- yData[indices],
- dataPos[0], dataPos[1],
- x, y)
- return eventDict
-
- elif picked[0] == 'image':
- image = picked[1]
-
- dataPos = self.plot.pixelToData(x, y)
- assert dataPos is not None
-
- # Get corresponding coordinate in image
- origin = image.getOrigin()
- scale = image.getScale()
- column = int((dataPos[0] - origin[0]) / float(scale[0]))
- row = int((dataPos[1] - origin[1]) / float(scale[1]))
- eventDict = prepareImageSignal('left',
- image.getLegend(),
- 'image',
- column, row,
- dataPos[0], dataPos[1],
- x, y)
- return eventDict
+ elif isinstance(item, items.Curve):
+ dataPos = self.plot.pixelToData(x, y)
+ assert dataPos is not None
+
+ xData = item.getXData(copy=False)
+ yData = item.getYData(copy=False)
+
+ indices = result.getIndices(copy=False)
+ eventDict = prepareCurveSignal('left',
+ item.getLegend(),
+ 'curve',
+ xData[indices],
+ yData[indices],
+ dataPos[0], dataPos[1],
+ x, y)
+ return eventDict
+
+ elif isinstance(item, items.ImageBase):
+ dataPos = self.plot.pixelToData(x, y)
+ assert dataPos is not None
+
+ indices = result.getIndices(copy=False)
+ row, column = indices[0][0], indices[1][0]
+ eventDict = prepareImageSignal('left',
+ item.getLegend(),
+ 'image',
+ column, row,
+ dataPos[0], dataPos[1],
+ x, y)
+ return eventDict
return None
@@ -1240,6 +1233,15 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction):
posDataCursor)
self.plot.notify(**eventDict)
+ @staticmethod
+ def __isDraggableItem(item):
+ return isinstance(item, items.DraggableMixIn) and item.isDraggable()
+
+ def __terminateDrag(self):
+ """Finalize a drag operation by reseting to initial state"""
+ self.plot.setGraphCursorShape()
+ self.draggedItemRef = None
+
def beginDrag(self, x, y):
"""Handle begining of drag interaction
@@ -1250,78 +1252,56 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction):
self._lastPos = self.plot.pixelToData(x, y)
assert self._lastPos is not None
- self.imageLegend = None
- self.markerLegend = None
- marker = self.plot._pickMarker(
- x, y, lambda m: m.isDraggable())
+ result = self.plot._pickTopMost(x, y, self.__isDraggableItem)
+ item = result.getItem() if result is not None else None
+
+ self.draggedItemRef = None if item is None else weakref.ref(item)
+
+ if item is None:
+ self.__terminateDrag()
+ return False
+
+ if isinstance(item, items.MarkerBase):
+ self._signalMarkerMovingEvent('markerMoving', item, x, y)
- if marker is not None:
- self.markerLegend = marker.getLegend()
- self._signalMarkerMovingEvent('markerMoving', marker, x, y)
- else:
- picked = self.plot._pickImageOrCurve(
- x,
- y,
- lambda item:
- hasattr(item, 'isDraggable') and item.isDraggable())
- if picked is None:
- self.imageLegend = None
- self.plot.setGraphCursorShape()
- return False
- else:
- assert picked[0] == 'image' # For now only drag images
- self.imageLegend = picked[1].getLegend()
return True
def drag(self, x, y):
dataPos = self.plot.pixelToData(x, y)
assert dataPos is not None
- xData, yData = dataPos
- if self.markerLegend is not None:
- marker = self.plot._getMarker(self.markerLegend)
- if marker is not None:
- marker.setPosition(xData, yData)
+ item = None if self.draggedItemRef is None else self.draggedItemRef()
+ if item is not None:
+ item.drag(self._lastPos, dataPos)
- self._signalMarkerMovingEvent(
- 'markerMoving', marker, x, y)
+ if isinstance(item, items.MarkerBase):
+ self._signalMarkerMovingEvent('markerMoving', item, x, y)
- if self.imageLegend is not None:
- image = self.plot.getImage(self.imageLegend)
- origin = image.getOrigin()
- xImage = origin[0] + xData - self._lastPos[0]
- yImage = origin[1] + yData - self._lastPos[1]
- image.setOrigin((xImage, yImage))
-
- self._lastPos = xData, yData
+ self._lastPos = dataPos
def endDrag(self, startPos, endPos):
- if self.markerLegend is not None:
- marker = self.plot._getMarker(self.markerLegend)
- posData = list(marker.getPosition())
+ item = None if self.draggedItemRef is None else self.draggedItemRef()
+ if item is not None and isinstance(item, items.MarkerBase):
+ posData = list(item.getPosition())
if posData[0] is None:
- posData[0] = [0, 1]
+ posData[0] = 1.
if posData[1] is None:
- posData[1] = [0, 1]
+ posData[1] = 1.
eventDict = prepareMarkerSignal(
'markerMoved',
'left',
- marker.getLegend(),
+ item.getLegend(),
'marker',
- marker.isDraggable(),
- marker.isSelectable(),
+ item.isDraggable(),
+ item.isSelectable(),
posData)
self.plot.notify(**eventDict)
- self.plot.setGraphCursorShape()
-
- del self.markerLegend
- del self.imageLegend
- del self._lastPos
+ self.__terminateDrag()
def cancel(self):
- self.plot.setGraphCursorShape()
+ self.__terminateDrag()
class ItemsInteractionForCombo(ItemsInteraction):
@@ -1329,22 +1309,16 @@ class ItemsInteractionForCombo(ItemsInteraction):
"""
class Idle(ItemsInteraction.Idle):
+ @staticmethod
+ def __isItemSelectableOrDraggable(item):
+ return (item.isSelectable() or (
+ isinstance(item, items.DraggableMixIn) and item.isDraggable()))
+
def onPress(self, x, y, btn):
if btn == LEFT_BTN:
- def test(item):
- return (item.isSelectable() or
- (isinstance(item, items.DraggableMixIn) and
- item.isDraggable()))
-
- picked = self.machine.plot._pickMarker(x, y, test)
- if picked is not None:
- itemInteraction = True
-
- else:
- picked = self.machine.plot._pickImageOrCurve(x, y, test)
- itemInteraction = picked is not None
-
- if itemInteraction: # Request focus and handle interaction
+ result = self.machine.plot._pickTopMost(
+ x, y, self.__isItemSelectableOrDraggable)
+ if result is not None: # Request focus and handle interaction
self.goto('clickOrDrag', x, y)
return True
else: # Do not request focus
@@ -1658,7 +1632,7 @@ class PlotInteraction(object):
plot = self._plot()
assert plot is not None
- if color not in (None, 'video inverted'):
+ if isinstance(color, numpy.ndarray) or color not in (None, 'video inverted'):
color = colors.rgba(color)
if mode in ('draw', 'select-draw'):
diff --git a/silx/gui/plot/PlotWidget.py b/silx/gui/plot/PlotWidget.py
index 9b9b4d2..49e444a 100644..100755
--- a/silx/gui/plot/PlotWidget.py
+++ b/silx/gui/plot/PlotWidget.py
@@ -39,10 +39,6 @@ _logger = logging.getLogger(__name__)
from collections import OrderedDict, namedtuple
-try:
- from collections import abc
-except ImportError: # Python2 support
- import collections as abc
from contextlib import contextmanager
import datetime as dt
import itertools
@@ -60,6 +56,7 @@ try:
except ImportError:
_logger.debug("matplotlib not available")
+import six
from ..colors import Colormap
from .. import colors
from . import PlotInteraction
@@ -311,7 +308,7 @@ class PlotWidget(qt.QMainWindow):
if callable(backend):
return backend
- elif isinstance(backend, str):
+ elif isinstance(backend, six.string_types):
backend = backend.lower()
if backend in ('matplotlib', 'mpl'):
try:
@@ -337,7 +334,7 @@ class PlotWidget(qt.QMainWindow):
return backendClass
- elif isinstance(backend, abc.Iterable):
+ elif isinstance(backend, (tuple, list)):
for b in backend:
try:
return self.__getBackendClass(b)
@@ -606,7 +603,7 @@ class PlotWidget(qt.QMainWindow):
elif isinstance(item, (items.Marker,
items.XMarker, items.YMarker)):
kind = 'marker'
- elif isinstance(item, items.Shape):
+ elif isinstance(item, (items.Shape, items.BoundingRect)):
kind = 'item'
elif isinstance(item, items.Histogram):
kind = 'histogram'
@@ -710,7 +707,8 @@ class PlotWidget(qt.QMainWindow):
xlabel=None, ylabel=None, yaxis=None,
xerror=None, yerror=None, z=None, selectable=None,
fill=None, resetzoom=True,
- histogram=None, copy=True):
+ histogram=None, copy=True,
+ baseline=None):
"""Add a 1D curve given by x an y to the graph.
Curves are uniquely identified by their legend.
@@ -791,6 +789,8 @@ class PlotWidget(qt.QMainWindow):
- 'center'
:param bool copy: True make a copy of the data (default),
False to use provided arrays.
+ :param baseline: curve baseline
+ :type: Union[None,float,numpy.ndarray]
:returns: The key string identify this curve
"""
# This is an histogram, use addHistogram
@@ -845,6 +845,7 @@ class PlotWidget(qt.QMainWindow):
curve.setColor(default_color)
curve.setLineStyle(default_linestyle)
curve.setSymbol(self._defaultPlotPoints)
+ curve._setBaseline(baseline=baseline)
# Do not emit sigActiveCurveChanged,
# it will be sent once with _setActiveItem
@@ -887,7 +888,7 @@ class PlotWidget(qt.QMainWindow):
if len(x) > 0 and isinstance(x[0], dt.datetime):
x = [timestamp(d) for d in x]
- curve.setData(x, y, xerror, yerror, copy=copy)
+ curve.setData(x, y, xerror, yerror, baseline=baseline, copy=copy)
if replace: # Then remove all other curves
for c in self.getAllCurves(withhidden=True):
@@ -924,7 +925,9 @@ class PlotWidget(qt.QMainWindow):
fill=None,
align='center',
resetzoom=True,
- copy=True):
+ copy=True,
+ z=None,
+ baseline=None):
"""Add an histogram to the graph.
This is NOT computing the histogram, this method takes as parameter
@@ -955,6 +958,9 @@ class PlotWidget(qt.QMainWindow):
:param bool resetzoom: True (the default) to reset the zoom.
:param bool copy: True make a copy of the data (default),
False to use provided arrays.
+ :param int z: Layer on which to draw the histogram
+ :param baseline: histogram baseline
+ :type: Union[None,float,numpy.ndarray]
:returns: The key string identify this histogram
"""
legend = 'Unnamed histogram' if legend is None else str(legend)
@@ -974,9 +980,12 @@ class PlotWidget(qt.QMainWindow):
histo.setColor(color)
if fill is not None:
histo.setFill(fill)
+ if z is not None:
+ histo.setZValue(z=z)
# Set histogram data
- histo.setData(histogram, edges, align=align, copy=copy)
+ histo.setData(histogram=histogram, edges=edges, baseline=baseline,
+ align=align, copy=copy)
if mustBeAdded:
self._add(histo)
@@ -1307,7 +1316,8 @@ class PlotWidget(qt.QMainWindow):
color=None,
selectable=False,
draggable=False,
- constraint=None):
+ constraint=None,
+ yaxis='left'):
"""Add a vertical line marker to the plot.
Markers are uniquely identified by their legend.
@@ -1333,12 +1343,14 @@ class PlotWidget(qt.QMainWindow):
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
+ :param str yaxis: The Y axis this marker belongs to in: 'left', 'right'
:return: The key string identify this marker
"""
return self._addMarker(x=x, y=None, legend=legend,
text=text, color=color,
selectable=selectable, draggable=draggable,
- symbol=None, constraint=constraint)
+ symbol=None, constraint=constraint,
+ yaxis=yaxis)
def addYMarker(self, y,
legend=None,
@@ -1346,7 +1358,8 @@ class PlotWidget(qt.QMainWindow):
color=None,
selectable=False,
draggable=False,
- constraint=None):
+ constraint=None,
+ yaxis='left'):
"""Add a horizontal line marker to the plot.
Markers are uniquely identified by their legend.
@@ -1372,12 +1385,14 @@ class PlotWidget(qt.QMainWindow):
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
+ :param str yaxis: The Y axis this marker belongs to in: 'left', 'right'
:return: The key string identify this marker
"""
return self._addMarker(x=None, y=y, legend=legend,
text=text, color=color,
selectable=selectable, draggable=draggable,
- symbol=None, constraint=constraint)
+ symbol=None, constraint=constraint,
+ yaxis=yaxis)
def addMarker(self, x, y, legend=None,
text=None,
@@ -1385,7 +1400,8 @@ class PlotWidget(qt.QMainWindow):
selectable=False,
draggable=False,
symbol='+',
- constraint=None):
+ constraint=None,
+ yaxis='left'):
"""Add a point marker to the plot.
Markers are uniquely identified by their legend.
@@ -1423,6 +1439,7 @@ class PlotWidget(qt.QMainWindow):
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
+ :param str yaxis: The Y axis this marker belongs to in: 'left', 'right'
:return: The key string identify this marker
"""
if x is None:
@@ -1436,12 +1453,14 @@ class PlotWidget(qt.QMainWindow):
return self._addMarker(x=x, y=y, legend=legend,
text=text, color=color,
selectable=selectable, draggable=draggable,
- symbol=symbol, constraint=constraint)
+ symbol=symbol, constraint=constraint,
+ yaxis=yaxis)
def _addMarker(self, x, y, legend,
text, color,
selectable, draggable,
- symbol, constraint):
+ symbol, constraint,
+ yaxis=None):
"""Common method for adding point, vline and hline marker.
See :meth:`addMarker` for argument documentation.
@@ -1487,6 +1506,7 @@ class PlotWidget(qt.QMainWindow):
marker._setDraggable(draggable)
if symbol is not None:
marker.setSymbol(symbol)
+ marker.setYAxis(yaxis)
# TODO to improve, but this ensure constraint is applied
marker.setPosition(x, y)
@@ -2692,6 +2712,7 @@ class PlotWidget(qt.QMainWindow):
"""Redraw the plot immediately."""
for item in self._contentToUpdate:
item._update(self._backend)
+
self._contentToUpdate = []
self._backend.replot()
self._dirty = False # reset dirty flag
@@ -2862,7 +2883,18 @@ class PlotWidget(qt.QMainWindow):
:rtype: A tuple of 2 floats: (xData, yData) or None.
"""
assert axis in ("left", "right")
- return self._backend.pixelToData(x, y, axis=axis, check=check)
+
+ if x is None:
+ x = self.width() // 2
+ if y is None:
+ y = self.height() // 2
+
+ if check:
+ left, top, width, height = self.getPlotBoundsInPixels()
+ if not (left <= x <= left + width and top <= y <= top + height):
+ return None
+
+ return self._backend.pixelToData(x, y, axis)
def getPlotBoundsInPixels(self):
"""Plot area bounds in widget coordinates in pixels.
@@ -2880,29 +2912,6 @@ class PlotWidget(qt.QMainWindow):
"""
self._backend.setGraphCursorShape(cursor)
- def _pickMarker(self, x, y, test=None):
- """Pick a marker at the given position.
-
- To use for interaction implementation.
-
- :param float x: X position in pixels.
- :param float y: Y position in pixels.
- :param test: A callable to call for each picked marker to filter
- picked markers. If None (default), do not filter markers.
- """
- if test is None:
- def test(mark):
- return True
-
- markers = self._backend.pickItems(x, y, kinds=('marker',))
- legends = [m['legend'] for m in markers if m['kind'] == 'marker']
-
- for legend in reversed(legends):
- marker = self._getMarker(legend)
- if marker is not None and test(marker):
- return marker
- return None
-
def _getAllMarkers(self, just_legend=False):
"""Returns all markers' legend or objects
@@ -2924,73 +2933,41 @@ class PlotWidget(qt.QMainWindow):
"""
return self._getItem(kind='marker', legend=legend)
- def _pickImageOrCurve(self, x, y, test=None):
- """Pick an image or a curve at the given position.
+ def pickItems(self, x, y, condition=None):
+ """Generator of picked items in the plot at given position.
- To use for interaction implementation.
+ Items are returned from front to back.
:param float x: X position in pixels
:param float y: Y position in pixels
- :param test: A callable to call for each picked item to filter
- picked items. If None (default), do not filter items.
+ :param callable condition:
+ Callable taking an item as input and returning False for items
+ to skip during picking. If None (default) no item is skipped.
+ :return: Iterable of :class:`PickingResult` objects at picked position.
+ Items are ordered from front to back.
"""
- if test is None:
- def test(i):
- return True
-
- allItems = self._backend.pickItems(x, y, kinds=('curve', 'image'))
- allItems = [item for item in allItems
- if item['kind'] in ['curve', 'image']]
-
- for item in reversed(allItems):
- kind, legend = item['kind'], item['legend']
- if kind == 'curve':
- curve = self.getCurve(legend)
- if curve is not None and test(curve):
- return kind, curve, item['indices']
-
- elif kind == 'image':
- image = self.getImage(legend)
- if image is not None and test(image):
- return kind, image, None
+ for item in reversed(self._backend.getItemsFromBackToFront(condition=condition)):
+ result = item.pick(x, y)
+ if result is not None:
+ yield result
- else:
- _logger.warning('Unsupported kind: %s', kind)
-
- return None
+ def _pickTopMost(self, x, y, condition=None):
+ """Returns top-most picked item in the plot at given position.
- def _pick(self, x, y):
- """Pick items in the plot at given position.
+ Items are checked from front to back.
:param float x: X position in pixels
:param float y: Y position in pixels
- :return: Iterable of (plot item, indices) at picked position.
- Items are ordered from back to front.
- """
- items = []
-
- # Convert backend result to plot items
- for itemInfo in self._backend.pickItems(
- x, y, kinds=('marker', 'curve', 'image')):
- kind, legend = itemInfo['kind'], itemInfo['legend']
-
- if kind in ('marker', 'image'):
- item = self._getItem(kind=kind, legend=legend)
- indices = None # TODO compute indices for images
-
- else: # backend kind == 'curve'
- for kind in ('curve', 'histogram', 'scatter'):
- item = self._getItem(kind=kind, legend=legend)
- if item is not None:
- indices = itemInfo['indices']
- break
- else:
- _logger.error(
- 'Cannot find corresponding picked item')
- continue
- items.append((item, indices))
-
- return tuple(items)
+ :param callable condition:
+ Callable taking an item as input and returning False for items
+ to skip during picking. If None (default) no item is skipped.
+ :return: :class:`PickingResult` object at picked position.
+ If no item is picked, it returns None
+ :rtype: Union[None,PickingResult]
+ """
+ for result in self.pickItems(x, y, condition):
+ return result
+ return None
# User event handling #
@@ -3123,7 +3100,7 @@ class PlotWidget(qt.QMainWindow):
# Panning with arrow keys
def isPanWithArrowKeys(self):
- """Returns whether or not panning the graph with arrow keys is enable.
+ """Returns whether or not panning the graph with arrow keys is enabled.
See :meth:`setPanWithArrowKeys`.
"""
diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py
index a39430e..0196050 100644
--- a/silx/gui/plot/PlotWindow.py
+++ b/silx/gui/plot/PlotWindow.py
@@ -122,7 +122,7 @@ class PlotWindow(PlotWidget):
self._curvesROIDockWidget = None
self._maskToolsDockWidget = None
self._consoleDockWidget = None
- self._statsWidget = None
+ self._statsDockWidget = None
# Create color bar, hidden by default for backward compatibility
self._colorbar = ColorBarWidget(parent=self, plot=self)
@@ -485,6 +485,22 @@ class PlotWindow(PlotWidget):
self.tabifyDockWidget(self._dockWidgets[0],
dock_widget)
+ def __handleFirstDockWidgetShow(self, visible):
+ """Handle QDockWidget.visibilityChanged
+
+ It calls :meth:`addTabbedDockWidget` for the `sender` widget.
+ This allows to call `addTabbedDockWidget` lazily.
+
+ It disconnect itself from the signal once done.
+
+ :param bool visible:
+ """
+ if visible:
+ dockWidget = self.sender()
+ dockWidget.visibilityChanged.disconnect(
+ self.__handleFirstDockWidgetShow)
+ self.addTabbedDockWidget(dockWidget)
+
def getColorBarWidget(self):
"""Returns the embedded :class:`ColorBarWidget` widget.
@@ -499,7 +515,8 @@ class PlotWindow(PlotWidget):
if self._legendsDockWidget is None:
self._legendsDockWidget = LegendsDockWidget(plot=self)
self._legendsDockWidget.hide()
- self.addTabbedDockWidget(self._legendsDockWidget)
+ self._legendsDockWidget.visibilityChanged.connect(
+ self.__handleFirstDockWidgetShow)
return self._legendsDockWidget
def getCurvesRoiDockWidget(self):
@@ -509,7 +526,8 @@ class PlotWindow(PlotWidget):
self._curvesROIDockWidget = CurvesROIDockWidget(
plot=self, name='Regions Of Interest')
self._curvesROIDockWidget.hide()
- self.addTabbedDockWidget(self._curvesROIDockWidget)
+ self._curvesROIDockWidget.visibilityChanged.connect(
+ self.__handleFirstDockWidgetShow)
return self._curvesROIDockWidget
def getCurvesRoiWidget(self):
@@ -529,7 +547,8 @@ class PlotWindow(PlotWidget):
self._maskToolsDockWidget = MaskToolsDockWidget(
plot=self, name='Mask')
self._maskToolsDockWidget.hide()
- self.addTabbedDockWidget(self._maskToolsDockWidget)
+ self._maskToolsDockWidget.visibilityChanged.connect(
+ self.__handleFirstDockWidgetShow)
return self._maskToolsDockWidget
def getStatsWidget(self):
@@ -537,16 +556,18 @@ class PlotWindow(PlotWidget):
:rtype: BasicStatsWidget
"""
- if self._statsWidget is None:
- dockWidget = qt.QDockWidget(parent=self)
- dockWidget.setWindowTitle("Curves stats")
- dockWidget.layout().setContentsMargins(0, 0, 0, 0)
- self._statsWidget = BasicStatsWidget(parent=self, plot=self)
- self._statsWidget.sigVisibilityChanged.connect(self.getStatsAction().setChecked)
- dockWidget.setWidget(self._statsWidget)
- dockWidget.hide()
- self.addTabbedDockWidget(dockWidget)
- return self._statsWidget
+ if self._statsDockWidget is None:
+ self._statsDockWidget = qt.QDockWidget()
+ self._statsDockWidget.setWindowTitle("Curves stats")
+ 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.visibilityChanged.connect(
+ self.__handleFirstDockWidgetShow)
+ return self._statsDockWidget.widget()
# getters for actions
@property
diff --git a/silx/gui/plot/ScatterMaskToolsWidget.py b/silx/gui/plot/ScatterMaskToolsWidget.py
index 0c6797f..9a15763 100644
--- a/silx/gui/plot/ScatterMaskToolsWidget.py
+++ b/silx/gui/plot/ScatterMaskToolsWidget.py
@@ -276,7 +276,12 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget):
self.plot.sigActiveScatterChanged.connect(self._activeScatterChanged)
def hideEvent(self, event):
- self.plot.sigActiveScatterChanged.disconnect(self._activeScatterChanged)
+ try:
+ # if the method is not connected this raises a TypeError and there is no way
+ # to know the connected slots
+ self.plot.sigActiveScatterChanged.disconnect(self._activeScatterChanged)
+ except (RuntimeError, TypeError):
+ _logger.info(sys.exc_info()[1])
if not self.browseAction.isChecked():
self.browseAction.trigger() # Disable drawing tool
diff --git a/silx/gui/plot/ScatterView.py b/silx/gui/plot/ScatterView.py
index 1d015d4..bdbf3ab 100644
--- a/silx/gui/plot/ScatterView.py
+++ b/silx/gui/plot/ScatterView.py
@@ -79,7 +79,7 @@ class ScatterView(qt.QMainWindow):
self._plot = weakref.ref(plot)
# Add an empty scatter
- plot.addScatter(x=(), y=(), value=(), legend=self._SCATTER_LEGEND)
+ self.__createEmptyScatter()
# Create colorbar widget with white background
self._colorbar = ColorBarWidget(parent=self, plot=plot)
@@ -145,6 +145,21 @@ class ScatterView(qt.QMainWindow):
for action in toolbar.actions():
self.addAction(action)
+
+ def __createEmptyScatter(self):
+ """Create an empty scatter item that is used to display the data
+
+ :rtype: ~silx.gui.plot.items.Scatter
+ """
+ plot = self.getPlotWidget()
+ plot.addScatter(x=(), y=(), value=(), legend=self._SCATTER_LEGEND)
+ scatter = plot._getItem(
+ kind='scatter', legend=self._SCATTER_LEGEND)
+ # Profile is not selectable,
+ # so it does not interfere with profile interaction
+ scatter._setSelectable(False)
+ return scatter
+
def _pickScatterData(self, x, y):
"""Get data and index and value of top most scatter plot at position (x, y)
@@ -162,17 +177,19 @@ class ScatterView(qt.QMainWindow):
pixelPos = plot.dataToPixel(x, y)
if pixelPos is not None:
# Start from top-most item
- for item, indices in reversed(plot._pick(*pixelPos)):
- if isinstance(item, items.Scatter):
- # Get last index
- # with matplotlib it should be the top-most point
- dataIndex = indices[-1]
- self.__pickingCache = (
- dataIndex,
- item.getXData(copy=False)[dataIndex],
- item.getYData(copy=False)[dataIndex],
- item.getValueData(copy=False)[dataIndex])
- break
+ result = plot._pickTopMost(
+ pixelPos[0], pixelPos[1],
+ lambda item: isinstance(item, items.Scatter))
+ if result is not None:
+ # Get last index
+ # with matplotlib it should be the top-most point
+ dataIndex = result.getIndices(copy=False)[-1]
+ item = result.getItem()
+ self.__pickingCache = (
+ dataIndex,
+ item.getXData(copy=False)[dataIndex],
+ item.getYData(copy=False)[dataIndex],
+ item.getValueData(copy=False)[dataIndex])
return self.__pickingCache
@@ -343,9 +360,7 @@ class ScatterView(qt.QMainWindow):
plot = self.getPlotWidget()
scatter = plot._getItem(kind='scatter', legend=self._SCATTER_LEGEND)
if scatter is None: # Resilient to call to PlotWidget API (e.g., clear)
- plot.addScatter(x=(), y=(), value=(), legend=self._SCATTER_LEGEND)
- scatter = plot._getItem(
- kind='scatter', legend=self._SCATTER_LEGEND)
+ scatter = self.__createEmptyScatter()
return scatter
# Convenient proxies
diff --git a/silx/gui/plot/StackView.py b/silx/gui/plot/StackView.py
index 2a3d7e8..7e4c389 100644
--- a/silx/gui/plot/StackView.py
+++ b/silx/gui/plot/StackView.py
@@ -85,6 +85,8 @@ from .Profile import Profile3DToolBar
from ..widgets.FrameBrowser import HorizontalSliderWithBrowser
from silx.gui.plot.actions import control as actions_control
+from silx.gui.plot.actions import io as silx_io
+from silx.io.nxdata import save_NXdata
from silx.utils.array_like import DatasetView, ListOfImages
from silx.math import calibration
from silx.utils.deprecation import deprecated_warning
@@ -160,6 +162,9 @@ class StackView(qt.QMainWindow):
This signal provides the current frame number.
"""
+ IMAGE_STACK_FILTER_NXDATA = 'Stack of images as NXdata (%s)' % silx_io._NEXUS_HDF5_EXT_STR
+
+
def __init__(self, parent=None, resetzoom=True, backend=None,
autoScale=False, logScale=False, grid=False,
colormap=True, aspectRatio=True, yinverted=True,
@@ -226,6 +231,7 @@ class StackView(qt.QMainWindow):
self._plot.getXAxis().setLabel('Columns')
self._plot.getYAxis().setLabel('Rows')
self._plot.sigPlotSignal.connect(self._plotCallback)
+ self._plot.getSaveAction().setFileFilter('image', self.IMAGE_STACK_FILTER_NXDATA, func=self._saveImageStack, appendToFile=True)
self.__planeSelection = PlanesWidget(self._plot)
self.__planeSelection.sigPlaneSelectionChanged.connect(self.setPerspective)
@@ -253,6 +259,25 @@ class StackView(qt.QMainWindow):
self.__planeSelection.sigPlaneSelectionChanged.connect(
self._plot.profile.clearProfile)
+ def _saveImageStack(self, plot, filename, nameFilter):
+ """Save all images from the stack into a volume.
+
+ :param str filename: The name of the file to write
+ :param str nameFilter: The selected name filter
+ :return: False if format is not supported or save failed,
+ True otherwise.
+ :raises: ValueError if nameFilter is invalid
+ """
+ if not nameFilter == self.IMAGE_STACK_FILTER_NXDATA:
+ raise ValueError('Wrong callback')
+ entryPath = silx_io.SaveAction._selectWriteableOutputGroup(filename, parent=self)
+ if entryPath is None:
+ return False
+ return save_NXdata(filename,
+ nxentry_name=entryPath,
+ 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()
@@ -517,7 +542,12 @@ class StackView(qt.QMainWindow):
# This call to setColormap redefines the meaning of autoscale
# for 3D volume: take global min/max rather than frame min/max
if self.__autoscaleCmap:
- self.setColormap(autoscale=True)
+ # note: there is no real autoscale in the stack widget, it is more
+ # like a hack computing stack min and max
+ colormap = self.getColormap()
+ _vmin, _vmax = colormap.getColormapRange(data=self._stack)
+ colormap.setVRange(_vmin, _vmax)
+ self.setColormap(colormap=colormap)
# init plot
self._plot.addImage(self.__transposed_view[0, :, :],
diff --git a/silx/gui/plot/StatsWidget.py b/silx/gui/plot/StatsWidget.py
index 5e2dc58..80bc05d 100644
--- a/silx/gui/plot/StatsWidget.py
+++ b/silx/gui/plot/StatsWidget.py
@@ -1323,6 +1323,7 @@ class _BaseLineStatsWidget(_StatsWidgetBase, qt.QWidget):
def setStats(self, statsHandler):
"""Set which stats to display and the associated formatting.
+
:param StatsHandler statsHandler:
Set the statistics to be displayed and how to format them using
"""
@@ -1541,12 +1542,12 @@ class BasicGridStatsWidget(qt.QWidget):
only visible ones.
:param int statsPerLine: number of statistic to be displayed per line
- .. snapshotqt:: img/_BasicGridStatsWidget.png
+ .. snapshotqt:: img/BasicGridStatsWidget.png
:width: 600px
:align: center
from silx.gui.plot import Plot1D
- from silx.gui.plot.StatsWidget import _BasicGridStatsWidget
+ from silx.gui.plot.StatsWidget import BasicGridStatsWidget
plot = Plot1D()
x = range(100)
@@ -1554,7 +1555,7 @@ class BasicGridStatsWidget(qt.QWidget):
plot.addCurve(x, y, legend='curve_0')
plot.setActiveCurve('curve_0')
- widget = _BasicGridStatsWidget(plot=plot, kind='curve')
+ widget = BasicGridStatsWidget(plot=plot, kind='curve')
widget.show()
"""
diff --git a/silx/gui/plot/actions/control.py b/silx/gui/plot/actions/control.py
index ec4a3de..e2fa6b1 100644..100755
--- a/silx/gui/plot/actions/control.py
+++ b/silx/gui/plot/actions/control.py
@@ -360,8 +360,8 @@ class ColormapAction(PlotAction):
# Run the dialog listening to colormap change
if checked is True:
- self._dialog.show()
self._updateColormap()
+ self._dialog.show()
else:
self._dialog.hide()
diff --git a/silx/gui/plot/actions/fit.py b/silx/gui/plot/actions/fit.py
index cb70733..6fc5c75 100644
--- a/silx/gui/plot/actions/fit.py
+++ b/silx/gui/plot/actions/fit.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-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
@@ -98,18 +98,15 @@ class FitAction(PlotToolAction):
plot, icon='math-fit', text='Fit curve',
tooltip='Open a fit dialog',
parent=parent)
- self.fit_widget = None
def _createToolWindow(self):
- window = qt.QMainWindow(parent=self.plot)
# import done here rather than at module level to avoid circular import
# FitWidget -> BackgroundWidget -> PlotWindow -> actions -> fit -> FitWidget
from ...fit.FitWidget import FitWidget
- fit_widget = FitWidget(parent=window)
- window.setCentralWidget(fit_widget)
- fit_widget.guibuttons.DismissButton.clicked.connect(window.close)
- fit_widget.sigFitWidgetSignal.connect(self.handle_signal)
- self.fit_widget = fit_widget
+
+ window = FitWidget(parent=self.plot)
+ window.setWindowFlags(qt.Qt.Window)
+ window.sigFitWidgetSignal.connect(self.handle_signal)
return window
def _connectPlot(self, window):
@@ -158,8 +155,8 @@ class FitAction(PlotToolAction):
self.x = item.getXData(copy=False)
self.y = item.getYData(copy=False)
- self.fit_widget.setData(self.x, self.y,
- xmin=self.xmin, xmax=self.xmax)
+ window.setData(self.x, self.y,
+ xmin=self.xmin, xmax=self.xmax)
window.setWindowTitle(
"Fitting " + self.legend +
" on x range %f-%f" % (self.xmin, self.xmax))
@@ -171,7 +168,10 @@ class FitAction(PlotToolAction):
fit_curve = self.plot.getCurve(fit_legend)
if ddict["event"] == "FitFinished":
- y_fit = self.fit_widget.fitmanager.gendata()
+ fit_widget = self._getToolWindow()
+ if fit_widget is None:
+ return
+ y_fit = fit_widget.fitmanager.gendata()
if fit_curve is None:
self.plot.addCurve(x_fit, y_fit,
fit_legend,
diff --git a/silx/gui/plot/actions/histogram.py b/silx/gui/plot/actions/histogram.py
index 9181f53..3bb3e6a 100644
--- a/silx/gui/plot/actions/histogram.py
+++ b/silx/gui/plot/actions/histogram.py
@@ -134,6 +134,7 @@ class PixelIntensitiesHistoAction(PlotToolAction):
window = Plot1D(parent=self.plot)
window.setWindowFlags(qt.Qt.Window)
window.setWindowTitle('Image Intensity Histogram')
+ window.setDataMargins(0.1, 0.1, 0.1, 0.1)
window.getXAxis().setLabel("Value")
window.getYAxis().setLabel("Count")
return window
diff --git a/silx/gui/plot/actions/io.py b/silx/gui/plot/actions/io.py
index 09e4a99..43b3b3a 100644
--- a/silx/gui/plot/actions/io.py
+++ b/silx/gui/plot/actions/io.py
@@ -131,6 +131,7 @@ class SaveAction(PlotAction):
IMAGE_FILTER_CSV_TAB = 'Image data as tab-separated CSV (*.csv)'
IMAGE_FILTER_RGB_PNG = 'Image as PNG (*.png)'
IMAGE_FILTER_NXDATA = 'Image as NXdata (%s)' % _NEXUS_HDF5_EXT_STR
+
DEFAULT_IMAGE_FILTERS = (IMAGE_FILTER_EDF,
IMAGE_FILTER_TIFF,
IMAGE_FILTER_NUMPY,
@@ -156,6 +157,8 @@ class SaveAction(PlotAction):
'image': OrderedDict(),
'scatter': OrderedDict()}
+ self._appendFilters = list(self.DEFAULT_APPEND_FILTERS)
+
# Initialize filters
for nameFilter in self.DEFAULT_ALL_FILTERS:
self.setFileFilter(
@@ -185,10 +188,11 @@ class SaveAction(PlotAction):
self.setShortcut(qt.QKeySequence.Save)
self.setShortcutContext(qt.Qt.WidgetShortcut)
- def _errorMessage(self, informativeText=''):
+ @staticmethod
+ def _errorMessage(informativeText='', parent=None):
"""Display an error message."""
# TODO issue with QMessageBox size fixed and too small
- msg = qt.QMessageBox(self.plot)
+ msg = qt.QMessageBox(parent)
msg.setIcon(qt.QMessageBox.Critical)
msg.setInformativeText(informativeText + ' ' + str(sys.exc_info()[1]))
msg.setDetailedText(traceback.format_exc())
@@ -220,7 +224,8 @@ class SaveAction(PlotAction):
ylabel = item.getYLabel() or self.plot.getYAxis().getLabel()
return xlabel, ylabel
- def _selectWriteableOutputGroup(self, filename):
+ @staticmethod
+ def _selectWriteableOutputGroup(filename, parent):
if os.path.exists(filename) and os.path.isfile(filename) \
and os.access(filename, os.W_OK):
entryPath = selectOutputGroup(filename)
@@ -232,11 +237,11 @@ class SaveAction(PlotAction):
# create new entry in new file
return "/entry"
else:
- self._errorMessage('Save failed (file access issue)\n')
+ SaveAction._errorMessage('Save failed (file access issue)\n', parent=parent)
return None
def _saveCurveAsNXdata(self, curve, filename):
- entryPath = self._selectWriteableOutputGroup(filename)
+ entryPath = self._selectWriteableOutputGroup(filename, parent=self.plot)
if entryPath is None:
return False
@@ -273,7 +278,7 @@ class SaveAction(PlotAction):
if curve is None:
curves = plot.getAllCurves()
if not curves:
- self._errorMessage("No curve to be saved")
+ self._errorMessage("No curve to be saved", parent=self.plot)
return False
curve = curves[0]
@@ -299,7 +304,7 @@ class SaveAction(PlotAction):
fmt=fmt, csvdelim=csvdelim,
autoheader=autoheader)
except IOError:
- self._errorMessage('Save failed\n')
+ self._errorMessage('Save failed\n', parent=self.plot)
return False
return True
@@ -317,7 +322,7 @@ class SaveAction(PlotAction):
curves = plot.getAllCurves()
if not curves:
- self._errorMessage("No curves to be saved")
+ self._errorMessage("No curves to be saved", parent=self.plot)
return False
curve = curves[0]
@@ -334,7 +339,7 @@ class SaveAction(PlotAction):
write_file_header=True,
close_file=False)
except IOError:
- self._errorMessage('Save failed\n')
+ self._errorMessage('Save failed\n', parent=self.plot)
return False
for curve in curves[1:]:
@@ -351,7 +356,7 @@ class SaveAction(PlotAction):
write_file_header=False,
close_file=False)
except IOError:
- self._errorMessage('Save failed\n')
+ self._errorMessage('Save failed\n', parent=self.plot)
return False
specfile.close()
@@ -391,12 +396,12 @@ class SaveAction(PlotAction):
try:
numpy.save(filename, data)
except IOError:
- self._errorMessage('Save failed\n')
+ self._errorMessage('Save failed\n', parent=self.plot)
return False
return True
elif nameFilter == self.IMAGE_FILTER_NXDATA:
- entryPath = self._selectWriteableOutputGroup(filename)
+ entryPath = self._selectWriteableOutputGroup(filename, parent=self.plot)
if entryPath is None:
return False
xorigin, yorigin = image.getOrigin()
@@ -438,7 +443,7 @@ class SaveAction(PlotAction):
autoheader=True)
except IOError:
- self._errorMessage('Save failed\n')
+ self._errorMessage('Save failed\n', parent=self.plot)
return False
return True
@@ -471,7 +476,7 @@ class SaveAction(PlotAction):
return False
if nameFilter == self.SCATTER_FILTER_NXDATA:
- entryPath = self._selectWriteableOutputGroup(filename)
+ entryPath = self._selectWriteableOutputGroup(filename, parent=self.plot)
if entryPath is None:
return False
scatter = plot.getScatter()
@@ -502,7 +507,7 @@ class SaveAction(PlotAction):
axes_errors=[xerror, yerror],
title=plot.getGraphTitle())
- def setFileFilter(self, dataKind, nameFilter, func, index=None):
+ def setFileFilter(self, dataKind, nameFilter, func, index=None, appendToFile=False):
"""Set a name filter to add/replace a file format support
:param str dataKind:
@@ -513,10 +518,15 @@ class SaveAction(PlotAction):
:param callable func: The function to call to perform saving.
Expected signature is:
bool func(PlotWidget plot, str filename, str nameFilter)
+ :param bool appendToFile: True to append the data into the selected
+ file.
:param integer index: Index of the filter in the final list (or None)
"""
assert dataKind in ('all', 'curve', 'curves', 'image', 'scatter')
+ if appendToFile:
+ self._appendFilters.append(nameFilter)
+
# first append or replace the new filter to prevent colissions
self._filters[dataKind][nameFilter] = func
if index is None:
@@ -601,7 +611,7 @@ class SaveAction(PlotAction):
def onFilterSelection(filt_):
# disable overwrite confirmation for NXdata types,
# because we append the data to existing files
- if filt_ in self.DEFAULT_APPEND_FILTERS:
+ if filt_ in self._appendFilters:
dialog.setOption(dialog.DontConfirmOverwrite)
else:
dialog.setOption(dialog.DontConfirmOverwrite, False)
diff --git a/silx/gui/plot/backends/BackendBase.py b/silx/gui/plot/backends/BackendBase.py
index af37543..75d999b 100644..100755
--- a/silx/gui/plot/backends/BackendBase.py
+++ b/silx/gui/plot/backends/BackendBase.py
@@ -97,16 +97,15 @@ class BackendBase(object):
# Add methods
- def addCurve(self, x, y, legend,
+ def addCurve(self, x, y,
color, symbol, linewidth, linestyle,
yaxis,
- xerror, yerror, z, selectable,
- fill, alpha, symbolsize):
+ xerror, yerror, z,
+ fill, alpha, symbolsize, baseline):
"""Add a 1D curve given by x an y to the graph.
:param numpy.ndarray x: The data corresponding to the x axis
:param numpy.ndarray y: The data corresponding to the y axis
- :param str legend: The legend to be associated to the curve
:param color: color(s) to be used
:type color: string ("#RRGGBB") or (npoints, 4) unsigned byte array or
one of the predefined color names defined in colors.py
@@ -136,24 +135,21 @@ class BackendBase(object):
:param yerror: Values with the uncertainties on the y values
:type yerror: numpy.ndarray or None
:param int z: Layer on which to draw the cuve
- :param bool selectable: indicate if the curve can be selected
:param bool fill: True to fill the curve, False otherwise
:param float alpha: Curve opacity, as a float in [0., 1.]
:param float symbolsize: Size of the symbol (if any) drawn
at each (x, y) position.
:returns: The handle used by the backend to univocally access the curve
"""
- return legend
+ return object()
- def addImage(self, data, legend,
+ def addImage(self, data,
origin, scale, z,
- selectable, draggable,
colormap, alpha):
"""Add an image to the plot.
:param numpy.ndarray data: (nrows, ncolumns) data or
(nrows, ncolumns, RGBA) ubyte array
- :param str legend: The legend to be associated to the image
:param origin: (origin X, origin Y) of the data.
Default: (0., 0.)
:type origin: 2-tuple of float
@@ -161,39 +157,34 @@ class BackendBase(object):
Default: (1., 1.)
:type scale: 2-tuple of float
:param int z: Layer on which to draw the image
- :param bool selectable: indicate if the image can be selected
- :param bool draggable: indicate if the image can be moved
:param ~silx.gui.colors.Colormap colormap: Colormap object to use.
Ignored if data is RGB(A).
:param float alpha: Opacity of the image, as a float in range [0, 1].
:returns: The handle used by the backend to univocally access the image
"""
- return legend
+ return object()
- def addTriangles(self, x, y, triangles, legend,
- color, z, selectable, alpha):
+ def addTriangles(self, x, y, triangles,
+ color, z, alpha):
"""Add a set of triangles.
:param numpy.ndarray x: The data corresponding to the x axis
:param numpy.ndarray y: The data corresponding to the y axis
:param numpy.ndarray triangles: The indices to make triangles
as a (Ntriangle, 3) array
- :param str legend: The legend to be associated to the curve
:param numpy.ndarray color: color(s) as (npoints, 4) array
:param int z: Layer on which to draw the cuve
- :param bool selectable: indicate if the curve can be selected
:param float alpha: Opacity as a float in [0., 1.]
:returns: The triangles' unique identifier used by the backend
"""
- return legend
+ return object()
- def addItem(self, x, y, legend, shape, color, fill, overlay, z,
+ def addItem(self, x, y, shape, color, fill, overlay, z,
linestyle, linewidth, linebgcolor):
"""Add an item (i.e. a shape) to the plot.
:param numpy.ndarray x: The X coords of the points of the shape
:param numpy.ndarray y: The Y coords of the points of the shape
- :param str legend: The legend to be associated to the item
:param str shape: Type of item to be drawn in
hline, polygon, rectangle, vline, polylines
:param str color: Color of the item
@@ -215,22 +206,18 @@ class BackendBase(object):
'#FF0000'. It is used to draw dotted line using a second color.
:returns: The handle used by the backend to univocally access the item
"""
- return legend
+ return object()
- def addMarker(self, x, y, legend, text, color,
- selectable, draggable,
- symbol, linestyle, linewidth, constraint):
+ def addMarker(self, x, y, text, color,
+ symbol, linestyle, linewidth, constraint, yaxis):
"""Add a point, vertical line or horizontal line marker to the plot.
:param float x: Horizontal position of the marker in graph coordinates.
If None, the marker is a horizontal line.
:param float y: Vertical position of the marker in graph coordinates.
If None, the marker is a vertical line.
- :param str legend: Legend associated to the marker
:param str text: Text associated to the marker (or None for no text)
:param str color: Color to be used for instance 'blue', 'b', '#FF0000'
- :param bool selectable: indicate if the marker can be selected
- :param bool draggable: indicate if the marker can be moved
:param str symbol: Symbol representing the marker.
Only relevant for point markers where X and Y are not None.
Value in:
@@ -257,13 +244,13 @@ class BackendBase(object):
dragging operations or None for no filter.
This function is called each time a marker is
moved.
- This parameter is only used if draggable is True.
:type constraint: None or a callable that takes the coordinates of
the current cursor position in the plot as input
and that returns the filtered coordinates.
+ :param str yaxis: The Y axis this marker belongs to in: 'left', 'right'
:return: Handle used by the backend to univocally access the marker
"""
- return legend
+ return object()
# Remove methods
@@ -307,22 +294,40 @@ class BackendBase(object):
"""
pass
- def pickItems(self, x, y, kinds):
- """Get a list of items at a pixel position.
+ def getItemsFromBackToFront(self, condition=None):
+ """Returns the list of plot items order as rendered by the backend.
+
+ This is the order used for rendering.
+ By default, it takes into account overlays, z value and order of addition of items,
+ but backends can override it.
+
+ :param callable condition:
+ Callable taking an item as input and returning False for items to skip.
+ If None (default), no item is skipped.
+ :rtype: List[~silx.gui.plot.items.Item]
+ """
+ # Sort items: Overlays first, then others
+ # and in each category ordered by z and then by order of addition
+ # as content keeps this order.
+ content = self._plot.getItems()
+ if condition is not None:
+ content = [item for item in content if condition(item)]
+
+ return sorted(
+ content,
+ key=lambda i: ((1 if i.isOverlay() else 0), i.getZValue()))
+
+ def pickItem(self, x, y, item):
+ """Return picked indices if any, or None.
:param float x: The x pixel coord where to pick.
:param float y: The y pixel coord where to pick.
- :param List[str] kind: List of item kinds to pick.
- Supported kinds: 'marker', 'curve', 'image'.
- :return: All picked items from back to front.
- One dict per item,
- with 'kind' key in 'curve', 'marker', 'image';
- 'legend' key, the item legend.
- and for curves, 'xdata' and 'ydata' keys storing picked
- position on the curve.
- :rtype: list of dict
- """
- return []
+ :param item: A backend item created with add* methods.
+ :return: None if item was not picked, else returns
+ picked indices information.
+ :rtype: Union[None,List]
+ """
+ return None
# Update curve
diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index 7739329..075f6aa 100644..100755
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -56,12 +56,13 @@ from matplotlib.collections import PathCollection, LineCollection
from matplotlib.ticker import Formatter, ScalarFormatter, Locator
from matplotlib.tri import Triangulation
from matplotlib.collections import TriMesh
+from matplotlib import path as mpath
from . import BackendBase
+from .. import items
from .._utils import FLOAT32_MINPOS
from .._utils.dtime_ticklayout import calcTicks, bestFormatString, timestamp
-
_PATCH_LINESTYLE = {
"-": 'solid',
"--": 'dashed',
@@ -72,11 +73,54 @@ _PATCH_LINESTYLE = {
}
"""Patches do not uses the same matplotlib syntax"""
+_MARKER_PATHS = {}
+"""Store cached extra marker paths"""
+
+_SPECIAL_MARKERS = {
+ 'tickleft': 0,
+ 'tickright': 1,
+ 'tickup': 2,
+ 'tickdown': 3,
+ 'caretleft': 4,
+ 'caretright': 5,
+ 'caretup': 6,
+ 'caretdown': 7,
+}
+
def normalize_linestyle(linestyle):
"""Normalize known old-style linestyle, else return the provided value."""
return _PATCH_LINESTYLE.get(linestyle, linestyle)
+def get_path_from_symbol(symbol):
+ """Get the path representation of a symbol, else None if
+ it is not provided.
+
+ :param str symbol: Symbol description used by silx
+ :rtype: Union[None,matplotlib.path.Path]
+ """
+ if symbol == u'\u2665':
+ path = _MARKER_PATHS.get(symbol, None)
+ if path is not None:
+ return path
+ vertices = numpy.array([
+ [0,-99],
+ [31,-73], [47,-55], [55,-46],
+ [63,-37], [94,-2], [94,33],
+ [94,69], [71,89], [47,89],
+ [24,89], [8,74], [0,58],
+ [-8,74], [-24,89], [-47,89],
+ [-71,89], [-94,69], [-94,33],
+ [-94,-2], [-63,-37], [-55,-46],
+ [-47,-55], [-31,-73], [0,-99],
+ [0,-99]])
+ codes = [mpath.Path.CURVE4] * len(vertices)
+ codes[0] = mpath.Path.MOVETO
+ codes[-1] = mpath.Path.CLOSEPOLY
+ path = mpath.Path(vertices, codes)
+ _MARKER_PATHS[symbol] = path
+ return path
+ return None
class NiceDateLocator(Locator):
"""
@@ -162,7 +206,53 @@ class NiceAutoDateFormatter(Formatter):
return tickStr
-class _MarkerContainer(Container):
+class _PickableContainer(Container):
+ """Artists container with a :meth:`contains` method"""
+
+ def __init__(self, *args, **kwargs):
+ Container.__init__(self, *args, **kwargs)
+ self.__zorder = None
+
+ @property
+ def axes(self):
+ """Mimin Artist.axes"""
+ for child in self.get_children():
+ if hasattr(child, 'axes'):
+ return child.axes
+ return None
+
+ def draw(self, *args, **kwargs):
+ """artist-like draw to broadcast draw to children"""
+ for child in self.get_children():
+ child.draw(*args, **kwargs)
+
+ def get_zorder(self):
+ """Mimic Artist.get_zorder"""
+ return self.__zorder
+
+ def set_zorder(self, z):
+ """Mimic Artist.set_zorder to broadcast to children"""
+ if z != self.__zorder:
+ self.__zorder = z
+ for child in self.get_children():
+ child.set_zorder(z)
+
+ def contains(self, mouseevent):
+ """Mimic Artist.contains, and call it on all children.
+
+ :param mouseevent:
+ :return: Picking status and associated information as a dict
+ :rtype: (bool,dict)
+ """
+ # Goes through children from front to back and return first picked one.
+ for child in reversed(self.get_children()):
+ picked, info = child.contains(mouseevent)
+ if picked:
+ return picked, info
+ return False, {}
+
+
+class _MarkerContainer(_PickableContainer):
"""Marker artists container supporting draw/remove and text position update
:param artists:
@@ -173,13 +263,14 @@ class _MarkerContainer(Container):
:param y: Y coordinate of the marker (None for vertical lines)
"""
- def __init__(self, artists, x, y):
+ def __init__(self, artists, x, y, yAxis):
self.line = artists[0]
self.text = artists[1] if len(artists) > 1 else None
self.x = x
self.y = y
+ self.yAxis = yAxis
- Container.__init__(self, artists)
+ _PickableContainer.__init__(self, artists)
def draw(self, *args, **kwargs):
"""artist-like draw to broadcast draw to line and text"""
@@ -214,6 +305,15 @@ class _MarkerContainer(Container):
xmax -= 0.005 * delta
self.text.set_x(xmax)
+ def contains(self, mouseevent):
+ """Mimic Artist.contains, and call it on the line Artist.
+
+ :param mouseevent:
+ :return: Picking status and associated information as a dict
+ :rtype: (bool,dict)
+ """
+ return self.line.contains(mouseevent)
+
class _DoubleColoredLinePatch(matplotlib.patches.Patch):
"""Matplotlib patch to display any patch using double color."""
@@ -294,7 +394,11 @@ class BackendMatplotlib(BackendBase.BackendBase):
self.ax2 = self.ax.twinx()
self.ax2.set_label("right")
# Make sure background of Axes is displayed
- self.ax2.patch.set_visible(True)
+ self.ax2.patch.set_visible(False)
+ self.ax.patch.set_visible(True)
+
+ # Set axis zorder=0.5 so grid is displayed at 0.5
+ self.ax.set_axisbelow(True)
# disable the use of offsets
try:
@@ -306,10 +410,8 @@ class BackendMatplotlib(BackendBase.BackendBase):
_logger.warning('Cannot disabled axes offsets in %s '
% matplotlib.__version__)
- # critical for picking!!!!
- self.ax2.set_zorder(0)
self.ax2.set_autoscaley_on(True)
- self.ax.set_zorder(1)
+
# this works but the figure color is left
if self._matplotlibVersion < _parse_version('2'):
self.ax.set_axis_bgcolor('none')
@@ -317,7 +419,6 @@ class BackendMatplotlib(BackendBase.BackendBase):
self.ax.set_facecolor('none')
self.fig.sca(self.ax)
- self._overlays = set()
self._background = None
self._colormaps = {}
@@ -327,15 +428,67 @@ class BackendMatplotlib(BackendBase.BackendBase):
self._enableAxis('right', False)
self._isXAxisTimeSeries = False
+ def getItemsFromBackToFront(self, condition=None):
+ """Order as BackendBase + take into account matplotlib Axes structure"""
+ def axesOrder(item):
+ if item.isOverlay():
+ return 2
+ elif isinstance(item, items.YAxisMixIn) and item.getYAxis() == 'right':
+ return 1
+ else:
+ return 0
+
+ return sorted(
+ BackendBase.BackendBase.getItemsFromBackToFront(
+ self, condition=condition),
+ key=axesOrder)
+
+ def _overlayItems(self):
+ """Generator of backend renderer for overlay items"""
+ for item in self._plot.getItems():
+ if (item.isOverlay() and
+ item.isVisible() and
+ item._backendRenderer is not None):
+ yield item._backendRenderer
+
+ def _hasOverlays(self):
+ """Returns whether there is an overlay layer or not.
+
+ The overlay layers contains overlay items and the crosshair.
+
+ :rtype: bool
+ """
+ if self._graphCursor:
+ return True # There is the crosshair
+
+ for item in self._overlayItems():
+ return True # There is at least one overlay item
+ return False
+
# Add methods
- def addCurve(self, x, y, legend,
+ def _getMarkerFromSymbol(self, symbol):
+ """Returns a marker that can be displayed by matplotlib.
+
+ :param str symbol: A symbol description used by silx
+ :rtype: Union[str,int,matplotlib.path.Path]
+ """
+ path = get_path_from_symbol(symbol)
+ if path is not None:
+ return path
+ num = _SPECIAL_MARKERS.get(symbol, None)
+ if num is not None:
+ return num
+ # This symbol must be supported by matplotlib
+ return symbol
+
+ def addCurve(self, x, y,
color, symbol, linewidth, linestyle,
yaxis,
- xerror, yerror, z, selectable,
- fill, alpha, symbolsize):
- for parameter in (x, y, legend, color, symbol, linewidth, linestyle,
- yaxis, z, selectable, fill, alpha, symbolsize):
+ xerror, yerror, z,
+ fill, alpha, symbolsize, baseline):
+ for parameter in (x, y, color, symbol, linewidth, linestyle,
+ yaxis, z, fill, alpha, symbolsize):
assert parameter is not None
assert yaxis in ('left', 'right')
@@ -349,7 +502,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
else:
axes = self.ax
- picker = 3 if selectable else None
+ picker = 3
artists = [] # All the artists composing the curve
@@ -368,7 +521,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
yerror.shape[1] == 1):
yerror = numpy.ravel(yerror)
- errorbars = axes.errorbar(x, y, label=legend,
+ errorbars = axes.errorbar(x, y,
xerr=xerror, yerr=yerror,
linestyle=' ', color=errorbarColor)
artists += list(errorbars.get_children())
@@ -383,7 +536,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
if linestyle not in ["", " ", None]:
# scatter plot with an actual line ...
# we need to assign a color ...
- curveList = axes.plot(x, y, label=legend,
+ curveList = axes.plot(x, y,
linestyle=linestyle,
color=actualColor[0],
linewidth=linewidth,
@@ -391,21 +544,24 @@ class BackendMatplotlib(BackendBase.BackendBase):
marker=None)
artists += list(curveList)
+ marker = self._getMarkerFromSymbol(symbol)
scatter = axes.scatter(x, y,
- label=legend,
color=actualColor,
- marker=symbol,
+ marker=marker,
picker=picker,
s=symbolsize**2)
artists.append(scatter)
if fill:
+ if baseline is None:
+ _baseline = FLOAT32_MINPOS
+ else:
+ _baseline = baseline
artists.append(axes.fill_between(
- x, FLOAT32_MINPOS, y, facecolor=actualColor[0], linestyle=''))
+ x, _baseline, y, facecolor=actualColor[0], linestyle=''))
else: # Curve
curveList = axes.plot(x, y,
- label=legend,
linestyle=linestyle,
color=color,
linewidth=linewidth,
@@ -415,40 +571,35 @@ class BackendMatplotlib(BackendBase.BackendBase):
artists += list(curveList)
if fill:
+ if baseline is None:
+ _baseline = FLOAT32_MINPOS
+ else:
+ _baseline = baseline
artists.append(
- axes.fill_between(x, FLOAT32_MINPOS, y, facecolor=color))
+ axes.fill_between(x, _baseline, y, facecolor=color))
for artist in artists:
- artist.set_zorder(z)
if alpha < 1:
artist.set_alpha(alpha)
- return Container(artists)
+ return _PickableContainer(artists)
- def addImage(self, data, legend,
- origin, scale, z,
- selectable, draggable,
- colormap, alpha):
+ def addImage(self, data, origin, scale, z, colormap, alpha):
# Non-uniform image
# http://wiki.scipy.org/Cookbook/Histograms
# Non-linear axes
# http://stackoverflow.com/questions/11488800/non-linear-axes-for-imshow-in-matplotlib
- for parameter in (data, legend, origin, scale, z,
- selectable, draggable):
+ for parameter in (data, origin, scale, z):
assert parameter is not None
origin = float(origin[0]), float(origin[1])
scale = float(scale[0]), float(scale[1])
height, width = data.shape[0:2]
- picker = (selectable or draggable)
-
# All image are shown as RGBA image
image = Image(self.ax,
- label="__IMAGE__" + legend,
interpolation='nearest',
- picker=picker,
- zorder=z,
+ picker=True,
origin='lower')
if alpha < 1:
@@ -481,15 +632,10 @@ class BackendMatplotlib(BackendBase.BackendBase):
self.ax.add_artist(image)
return image
- def addTriangles(self, x, y, triangles, legend,
- color, z, selectable, alpha):
- for parameter in (x, y, triangles, legend, color,
- z, selectable, alpha):
+ def addTriangles(self, x, y, triangles, color, z, alpha):
+ for parameter in (x, y, triangles, color, z, alpha):
assert parameter is not None
- # 0 enables picking on filled triangle
- picker = 0 if selectable else None
-
color = numpy.array(color, copy=False)
assert color.ndim == 2 and len(color) == len(x)
@@ -498,16 +644,14 @@ class BackendMatplotlib(BackendBase.BackendBase):
collection = TriMesh(
Triangulation(x, y, triangles),
- label=legend,
alpha=alpha,
- picker=picker,
- zorder=z)
+ picker=0) # 0 enables picking on filled triangle
collection.set_color(color)
self.ax.add_collection(collection)
return collection
- def addItem(self, x, y, legend, shape, color, fill, overlay, z,
+ def addItem(self, x, y, shape, color, fill, overlay, z,
linestyle, linewidth, linebgcolor):
if (linebgcolor is not None and
shape not in ('rectangle', 'polygon', 'polylines')):
@@ -520,20 +664,20 @@ class BackendMatplotlib(BackendBase.BackendBase):
linestyle = normalize_linestyle(linestyle)
if shape == "line":
- item = self.ax.plot(x, y, label=legend, color=color,
+ item = self.ax.plot(x, y, color=color,
linestyle=linestyle, linewidth=linewidth,
marker=None)[0]
elif shape == "hline":
if hasattr(y, "__len__"):
y = y[-1]
- item = self.ax.axhline(y, label=legend, color=color,
+ item = self.ax.axhline(y, color=color,
linestyle=linestyle, linewidth=linewidth)
elif shape == "vline":
if hasattr(x, "__len__"):
x = x[-1]
- item = self.ax.axvline(x, label=legend, color=color,
+ item = self.ax.axvline(x, color=color,
linestyle=linestyle, linewidth=linewidth)
elif shape == 'rectangle':
@@ -568,7 +712,6 @@ class BackendMatplotlib(BackendBase.BackendBase):
item = Polygon(points,
closed=closed,
fill=False,
- label=legend,
color=color,
linestyle=linestyle,
linewidth=linewidth)
@@ -584,30 +727,32 @@ class BackendMatplotlib(BackendBase.BackendBase):
else:
raise NotImplementedError("Unsupported item shape %s" % shape)
- item.set_zorder(z)
-
if overlay:
item.set_animated(True)
- self._overlays.add(item)
return item
- def addMarker(self, x, y, legend, text, color,
- selectable, draggable,
- symbol, linestyle, linewidth, constraint):
- legend = "__MARKER__" + legend
-
+ def addMarker(self, x, y, text, color,
+ symbol, linestyle, linewidth, constraint, yaxis):
textArtist = None
xmin, xmax = self.getGraphXLimits()
- ymin, ymax = self.getGraphYLimits(axis='left')
+ ymin, ymax = self.getGraphYLimits(axis=yaxis)
+
+ if yaxis == 'left':
+ ax = self.ax
+ elif yaxis == 'right':
+ ax = self.ax2
+ else:
+ assert(False)
+ marker = self._getMarkerFromSymbol(symbol)
if x is not None and y is not None:
- line = self.ax.plot(x, y, label=legend,
- linestyle=" ",
- color=color,
- marker=symbol,
- markersize=10.)[-1]
+ line = ax.plot(x, y,
+ linestyle=" ",
+ color=color,
+ marker=marker,
+ markersize=10.)[-1]
if text is not None:
if symbol is None:
@@ -616,43 +761,40 @@ class BackendMatplotlib(BackendBase.BackendBase):
valign = 'top'
text = " " + text
- textArtist = self.ax.text(x, y, text,
- color=color,
- horizontalalignment='left',
- verticalalignment=valign)
+ textArtist = ax.text(x, y, text,
+ color=color,
+ horizontalalignment='left',
+ verticalalignment=valign)
elif x is not None:
- line = self.ax.axvline(x,
- label=legend,
- color=color,
- linewidth=linewidth,
- linestyle=linestyle)
+ line = ax.axvline(x,
+ color=color,
+ linewidth=linewidth,
+ linestyle=linestyle)
if text is not None:
# Y position will be updated in updateMarkerText call
- textArtist = self.ax.text(x, 1., " " + text,
- color=color,
- horizontalalignment='left',
- verticalalignment='top')
+ textArtist = ax.text(x, 1., " " + text,
+ color=color,
+ horizontalalignment='left',
+ verticalalignment='top')
elif y is not None:
- line = self.ax.axhline(y,
- label=legend,
- color=color,
- linewidth=linewidth,
- linestyle=linestyle)
+ line = ax.axhline(y,
+ color=color,
+ linewidth=linewidth,
+ linestyle=linestyle)
if text is not None:
# X position will be updated in updateMarkerText call
- textArtist = self.ax.text(1., y, " " + text,
- color=color,
- horizontalalignment='right',
- verticalalignment='top')
+ textArtist = ax.text(1., y, " " + text,
+ color=color,
+ horizontalalignment='right',
+ verticalalignment='top')
else:
raise RuntimeError('A marker must at least have one coordinate')
- if selectable or draggable:
- line.set_picker(5)
+ line.set_picker(5)
# All markers are overlays
line.set_animated(True)
@@ -660,24 +802,25 @@ class BackendMatplotlib(BackendBase.BackendBase):
textArtist.set_animated(True)
artists = [line] if textArtist is None else [line, textArtist]
- container = _MarkerContainer(artists, x, y)
+ container = _MarkerContainer(artists, x, y, yaxis)
container.updateMarkerText(xmin, xmax, ymin, ymax)
- self._overlays.add(container)
return container
def _updateMarkers(self):
xmin, xmax = self.ax.get_xbound()
- ymin, ymax = self.ax.get_ybound()
- for item in self._overlays:
+ ymin1, ymax1 = self.ax.get_ybound()
+ ymin2, ymax2 = self.ax2.get_ybound()
+ for item in self._overlayItems():
if isinstance(item, _MarkerContainer):
- item.updateMarkerText(xmin, xmax, ymin, ymax)
+ if item.yAxis == 'left':
+ item.updateMarkerText(xmin, xmax, ymin1, ymax1)
+ else:
+ item.updateMarkerText(xmin, xmax, ymin2, ymax2)
# Remove methods
def remove(self, item):
- # Warning: It also needs to remove extra stuff if added as for markers
- self._overlays.discard(item)
try:
item.remove()
except ValueError:
@@ -699,7 +842,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
self._graphCursor = lineh, linev
else:
- if self._graphCursor is not None:
+ if self._graphCursor:
lineh, linev = self._graphCursor
lineh.remove()
linev.remove()
@@ -746,7 +889,37 @@ class BackendMatplotlib(BackendBase.BackendBase):
if not self.ax2.lines:
self._enableAxis('right', False)
+ def _drawOverlays(self):
+ """Draw overlays if any."""
+ def condition(item):
+ return (item.isVisible() and
+ item._backendRenderer is not None and
+ item.isOverlay())
+
+ for item in self.getItemsFromBackToFront(condition=condition):
+ if (isinstance(item, items.YAxisMixIn) and
+ item.getYAxis() == 'right'):
+ axes = self.ax2
+ else:
+ axes = self.ax
+ axes.draw_artist(item._backendRenderer)
+
+ for item in self._graphCursor:
+ self.ax.draw_artist(item)
+
+ def updateZOrder(self):
+ """Reorder all items with z order from 0 to 1"""
+ items = self.getItemsFromBackToFront(
+ lambda item: item.isVisible() and item._backendRenderer is not None)
+ count = len(items)
+ for index, item in enumerate(items):
+ zorder = 1. + index / count
+ if zorder != item._backendRenderer.get_zorder():
+ item._backendRenderer.set_zorder(zorder)
+
def saveGraph(self, fileName, fileFormat, dpi):
+ self.updateZOrder()
+
# fileName can be also a StringIO or file instance
if dpi is not None:
self.fig.savefig(fileName, format=fileFormat, dpi=dpi)
@@ -788,7 +961,9 @@ class BackendMatplotlib(BackendBase.BackendBase):
def getGraphXLimits(self):
if self._dirtyLimits and self.isKeepDataAspectRatio():
- self.replot() # makes sure we get the right limits
+ self.ax.apply_aspect()
+ self.ax2.apply_aspect()
+ self._dirtyLimits = False
return self.ax.get_xbound()
def setGraphXLimits(self, xmin, xmax):
@@ -804,7 +979,9 @@ class BackendMatplotlib(BackendBase.BackendBase):
return None
if self._dirtyLimits and self.isKeepDataAspectRatio():
- self.replot() # makes sure we get the right limits
+ self.ax.apply_aspect()
+ self.ax2.apply_aspect()
+ self._dirtyLimits = False
return ax.get_ybound()
@@ -936,7 +1113,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
return xPixel, yPixel
- def pixelToData(self, x, y, axis, check):
+ def pixelToData(self, x, y, axis):
ax = self.ax2 if axis == "right" else self.ax
# Convert from Qt origin (top) to matplotlib origin (bottom)
@@ -944,14 +1121,6 @@ class BackendMatplotlib(BackendBase.BackendBase):
inv = ax.transData.inverted()
x, y = inv.transform_point((x, y))
-
- if check:
- xmin, xmax = self.getGraphXLimits()
- ymin, ymax = self.getGraphYLimits(axis=axis)
-
- if x > xmax or x < xmin or y > ymax or y < ymin:
- return None # (x, y) is out of plot area
-
return x, y
def getPlotBoundsInPixels(self):
@@ -996,12 +1165,12 @@ class BackendMatplotlib(BackendBase.BackendBase):
else:
dataBackgroundColor = backgroundColor
- if self.ax2.axison:
+ if self.ax.axison:
self.fig.patch.set_facecolor(backgroundColor)
if self._matplotlibVersion < _parse_version('2'):
- self.ax2.set_axis_bgcolor(dataBackgroundColor)
+ self.ax.set_axis_bgcolor(dataBackgroundColor)
else:
- self.ax2.set_facecolor(dataBackgroundColor)
+ self.ax.set_facecolor(dataBackgroundColor)
else:
self.fig.patch.set_facecolor(dataBackgroundColor)
@@ -1033,6 +1202,12 @@ class BackendMatplotlib(BackendBase.BackendBase):
line.set_color(gridColor)
# axes.grid().set_markeredgecolor(gridColor)
+ def setBackgroundColors(self, backgroundColor, dataBackgroundColor):
+ self._synchronizeBackgroundColors()
+
+ def setForegroundColors(self, foregroundColor, gridColor):
+ self._synchronizeForegroundColors()
+
class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
"""QWidget matplotlib backend using a QtAgg canvas.
@@ -1079,9 +1254,11 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
_MPL_TO_PLOT_BUTTONS = {1: 'left', 2: 'middle', 3: 'right'}
def _onMousePress(self, event):
- self._plot.onMousePress(
- event.x, self._mplQtYAxisCoordConversion(event.y),
- self._MPL_TO_PLOT_BUTTONS[event.button])
+ button = self._MPL_TO_PLOT_BUTTONS.get(event.button, None)
+ if button is not None:
+ self._plot.onMousePress(
+ event.x, self._mplQtYAxisCoordConversion(event.y),
+ button)
def _onMouseMove(self, event):
if self._graphCursor:
@@ -1102,9 +1279,11 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
event.x, self._mplQtYAxisCoordConversion(event.y))
def _onMouseRelease(self, event):
- self._plot.onMouseRelease(
- event.x, self._mplQtYAxisCoordConversion(event.y),
- self._MPL_TO_PLOT_BUTTONS[event.button])
+ button = self._MPL_TO_PLOT_BUTTONS.get(event.button, None)
+ if button is not None:
+ self._plot.onMouseRelease(
+ event.x, self._mplQtYAxisCoordConversion(event.y),
+ button)
def _onMouseWheel(self, event):
self._plot.onMouseWheel(
@@ -1116,58 +1295,31 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
# picking
- def _onPick(self, event):
- # TODO not very nice and fragile, find a better way?
- # Make a selection according to kind
- if self._picked is None:
- _logger.error('Internal picking error')
- return
-
- label = event.artist.get_label()
- if label.startswith('__MARKER__'):
- self._picked.append({'kind': 'marker', 'legend': label[10:]})
+ def pickItem(self, x, y, item):
+ mouseEvent = MouseEvent(
+ 'button_press_event', self, x, self._mplQtYAxisCoordConversion(y))
+ mouseEvent.inaxes = item.axes
+ picked, info = item.contains(mouseEvent)
- elif label.startswith('__IMAGE__'):
- self._picked.append({'kind': 'image', 'legend': label[9:]})
+ if not picked:
+ return None
- elif isinstance(event.artist, TriMesh):
+ elif isinstance(item, TriMesh):
# Convert selected triangle to data point indices
- triangulation = event.artist._triangulation
- indices = triangulation.get_masked_triangles()[event.ind[0]]
+ triangulation = item._triangulation
+ indices = triangulation.get_masked_triangles()[info['ind'][0]]
# Sort picked triangle points by distance to mouse
# from furthest to closest to put closest point last
# This is to be somewhat consistent with last scatter point
# being the top one.
- dists = ((triangulation.x[indices] - event.mouseevent.xdata) ** 2 +
- (triangulation.y[indices] - event.mouseevent.ydata) ** 2)
- indices = indices[numpy.flip(numpy.argsort(dists))]
-
- self._picked.append({'kind': 'curve', 'legend': label,
- 'indices': indices})
+ xdata, ydata = self.pixelToData(x, y, axis='left')
+ dists = ((triangulation.x[indices] - xdata) ** 2 +
+ (triangulation.y[indices] - ydata) ** 2)
+ return indices[numpy.flip(numpy.argsort(dists), axis=0)]
- else: # it's a curve, item have no picker for now
- if not isinstance(event.artist, (PathCollection, Line2D)):
- _logger.info('Unsupported artist, ignored')
- return
-
- self._picked.append({'kind': 'curve', 'legend': label,
- 'indices': event.ind})
-
- def pickItems(self, x, y, kinds):
- self._picked = []
-
- # Weird way to do an explicit picking: Simulate a button press event
- mouseEvent = MouseEvent('button_press_event',
- self, x, self._mplQtYAxisCoordConversion(y))
- cid = self.mpl_connect('pick_event', self._onPick)
- self.fig.pick(mouseEvent)
- self.mpl_disconnect(cid)
-
- picked = [p for p in self._picked if p['kind'] in kinds]
- self._picked = None
-
- return picked
+ else: # Returns indices if any
+ return info.get('ind', ())
# replot control
@@ -1177,22 +1329,10 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
self.ax.get_xbound(), self.ax.get_ybound(), self.ax2.get_ybound())
FigureCanvasQTAgg.resizeEvent(self, event)
- if self.isKeepDataAspectRatio() or self._overlays or self._graphCursor:
+ if self.isKeepDataAspectRatio() or self._hasOverlays():
# This is needed with matplotlib 1.5.x and 2.0.x
self._plot._setDirtyPlot()
- def _drawOverlays(self):
- """Draw overlays if any."""
- if self._overlays or self._graphCursor:
- # There is some overlays or crosshair
-
- # This assume that items are only on left/bottom Axes
- for item in self._overlays:
- self.ax.draw_artist(item)
-
- for item in self._graphCursor:
- self.ax.draw_artist(item)
-
def draw(self):
"""Overload draw
@@ -1201,6 +1341,8 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
This is directly called by matplotlib for widget resize.
"""
+ self.updateZOrder()
+
# Starting with mpl 2.1.0, toggling autoscale raises a ValueError
# in some situations. See #1081, #1136, #1163,
if self._matplotlibVersion >= _parse_version("2.0.0"):
@@ -1213,7 +1355,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
else:
FigureCanvasQTAgg.draw(self)
- if self._overlays or self._graphCursor:
+ if self._hasOverlays():
# Save background
self._background = self.copy_from_bbox(self.fig.bbox)
else:
@@ -1257,7 +1399,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
if (_parse_version('1.5') <= self._matplotlibVersion < _parse_version('2.1') and
not hasattr(self, '_firstReplot')):
self._firstReplot = False
- if self._overlays or self._graphCursor:
+ if self._hasOverlays():
qt.QTimer.singleShot(0, self.draw) # Request async draw
# cursor
@@ -1276,9 +1418,3 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
else:
cursor = self._QT_CURSORS[cursor]
FigureCanvasQTAgg.setCursor(self, qt.QCursor(cursor))
-
- def setBackgroundColors(self, backgroundColor, dataBackgroundColor):
- self._synchronizeBackgroundColors()
-
- def setForegroundColors(self, foregroundColor, gridColor):
- self._synchronizeForegroundColors()
diff --git a/silx/gui/plot/backends/BackendOpenGL.py b/silx/gui/plot/backends/BackendOpenGL.py
index 0420aa9..27f3894 100644..100755
--- a/silx/gui/plot/backends/BackendOpenGL.py
+++ b/silx/gui/plot/backends/BackendOpenGL.py
@@ -30,13 +30,13 @@ __authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "21/12/2018"
-from collections import OrderedDict, namedtuple
import logging
import warnings
import weakref
import numpy
+from .. import items
from .._utils import FLOAT32_MINPOS
from . import BackendBase
from ... import colors
@@ -59,186 +59,66 @@ _logger = logging.getLogger(__name__)
# TODO check if OpenGL is available
# TODO make an off-screen mesa backend
-# Bounds ######################################################################
-
-class Range(namedtuple('Range', ('min_', 'max_'))):
- """Describes a 1D range"""
-
- @property
- def range_(self):
- return self.max_ - self.min_
-
- @property
- def center(self):
- return 0.5 * (self.min_ + self.max_)
-
-
-class Bounds(object):
- """Describes plot bounds with 2 y axis"""
-
- def __init__(self, xMin, xMax, yMin, yMax, y2Min, y2Max):
- self._xAxis = Range(xMin, xMax)
- self._yAxis = Range(yMin, yMax)
- self._y2Axis = Range(y2Min, y2Max)
-
- def __repr__(self):
- return "x: %s, y: %s, y2: %s" % (repr(self._xAxis),
- repr(self._yAxis),
- repr(self._y2Axis))
-
- @property
- def xAxis(self):
- return self._xAxis
-
- @property
- def yAxis(self):
- return self._yAxis
-
- @property
- def y2Axis(self):
- return self._y2Axis
-
-
# Content #####################################################################
-class PlotDataContent(object):
- """Manage plot data content: images and curves.
-
- This class is only meant to work with _OpenGLPlotCanvas.
- """
-
- _PRIMITIVE_TYPES = 'curve', 'image', 'triangles'
-
- def __init__(self):
- self._primitives = OrderedDict() # For images and curves
-
- def add(self, primitive):
- """Add a curve or image to the content dictionary.
-
- This function generates the key in the dict from the primitive.
-
- :param primitive: The primitive to add.
- :type primitive: Instance of GLPlotCurve2D, GLPlotColormap,
- GLPlotRGBAImage.
- """
- if isinstance(primitive, GLPlotCurve2D):
- primitiveType = 'curve'
- elif isinstance(primitive, (GLPlotColormap, GLPlotRGBAImage)):
- primitiveType = 'image'
- elif isinstance(primitive, GLPlotTriangles):
- primitiveType = 'triangles'
- else:
- raise RuntimeError('Unsupported object type: %s', primitive)
-
- key = primitiveType, primitive.info['legend']
- self._primitives[key] = primitive
+class _ShapeItem(dict):
+ def __init__(self, x, y, shape, color, fill, overlay, z,
+ linestyle, linewidth, linebgcolor):
+ super(_ShapeItem, self).__init__()
- def get(self, primitiveType, legend):
- """Get the corresponding primitive of given type with given legend.
+ if shape not in ('polygon', 'rectangle', 'line',
+ 'vline', 'hline', 'polylines'):
+ raise NotImplementedError("Unsupported shape {0}".format(shape))
- :param str primitiveType: Type of primitive ('curve' or 'image').
- :param str legend: The legend of the primitive to retrieve.
- :return: The corresponding curve or None if no such curve.
- """
- assert primitiveType in self._PRIMITIVE_TYPES
- return self._primitives.get((primitiveType, legend))
+ x = numpy.array(x, copy=False)
+ y = numpy.array(y, copy=False)
- def pop(self, primitiveType, key):
- """Pop the corresponding curve or return None if no such curve.
+ if shape == 'rectangle':
+ xMin, xMax = x
+ x = numpy.array((xMin, xMin, xMax, xMax))
+ yMin, yMax = y
+ y = numpy.array((yMin, yMax, yMax, yMin))
- :param str primitiveType:
- :param str key:
- :return:
- """
- assert primitiveType in self._PRIMITIVE_TYPES
- return self._primitives.pop((primitiveType, key), None)
+ # Ignore fill for polylines to mimic matplotlib
+ fill = fill if shape != 'polylines' else False
- def zOrderedPrimitives(self, reverse=False):
- """List of primitives sorted according to their z order.
+ self.update({
+ 'shape': shape,
+ 'color': colors.rgba(color),
+ 'fill': 'hatch' if fill else None,
+ 'x': x,
+ 'y': y,
+ 'linestyle': linestyle,
+ 'linewidth': linewidth,
+ 'linebgcolor': linebgcolor,
+ })
- It is a stable sort (as sorted):
- Original order is preserved when key is the same.
- :param bool reverse: Ascending (True, default) or descending (False).
- """
- return sorted(self._primitives.values(),
- key=lambda primitive: primitive.info['zOrder'],
- reverse=reverse)
-
- def primitives(self):
- """Iterator over all primitives."""
- return self._primitives.values()
-
- def primitiveKeys(self, primitiveType):
- """Iterator over primitives of a specific type."""
- assert primitiveType in self._PRIMITIVE_TYPES
- for type_, key in self._primitives.keys():
- if type_ == primitiveType:
- yield key
-
- def getBounds(self, xPositive=False, yPositive=False):
- """Bounds of the data.
-
- Can return strictly positive bounds (for log scale).
- In this case, curves are clipped to their smaller positive value
- and images with negative min are ignored.
-
- :param bool xPositive: True to get strictly positive range.
- :param bool yPositive: True to get strictly positive range.
- :return: The range of data for x, y and y2, or default (1., 100.)
- if no range found for one dimension.
- :rtype: Bounds
- """
- xMin, yMin, y2Min = float('inf'), float('inf'), float('inf')
- xMax = 0. if xPositive else -float('inf')
- if yPositive:
- yMax, y2Max = 0., 0.
- else:
- yMax, y2Max = -float('inf'), -float('inf')
-
- for item in self._primitives.values():
- # To support curve <= 0. and log and bypass images:
- # If positive only, uses x|yMinPos if available
- # and bypass other data with negative min bounds
- if xPositive:
- itemXMin = getattr(item, 'xMinPos', item.xMin)
- if itemXMin is None or itemXMin < FLOAT32_MINPOS:
- continue
- else:
- itemXMin = item.xMin
+class _MarkerItem(dict):
+ def __init__(self, x, y, text, color,
+ symbol, linestyle, linewidth, constraint, yaxis):
+ super(_MarkerItem, self).__init__()
- if yPositive:
- itemYMin = getattr(item, 'yMinPos', item.yMin)
- if itemYMin is None or itemYMin < FLOAT32_MINPOS:
- continue
- else:
- itemYMin = item.yMin
-
- if itemXMin < xMin:
- xMin = itemXMin
- if item.xMax > xMax:
- xMax = item.xMax
-
- if item.info.get('yAxis') == 'right':
- if itemYMin < y2Min:
- y2Min = itemYMin
- if item.yMax > y2Max:
- y2Max = item.yMax
- else:
- if itemYMin < yMin:
- yMin = itemYMin
- if item.yMax > yMax:
- yMax = item.yMax
+ if symbol is None:
+ symbol = '+'
- # One of the limit has not been updated, return default range
- if xMin >= xMax:
- xMin, xMax = 1., 100.
- if yMin >= yMax:
- yMin, yMax = 1., 100.
- if y2Min >= y2Max:
- y2Min, y2Max = 1., 100.
+ # Apply constraint to provided position
+ isConstraint = (constraint is not None and
+ x is not None and y is not None)
+ if isConstraint:
+ x, y = constraint(x, y)
- return Bounds(xMin, xMax, yMin, yMax, y2Min, y2Max)
+ self.update({
+ 'x': x,
+ 'y': y,
+ 'text': text,
+ 'color': colors.rgba(color),
+ 'constraint': constraint if isConstraint else None,
+ 'symbol': symbol,
+ 'linestyle': linestyle,
+ 'linewidth': linewidth,
+ 'yaxis': yaxis,
+ })
# shaders #####################################################################
@@ -350,9 +230,6 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
self._crosshairCursor = None
self._mousePosInPixels = None
- self._markers = OrderedDict()
- self._items = OrderedDict()
- self._plotContent = PlotDataContent() # For images and curves
self._glGarbageCollector = []
self._plotFrame = GLPlotFrame2D(
@@ -457,7 +334,6 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
def _paintDirectGL(self):
self._renderPlotAreaGL()
self._plotFrame.render()
- self._renderMarkersGL()
self._renderOverlayGL()
def _paintFBOGL(self):
@@ -522,7 +398,6 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
with plotFBOTex.texture:
gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, len(self._plotVertices[0]))
- self._renderMarkersGL()
self._renderOverlayGL()
def paintGL(self):
@@ -543,120 +418,203 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# self._paintDirectGL()
self._paintFBOGL()
- def _renderMarkersGL(self):
- if len(self._markers) == 0:
- return
+ def _renderItems(self, overlay=False):
+ """Render items according to :class:`PlotWidget` order
- plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
+ Note: Scissor test should already be set.
- # Render in plot area
- gl.glScissor(self._plotFrame.margins.left,
- self._plotFrame.margins.bottom,
- plotWidth, plotHeight)
- gl.glEnable(gl.GL_SCISSOR_TEST)
-
- gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
+ :param bool overlay:
+ False (the default) to render item that are not overlays.
+ True to render items that are overlays.
+ """
+ # Values that are often used
+ plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
+ isXLog = self._plotFrame.xAxis.isLog
+ isYLog = self._plotFrame.yAxis.isLog
+ # Used by marker rendering
labels = []
pixelOffset = 3
- for marker in self._markers.values():
- xCoord, yCoord = marker['x'], marker['y']
-
- if ((self._plotFrame.xAxis.isLog and
- xCoord is not None and
- xCoord <= 0) or
- (self._plotFrame.yAxis.isLog and
- yCoord is not None and
- yCoord <= 0)):
- # Do not render markers with negative coords on log axis
+ for plotItem in self.getItemsFromBackToFront(
+ condition=lambda i: i.isVisible() and i.isOverlay() == overlay):
+ if plotItem._backendRenderer is None:
continue
- if xCoord is None or yCoord is None:
- pixelPos = self.dataToPixel(
- xCoord, yCoord, axis='left', check=False)
-
- if xCoord is None: # Horizontal line in data space
- if marker['text'] is not None:
- x = self._plotFrame.size[0] - \
- self._plotFrame.margins.right - pixelOffset
- y = pixelPos[1] - pixelOffset
- label = Text2D(marker['text'], x, y,
- color=marker['color'],
- bgColor=(1., 1., 1., 0.5),
- align=RIGHT, valign=BOTTOM)
- labels.append(label)
+ item = plotItem._backendRenderer
+
+ if isinstance(item, (GLPlotCurve2D,
+ GLPlotColormap,
+ GLPlotRGBAImage,
+ GLPlotTriangles)): # Render data items
+ gl.glViewport(self._plotFrame.margins.left,
+ self._plotFrame.margins.bottom,
+ plotWidth, plotHeight)
+ if isinstance(item, GLPlotCurve2D) and item.info.get('yAxis') == 'right':
+ item.render(self._plotFrame.transformedDataY2ProjMat,
+ isXLog, isYLog)
+ else:
+ item.render(self._plotFrame.transformedDataProjMat,
+ isXLog, isYLog)
+
+ elif isinstance(item, _ShapeItem): # Render shape items
+ gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
+
+ if ((isXLog and numpy.min(item['x']) < FLOAT32_MINPOS) or
+ (isYLog and numpy.min(item['y']) < FLOAT32_MINPOS)):
+ # Ignore items <= 0. on log axes
+ continue
+
+ if item['shape'] == 'hline':
width = self._plotFrame.size[0]
- lines = GLLines2D((0, width), (pixelPos[1], pixelPos[1]),
- style=marker['linestyle'],
- color=marker['color'],
- width=marker['linewidth'])
+ _, yPixel = self._plot.dataToPixel(
+ None, item['y'], axis='left', check=False)
+ points = numpy.array(((0., yPixel), (width, yPixel)),
+ dtype=numpy.float32)
+
+ elif item['shape'] == 'vline':
+ xPixel, _ = self._plot.dataToPixel(
+ item['x'], None, axis='left', check=False)
+ height = self._plotFrame.size[1]
+ points = numpy.array(((xPixel, 0), (xPixel, height)),
+ dtype=numpy.float32)
+
+ else:
+ points = numpy.array([
+ self._plot.dataToPixel(x, y, axis='left', check=False)
+ for (x, y) in zip(item['x'], item['y'])])
+
+ # Draw the fill
+ if (item['fill'] is not None and
+ item['shape'] not in ('hline', 'vline')):
+ self._progBase.use()
+ gl.glUniformMatrix4fv(
+ self._progBase.uniforms['matrix'], 1, gl.GL_TRUE,
+ self.matScreenProj.astype(numpy.float32))
+ gl.glUniform2i(self._progBase.uniforms['isLog'], False, False)
+ gl.glUniform1f(self._progBase.uniforms['tickLen'], 0.)
+
+ shape2D = FilledShape2D(
+ points, style=item['fill'], color=item['color'])
+ shape2D.render(
+ posAttrib=self._progBase.attributes['position'],
+ colorUnif=self._progBase.uniforms['color'],
+ hatchStepUnif=self._progBase.uniforms['hatchStep'])
+
+ # Draw the stroke
+ if item['linestyle'] not in ('', ' ', None):
+ if item['shape'] != 'polylines':
+ # close the polyline
+ points = numpy.append(points,
+ numpy.atleast_2d(points[0]), axis=0)
+
+ lines = GLLines2D(points[:, 0], points[:, 1],
+ style=item['linestyle'],
+ color=item['color'],
+ dash2ndColor=item['linebgcolor'],
+ width=item['linewidth'])
lines.render(self.matScreenProj)
- else: # yCoord is None: vertical line in data space
- if marker['text'] is not None:
+ elif isinstance(item, _MarkerItem):
+ gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
+
+ xCoord, yCoord, yAxis = item['x'], item['y'], item['yaxis']
+
+ if ((isXLog and xCoord is not None and xCoord <= 0) or
+ (isYLog and yCoord is not None and yCoord <= 0)):
+ # Do not render markers with negative coords on log axis
+ continue
+
+ if xCoord is None or yCoord is None:
+ pixelPos = self._plot.dataToPixel(
+ xCoord, yCoord, axis=yAxis, check=False)
+
+ if xCoord is None: # Horizontal line in data space
+ if item['text'] is not None:
+ x = self._plotFrame.size[0] - \
+ self._plotFrame.margins.right - pixelOffset
+ y = pixelPos[1] - pixelOffset
+ label = Text2D(item['text'], x, y,
+ color=item['color'],
+ bgColor=(1., 1., 1., 0.5),
+ align=RIGHT, valign=BOTTOM)
+ labels.append(label)
+
+ width = self._plotFrame.size[0]
+ lines = GLLines2D((0, width), (pixelPos[1], pixelPos[1]),
+ style=item['linestyle'],
+ color=item['color'],
+ width=item['linewidth'])
+ lines.render(self.matScreenProj)
+
+ else: # yCoord is None: vertical line in data space
+ if item['text'] is not None:
+ x = pixelPos[0] + pixelOffset
+ y = self._plotFrame.margins.top + pixelOffset
+ label = Text2D(item['text'], x, y,
+ color=item['color'],
+ bgColor=(1., 1., 1., 0.5),
+ align=LEFT, valign=TOP)
+ labels.append(label)
+
+ height = self._plotFrame.size[1]
+ lines = GLLines2D((pixelPos[0], pixelPos[0]), (0, height),
+ style=item['linestyle'],
+ color=item['color'],
+ width=item['linewidth'])
+ lines.render(self.matScreenProj)
+
+ else:
+ pixelPos = self._plot.dataToPixel(
+ xCoord, yCoord, axis=yAxis, check=True)
+ if pixelPos is None:
+ # Do not render markers outside visible plot area
+ continue
+
+ if item['text'] is not None:
x = pixelPos[0] + pixelOffset
- y = self._plotFrame.margins.top + pixelOffset
- label = Text2D(marker['text'], x, y,
- color=marker['color'],
+ y = pixelPos[1] + pixelOffset
+ label = Text2D(item['text'], x, y,
+ color=item['color'],
bgColor=(1., 1., 1., 0.5),
align=LEFT, valign=TOP)
labels.append(label)
- height = self._plotFrame.size[1]
- lines = GLLines2D((pixelPos[0], pixelPos[0]), (0, height),
- style=marker['linestyle'],
- color=marker['color'],
- width=marker['linewidth'])
- lines.render(self.matScreenProj)
+ # For now simple implementation: using a curve for each marker
+ # Should pack all markers to a single set of points
+ markerCurve = GLPlotCurve2D(
+ numpy.array((pixelPos[0],), dtype=numpy.float64),
+ numpy.array((pixelPos[1],), dtype=numpy.float64),
+ marker=item['symbol'],
+ markerColor=item['color'],
+ markerSize=11)
+ markerCurve.render(self.matScreenProj, False, False)
+ markerCurve.discard()
else:
- pixelPos = self.dataToPixel(
- xCoord, yCoord, axis='left', check=True)
- if pixelPos is None:
- # Do not render markers outside visible plot area
- continue
-
- if marker['text'] is not None:
- x = pixelPos[0] + pixelOffset
- y = pixelPos[1] + pixelOffset
- label = Text2D(marker['text'], x, y,
- color=marker['color'],
- bgColor=(1., 1., 1., 0.5),
- align=LEFT, valign=TOP)
- labels.append(label)
-
- # For now simple implementation: using a curve for each marker
- # Should pack all markers to a single set of points
- markerCurve = GLPlotCurve2D(
- numpy.array((pixelPos[0],), dtype=numpy.float64),
- numpy.array((pixelPos[1],), dtype=numpy.float64),
- marker=marker['symbol'],
- markerColor=marker['color'],
- markerSize=11)
- markerCurve.render(self.matScreenProj, False, False)
- markerCurve.discard()
-
- gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
+ _logger.error('Unsupported item: %s', str(item))
+ continue
# Render marker labels
+ gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
for label in labels:
label.render(self.matScreenProj)
- gl.glDisable(gl.GL_SCISSOR_TEST)
-
def _renderOverlayGL(self):
- # Render crosshair cursor
- if self._crosshairCursor is not None:
- plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
+ """Render overlay layer: overlay items and crosshair."""
+ plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
+
+ # Scissor to plot area
+ gl.glScissor(self._plotFrame.margins.left,
+ self._plotFrame.margins.bottom,
+ plotWidth, plotHeight)
+ gl.glEnable(gl.GL_SCISSOR_TEST)
- # Scissor to plot area
- gl.glScissor(self._plotFrame.margins.left,
- self._plotFrame.margins.bottom,
- plotWidth, plotHeight)
- gl.glEnable(gl.GL_SCISSOR_TEST)
+ self._renderItems(overlay=True)
+ # Render crosshair cursor
+ if self._crosshairCursor is not None and self._mousePosInPixels is not None:
self._progBase.use()
gl.glUniform2i(self._progBase.uniforms['isLog'], False, False)
gl.glUniform1f(self._progBase.uniforms['tickLen'], 0.)
@@ -665,39 +623,39 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
colorUnif = self._progBase.uniforms['color']
hatchStepUnif = self._progBase.uniforms['hatchStep']
- # Render crosshair cursor in screen frame but with scissor
- if (self._crosshairCursor is not None and
- self._mousePosInPixels is not None):
- gl.glViewport(
- 0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
-
- gl.glUniformMatrix4fv(matrixUnif, 1, gl.GL_TRUE,
- self.matScreenProj.astype(numpy.float32))
-
- color, lineWidth = self._crosshairCursor
- gl.glUniform4f(colorUnif, *color)
- gl.glUniform1i(hatchStepUnif, 0)
-
- xPixel, yPixel = self._mousePosInPixels
- xPixel, yPixel = xPixel + 0.5, yPixel + 0.5
- vertices = numpy.array(((0., yPixel),
- (self._plotFrame.size[0], yPixel),
- (xPixel, 0.),
- (xPixel, self._plotFrame.size[1])),
- dtype=numpy.float32)
-
- gl.glEnableVertexAttribArray(posAttrib)
- gl.glVertexAttribPointer(posAttrib,
- 2,
- gl.GL_FLOAT,
- gl.GL_FALSE,
- 0, vertices)
- gl.glLineWidth(lineWidth)
- gl.glDrawArrays(gl.GL_LINES, 0, len(vertices))
-
- gl.glDisable(gl.GL_SCISSOR_TEST)
+ gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
+
+ gl.glUniformMatrix4fv(matrixUnif, 1, gl.GL_TRUE,
+ self.matScreenProj.astype(numpy.float32))
+
+ color, lineWidth = self._crosshairCursor
+ gl.glUniform4f(colorUnif, *color)
+ gl.glUniform1i(hatchStepUnif, 0)
+
+ xPixel, yPixel = self._mousePosInPixels
+ xPixel, yPixel = xPixel + 0.5, yPixel + 0.5
+ vertices = numpy.array(((0., yPixel),
+ (self._plotFrame.size[0], yPixel),
+ (xPixel, 0.),
+ (xPixel, self._plotFrame.size[1])),
+ dtype=numpy.float32)
+
+ gl.glEnableVertexAttribArray(posAttrib)
+ gl.glVertexAttribPointer(posAttrib,
+ 2,
+ gl.GL_FLOAT,
+ gl.GL_FALSE,
+ 0, vertices)
+ gl.glLineWidth(lineWidth)
+ gl.glDrawArrays(gl.GL_LINES, 0, len(vertices))
+
+ gl.glDisable(gl.GL_SCISSOR_TEST)
def _renderPlotAreaGL(self):
+ """Render base layer of plot area.
+
+ It renders the background, grid and items except overlays
+ """
plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
gl.glScissor(self._plotFrame.margins.left,
@@ -713,85 +671,9 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# Matrix
trBounds = self._plotFrame.transformedDataRanges
- if trBounds.x[0] == trBounds.x[1] or \
- trBounds.y[0] == trBounds.y[1]:
- return
-
- isXLog = self._plotFrame.xAxis.isLog
- isYLog = self._plotFrame.yAxis.isLog
-
- gl.glViewport(self._plotFrame.margins.left,
- self._plotFrame.margins.bottom,
- plotWidth, plotHeight)
-
- # Render images and curves
- # sorted is stable: original order is preserved when key is the same
- for item in self._plotContent.zOrderedPrimitives():
- if item.info.get('yAxis') == 'right':
- item.render(self._plotFrame.transformedDataY2ProjMat,
- isXLog, isYLog)
- else:
- item.render(self._plotFrame.transformedDataProjMat,
- isXLog, isYLog)
-
- # Render Items
- gl.glViewport(0, 0, self._plotFrame.size[0], self._plotFrame.size[1])
-
- for item in self._items.values():
- if ((isXLog and numpy.min(item['x']) < FLOAT32_MINPOS) or
- (isYLog and numpy.min(item['y']) < FLOAT32_MINPOS)):
- # Ignore items <= 0. on log axes
- continue
-
- if item['shape'] == 'hline':
- width = self._plotFrame.size[0]
- _, yPixel = self.dataToPixel(
- None, item['y'], axis='left', check=False)
- points = numpy.array(((0., yPixel), (width, yPixel)),
- dtype=numpy.float32)
-
- elif item['shape'] == 'vline':
- xPixel, _ = self.dataToPixel(
- item['x'], None, axis='left', check=False)
- height = self._plotFrame.size[1]
- points = numpy.array(((xPixel, 0), (xPixel, height)),
- dtype=numpy.float32)
-
- else:
- points = numpy.array([
- self.dataToPixel(x, y, axis='left', check=False)
- for (x, y) in zip(item['x'], item['y'])])
-
- # Draw the fill
- if (item['fill'] is not None and
- item['shape'] not in ('hline', 'vline')):
- self._progBase.use()
- gl.glUniformMatrix4fv(
- self._progBase.uniforms['matrix'], 1, gl.GL_TRUE,
- self.matScreenProj.astype(numpy.float32))
- gl.glUniform2i(self._progBase.uniforms['isLog'], False, False)
- gl.glUniform1f(self._progBase.uniforms['tickLen'], 0.)
-
- shape2D = FilledShape2D(
- points, style=item['fill'], color=item['color'])
- shape2D.render(
- posAttrib=self._progBase.attributes['position'],
- colorUnif=self._progBase.uniforms['color'],
- hatchStepUnif=self._progBase.uniforms['hatchStep'])
-
- # Draw the stroke
- if item['linestyle'] not in ('', ' ', None):
- if item['shape'] != 'polylines':
- # close the polyline
- points = numpy.append(points,
- numpy.atleast_2d(points[0]), axis=0)
-
- lines = GLLines2D(points[:, 0], points[:, 1],
- style=item['linestyle'],
- color=item['color'],
- dash2ndColor=item['linebgcolor'],
- width=item['linewidth'])
- lines.render(self.matScreenProj)
+ if trBounds.x[0] != trBounds.x[1] and trBounds.y[0] != trBounds.y[1]:
+ # Do rendering of items
+ self._renderItems(overlay=False)
gl.glDisable(gl.GL_SCISSOR_TEST)
@@ -841,13 +723,13 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
else:
raise ValueError('Unsupported data type')
- def addCurve(self, x, y, legend,
+ def addCurve(self, x, y,
color, symbol, linewidth, linestyle,
yaxis,
- xerror, yerror, z, selectable,
- fill, alpha, symbolsize):
- for parameter in (x, y, legend, color, symbol, linewidth, linestyle,
- yaxis, z, selectable, fill, symbolsize):
+ xerror, yerror, z,
+ fill, alpha, symbolsize, baseline):
+ for parameter in (x, y, color, symbol, linewidth, linestyle,
+ yaxis, z, fill, symbolsize):
assert parameter is not None
assert yaxis in ('left', 'right')
@@ -939,10 +821,9 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
if color is not None:
color = color[0], color[1], color[2], color[3] * alpha
- behaviors = set()
- if selectable:
- behaviors.add('selectable')
-
+ fillColor = None
+ if fill is True:
+ fillColor = color
curve = GLPlotCurve2D(x, y, colorArray,
xError=xerror,
yError=yerror,
@@ -952,36 +833,24 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
marker=symbol,
markerColor=color,
markerSize=symbolsize,
- fillColor=color if fill else None,
+ fillColor=fillColor,
+ baseline=baseline,
isYLog=isYLog)
curve.info = {
- 'legend': legend,
- 'zOrder': z,
- 'behaviors': behaviors,
'yAxis': 'left' if yaxis is None else yaxis,
}
if yaxis == "right":
self._plotFrame.isY2Axis = True
- self._plotContent.add(curve)
+ return curve
- return legend, 'curve'
-
- def addImage(self, data, legend,
+ def addImage(self, data,
origin, scale, z,
- selectable, draggable,
colormap, alpha):
- for parameter in (data, legend, origin, scale, z,
- selectable, draggable):
+ for parameter in (data, origin, scale, z):
assert parameter is not None
- behaviors = set()
- if selectable:
- behaviors.add('selectable')
- if draggable:
- behaviors.add('draggable')
-
if data.ndim == 2:
# Ensure array is contiguous and eventually convert its type
if data.dtype in (numpy.float32, numpy.uint8, numpy.uint16):
@@ -1002,12 +871,6 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
colormapIsLog,
cmapRange,
alpha)
- image.info = {
- 'legend': legend,
- 'zOrder': z,
- 'behaviors': behaviors
- }
- self._plotContent.add(image)
elif len(data.shape) == 3:
# For RGB, RGBA data
@@ -1022,29 +885,21 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
image = GLPlotRGBAImage(data, origin, scale, alpha)
- image.info = {
- 'legend': legend,
- 'zOrder': z,
- 'behaviors': behaviors
- }
-
- if self._plotFrame.xAxis.isLog and image.xMin <= 0.:
- raise RuntimeError(
- 'Cannot add image with X <= 0 with X axis log scale')
- if self._plotFrame.yAxis.isLog and image.yMin <= 0.:
- raise RuntimeError(
- 'Cannot add image with Y <= 0 with Y axis log scale')
-
- self._plotContent.add(image)
-
else:
raise RuntimeError("Unsupported data shape {0}".format(data.shape))
- return legend, 'image'
+ # TODO is this needed?
+ if self._plotFrame.xAxis.isLog and image.xMin <= 0.:
+ raise RuntimeError(
+ 'Cannot add image with X <= 0 with X axis log scale')
+ if self._plotFrame.yAxis.isLog and image.yMin <= 0.:
+ raise RuntimeError(
+ 'Cannot add image with Y <= 0 with Y axis log scale')
- def addTriangles(self, x, y, triangles, legend,
- color, z, selectable, alpha):
+ return image
+ def addTriangles(self, x, y, triangles,
+ color, z, alpha):
# Handle axes log scale: convert data
if self._plotFrame.xAxis.isLog:
x = numpy.log10(x)
@@ -1052,31 +907,14 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
y = numpy.log10(y)
triangles = GLPlotTriangles(x, y, color, triangles, alpha)
- triangles.info = {
- 'legend': legend,
- 'zOrder': z,
- 'behaviors': set(['selectable']) if selectable else set(),
- }
- self._plotContent.add(triangles)
- return legend, 'triangles'
+ return triangles
- def addItem(self, x, y, legend, shape, color, fill, overlay, z,
+ def addItem(self, x, y, shape, color, fill, overlay, z,
linestyle, linewidth, linebgcolor):
- # TODO handle overlay
- if shape not in ('polygon', 'rectangle', 'line',
- 'vline', 'hline', 'polylines'):
- raise NotImplementedError("Unsupported shape {0}".format(shape))
-
x = numpy.array(x, copy=False)
y = numpy.array(y, copy=False)
- if shape == 'rectangle':
- xMin, xMax = x
- x = numpy.array((xMin, xMin, xMax, xMax))
- yMin, yMax = y
- y = numpy.array((yMin, yMax, yMax, yMin))
-
# TODO is this needed?
if self._plotFrame.xAxis.isLog and x.min() <= 0.:
raise RuntimeError(
@@ -1085,84 +923,35 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
raise RuntimeError(
'Cannot add item with Y <= 0 with Y axis log scale')
- # Ignore fill for polylines to mimic matplotlib
- fill = fill if shape != 'polylines' else False
-
- self._items[legend] = {
- 'shape': shape,
- 'color': colors.rgba(color),
- 'fill': 'hatch' if fill else None,
- 'x': x,
- 'y': y,
- 'linestyle': linestyle,
- 'linewidth': linewidth,
- 'linebgcolor': linebgcolor,
- }
-
- return legend, 'item'
-
- def addMarker(self, x, y, legend, text, color,
- selectable, draggable,
- symbol, linestyle, linewidth, constraint):
-
- if symbol is None:
- symbol = '+'
-
- behaviors = set()
- if selectable:
- behaviors.add('selectable')
- if draggable:
- behaviors.add('draggable')
-
- # Apply constraint to provided position
- isConstraint = (draggable and constraint is not None and
- x is not None and y is not None)
- if isConstraint:
- x, y = constraint(x, y)
-
- self._markers[legend] = {
- 'x': x,
- 'y': y,
- 'legend': legend,
- 'text': text,
- 'color': colors.rgba(color),
- 'behaviors': behaviors,
- 'constraint': constraint if isConstraint else None,
- 'symbol': symbol,
- 'linestyle': linestyle,
- 'linewidth': linewidth,
- }
+ return _ShapeItem(x, y, shape, color, fill, overlay, z,
+ linestyle, linewidth, linebgcolor)
- return legend, 'marker'
+ def addMarker(self, x, y, text, color,
+ symbol, linestyle, linewidth, constraint, yaxis):
+ return _MarkerItem(x, y, text, color,
+ symbol, linestyle, linewidth, constraint, yaxis)
# Remove methods
def remove(self, item):
- legend, kind = item
-
- if kind == 'curve':
- curve = self._plotContent.pop('curve', legend)
- if curve is not None:
+ if isinstance(item, (GLPlotCurve2D,
+ GLPlotColormap,
+ GLPlotRGBAImage,
+ GLPlotTriangles)):
+ if isinstance(item, GLPlotCurve2D):
# Check if some curves remains on the right Y axis
- y2AxisItems = (item for item in self._plotContent.primitives()
- if item.info.get('yAxis', 'left') == 'right')
+ y2AxisItems = (item for item in self._plot.getItems()
+ if isinstance(item, items.YAxisMixIn) and
+ item.getYAxis() == 'right')
self._plotFrame.isY2Axis = next(y2AxisItems, None) is not None
- self._glGarbageCollector.append(curve)
-
- elif kind in ('image', 'triangles'):
- item = self._plotContent.pop(kind, legend)
- if item is not None:
- self._glGarbageCollector.append(item)
+ self._glGarbageCollector.append(item)
- elif kind == 'marker':
- self._markers.pop(legend, False)
-
- elif kind == 'item':
- self._items.pop(legend, False)
+ elif isinstance(item, (_MarkerItem, _ShapeItem)):
+ pass # No-op
else:
- _logger.error('Unsupported kind: %s', str(kind))
+ _logger.error('Unsupported item: %s', str(item))
# Interaction methods
@@ -1212,8 +1001,8 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
:param GLPlotCurve2D item:
:param float x: X position of the mouse in widget coordinates
:param float y: Y position of the mouse in widget coordinates
- :return: List of indices of picked points
- :rtype: List[int]
+ :return: List of indices of picked points or None if not picked
+ :rtype: Union[List[int],None]
"""
offset = self._PICK_OFFSET
if item.marker is not None:
@@ -1224,17 +1013,17 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
yAxis = item.info['yAxis']
inAreaPos = self._mouseInPlotArea(x - offset, y - offset)
- dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
- axis=yAxis, check=True)
+ dataPos = self._plot.pixelToData(inAreaPos[0], inAreaPos[1],
+ axis=yAxis, check=True)
if dataPos is None:
- return []
+ return None
xPick0, yPick0 = dataPos
inAreaPos = self._mouseInPlotArea(x + offset, y + offset)
- dataPos = self.pixelToData(inAreaPos[0], inAreaPos[1],
- axis=yAxis, check=True)
+ dataPos = self._plot.pixelToData(inAreaPos[0], inAreaPos[1],
+ axis=yAxis, check=True)
if dataPos is None:
- return []
+ return None
xPick1, yPick1 = dataPos
if xPick0 < xPick1:
@@ -1260,69 +1049,58 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
return item.pick(xPickMin, yPickMin,
xPickMax, yPickMax)
- def pickItems(self, x, y, kinds):
- picked = []
-
- dataPos = self.pixelToData(x, y, axis='left', check=True)
- if dataPos is not None:
- # Pick markers
- if 'marker' in kinds:
- for marker in reversed(list(self._markers.values())):
- pixelPos = self.dataToPixel(
- marker['x'], marker['y'], axis='left', check=False)
- if pixelPos is None: # negative coord on a log axis
- continue
+ def pickItem(self, x, y, item):
+ dataPos = self._plot.pixelToData(x, y, axis='left', check=True)
+ if dataPos is None:
+ return None # Outside plot area
+
+ if item is None:
+ _logger.error("No item provided for picking")
+ return None
+
+ # Pick markers
+ if isinstance(item, _MarkerItem):
+ yaxis = item['yaxis']
+ pixelPos = self._plot.dataToPixel(
+ item['x'], item['y'], axis=yaxis, check=False)
+ if pixelPos is None:
+ return None # negative coord on a log axis
+
+ if item['x'] is None: # Horizontal line
+ pt1 = self._plot.pixelToData(
+ x, y - self._PICK_OFFSET, axis=yaxis, check=False)
+ pt2 = self._plot.pixelToData(
+ x, y + self._PICK_OFFSET, axis=yaxis, check=False)
+ isPicked = (min(pt1[1], pt2[1]) <= item['y'] <=
+ max(pt1[1], pt2[1]))
+
+ elif item['y'] is None: # Vertical line
+ pt1 = self._plot.pixelToData(
+ x - self._PICK_OFFSET, y, axis=yaxis, check=False)
+ pt2 = self._plot.pixelToData(
+ x + self._PICK_OFFSET, y, axis=yaxis, check=False)
+ isPicked = (min(pt1[0], pt2[0]) <= item['x'] <=
+ max(pt1[0], pt2[0]))
- if marker['x'] is None: # Horizontal line
- pt1 = self.pixelToData(
- x, y - self._PICK_OFFSET, axis='left', check=False)
- pt2 = self.pixelToData(
- x, y + self._PICK_OFFSET, axis='left', check=False)
- isPicked = (min(pt1[1], pt2[1]) <= marker['y'] <=
- max(pt1[1], pt2[1]))
-
- elif marker['y'] is None: # Vertical line
- pt1 = self.pixelToData(
- x - self._PICK_OFFSET, y, axis='left', check=False)
- pt2 = self.pixelToData(
- x + self._PICK_OFFSET, y, axis='left', check=False)
- isPicked = (min(pt1[0], pt2[0]) <= marker['x'] <=
- max(pt1[0], pt2[0]))
-
- else:
- isPicked = (
- numpy.fabs(x - pixelPos[0]) <= self._PICK_OFFSET and
- numpy.fabs(y - pixelPos[1]) <= self._PICK_OFFSET)
-
- if isPicked:
- picked.append(dict(kind='marker',
- legend=marker['legend']))
-
- # Pick image and curves
- if 'image' in kinds or 'curve' in kinds:
- for item in self._plotContent.zOrderedPrimitives(reverse=True):
- if ('image' in kinds and
- isinstance(item, (GLPlotColormap, GLPlotRGBAImage))):
- pickedPos = item.pick(*dataPos)
- if pickedPos is not None:
- picked.append(dict(kind='image',
- legend=item.info['legend']))
-
- elif 'curve' in kinds:
- if isinstance(item, GLPlotCurve2D):
- pickedIndices = self.__pickCurves(item, x, y)
- if pickedIndices:
- picked.append(dict(kind='curve',
- legend=item.info['legend'],
- indices=pickedIndices))
-
- elif isinstance(item, GLPlotTriangles):
- pickedIndices = item.pick(*dataPos)
- if pickedIndices:
- picked.append(dict(kind='curve',
- legend=item.info['legend'],
- indices=pickedIndices))
- return picked
+ else:
+ isPicked = (
+ numpy.fabs(x - pixelPos[0]) <= self._PICK_OFFSET and
+ numpy.fabs(y - pixelPos[1]) <= self._PICK_OFFSET)
+
+ return (0,) if isPicked else None
+
+ # Pick image, curve, triangles
+ elif isinstance(item, (GLPlotCurve2D,
+ GLPlotColormap,
+ GLPlotRGBAImage,
+ GLPlotTriangles)):
+ if isinstance(item, (GLPlotColormap, GLPlotRGBAImage, GLPlotTriangles)):
+ return item.pick(*dataPos) # Might be None
+
+ elif isinstance(item, GLPlotCurve2D):
+ return self.__pickCurves(item, x, y)
+ else:
+ return None
# Update curve
@@ -1426,12 +1204,11 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
return
if keepDim is None:
- dataBounds = self._plotContent.getBounds(
- self._plotFrame.xAxis.isLog, self._plotFrame.yAxis.isLog)
- if dataBounds.yAxis.range_ != 0.:
- dataRatio = dataBounds.xAxis.range_
- dataRatio /= float(dataBounds.yAxis.range_)
-
+ ranges = self._plot.getDataRange()
+ if (ranges.y is not None and
+ ranges.x is not None and
+ (ranges.y[1] - ranges.y[0]) != 0.):
+ dataRatio = (ranges.x[1] - ranges.x[0]) / float(ranges.y[1] - ranges.y[0])
plotRatio = plotWidth / float(plotHeight) # Test != 0 before
keepDim = 'x' if dataRatio > plotRatio else 'y'
@@ -1564,51 +1341,10 @@ class BackendOpenGL(BackendBase.BackendBase, glu.OpenGLWidget):
# Data <-> Pixel coordinates conversion
- def dataToPixel(self, x, y, axis, check=False):
- assert axis in ('left', 'right')
-
- if x is None or y is None:
- dataBounds = self._plotContent.getBounds(
- self._plotFrame.xAxis.isLog, self._plotFrame.yAxis.isLog)
-
- if x is None:
- x = dataBounds.xAxis.center
-
- if y is None:
- if axis == 'left':
- y = dataBounds.yAxis.center
- else:
- y = dataBounds.y2Axis.center
-
- result = self._plotFrame.dataToPixel(x, y, axis)
-
- if check and result is not None:
- xPixel, yPixel = result
- width, height = self._plotFrame.size
- if (xPixel < self._plotFrame.margins.left or
- xPixel > (width - self._plotFrame.margins.right) or
- yPixel < self._plotFrame.margins.top or
- yPixel > height - self._plotFrame.margins.bottom):
- return None # (x, y) is out of plot area
-
- return result
-
- def pixelToData(self, x, y, axis, check):
- assert axis in ("left", "right")
-
- if x is None:
- x = self._plotFrame.size[0] / 2.
- if y is None:
- y = self._plotFrame.size[1] / 2.
-
- if check and (x < self._plotFrame.margins.left or
- x > (self._plotFrame.size[0] -
- self._plotFrame.margins.right) or
- y < self._plotFrame.margins.top or
- y > (self._plotFrame.size[1] -
- self._plotFrame.margins.bottom)):
- return None # (x, y) is out of plot area
+ def dataToPixel(self, x, y, axis):
+ return self._plotFrame.dataToPixel(x, y, axis)
+ def pixelToData(self, x, y, axis):
return self._plotFrame.pixelToData(x, y, axis)
def getPlotBoundsInPixels(self):
diff --git a/silx/gui/plot/backends/glutils/GLPlotCurve.py b/silx/gui/plot/backends/glutils/GLPlotCurve.py
index 5f8d652..3a0ebac 100644
--- a/silx/gui/plot/backends/glutils/GLPlotCurve.py
+++ b/silx/gui/plot/backends/glutils/GLPlotCurve.py
@@ -132,8 +132,7 @@ class _Fill2D(object):
self.xData is not None and self.yData is not None):
# Get slices of not NaN values longer than 1 element
- isnan = numpy.logical_or(numpy.isnan(self.xData),
- numpy.isnan(self.yData))
+ isnan = numpy.logical_or(numpy.isnan(self.xData), numpy.isnan(self.yData))
notnan = numpy.logical_not(isnan)
start = numpy.where(numpy.logical_and(isnan[:-1], notnan[1:]))[0] + 1
if notnan[0]:
@@ -147,22 +146,25 @@ class _Fill2D(object):
# Number of points: slice + 2 * leading and trailing points
# Twice leading and trailing points to produce degenerated triangles
- nbPoints = numpy.sum(numpy.diff(slices, axis=1)) + 4 * len(slices)
+ nbPoints = numpy.sum(numpy.diff(slices, axis=1)) * 2 + 4 * len(slices)
points = numpy.empty((nbPoints, 2), dtype=numpy.float32)
offset = 0
+ # invert baseline for filling
+ new_y_data = numpy.append(self.yData, self.baseline)
for start, end in slices:
# Duplicate first point for connecting degenerated triangle
- points[offset:offset+2] = self.xData[start], self.baseline
+ points[offset:offset+2] = self.xData[start], new_y_data[start]
# 2nd point of the polygon is last point
- points[offset+2] = self.xData[end-1], self.baseline
+ points[offset+2] = self.xData[start], self.baseline[start]
- # Add all points from the data
- indices = start + buildFillMaskIndices(end - start)
+ indices = numpy.append(numpy.arange(start, end),
+ numpy.arange(len(self.xData) + end-1, len(self.xData) + start-1, -1))
+ indices = indices[buildFillMaskIndices(len(indices))]
- points[offset+3:offset+3+len(indices), 0] = self.xData[indices]
- points[offset+3:offset+3+len(indices), 1] = self.yData[indices]
+ points[offset+3:offset+3+len(indices), 0] = self.xData[indices % len(self.xData)]
+ points[offset+3:offset+3+len(indices), 1] = new_y_data[indices]
# Duplicate last point for connecting degenerated triangle
points[offset+3+len(indices)] = points[offset+3+len(indices)-1]
@@ -526,7 +528,16 @@ def distancesFromArrays(xData, yData):
DIAMOND, CIRCLE, SQUARE, PLUS, X_MARKER, POINT, PIXEL, ASTERISK = \
'd', 'o', 's', '+', 'x', '.', ',', '*'
-H_LINE, V_LINE = '_', '|'
+H_LINE, V_LINE, HEART = '_', '|', u'\u2665'
+
+TICK_LEFT = "tickleft"
+TICK_RIGHT = "tickright"
+TICK_UP = "tickup"
+TICK_DOWN = "tickdown"
+CARET_LEFT = "caretleft"
+CARET_RIGHT = "caretright"
+CARET_UP = "caretup"
+CARET_DOWN = "caretdown"
class _Points2D(object):
@@ -542,7 +553,8 @@ class _Points2D(object):
"""
MARKERS = (DIAMOND, CIRCLE, SQUARE, PLUS, X_MARKER, POINT, PIXEL, ASTERISK,
- H_LINE, V_LINE)
+ H_LINE, V_LINE, HEART, TICK_LEFT, TICK_RIGHT, TICK_UP, TICK_DOWN,
+ CARET_LEFT, CARET_RIGHT, CARET_UP, CARET_DOWN)
"""List of supported markers"""
_VERTEX_SHADER = """
@@ -640,7 +652,110 @@ class _Points2D(object):
return 0.0;
}
}
- """
+ """,
+ HEART: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = (coord - 0.5) * 2.;
+ coord *= 0.75;
+ coord.y += 0.25;
+ float a = atan(coord.x,-coord.y)/3.141593;
+ float r = length(coord);
+ float h = abs(a);
+ float d = (13.0*h - 22.0*h*h + 10.0*h*h*h)/(6.0-5.0*h);
+ float res = clamp(r-d, 0., 1.);
+ // antialiasing
+ res = smoothstep(0.1, 0.001, res);
+ return res;
+ }
+ """,
+ TICK_LEFT: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float dy = abs(coord.y);
+ if (dy < 0.5 && coord.x < 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ TICK_RIGHT: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float dy = abs(coord.y);
+ if (dy < 0.5 && coord.x > -0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ TICK_UP: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float dx = abs(coord.x);
+ if (dx < 0.5 && coord.y < 0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ TICK_DOWN: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float dx = abs(coord.x);
+ if (dx < 0.5 && coord.y > -0.5) {
+ return 1.0;
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ CARET_LEFT: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float d = abs(coord.x) - abs(coord.y);
+ if (d >= -0.1 && coord.x > 0.5) {
+ return smoothstep(-0.1, 0.1, d);
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ CARET_RIGHT: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float d = abs(coord.x) - abs(coord.y);
+ if (d >= -0.1 && coord.x < 0.5) {
+ return smoothstep(-0.1, 0.1, d);
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ CARET_UP: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float d = abs(coord.y) - abs(coord.x);
+ if (d >= -0.1 && coord.y > 0.5) {
+ return smoothstep(-0.1, 0.1, d);
+ } else {
+ return 0.0;
+ }
+ }
+ """,
+ CARET_DOWN: """
+ float alphaSymbol(vec2 coord, float size) {
+ coord = size * (coord - 0.5);
+ float d = abs(coord.y) - abs(coord.x);
+ if (d >= -0.1 && coord.y < 0.5) {
+ return smoothstep(-0.1, 0.1, d);
+ } else {
+ return 0.0;
+ }
+ }
+ """,
}
_FRAGMENT_SHADER_TEMPLATE = """
@@ -964,6 +1079,7 @@ class GLPlotCurve2D(object):
markerColor=(0., 0., 0., 1.),
markerSize=7,
fillColor=None,
+ baseline=None,
isYLog=False):
self.colorData = colorData
@@ -1003,11 +1119,28 @@ class GLPlotCurve2D(object):
self.offset = 0., 0.
self.xData = xData
self.yData = yData
-
if fillColor is not None:
+ def deduce_baseline(baseline):
+ if baseline is None:
+ _baseline = 0
+ else:
+ _baseline = baseline
+ if not isinstance(_baseline, numpy.ndarray):
+ _baseline = numpy.repeat(_baseline,
+ len(self.xData))
+ if isYLog is True:
+ with warnings.catch_warnings(): # Ignore NaN comparison warnings
+ warnings.simplefilter('ignore',
+ category=RuntimeWarning)
+ log_val = numpy.log10(_baseline)
+ _baseline = numpy.where(_baseline>0.0, log_val, -38)
+ return _baseline
+
+ _baseline = deduce_baseline(baseline)
+
# Use different baseline depending of Y log scale
self.fill = _Fill2D(self.xData, self.yData,
- baseline=-38 if isYLog else 0,
+ baseline=_baseline,
color=fillColor,
offset=self.offset)
else:
@@ -1129,7 +1262,7 @@ class GLPlotCurve2D(object):
and the segment [i-1, i] is not tested for picking.
:return: The indices of the picked data
- :rtype: list of int
+ :rtype: Union[List[int],None]
"""
if (self.marker is None and self.lineStyle is None) or \
self.xMin > xPickMax or xPickMin > self.xMax or \
@@ -1209,4 +1342,4 @@ class GLPlotCurve2D(object):
(self.yData >= yPickMin) &
(self.yData <= yPickMax))[0].tolist()
- return indices
+ return tuple(indices) if len(indices) > 0 else None
diff --git a/silx/gui/plot/backends/glutils/GLPlotImage.py b/silx/gui/plot/backends/glutils/GLPlotImage.py
index 6f3c487..5d79023 100644
--- a/silx/gui/plot/backends/glutils/GLPlotImage.py
+++ b/silx/gui/plot/backends/glutils/GLPlotImage.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2014-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2014-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
@@ -56,7 +56,7 @@ class _GLPlotData2D(object):
sx, sy = self.scale
col = int((x - ox) / sx)
row = int((y - oy) / sy)
- return col, row
+ return ((row, col),)
else:
return None
diff --git a/silx/gui/plot/backends/glutils/GLPlotTriangles.py b/silx/gui/plot/backends/glutils/GLPlotTriangles.py
index c756749..7aeb5ab 100644
--- a/silx/gui/plot/backends/glutils/GLPlotTriangles.py
+++ b/silx/gui/plot/backends/glutils/GLPlotTriangles.py
@@ -114,11 +114,12 @@ class GLPlotTriangles(object):
:param float x: X coordinates in plot data frame
:param float y: Y coordinates in plot data frame
:return: List of picked data point indices
- :rtype: numpy.ndarray
+ :rtype: Union[List[int],None]
"""
if (x < self.xMin or x > self.xMax or
y < self.yMin or y > self.yMax):
- return ()
+ return None
+
xPts, yPts = self.__x_y_color[:2]
if self.__picking_triangles is None:
self.__picking_triangles = numpy.zeros(
@@ -135,9 +136,9 @@ class GLPlotTriangles(object):
# Sorted from furthest to closest point
dists = (xPts[indices] - x) ** 2 + (yPts[indices] - y) ** 2
- indices = indices[numpy.flip(numpy.argsort(dists))]
+ indices = indices[numpy.flip(numpy.argsort(dists), axis=0)]
- return tuple(indices)
+ return tuple(indices) if len(indices) > 0 else None
def discard(self):
"""Release resources on the GPU"""
diff --git a/silx/gui/plot/items/__init__.py b/silx/gui/plot/items/__init__.py
index f3a36db..7eff1d0 100644
--- a/silx/gui/plot/items/__init__.py
+++ b/silx/gui/plot/items/__init__.py
@@ -40,11 +40,11 @@ from .complex import ImageComplexData # noqa
from .curve import Curve, CurveStyle # noqa
from .histogram import Histogram # noqa
from .image import ImageBase, ImageData, ImageRgba, MaskImageData # noqa
-from .shape import Shape # noqa
+from .shape import Shape, BoundingRect # noqa
from .scatter import Scatter # noqa
from .marker import MarkerBase, Marker, XMarker, YMarker # noqa
from .axis import Axis, XAxis, YAxis, YRightAxis
-DATA_ITEMS = ImageComplexData, Curve, Histogram, ImageBase, Scatter
+DATA_ITEMS = ImageComplexData, Curve, Histogram, ImageBase, Scatter, BoundingRect
"""Classes of items representing data and to consider to compute data bounds.
"""
diff --git a/silx/gui/plot/items/_pick.py b/silx/gui/plot/items/_pick.py
new file mode 100644
index 0000000..14078fd
--- /dev/null
+++ b/silx/gui/plot/items/_pick.py
@@ -0,0 +1,70 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 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.
+#
+# ###########################################################################*/
+"""This module provides classes supporting item picking."""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "04/06/2019"
+
+import numpy
+
+
+class PickingResult(object):
+ """Class to access picking information in a :class:`PlotWidget`"""
+
+ def __init__(self, item, indices=None):
+ """Init
+
+ :param item: The picked item
+ :param numpy.ndarray indices: Array-like of indices of picked data.
+ Either 1D or 2D with dim0: data dimension and dim1: indices.
+ No copy is made.
+ """
+ self._item = item
+
+ if indices is None or len(indices) == 0:
+ self._indices = None
+ else:
+ self._indices = numpy.array(indices, copy=False, dtype=numpy.int)
+
+ def getItem(self):
+ """Returns the item this results corresponds to."""
+ return self._item
+
+ def getIndices(self, copy=True):
+ """Returns indices of picked data.
+
+ If data is 1D, it returns a numpy.ndarray, otherwise
+ it returns a tuple with as many numpy.ndarray as there are
+ dimensions in the data.
+
+ :param bool copy: True (default) to get a copy,
+ False to return internal arrays
+ :rtype: Union[None,numpy.ndarray,List[numpy.ndarray]]
+ """
+ if self._indices is None:
+ return None
+ indices = numpy.array(self._indices, copy=copy)
+ return indices if indices.ndim == 1 else tuple(indices)
diff --git a/silx/gui/plot/items/complex.py b/silx/gui/plot/items/complex.py
index 3869a05..988022a 100644
--- a/silx/gui/plot/items/complex.py
+++ b/silx/gui/plot/items/complex.py
@@ -113,6 +113,16 @@ class ImageComplexData(ImageBase, ColormapMixIn, ComplexMixIn):
colored phase + amplitude.
"""
+ _SUPPORTED_COMPLEX_MODES = (
+ ComplexMixIn.ComplexMode.ABSOLUTE,
+ ComplexMixIn.ComplexMode.PHASE,
+ ComplexMixIn.ComplexMode.REAL,
+ ComplexMixIn.ComplexMode.IMAGINARY,
+ ComplexMixIn.ComplexMode.AMPLITUDE_PHASE,
+ ComplexMixIn.ComplexMode.LOG10_AMPLITUDE_PHASE,
+ ComplexMixIn.ComplexMode.SQUARE_AMPLITUDE)
+ """Overrides supported ComplexMode"""
+
def __init__(self):
ImageBase.__init__(self)
ColormapMixIn.__init__(self)
@@ -161,12 +171,9 @@ class ImageComplexData(ImageBase, ColormapMixIn, ComplexMixIn):
return None # No data to display
return backend.addImage(data,
- legend=self.getLegend(),
origin=self.getOrigin(),
scale=self.getScale(),
z=self.getZValue(),
- selectable=self.isSelectable(),
- draggable=self.isDraggable(),
colormap=colormap,
alpha=self.getAlpha())
diff --git a/silx/gui/plot/items/core.py b/silx/gui/plot/items/core.py
index e7342b0..6d6575b 100644
--- a/silx/gui/plot/items/core.py
+++ b/silx/gui/plot/items/core.py
@@ -47,6 +47,7 @@ from ....utils.enum import Enum as _Enum
from ... import qt
from ... import colors
from ...colors import Colormap
+from ._pick import PickingResult
from silx import config
@@ -136,6 +137,12 @@ class ItemChangedType(enum.Enum):
COMPLEX_MODE = 'complexModeChanged'
"""Item's complex data visualization mode changed flag."""
+ NAME = 'nameChanged'
+ """Item's name changed flag."""
+
+ EDITABLE = 'editableChanged'
+ """Item's editable state changed flags."""
+
class Item(qt.QObject):
"""Description of an item of the plot"""
@@ -330,6 +337,26 @@ class Item(qt.QObject):
backend.remove(self._backendRenderer)
self._backendRenderer = None
+ def pick(self, x, y):
+ """Run picking test on this item
+
+ :param float x: The x pixel coord where to pick.
+ :param float y: The y pixel coord where to pick.
+ :return: None if not picked, else the picked position information
+ :rtype: Union[None,PickingResult]
+ """
+ if not self.isVisible() or self._backendRenderer is None:
+ return None
+ plot = self.getPlot()
+ if plot is None:
+ return None
+
+ indices = plot._backend.pickItem(x, y, self._backendRenderer)
+ if indices is None:
+ return None
+ else:
+ return PickingResult(self, indices if len(indices) != 0 else None)
+
# Mix-in classes ##############################################################
@@ -471,6 +498,17 @@ class SymbolMixIn(ItemMixInBase):
('x', 'Cross'),
('.', 'Point'),
(',', 'Pixel'),
+ ('|', 'Vertical line'),
+ ('_', 'Horizontal line'),
+ ('tickleft', 'Tick left'),
+ ('tickright', 'Tick right'),
+ ('tickup', 'Tick up'),
+ ('tickdown', 'Tick down'),
+ ('caretleft', 'Caret left'),
+ ('caretright', 'Caret right'),
+ ('caretup', 'Caret up'),
+ ('caretdown', 'Caret down'),
+ (u'\u2665', 'Heart'),
('', 'None')))
"""Dict of supported symbols"""
@@ -781,6 +819,7 @@ class ComplexMixIn(ItemMixInBase):
class ComplexMode(_Enum):
"""Identify available display mode for complex"""
+ NONE = 'none'
ABSOLUTE = 'amplitude'
PHASE = 'phase'
REAL = 'real'
@@ -884,8 +923,54 @@ class ScatterVisualizationMixIn(ItemMixInBase):
This is based on Delaunay triangulation
"""
+ REGULAR_GRID = 'regular_grid'
+ """Display scatter plot as an image.
+
+ It expects the points to be the intersection of a regular grid,
+ and the order of points following that of an image.
+ First line, then second one, and always in the same direction
+ (either all lines from left to right or all from right to left).
+ """
+
+ IRREGULAR_GRID = 'irregular_grid'
+ """Display scatter plot as contiguous quadrilaterals.
+
+ It expects the points to be the intersection of an irregular grid,
+ and the order of points following that of an image.
+ First line, then second one, and always in the same direction
+ (either all lines from left to right or all from right to left).
+ """
+
+ @enum.unique
+ class VisualizationParameter(_Enum):
+ """Different parameter names for scatter plot visualizations"""
+
+ GRID_MAJOR_ORDER = 'grid_major_order'
+ """The major order of points in the regular grid.
+
+ Either 'row' (row-major, fast X) or 'column' (column-major, fast Y).
+ """
+
+ GRID_BOUNDS = 'grid_bounds'
+ """The expected range in data coordinates of the regular grid.
+
+ A 2-tuple of 2-tuple: (begin (x, y), end (x, y)).
+ This provides the data coordinates of the first point and the expected
+ last on.
+ As for `GRID_SHAPE`, this can be wider than the current data.
+ """
+
+ GRID_SHAPE = 'grid_shape'
+ """The expected size of the regular grid (height, width).
+
+ The given shape can be wider than the number of points,
+ in which case the grid is not fully filled.
+ """
+
def __init__(self):
self.__visualization = self.Visualization.POINTS
+ self.__parameters = dict( # Init parameters to None
+ (parameter, None) for parameter in self.VisualizationParameter)
@classmethod
def supportedVisualizations(cls):
@@ -929,6 +1014,54 @@ class ScatterVisualizationMixIn(ItemMixInBase):
"""
return self.__visualization
+ def setVisualizationParameter(self, parameter, value=None):
+ """Set the given visualization parameter.
+
+ :param Union[str,VisualizationParameter] parameter:
+ The name of the parameter to set
+ :param value: The value to use for this parameter
+ Set to None to automatically set the parameter
+ :raises ValueError: If parameter is not supported
+ :return: True if parameter was set, False if is was already set
+ :rtype: bool
+ """
+ parameter = self.VisualizationParameter.from_value(parameter)
+
+ if self.__parameters[parameter] != value:
+ self.__parameters[parameter] = value
+ self._updated(ItemChangedType.VISUALIZATION_MODE)
+ return True
+ return False
+
+ def getVisualizationParameter(self, parameter):
+ """Returns the value of the given visualization parameter.
+
+ This method returns the parameter as set by
+ :meth:`setVisualizationParameter`.
+
+ :param parameter: The name of the parameter to retrieve
+ :returns: The value previously set or None if automatically set
+ :raises ValueError: If parameter is not supported
+ """
+ if parameter not in self.VisualizationParameter:
+ raise ValueError("parameter not supported: %s", parameter)
+
+ return self.__parameters[parameter]
+
+ def getCurrentVisualizationParameter(self, parameter):
+ """Returns the current value of the given visualization parameter.
+
+ If the parameter was set by :meth:`setVisualizationParameter` to
+ a value that is not None, this value is returned;
+ else the current value that is automatically computed is returned.
+
+ :param parameter: The name of the parameter to retrieve
+ :returns: The current value (either set or automatically computed)
+ :raises ValueError: If parameter is not supported
+ """
+ # Override in subclass to provide automatically computed parameters
+ return self.getVisualizationParameter(parameter)
+
class PointsBase(Item, SymbolMixIn, AlphaMixIn):
"""Base class for :class:`Curve` and :class:`Scatter`"""
@@ -1224,3 +1357,32 @@ class PointsBase(Item, SymbolMixIn, AlphaMixIn):
if plot is not None:
plot._invalidateDataRange()
self._updated(ItemChangedType.DATA)
+
+
+class BaselineMixIn(object):
+ """Base class for Baseline mix-in"""
+ def __init__(self, baseline=None):
+ self._baseline = baseline
+
+ def _setBaseline(self, baseline):
+ """
+ Set baseline value
+
+ :param baseline: baseline value(s)
+ :type: Union[None,float,numpy.ndarray]
+ """
+ if (isinstance(baseline, abc.Iterable)):
+ baseline = numpy.array(baseline)
+ self._baseline = baseline
+
+ def getBaseline(self, copy=True):
+ """
+
+ :param bool copy:
+ :return: histogram baseline
+ :rtype: Union[None,float,numpy.ndarray]
+ """
+ if isinstance(self._baseline, numpy.ndarray):
+ return numpy.array(self._baseline, copy=True)
+ else:
+ return self._baseline
diff --git a/silx/gui/plot/items/curve.py b/silx/gui/plot/items/curve.py
index 439af33..5853ef5 100644
--- a/silx/gui/plot/items/curve.py
+++ b/silx/gui/plot/items/curve.py
@@ -38,7 +38,8 @@ import six
from ....utils.deprecation import deprecated
from ... import colors
from .core import (PointsBase, LabelsMixIn, ColorMixIn, YAxisMixIn,
- FillMixIn, LineMixIn, SymbolMixIn, ItemChangedType)
+ FillMixIn, LineMixIn, SymbolMixIn, ItemChangedType,
+ BaselineMixIn)
_logger = logging.getLogger(__name__)
@@ -151,7 +152,8 @@ class CurveStyle(object):
return False
-class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixIn):
+class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn,
+ LineMixIn, BaselineMixIn):
"""Description of a curve"""
_DEFAULT_Z_LAYER = 1
@@ -169,6 +171,8 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
_DEFAULT_HIGHLIGHT_STYLE = CurveStyle(color='black')
"""Default highlight style of the item"""
+ _DEFAULT_BASELINE = None
+
def __init__(self):
PointsBase.__init__(self)
ColorMixIn.__init__(self)
@@ -176,9 +180,11 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
FillMixIn.__init__(self)
LabelsMixIn.__init__(self)
LineMixIn.__init__(self)
+ BaselineMixIn.__init__(self)
self._highlightStyle = self._DEFAULT_HIGHLIGHT_STYLE
self._highlighted = False
+ self._setBaseline(Curve._DEFAULT_BASELINE)
self.sigItemChanged.connect(self.__itemChanged)
@@ -200,7 +206,7 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
style = self.getCurrentStyle()
- return backend.addCurve(xFiltered, yFiltered, self.getLegend(),
+ return backend.addCurve(xFiltered, yFiltered,
color=style.getColor(),
symbol=style.getSymbol(),
linestyle=style.getLineStyle(),
@@ -209,10 +215,10 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
xerror=xerror,
yerror=yerror,
z=self.getZValue(),
- selectable=self.isSelectable(),
fill=self.isFill(),
alpha=self.getAlpha(),
- symbolsize=style.getSymbolSize())
+ symbolsize=style.getSymbolSize(),
+ baseline=self.getBaseline(copy=False))
def __getitem__(self, item):
"""Compatibility with PyMca and silx <= 0.4.0"""
@@ -241,7 +247,7 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
'yerror': self.getYErrorData(copy=False),
'z': self.getZValue(),
'selectable': self.isSelectable(),
- 'fill': self.isFill()
+ 'fill': self.isFill(),
}
return params
else:
@@ -361,3 +367,25 @@ class Curve(PointsBase, ColorMixIn, YAxisMixIn, FillMixIn, LabelsMixIn, LineMixI
:rtype: 4-tuple of float in [0, 1]
"""
return self.getCurrentStyle().getColor()
+
+ def setData(self, x, y, xerror=None, yerror=None, baseline=None, copy=True):
+ """Set the data of the curve.
+
+ :param numpy.ndarray x: The data corresponding to the x coordinates.
+ :param numpy.ndarray y: The data corresponding to the y coordinates.
+ :param xerror: Values with the uncertainties on the x values
+ :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.
+ :param yerror: Values with the uncertainties on the y values.
+ :type yerror: A float, or a numpy.ndarray of float32. See xerror.
+ :param baseline: curve baseline
+ :type baseline: Union[None,float,numpy.ndarray]
+ :param bool copy: True make a copy of the data (default),
+ False to use provided arrays.
+ """
+ PointsBase.setData(self, x=x, y=y, xerror=xerror, yerror=yerror,
+ copy=copy)
+ self._setBaseline(baseline=baseline)
diff --git a/silx/gui/plot/items/histogram.py b/silx/gui/plot/items/histogram.py
index a1d6586..993c0f0 100644
--- a/silx/gui/plot/items/histogram.py
+++ b/silx/gui/plot/items/histogram.py
@@ -8,7 +8,7 @@
# 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:
+# furnished to do so, subject to the following conditions::t
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
@@ -32,8 +32,13 @@ __date__ = "28/08/2018"
import logging
import numpy
+from collections import OrderedDict, namedtuple
+try:
+ from collections import abc
+except ImportError: # Python2 support
+ import collections as abc
-from .core import (Item, AlphaMixIn, ColorMixIn, FillMixIn,
+from .core import (Item, AlphaMixIn, BaselineMixIn, ColorMixIn, FillMixIn,
LineMixIn, YAxisMixIn, ItemChangedType)
_logger = logging.getLogger(__name__)
@@ -96,7 +101,7 @@ def _getHistogramCurve(histogram, edges):
# TODO: Yerror, test log scale
class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
- LineMixIn, YAxisMixIn):
+ LineMixIn, YAxisMixIn, BaselineMixIn):
"""Description of an histogram"""
_DEFAULT_Z_LAYER = 1
@@ -111,9 +116,12 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
_DEFAULT_LINESTYLE = '-'
"""Default line style of the histogram"""
+ _DEFAULT_BASELINE = None
+
def __init__(self):
Item.__init__(self)
AlphaMixIn.__init__(self)
+ BaselineMixIn.__init__(self)
ColorMixIn.__init__(self)
FillMixIn.__init__(self)
LineMixIn.__init__(self)
@@ -121,10 +129,11 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
self._histogram = ()
self._edges = ()
+ self._setBaseline(Histogram._DEFAULT_BASELINE)
def _addBackendRenderer(self, backend):
"""Update backend renderer"""
- values, edges = self.getData(copy=False)
+ values, edges, baseline = self.getData(copy=False)
if values.size == 0:
return None # No data to display, do not add renderer
@@ -153,7 +162,7 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
x[clipped] = numpy.nan
y[clipped] = numpy.nan
- return backend.addCurve(x, y, self.getLegend(),
+ return backend.addCurve(x, y,
color=self.getColor(),
symbol='',
linestyle=self.getLineStyle(),
@@ -162,13 +171,13 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
xerror=None,
yerror=None,
z=self.getZValue(),
- selectable=self.isSelectable(),
fill=self.isFill(),
alpha=self.getAlpha(),
+ baseline=baseline,
symbolsize=1)
def _getBounds(self):
- values, edges = self.getData(copy=False)
+ values, edges, baseline = self.getData(copy=False)
plot = self.getPlot()
if plot is not None:
@@ -243,16 +252,19 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
return numpy.array(self._edges, copy=copy)
def getData(self, copy=True):
- """Return the histogram values and the bin edges
+ """Return the histogram values, bin edges and baseline
:param copy: True (Default) to get a copy,
False to use internal representation (do not modify!)
:returns: (N histogram value, N+1 bin edges)
:rtype: 2-tuple of numpy.nadarray
"""
- return self.getValueData(copy), self.getBinEdgesData(copy)
+ return (self.getValueData(copy),
+ self.getBinEdgesData(copy),
+ self.getBaseline(copy))
- def setData(self, histogram, edges, align='center', copy=True):
+ def setData(self, histogram, edges, align='center', baseline=None,
+ copy=True):
"""Set the histogram values and bin edges.
:param numpy.ndarray histogram: The values of the histogram.
@@ -264,6 +276,8 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
In case histogram values and edges have the same length N,
the N+1 bin edges are computed according to the alignment in:
'center' (default), 'left', 'right'.
+ :param baseline: histogram baseline
+ :type baseline: Union[None,float,numpy.ndarray]
:param bool copy: True make a copy of the data (default),
False to use provided arrays.
"""
@@ -285,10 +299,18 @@ class Histogram(Item, AlphaMixIn, ColorMixIn, FillMixIn,
# Check that bin edges are monotonic
edgesDiff = numpy.diff(edges)
assert numpy.all(edgesDiff >= 0) or numpy.all(edgesDiff <= 0)
-
+ # manage baseline
+ if (isinstance(baseline, abc.Iterable)):
+ baseline = numpy.array(baseline)
+ if baseline.size == histogram.size:
+ new_baseline = numpy.empty(baseline.shape[0] * 2)
+ for i_value, value in enumerate(baseline):
+ new_baseline[i_value*2:i_value*2+2] = value
+ baseline = new_baseline
self._histogram = histogram
self._edges = edges
self._alignement = align
+ self._setBaseline(baseline)
if self.isVisible():
plot = self.getPlot()
diff --git a/silx/gui/plot/items/image.py b/silx/gui/plot/items/image.py
index d74f4d3..44cb70f 100644
--- a/silx/gui/plot/items/image.py
+++ b/silx/gui/plot/items/image.py
@@ -42,6 +42,7 @@ import numpy
from ....utils.proxy import docstring
from .core import (Item, LabelsMixIn, DraggableMixIn, ColormapMixIn,
AlphaMixIn, ItemChangedType)
+from ._pick import PickingResult
_logger = logging.getLogger(__name__)
@@ -142,6 +143,25 @@ class ImageBase(Item, LabelsMixIn, DraggableMixIn, AlphaMixIn):
plot._invalidateDataRange()
super(ImageBase, self).setVisible(visible)
+ @docstring(Item)
+ def pick(self, x, y):
+ if super(ImageBase, self).pick(x, y) is not None:
+ plot = self.getPlot()
+ if plot is None:
+ return None
+
+ dataPos = plot.pixelToData(x, y)
+ if dataPos is None:
+ return None
+
+ origin = self.getOrigin()
+ scale = self.getScale()
+ column = int((dataPos[0] - origin[0]) / float(scale[0]))
+ row = int((dataPos[1] - origin[1]) / float(scale[1]))
+ return PickingResult(self, ([row], [column]))
+
+ return None
+
def _isPlotLinear(self, plot):
"""Return True if plot only uses linear scale for both of x and y
axes."""
@@ -282,12 +302,9 @@ class ImageData(ImageBase, ColormapMixIn):
return None # No data to display
return backend.addImage(dataToUse,
- legend=self.getLegend(),
origin=self.getOrigin(),
scale=self.getScale(),
z=self.getZValue(),
- selectable=self.isSelectable(),
- draggable=self.isDraggable(),
colormap=self.getColormap(),
alpha=self.getAlpha())
@@ -415,12 +432,9 @@ class ImageRgba(ImageBase):
return None # No data to display
return backend.addImage(data,
- legend=self.getLegend(),
origin=self.getOrigin(),
scale=self.getScale(),
z=self.getZValue(),
- selectable=self.isSelectable(),
- draggable=self.isDraggable(),
colormap=None,
alpha=self.getAlpha())
diff --git a/silx/gui/plot/items/marker.py b/silx/gui/plot/items/marker.py
index 80ca0b6..f5a1689 100644..100755
--- a/silx/gui/plot/items/marker.py
+++ b/silx/gui/plot/items/marker.py
@@ -34,13 +34,13 @@ import logging
from ....utils.proxy import docstring
from .core import (Item, DraggableMixIn, ColorMixIn, LineMixIn, SymbolMixIn,
- ItemChangedType)
+ ItemChangedType, YAxisMixIn)
_logger = logging.getLogger(__name__)
-class MarkerBase(Item, DraggableMixIn, ColorMixIn):
+class MarkerBase(Item, DraggableMixIn, ColorMixIn, YAxisMixIn):
"""Base class for markers"""
_DEFAULT_COLOR = (0., 0., 0., 1.)
@@ -50,6 +50,7 @@ class MarkerBase(Item, DraggableMixIn, ColorMixIn):
Item.__init__(self)
DraggableMixIn.__init__(self)
ColorMixIn.__init__(self)
+ YAxisMixIn.__init__(self)
self._text = ''
self._x = None
@@ -62,15 +63,13 @@ class MarkerBase(Item, DraggableMixIn, ColorMixIn):
return backend.addMarker(
x=self.getXPosition(),
y=self.getYPosition(),
- legend=self.getLegend(),
text=self.getText(),
color=self.getColor(),
- selectable=self.isSelectable(),
- draggable=self.isDraggable(),
symbol=symbol,
linestyle=linestyle,
linewidth=linewidth,
- constraint=self.getConstraint())
+ constraint=self.getConstraint(),
+ yaxis=self.getYAxis())
def _addBackendRenderer(self, backend):
"""Update backend renderer"""
@@ -81,13 +80,11 @@ class MarkerBase(Item, DraggableMixIn, ColorMixIn):
self.setPosition(to[0], to[1])
def isOverlay(self):
- """Return true if marker is drawn as an overlay.
-
- A marker is an overlay if it is draggable.
+ """Returns True: A marker is always rendered as an overlay.
:rtype: bool
"""
- return self.isDraggable()
+ return True
def getText(self):
"""Returns marker text.
diff --git a/silx/gui/plot/items/roi.py b/silx/gui/plot/items/roi.py
index 65831be..dcad943 100644
--- a/silx/gui/plot/items/roi.py
+++ b/silx/gui/plot/items/roi.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018 European Synchrotron Radiation Facility
+# Copyright (c) 2018-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
@@ -40,12 +40,51 @@ from ....utils.weakref import WeakList
from ... import qt
from .. import items
from ...colors import rgba
+import silx.utils.deprecation
+from silx.utils.proxy import docstring
logger = logging.getLogger(__name__)
-class RegionOfInterest(qt.QObject):
+class _RegionOfInterestBase(qt.QObject):
+ """Base class of 1D and 2D region of interest
+
+ :param QObject parent: See QObject
+ :param str name: The name of the ROI
+ """
+
+ sigItemChanged = qt.Signal(object)
+ """Signal emitted when item has changed.
+
+ It provides a flag describing which property of the item has changed.
+ See :class:`ItemChangedType` for flags description.
+ """
+
+ def __init__(self, parent=None, name=''):
+ qt.QObject.__init__(self)
+ self.__name = str(name)
+
+ def getName(self):
+ """Returns the name of the ROI
+
+ :return: name of the region of interest
+ :rtype: str
+ """
+ return self.__name
+
+ def setName(self, name):
+ """Set the name of the ROI
+
+ :param str name: name of the region of interest
+ """
+ name = str(name)
+ if self.__name != name:
+ self.__name = name
+ self.sigItemChanged.emit(items.ItemChangedType.NAME)
+
+
+class RegionOfInterest(_RegionOfInterestBase):
"""Object describing a region of interest in a plot.
:param QObject parent:
@@ -55,7 +94,7 @@ class RegionOfInterest(qt.QObject):
_kind = None
"""Label for this kind of ROI.
- Should be setted by inherited classes to custom the ROI manager widget.
+ Should be set by inherited classes to custom the ROI manager widget.
"""
sigRegionChanged = qt.Signal()
@@ -65,15 +104,20 @@ class RegionOfInterest(qt.QObject):
# Avoid circular dependancy
from ..tools import roi as roi_tools
assert parent is None or isinstance(parent, roi_tools.RegionOfInterestManager)
- qt.QObject.__init__(self, parent)
+ _RegionOfInterestBase.__init__(self, parent, '')
self._color = rgba('red')
self._items = WeakList()
self._editAnchors = WeakList()
self._points = None
- self._label = ''
self._labelItem = None
self._editable = False
self._visible = True
+ self.sigItemChanged.connect(self.__itemChanged)
+
+ def __itemChanged(self, event):
+ """Handle name change"""
+ if event == items.ItemChangedType.NAME:
+ self._updateLabelItem(self.getName())
def __del__(self):
# Clean-up plot items
@@ -140,22 +184,27 @@ class RegionOfInterest(qt.QObject):
if isinstance(item, items.ColorMixIn):
item.setColor(rgbaColor)
+ self.sigItemChanged.emit(items.ItemChangedType.COLOR)
+
+ @silx.utils.deprecation.deprecated(reason='API modification',
+ replacement='getName()',
+ since_version=0.12)
def getLabel(self):
"""Returns the label displayed for this ROI.
:rtype: str
"""
- return self._label
+ return self.getName()
+ @silx.utils.deprecation.deprecated(reason='API modification',
+ replacement='setName(name)',
+ since_version=0.12)
def setLabel(self, label):
"""Set the label displayed with this ROI.
:param str label: The text label to display
"""
- label = str(label)
- if label != self._label:
- self._label = label
- self._updateLabelItem(label)
+ self.setName(name=label)
def isEditable(self):
"""Returns whether the ROI is editable by the user or not.
@@ -176,6 +225,7 @@ class RegionOfInterest(qt.QObject):
# Recreate plot items
# This can be avoided once marker.setDraggable is public
self._createPlotItems()
+ self.sigItemChanged.emit(items.ItemChangedType.EDITABLE)
def isVisible(self):
"""Returns whether the ROI is visible in the plot.
@@ -197,13 +247,13 @@ class RegionOfInterest(qt.QObject):
hide it.
"""
visible = bool(visible)
- if self._visible == visible:
- return
- self._visible = visible
- if self._labelItem is not None:
- self._labelItem.setVisible(visible)
- for item in self._items + self._editAnchors:
- item.setVisible(visible)
+ if self._visible != visible:
+ self._visible = visible
+ if self._labelItem is not None:
+ self._labelItem.setVisible(visible)
+ for item in self._items + self._editAnchors:
+ item.setVisible(visible)
+ self.sigItemChanged.emit(items.ItemChangedType.VISIBLE)
def _getControlPoints(self):
"""Returns the current ROI control points.
@@ -371,7 +421,7 @@ class RegionOfInterest(qt.QObject):
markerPos = self._getLabelPosition()
marker = items.Marker()
marker.setPosition(*markerPos)
- marker.setText(self.getLabel())
+ marker.setText(self.getName())
marker.setColor(rgba(self.getColor()))
marker.setSymbol('')
marker._setDraggable(False)
@@ -465,6 +515,12 @@ class PointROI(RegionOfInterest, items.SymbolMixIn):
_plotShape = "point"
"""Plot shape which is used for the first interaction"""
+ _DEFAULT_SYMBOL = '+'
+ """Default symbol of the PointROI
+
+ It overwrite the `SymbolMixIn` class attribte.
+ """
+
def __init__(self, parent=None):
items.SymbolMixIn.__init__(self)
RegionOfInterest.__init__(self, parent=parent)
@@ -488,31 +544,31 @@ class PointROI(RegionOfInterest, items.SymbolMixIn):
return None
def _updateLabelItem(self, label):
- if self.isEditable():
- item = self._editAnchors[0]
- else:
+ self._items[0].setText(label)
+
+ def _updateShape(self):
+ if len(self._items) > 0:
+ controlPoints = self._getControlPoints()
item = self._items[0]
- item.setText(label)
+ item.setPosition(*controlPoints[0])
+
+ def __positionChanged(self, event):
+ """Handle position changed events of the marker"""
+ if event is items.ItemChangedType.POSITION:
+ marker = self.sender()
+ if isinstance(marker, items.Marker):
+ self.setPosition(marker.getPosition())
def _createShapeItems(self, points):
- if self.isEditable():
- return []
marker = items.Marker()
marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
- marker.setColor(rgba(self.getColor()))
+ marker.setText(self.getName())
marker.setSymbol(self.getSymbol())
marker.setSymbolSize(self.getSymbolSize())
- marker._setDraggable(False)
- return [marker]
-
- def _createAnchorItems(self, points):
- marker = items.Marker()
- marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
+ marker.setColor(rgba(self.getColor()))
marker._setDraggable(self.isEditable())
- marker.setSymbol(self.getSymbol())
- marker.setSymbolSize(self.getSymbolSize())
+ if self.isEditable():
+ marker.sigItemChanged.connect(self.__positionChanged)
return [marker]
def __str__(self):
@@ -672,38 +728,31 @@ class HorizontalLineROI(RegionOfInterest, items.LineMixIn):
return None
def _updateLabelItem(self, label):
- if self.isEditable():
- item = self._editAnchors[0]
- else:
- item = self._items[0]
- item.setText(label)
+ self._items[0].setText(label)
def _updateShape(self):
- if not self.isEditable():
- if len(self._items) > 0:
- controlPoints = self._getControlPoints()
- item = self._items[0]
- item.setPosition(*controlPoints[0])
+ if len(self._items) > 0:
+ controlPoints = self._getControlPoints()
+ item = self._items[0]
+ item.setPosition(*controlPoints[0])
+
+ def __positionChanged(self, event):
+ """Handle position changed events of the marker"""
+ if event is items.ItemChangedType.POSITION:
+ marker = self.sender()
+ if isinstance(marker, items.YMarker):
+ self.setPosition(marker.getYPosition())
def _createShapeItems(self, points):
- if self.isEditable():
- return []
marker = items.YMarker()
marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
+ marker.setText(self.getName())
marker.setColor(rgba(self.getColor()))
- marker._setDraggable(False)
marker.setLineWidth(self.getLineWidth())
marker.setLineStyle(self.getLineStyle())
- return [marker]
-
- def _createAnchorItems(self, points):
- marker = items.YMarker()
- marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
marker._setDraggable(self.isEditable())
- marker.setLineWidth(self.getLineWidth())
- marker.setLineStyle(self.getLineStyle())
+ if self.isEditable():
+ marker.sigItemChanged.connect(self.__positionChanged)
return [marker]
def __str__(self):
@@ -749,38 +798,31 @@ class VerticalLineROI(RegionOfInterest, items.LineMixIn):
return None
def _updateLabelItem(self, label):
- if self.isEditable():
- item = self._editAnchors[0]
- else:
- item = self._items[0]
- item.setText(label)
+ self._items[0].setText(label)
def _updateShape(self):
- if not self.isEditable():
- if len(self._items) > 0:
- controlPoints = self._getControlPoints()
- item = self._items[0]
- item.setPosition(*controlPoints[0])
+ if len(self._items) > 0:
+ controlPoints = self._getControlPoints()
+ item = self._items[0]
+ item.setPosition(*controlPoints[0])
+
+ def __positionChanged(self, event):
+ """Handle position changed events of the marker"""
+ if event is items.ItemChangedType.POSITION:
+ marker = self.sender()
+ if isinstance(marker, items.XMarker):
+ self.setPosition(marker.getXPosition())
def _createShapeItems(self, points):
- if self.isEditable():
- return []
marker = items.XMarker()
marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
+ marker.setText(self.getName())
marker.setColor(rgba(self.getColor()))
- marker._setDraggable(False)
marker.setLineWidth(self.getLineWidth())
marker.setLineStyle(self.getLineStyle())
- return [marker]
-
- def _createAnchorItems(self, points):
- marker = items.XMarker()
- marker.setPosition(points[0][0], points[0][1])
- marker.setText(self.getLabel())
marker._setDraggable(self.isEditable())
- marker.setLineWidth(self.getLineWidth())
- marker.setLineStyle(self.getLineStyle())
+ if self.isEditable():
+ marker.sigItemChanged.connect(self.__positionChanged)
return [marker]
def __str__(self):
diff --git a/silx/gui/plot/items/scatter.py b/silx/gui/plot/items/scatter.py
index b2f087b..50cc694 100644
--- a/silx/gui/plot/items/scatter.py
+++ b/silx/gui/plot/items/scatter.py
@@ -25,11 +25,15 @@
"""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"
+from collections import namedtuple
import logging
import threading
import numpy
@@ -37,10 +41,13 @@ import numpy
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor, CancelledError
+from ....utils.proxy import docstring
+from ....math.combo import min_max
from ....utils.weakref import WeakList
from .._utils.delaunay import delaunay
from .core import PointsBase, ColormapMixIn, ScatterVisualizationMixIn
from .axis import Axis
+from ._pick import PickingResult
_logger = logging.getLogger(__name__)
@@ -79,6 +86,184 @@ class _GreedyThreadPoolExecutor(ThreadPoolExecutor):
return future
+# Functions to guess grid shape from coordinates
+
+def _get_z_line_length(array):
+ """Return length of line if array is a Z-like 2D regular grid.
+
+ :param numpy.ndarray array: The 1D array of coordinates to check
+ :return: 0 if no line length could be found,
+ else the number of element per line.
+ :rtype: int
+ """
+ sign = numpy.sign(numpy.diff(array))
+ if len(sign) == 0 or sign[0] == 0: # We don't handle that
+ return 0
+ # Check this way to account for 0 sign (i.e., diff == 0)
+ beginnings = numpy.where(sign == - sign[0])[0] + 1
+ if len(beginnings) == 0:
+ return 0
+ length = beginnings[0]
+ if numpy.all(numpy.equal(numpy.diff(beginnings), length)):
+ return length
+ return 0
+
+
+def _guess_z_grid_shape(x, y):
+ """Guess the shape of a grid from (x, y) coordinates.
+
+ The grid might contain more elements than x and y,
+ as the last line might be partly filled.
+
+ :param numpy.ndarray x:
+ :paran numpy.ndarray y:
+ :returns: (order, (height, width)) of the regular grid,
+ or None if could not guess one.
+ 'order' is 'row' if X (i.e., column) is the fast dimension, else 'column'.
+ :rtype: Union[List(str,int),None]
+ """
+ width = _get_z_line_length(x)
+ if width != 0:
+ return 'row', (int(numpy.ceil(len(x) / width)), width)
+ else:
+ height = _get_z_line_length(y)
+ if height != 0:
+ return 'column', (height, int(numpy.ceil(len(y) / height)))
+ return None
+
+
+def is_monotonic(array):
+ """Returns whether array is monotonic (increasing or decreasing).
+
+ :param numpy.ndarray array: 1D array-like container.
+ :returns: 1 if array is monotonically increasing,
+ -1 if array is monotonically decreasing,
+ 0 if array is not monotonic
+ :rtype: int
+ """
+ diff = numpy.diff(numpy.ravel(array))
+ if numpy.all(diff >= 0):
+ return 1
+ elif numpy.all(diff <= 0):
+ return -1
+ else:
+ return 0
+
+
+def _guess_grid(x, y):
+ """Guess a regular grid from the points.
+
+ Result convention is (x, y)
+
+ :param numpy.ndarray x: X coordinates of the points
+ :param numpy.ndarray y: Y coordinates of the points
+ :returns: (order, (height, width)
+ order is 'row' or 'column'
+ :rtype: Union[List[str,List[int]],None]
+ """
+ x, y = numpy.ravel(x), numpy.ravel(y)
+
+ guess = _guess_z_grid_shape(x, y)
+ if guess is not None:
+ return guess
+
+ else:
+ # Cannot guess a regular grid
+ # Let's assume it's a single line
+ order = 'row' # or 'column' doesn't matter for a single line
+ y_monotonic = is_monotonic(y)
+ if is_monotonic(x) or y_monotonic: # we can guess a line
+ x_min, x_max = min_max(x)
+ y_min, y_max = min_max(y)
+
+ if not y_monotonic or x_max - x_min >= y_max - y_min:
+ # x only is monotonic or both are and X varies more
+ # line along X
+ shape = 1, len(x)
+ else:
+ # y only is monotonic or both are and Y varies more
+ # line along Y
+ shape = len(y), 1
+
+ else: # Cannot guess a line from the points
+ return None
+
+ return order, shape
+
+
+def _quadrilateral_grid_coords(points):
+ """Compute an irregular grid of quadrilaterals from a set of points
+
+ The input points are expected to lie on a grid.
+
+ :param numpy.ndarray points:
+ 3D data set of 2D input coordinates (height, width, 2)
+ height and width must be at least 2.
+ :return: 3D dataset of 2D coordinates of the grid (height+1, width+1, 2)
+ """
+ assert points.ndim == 3
+ assert points.shape[0] >= 2
+ assert points.shape[1] >= 2
+ assert points.shape[2] == 2
+
+ dim0, dim1 = points.shape[:2]
+ grid_points = numpy.zeros((dim0 + 1, dim1 + 1, 2), dtype=numpy.float64)
+
+ # Compute inner points as mean of 4 neighbours
+ neighbour_view = numpy.lib.stride_tricks.as_strided(
+ points,
+ shape=(dim0 - 1, dim1 - 1, 2, 2, points.shape[2]),
+ strides=points.strides[:2] + points.strides[:2] + points.strides[-1:], writeable=False)
+ inner_points = numpy.mean(neighbour_view, axis=(2, 3))
+ grid_points[1:-1, 1:-1] = inner_points
+
+ # Compute 'vertical' sides
+ # Alternative: grid_points[1:-1, [0, -1]] = points[:-1, [0, -1]] + points[1:, [0, -1]] - inner_points[:, [0, -1]]
+ grid_points[1:-1, [0, -1], 0] = points[:-1, [0, -1], 0] + points[1:, [0, -1], 0] - inner_points[:, [0, -1], 0]
+ grid_points[1:-1, [0, -1], 1] = inner_points[:, [0, -1], 1]
+
+ # Compute 'horizontal' sides
+ grid_points[[0, -1], 1:-1, 0] = inner_points[[0, -1], :, 0]
+ grid_points[[0, -1], 1:-1, 1] = points[[0, -1], :-1, 1] + points[[0, -1], 1:, 1] - inner_points[[0, -1], :, 1]
+
+ # Compute corners
+ d0, d1 = [0, 0, -1, -1], [0, -1, -1, 0]
+ grid_points[d0, d1] = 2 * points[d0, d1] - inner_points[d0, d1]
+ return grid_points
+
+
+def _quadrilateral_grid_as_triangles(points):
+ """Returns the points and indices to make a grid of quadirlaterals
+
+ :param numpy.ndarray points:
+ 3D array of points (height, width, 2)
+ :return: triangle corners (4 * N, 2), triangle indices (2 * N, 3)
+ With N = height * width, the number of input points
+ """
+ nbpoints = numpy.prod(points.shape[:2])
+
+ grid = _quadrilateral_grid_coords(points)
+ coords = numpy.empty((4 * nbpoints, 2), dtype=grid.dtype)
+ coords[::4] = grid[:-1, :-1].reshape(-1, 2)
+ coords[1::4] = grid[1:, :-1].reshape(-1, 2)
+ coords[2::4] = grid[:-1, 1:].reshape(-1, 2)
+ coords[3::4] = grid[1:, 1:].reshape(-1, 2)
+
+ indices = numpy.empty((2 * nbpoints, 3), dtype=numpy.uint32)
+ indices[::2, 0] = numpy.arange(0, 4 * nbpoints, 4)
+ indices[::2, 1] = numpy.arange(1, 4 * nbpoints, 4)
+ indices[::2, 2] = numpy.arange(2, 4 * nbpoints, 4)
+ indices[1::2, 0] = indices[::2, 1]
+ indices[1::2, 1] = indices[::2, 2]
+ indices[1::2, 2] = numpy.arange(3, 4 * nbpoints, 4)
+
+ return coords, indices
+
+
+_RegularGridInfo = namedtuple(
+ '_RegularGridInfo', ['bounds', 'origin', 'scale', 'shape', 'order'])
+
+
class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
"""Description of a scatter"""
@@ -87,7 +272,10 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
_SUPPORTED_SCATTER_VISUALIZATION = (
ScatterVisualizationMixIn.Visualization.POINTS,
- ScatterVisualizationMixIn.Visualization.SOLID)
+ ScatterVisualizationMixIn.Visualization.SOLID,
+ ScatterVisualizationMixIn.Visualization.REGULAR_GRID,
+ ScatterVisualizationMixIn.Visualization.IRREGULAR_GRID,
+ )
"""Overrides supported Visualizations"""
def __init__(self):
@@ -104,7 +292,86 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
# Cache triangles: x, y, indices
self.__cacheTriangles = None, None, None
+
+ # Cache regular grid info
+ self.__cacheRegularGridInfo = None
+
+ @docstring(ScatterVisualizationMixIn)
+ def setVisualizationParameter(self, parameter, value):
+ changed = super(Scatter, self).setVisualizationParameter(parameter, value)
+ if changed and parameter in (self.VisualizationParameter.GRID_BOUNDS,
+ self.VisualizationParameter.GRID_MAJOR_ORDER,
+ self.VisualizationParameter.GRID_SHAPE):
+ self.__cacheRegularGridInfo = None
+ return changed
+
+ @docstring(ScatterVisualizationMixIn)
+ def getCurrentVisualizationParameter(self, parameter):
+ value = self.getVisualizationParameter(parameter)
+ if value is not None:
+ return value # Value has been set, return it
+
+ elif parameter is self.VisualizationParameter.GRID_BOUNDS:
+ grid = self.__getRegularGridInfo()
+ return None if grid is None else grid.bounds
+ elif parameter is self.VisualizationParameter.GRID_MAJOR_ORDER:
+ grid = self.__getRegularGridInfo()
+ return None if grid is None else grid.order
+
+ elif parameter is self.VisualizationParameter.GRID_SHAPE:
+ grid = self.__getRegularGridInfo()
+ return None if grid is None else grid.shape
+
+ else:
+ raise NotImplementedError()
+
+ def __getRegularGridInfo(self):
+ """Get grid info"""
+ if self.__cacheRegularGridInfo is None:
+ shape = self.getVisualizationParameter(
+ self.VisualizationParameter.GRID_SHAPE)
+ order = self.getVisualizationParameter(
+ self.VisualizationParameter.GRID_MAJOR_ORDER)
+ if shape is None or order is None:
+ guess = _guess_grid(self.getXData(copy=False),
+ self.getYData(copy=False))
+ if guess is None:
+ _logger.warning(
+ 'Cannot guess a grid: Cannot display as regular grid image')
+ return None
+ if shape is None:
+ shape = guess[1]
+ if order is None:
+ order = guess[0]
+
+ bounds = self.getVisualizationParameter(
+ self.VisualizationParameter.GRID_BOUNDS)
+ if bounds is None:
+ x, y = self.getXData(copy=False), self.getYData(copy=False)
+ min_, max_ = min_max(x)
+ xRange = (min_, max_) if (x[0] - min_) < (max_ - x[0]) else (max_, min_)
+ min_, max_ = min_max(y)
+ yRange = (min_, max_) if (y[0] - min_) < (max_ - y[0]) else (max_, min_)
+ bounds = (xRange[0], yRange[0]), (xRange[1], yRange[1])
+
+ begin, end = bounds
+ scale = ((end[0] - begin[0]) / max(1, shape[1] - 1),
+ (end[1] - begin[1]) / max(1, shape[0] - 1))
+ if scale[0] == 0 and scale[1] == 0:
+ scale = 1., 1.
+ elif scale[0] == 0:
+ scale = scale[1], scale[1]
+ elif scale[1] == 0:
+ scale = scale[0], scale[0]
+
+ origin = begin[0] - 0.5 * scale[0], begin[1] - 0.5 * scale[1]
+
+ self.__cacheRegularGridInfo = _RegularGridInfo(
+ bounds=bounds, origin=origin, scale=scale, shape=shape, order=order)
+
+ return self.__cacheRegularGridInfo
+
def _addBackendRenderer(self, backend):
"""Update backend renderer"""
# Filter-out values <= 0
@@ -129,8 +396,10 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
# Apply mask to colors
rgbacolors = rgbacolors[mask]
- if self.getVisualization() is self.Visualization.POINTS:
- return backend.addCurve(xFiltered, yFiltered, self.getLegend(),
+ visualization = self.getVisualization()
+
+ if visualization is self.Visualization.POINTS:
+ return backend.addCurve(xFiltered, yFiltered,
color=rgbacolors,
symbol=self.getSymbol(),
linewidth=0,
@@ -139,32 +408,153 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
xerror=xerror,
yerror=yerror,
z=self.getZValue(),
- selectable=self.isSelectable(),
fill=False,
alpha=self.getAlpha(),
- symbolsize=self.getSymbolSize())
+ symbolsize=self.getSymbolSize(),
+ baseline=None)
- else: # 'solid'
+ else:
plot = self.getPlot()
if (plot is None or
plot.getXAxis().getScale() != Axis.LINEAR or
plot.getYAxis().getScale() != Axis.LINEAR):
- # Solid visualization is not available with log scaled axes
+ # Those visualizations are not available with log scaled axes
return None
- triangulation = self._getDelaunay().result()
- if triangulation is None:
- return None
- else:
- triangles = triangulation.simplices.astype(numpy.int32)
- return backend.addTriangles(xFiltered,
- yFiltered,
- triangles,
- legend=self.getLegend(),
- color=rgbacolors,
+ if visualization is self.Visualization.SOLID:
+ triangulation = self._getDelaunay().result()
+ if triangulation is None:
+ _logger.warning(
+ 'Cannot get a triangulation: Cannot display as solid surface')
+ return None
+ else:
+ triangles = triangulation.simplices.astype(numpy.int32)
+ return backend.addTriangles(xFiltered,
+ yFiltered,
+ triangles,
+ color=rgbacolors,
+ z=self.getZValue(),
+ alpha=self.getAlpha())
+
+ elif visualization is self.Visualization.REGULAR_GRID:
+ gridInfo = self.__getRegularGridInfo()
+ if gridInfo is None:
+ return None
+
+ dim0, dim1 = gridInfo.shape
+ if gridInfo.order == 'column': # transposition needed
+ dim0, dim1 = dim1, dim0
+
+ if len(rgbacolors) == dim0 * dim1:
+ image = rgbacolors.reshape(dim0, dim1, -1)
+ else:
+ # The points do not fill the whole image
+ image = numpy.empty((dim0 * dim1, 4), dtype=rgbacolors.dtype)
+ image[:len(rgbacolors)] = rgbacolors
+ image[len(rgbacolors):] = 0, 0, 0, 0 # Transparent pixels
+ image.shape = dim0, dim1, -1
+
+ if gridInfo.order == 'column':
+ image = numpy.transpose(image, axes=(1, 0, 2))
+
+ return backend.addImage(
+ data=image,
+ origin=gridInfo.origin,
+ scale=gridInfo.scale,
+ z=self.getZValue(),
+ colormap=None,
+ alpha=self.getAlpha())
+
+ elif visualization is self.Visualization.IRREGULAR_GRID:
+ gridInfo = self.__getRegularGridInfo()
+ if gridInfo is None:
+ return None
+
+ shape = gridInfo.shape
+ if shape is None: # No shape, no display
+ return None
+
+ # clip shape to fully filled lines
+ if len(xFiltered) != numpy.prod(shape):
+ if gridInfo.order == 'row':
+ shape = len(xFiltered) // shape[1], shape[1]
+ else: # column-major order
+ shape = shape[0], len(xFiltered) // shape[0]
+ if shape[0] < 2 or shape[1] < 2: # Not enough points
+ return None
+
+ nbpoints = numpy.prod(shape)
+ if gridInfo.order == 'row':
+ points = numpy.transpose((xFiltered[:nbpoints], yFiltered[:nbpoints]))
+ points = points.reshape(shape[0], shape[1], 2)
+
+ else: # column-major order
+ points = numpy.transpose((yFiltered[:nbpoints], xFiltered[:nbpoints]))
+ points = points.reshape(shape[1], shape[0], 2)
+
+ coords, indices = _quadrilateral_grid_as_triangles(points)
+
+ if gridInfo.order == 'row':
+ x, y = coords[:, 0], coords[:, 1]
+ else: # column-major order
+ y, x = coords[:, 0], coords[:, 1]
+
+ gridcolors = numpy.empty(
+ (4 * nbpoints, rgbacolors.shape[-1]), dtype=rgbacolors.dtype)
+ for first in range(4):
+ gridcolors[first::4] = rgbacolors[:nbpoints]
+
+ return backend.addTriangles(x,
+ y,
+ indices,
+ color=gridcolors,
z=self.getZValue(),
- selectable=self.isSelectable(),
alpha=self.getAlpha())
+ else:
+ _logger.error("Unhandled visualization %s", visualization)
+ return None
+
+ @docstring(PointsBase)
+ def pick(self, x, y):
+ result = super(Scatter, self).pick(x, y)
+
+ if result is not None:
+ visualization = self.getVisualization()
+
+ if visualization is self.Visualization.IRREGULAR_GRID:
+ # Specific handling of picking for the irregular grid mode
+ index = result.getIndices(copy=False)[0] // 4
+ result = PickingResult(self, (index,))
+
+ elif visualization is self.Visualization.REGULAR_GRID:
+ # Specific handling of picking for the regular grid mode
+ plot = self.getPlot()
+ if plot is None:
+ return None
+
+ dataPos = plot.pixelToData(x, y)
+ if dataPos is None:
+ return None
+
+ gridInfo = self.__getRegularGridInfo()
+ if gridInfo is None:
+ return None
+
+ origin = gridInfo.origin
+ scale = gridInfo.scale
+ column = int((dataPos[0] - origin[0]) / scale[0])
+ row = int((dataPos[1] - origin[1]) / scale[1])
+
+ if gridInfo.order == 'row':
+ index = row * gridInfo.shape[1] + column
+ else:
+ index = row + column * gridInfo.shape[0]
+ if index >= len(self.getXData(copy=False)): # OK as long as not log scale
+ return None # Image can be larger than scatter
+
+ result = PickingResult(self, (index,))
+
+ return result
def __getExecutor(self):
"""Returns async greedy executor
@@ -358,6 +748,9 @@ class Scatter(PointsBase, ColormapMixIn, ScatterVisualizationMixIn):
self.__interpolatorFuture.cancel()
self.__interpolatorFuture = None
+ # Data changed, this needs update
+ self.__cacheRegularGridInfo = None
+
self._value = value
if alpha is not None:
diff --git a/silx/gui/plot/items/shape.py b/silx/gui/plot/items/shape.py
index 9fc1306..e6dc529 100644
--- a/silx/gui/plot/items/shape.py
+++ b/silx/gui/plot/items/shape.py
@@ -36,7 +36,7 @@ import numpy
import six
from ... import colors
-from .core import Item, ColorMixIn, FillMixIn, ItemChangedType, LineMixIn
+from .core import Item, ColorMixIn, FillMixIn, ItemChangedType, LineMixIn, YAxisMixIn
_logger = logging.getLogger(__name__)
@@ -70,7 +70,6 @@ class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
x, y = points.T[0], points.T[1]
return backend.addItem(x,
y,
- legend=self.getLegend(),
shape=self.getType(),
color=self.getColor(),
fill=self.isFill(),
@@ -154,3 +153,64 @@ class Shape(Item, ColorMixIn, FillMixIn, LineMixIn):
self._lineBgColor = color
self._updated(ItemChangedType.LINE_BG_COLOR)
+
+
+class BoundingRect(Item, YAxisMixIn):
+ """An invisible shape which enforce the plot view to display the defined
+ space on autoscale.
+
+ This item do not display anything. But if the visible property is true,
+ this bounding box is used by the plot, if not, the bounding box is
+ ignored. That's the default behaviour for plot items.
+
+ It can be applied on the "left" or "right" axes. Not both at the same time.
+ """
+
+ def __init__(self):
+ Item.__init__(self)
+ YAxisMixIn.__init__(self)
+ self.__bounds = None
+
+ def _updated(self, event=None, checkVisibility=True):
+ if event in (ItemChangedType.YAXIS,
+ ItemChangedType.VISIBLE,
+ ItemChangedType.DATA):
+ # TODO hackish data range implementation
+ plot = self.getPlot()
+ if plot is not None:
+ plot._invalidateDataRange()
+
+ super(BoundingRect, self)._updated(event, checkVisibility)
+
+ def setBounds(self, rect):
+ """Set the bounding box of this item in data coordinates
+
+ :param Union[None,List[float]] rect: (xmin, xmax, ymin, ymax) or None
+ """
+ if rect is not None:
+ rect = float(rect[0]), float(rect[1]), float(rect[2]), float(rect[3])
+ assert rect[0] <= rect[1]
+ assert rect[2] <= rect[3]
+
+ if rect != self.__bounds:
+ self.__bounds = rect
+ self._updated(ItemChangedType.DATA)
+
+ def _getBounds(self):
+ plot = self.getPlot()
+ if plot is not None:
+ xPositive = plot.getXAxis()._isLogarithmic()
+ yPositive = plot.getYAxis()._isLogarithmic()
+ if xPositive or yPositive:
+ bounds = list(self.__bounds)
+ if xPositive and bounds[1] <= 0:
+ return None
+ if xPositive and bounds[0] <= 0:
+ bounds[0] = bounds[1]
+ if yPositive and bounds[3] <= 0:
+ return None
+ if yPositive and bounds[2] <= 0:
+ bounds[2] = bounds[3]
+ return tuple(bounds)
+
+ return self.__bounds
diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py
index 7449c12..9724ec6 100644..100755
--- a/silx/gui/plot/test/testPlotWidget.py
+++ b/silx/gui/plot/test/testPlotWidget.py
@@ -32,6 +32,7 @@ __date__ = "03/01/2019"
import unittest
import logging
import numpy
+import sys
from silx.utils.testutils import ParametricTestCase, parameterize
from silx.gui.utils.testutils import SignalListener
@@ -42,6 +43,7 @@ from silx.test.utils import test_options
from silx.gui import qt
from silx.gui.plot import PlotWidget
from silx.gui.plot.items.curve import CurveStyle
+from silx.gui.plot.items.shape import BoundingRect
from silx.gui.colors import Colormap
from .utils import PlotWidgetTestCase
@@ -57,6 +59,19 @@ DATA_2D = numpy.arange(SIZE ** 2).reshape(SIZE, SIZE)
logger = logging.getLogger(__name__)
+class TestSpecialBackend(PlotWidgetTestCase, ParametricTestCase):
+
+ def __init__(self, methodName='runTest', backend=None):
+ TestCaseQt.__init__(self, methodName=methodName)
+ self.__backend = backend
+
+ def _createPlot(self):
+ return PlotWidget(backend=self.__backend)
+
+ def testPlot(self):
+ self.assertIsNotNone(self.plot)
+
+
class TestPlotWidget(PlotWidgetTestCase, ParametricTestCase):
"""Basic tests for PlotWidget"""
@@ -475,6 +490,56 @@ class TestPlotCurve(PlotWidgetTestCase):
replace=False, resetzoom=False,
color=color, symbol='o')
+ def testPlotBaselineNumpyArray(self):
+ """simple test of the API with baseline as a numpy array"""
+ x = numpy.arange(0, 10, step=0.1)
+ my_sin = numpy.sin(x)
+ y = numpy.arange(-4, 6, step=0.1) + my_sin
+ baseline = y - 1.0
+
+ self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True,
+ baseline=baseline)
+
+ def testPlotBaselineScalar(self):
+ """simple test of the API with baseline as an int"""
+ x = numpy.arange(0, 10, step=0.1)
+ my_sin = numpy.sin(x)
+ y = numpy.arange(-4, 6, step=0.1) + my_sin
+
+ self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True,
+ baseline=0)
+
+ def testPlotBaselineList(self):
+ """simple test of the API with baseline as an int"""
+ x = numpy.arange(0, 10, step=0.1)
+ my_sin = numpy.sin(x)
+ y = numpy.arange(-4, 6, step=0.1) + my_sin
+
+ self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True,
+ baseline=list(range(0, 100, 1)))
+
+
+class TestPlotHistogram(PlotWidgetTestCase):
+ """Basic tests for add Histogram"""
+ def setUp(self):
+ super(TestPlotHistogram, self).setUp()
+ self.edges = numpy.arange(0, 10, step=1)
+ self.histogram = numpy.random.random(len(self.edges))
+
+ def testPlot(self):
+ self.plot.addHistogram(histogram=self.histogram,
+ edges=self.edges,
+ legend='histogram1')
+
+ def testPlotBaseline(self):
+ self.plot.addHistogram(histogram=self.histogram,
+ edges=self.edges,
+ legend='histogram1',
+ color='blue',
+ baseline=-2,
+ z=2,
+ fill=True)
+
class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase):
"""Basic tests for addScatter"""
@@ -487,7 +552,7 @@ class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase):
self.plot.resetZoom()
def testScatterVisualization(self):
- self.plot.addScatter((0, 1, 2, 3), (2, 0, 2, 1), (0, 1, 2, 3))
+ self.plot.addScatter((0, 1, 0, 1), (0, 0, 2, 2), (0, 1, 2, 3))
self.plot.resetZoom()
self.qapp.processEvents()
@@ -495,12 +560,76 @@ class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase):
for visualization in ('solid',
'points',
+ 'regular_grid',
scatter.Visualization.SOLID,
- scatter.Visualization.POINTS):
+ scatter.Visualization.POINTS,
+ scatter.Visualization.REGULAR_GRID):
with self.subTest(visualization=visualization):
scatter.setVisualization(visualization)
self.qapp.processEvents()
+ def testGridVisualization(self):
+ """Test regular and irregular grid mode with different points"""
+ points = { # name: (x, y, order)
+ 'single point': ((1.,), (1.,), 'row'),
+ 'horizontal line': ((0, 1, 2), (0, 0, 0), 'row'),
+ 'horizontal line backward': ((2, 1, 0), (0, 0, 0), 'row'),
+ 'vertical line': ((0, 0, 0), (0, 1, 2), 'row'),
+ 'vertical line backward': ((0, 0, 0), (2, 1, 0), 'row'),
+ 'grid fast x, +x +y': ((0, 1, 2, 0, 1, 2), (0, 0, 0, 1, 1, 1), 'row'),
+ 'grid fast x, +x -y': ((0, 1, 2, 0, 1, 2), (1, 1, 1, 0, 0, 0), 'row'),
+ 'grid fast x, -x -y': ((2, 1, 0, 2, 1, 0), (1, 1, 1, 0, 0, 0), 'row'),
+ 'grid fast x, -x +y': ((2, 1, 0, 2, 1, 0), (0, 0, 0, 1, 1, 1), 'row'),
+ 'grid fast y, +x +y': ((0, 0, 0, 1, 1, 1), (0, 1, 2, 0, 1, 2), 'column'),
+ 'grid fast y, +x -y': ((0, 0, 0, 1, 1, 1), (2, 1, 0, 2, 1, 0), 'column'),
+ 'grid fast y, -x -y': ((1, 1, 1, 0, 0, 0), (2, 1, 0, 2, 1, 0), 'column'),
+ 'grid fast y, -x +y': ((1, 1, 1, 0, 0, 0), (0, 1, 2, 0, 1, 2), 'column'),
+ }
+
+ self.plot.addScatter((), (), ())
+ scatter = self.plot.getItems()[0]
+
+ self.qapp.processEvents()
+
+ for visualization in (scatter.Visualization.REGULAR_GRID,
+ scatter.Visualization.IRREGULAR_GRID):
+ scatter.setVisualization(visualization)
+ self.assertIs(scatter.getVisualization(), visualization)
+
+ for name, (x, y, ref_order) in points.items():
+ with self.subTest(name=name, visualization=visualization.name):
+ scatter.setData(x, y, numpy.arange(len(x)))
+ self.plot.setGraphTitle(name)
+ self.plot.resetZoom()
+ self.qapp.processEvents()
+
+ order = scatter.getCurrentVisualizationParameter(
+ scatter.VisualizationParameter.GRID_MAJOR_ORDER)
+ self.assertEqual(ref_order, order)
+
+ ref_bounds = (x[0], y[0]), (x[-1], y[-1])
+ bounds = scatter.getCurrentVisualizationParameter(
+ scatter.VisualizationParameter.GRID_BOUNDS)
+ self.assertEqual(ref_bounds, bounds)
+
+ shape = scatter.getCurrentVisualizationParameter(
+ scatter.VisualizationParameter.GRID_SHAPE)
+
+ self.plot.getXAxis().setLimits(numpy.min(x) - 1, numpy.max(x) + 1)
+ self.plot.getYAxis().setLimits(numpy.min(y) - 1, numpy.max(y) + 1)
+ self.qapp.processEvents()
+
+ for index, position in enumerate(zip(x, y)):
+ xpixel, ypixel = self.plot.dataToPixel(*position)
+ result = scatter.pick(xpixel, ypixel)
+ if (visualization is scatter.Visualization.IRREGULAR_GRID and
+ (shape[0] < 2 or shape[1] < 2)):
+ self.assertIsNone(result)
+ else:
+ self.assertIsNotNone(result)
+ self.assertIs(result.getItem(), scatter)
+ self.assertEqual(result.getIndices()[0], (index,))
+
class TestPlotMarker(PlotWidgetTestCase):
"""Basic tests for add*Marker"""
@@ -593,6 +722,39 @@ class TestPlotMarker(PlotWidgetTestCase):
self.plot.resetZoom()
+ def testPlotMarkerYAxis(self):
+ # Check only the API
+
+ legend = self.plot.addMarker(10, 10)
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "left")
+
+ legend = self.plot.addMarker(10, 10, yaxis="right")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "right")
+
+ legend = self.plot.addMarker(10, 10, yaxis="left")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "left")
+
+ legend = self.plot.addXMarker(10, yaxis="right")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "right")
+
+ legend = self.plot.addXMarker(10, yaxis="left")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "left")
+
+ legend = self.plot.addYMarker(10, yaxis="right")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "right")
+
+ legend = self.plot.addYMarker(10, yaxis="left")
+ item = self.plot._getMarker(legend)
+ self.assertEqual(item.getYAxis(), "left")
+
+ self.plot.resetZoom()
+
# TestPlotItem ################################################################
@@ -1185,6 +1347,53 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
"""Test coverage on setAxesDisplayed(True)"""
self.plot.setAxesDisplayed(True)
+ def testBoundingRectItem(self):
+ item = BoundingRect()
+ item.setBounds((-1000, 1000, -2000, 2000))
+ self.plot._add(item)
+ self.plot.resetZoom()
+ limits = numpy.array(self.plot.getXAxis().getLimits())
+ numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000]))
+ limits = numpy.array(self.plot.getYAxis().getLimits())
+ numpy.testing.assert_almost_equal(limits, numpy.array([-2000, 2000]))
+
+ def testBoundingRectRightItem(self):
+ item = BoundingRect()
+ item.setYAxis("right")
+ item.setBounds((-1000, 1000, -2000, 2000))
+ self.plot._add(item)
+ self.plot.resetZoom()
+ limits = numpy.array(self.plot.getXAxis().getLimits())
+ numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000]))
+ limits = numpy.array(self.plot.getYAxis("right").getLimits())
+ numpy.testing.assert_almost_equal(limits, numpy.array([-2000, 2000]))
+
+ def testBoundingRectArguments(self):
+ item = BoundingRect()
+ with self.assertRaises(Exception):
+ item.setBounds((1000, -1000, -2000, 2000))
+ with self.assertRaises(Exception):
+ item.setBounds((-1000, 1000, 2000, -2000))
+
+ def testBoundingRectWithLog(self):
+ item = BoundingRect()
+ self.plot._add(item)
+
+ item.setBounds((-1000, 1000, -2000, 2000))
+ self.plot.getXAxis()._setLogarithmic(True)
+ self.plot.getYAxis()._setLogarithmic(False)
+ self.assertEqual(item.getBounds(), (1000, 1000, -2000, 2000))
+
+ item.setBounds((-1000, 1000, -2000, 2000))
+ self.plot.getXAxis()._setLogarithmic(False)
+ self.plot.getYAxis()._setLogarithmic(True)
+ self.assertEqual(item.getBounds(), (-1000, 1000, 2000, 2000))
+
+ item.setBounds((-1000, 0, -2000, 2000))
+ self.plot.getXAxis()._setLogarithmic(True)
+ self.plot.getYAxis()._setLogarithmic(False)
+ self.assertIsNone(item.getBounds())
+
class TestPlotCurveLog(PlotWidgetTestCase, ParametricTestCase):
"""Basic tests for addCurve with log scale axes"""
@@ -1564,6 +1773,7 @@ def suite():
testClasses = (TestPlotWidget,
TestPlotImage,
TestPlotCurve,
+ TestPlotHistogram,
TestPlotScatter,
TestPlotMarker,
TestPlotItem,
@@ -1581,6 +1791,10 @@ def suite():
for testClass in testClasses:
test_suite.addTest(parameterize(testClass, backend=None))
+ test_suite.addTest(parameterize(TestSpecialBackend, backend=u"mpl"))
+ if sys.version_info[0] == 2:
+ test_suite.addTest(parameterize(TestSpecialBackend, backend=b"mpl"))
+
if test_options.WITH_GL_TEST:
# Tests with OpenGL backend
for testClass in testClasses:
diff --git a/silx/gui/plot/test/testStats.py b/silx/gui/plot/test/testStats.py
index 4bc2144..185e79c 100644
--- a/silx/gui/plot/test/testStats.py
+++ b/silx/gui/plot/test/testStats.py
@@ -273,11 +273,12 @@ class TestStatsFormatter(TestCaseQt):
formatter.format(self.stat.calculate(self.curveContext)), '0.000')
-class TestStatsHandler(unittest.TestCase):
+class TestStatsHandler(TestCaseQt):
"""Make sure the StatHandler is correctly making the link between
:class:`StatBase` and :class:`StatFormatter` and checking the API is valid
"""
def setUp(self):
+ TestCaseQt.setUp(self)
self.plot1d = Plot1D()
x = range(20)
y = range(20)
@@ -289,6 +290,8 @@ class TestStatsHandler(unittest.TestCase):
def tearDown(self):
self.plot1d.setAttribute(qt.Qt.WA_DeleteOnClose)
self.plot1d.close()
+ self.plot1d = None
+ TestCaseQt.tearDown(self)
def testConstructor(self):
"""Make sure the constructor can deal will all possible arguments:
diff --git a/silx/gui/plot/tools/PositionInfo.py b/silx/gui/plot/tools/PositionInfo.py
index 83b61bd..fef11dd 100644
--- a/silx/gui/plot/tools/PositionInfo.py
+++ b/silx/gui/plot/tools/PositionInfo.py
@@ -121,7 +121,7 @@ class PositionInfo(qt.QWidget):
contentWidget.setText('------')
contentWidget.setTextInteractionFlags(qt.Qt.TextSelectableByMouse)
contentWidget.setFixedWidth(
- contentWidget.fontMetrics().width('##############'))
+ contentWidget.fontMetrics().boundingRect('##############').width())
layout.addWidget(contentWidget)
self._fields.append((contentWidget, name, func))
diff --git a/silx/gui/plot/tools/profile/_BaseProfileToolBar.py b/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
index 6d9d6d4..ced81da 100644
--- a/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
+++ b/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018 European Synchrotron Radiation Facility
+# Copyright (c) 2018-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
@@ -321,7 +321,7 @@ class _BaseProfileToolBar(qt.QToolBar):
def __roiAdded(self, roi):
"""Handle new ROI"""
- roi.setLabel('Profile')
+ roi.setName('Profile')
roi.setEditable(True)
# Remove any other ROI
diff --git a/silx/gui/plot/tools/roi.py b/silx/gui/plot/tools/roi.py
index eb933a0..3535097 100644
--- a/silx/gui/plot/tools/roi.py
+++ b/silx/gui/plot/tools/roi.py
@@ -253,7 +253,7 @@ class RegionOfInterestManager(qt.QObject):
else:
return False
- def _regionOfInterestChanged(self):
+ def _regionOfInterestChanged(self, event=None):
"""Handle ROI object changed"""
self.sigRoiChanged.emit()
@@ -271,7 +271,7 @@ class RegionOfInterestManager(qt.QObject):
number of ROIs has been reached.
"""
roi = roiClass(parent=None)
- roi.setLabel(str(label))
+ roi.setName(str(label))
roi.setFirstShapePoints(points)
self.addRoi(roi, index)
@@ -283,6 +283,9 @@ class RegionOfInterestManager(qt.QObject):
:param roi_items.RegionOfInterest roi: The ROI to add
:param int index: The position where to insert the ROI,
By default it is appended to the end of the list of ROIs
+ :param bool useManagerColor:
+ Whether to set the ROI color to the default one of the manager or not.
+ (Default: True).
:raise RuntimeError: When ROI cannot be added because the maximum
number of ROIs has been reached.
"""
@@ -297,6 +300,7 @@ class RegionOfInterestManager(qt.QObject):
roi.setColor(self.getColor())
roi.sigRegionChanged.connect(self._regionOfInterestChanged)
+ roi.sigItemChanged.connect(self._regionOfInterestChanged)
if index is None:
self._rois.append(roi)
@@ -321,6 +325,7 @@ class RegionOfInterestManager(qt.QObject):
self._rois.remove(roi)
roi.sigRegionChanged.disconnect(self._regionOfInterestChanged)
+ roi.sigItemChanged.disconnect(self._regionOfInterestChanged)
roi.setParent(None)
self._roisUpdated()
@@ -820,11 +825,14 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
return
if column == 0:
- roi.setVisible(item.checkState() == qt.Qt.Checked)
- roi.setLabel(item.text())
+ # First collect information from item, then update ROI
+ # Otherwise, this causes issues issues
+ checked = item.checkState() == qt.Qt.Checked
+ text= item.text()
+ roi.setVisible(checked)
+ roi.setName(text)
elif column == 1:
- roi.setEditable(
- item.checkState() == qt.Qt.Checked)
+ roi.setEditable(item.checkState() == qt.Qt.Checked)
elif column in (2, 3, 4):
pass # TODO
else:
@@ -888,7 +896,7 @@ class RegionOfInterestTableWidget(qt.QTableWidget):
baseFlags = qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled
# Label and visible
- label = roi.getLabel()
+ label = roi.getName()
item = qt.QTableWidgetItem(label)
item.setFlags(baseFlags | qt.Qt.ItemIsEditable | qt.Qt.ItemIsUserCheckable)
item.setData(qt.Qt.UserRole, index)
diff --git a/silx/gui/plot3d/_model/items.py b/silx/gui/plot3d/_model/items.py
index 9fe3e51..7f3921a 100644
--- a/silx/gui/plot3d/_model/items.py
+++ b/silx/gui/plot3d/_model/items.py
@@ -45,7 +45,7 @@ from ...utils.image import convertArrayToQImage
from ...colors import preferredColormaps
from ... import qt, icons
from .. import items
-from ..items.volume import Isosurface, CutPlane
+from ..items.volume import Isosurface, CutPlane, ComplexIsosurface
from ..Plot3DWidget import Plot3DWidget
@@ -867,6 +867,17 @@ class ColormapRow(_ColormapBaseProxyRow):
self._sigColormapChanged.connect(self._updateColormapImage)
+ def getColormapImage(self):
+ """Returns image representing the colormap or None
+
+ :rtype: Union[QImage,None]
+ """
+ if self._colormapImage is None and self._colormap is not None:
+ image = numpy.zeros((16, 130, 3), dtype=numpy.uint8)
+ image[1:-1, 1:-1] = self._colormap.getNColors(image.shape[1] - 2)[:, :3]
+ self._colormapImage = convertArrayToQImage(image)
+ return self._colormapImage
+
def _get(self):
"""Getter for ProxyRow subclass"""
return None
@@ -908,13 +919,9 @@ class ColormapRow(_ColormapBaseProxyRow):
def data(self, column, role):
if column == 1 and role == qt.Qt.DecorationRole:
- if self._colormapImage is None:
- image = numpy.zeros((16, 130, 3), dtype=numpy.uint8)
- image[1:-1, 1:-1] = self._colormap.getNColors(image.shape[1] - 2)[:, :3]
- self._colormapImage = convertArrayToQImage(image)
- return self._colormapImage
-
- return super(ColormapRow, self).data(column, role)
+ return self.getColormapImage()
+ else:
+ return super(ColormapRow, self).data(column, role)
class SymbolRow(ItemProxyRow):
@@ -1055,12 +1062,12 @@ class ComplexModeRow(ItemProxyRow):
:param Item3D item: Scene item with symbol property
"""
- def __init__(self, item):
+ def __init__(self, item, name='Mode'):
names = [m.value.replace('_', ' ').title()
for m in item.supportedComplexModes()]
super(ComplexModeRow, self).__init__(
item=item,
- name='Mode',
+ name=name,
fget=item.getComplexMode,
fset=item.setComplexMode,
events=items.ItemChangedType.COMPLEX_MODE,
@@ -1283,6 +1290,71 @@ class IsosurfaceRow(Item3DRow):
return super(IsosurfaceRow, self).setData(column, value, role)
+class ComplexIsosurfaceRow(IsosurfaceRow):
+ """Represents an :class:`ComplexIsosurface` item.
+
+ :param ComplexIsosurface item:
+ """
+
+ _EVENTS = (items.ItemChangedType.VISIBLE,
+ items.ItemChangedType.COLOR,
+ items.ItemChangedType.COMPLEX_MODE)
+ """Events for which to update the first column in the tree"""
+
+ def __init__(self, item):
+ super(ComplexIsosurfaceRow, self).__init__(item)
+
+ self.addRow(ComplexModeRow(item, "Color Complex Mode"), index=1)
+ for row in self.children():
+ if isinstance(row, ColorProxyRow):
+ self._colorRow = row
+ break
+ else:
+ raise RuntimeError("Cannot retrieve Color tree row")
+ self._colormapRow = ColormapRow(item)
+
+ self.__updateRowsForItem(item)
+ item.sigItemChanged.connect(self.__itemChanged)
+
+ def __itemChanged(self, event):
+ """Update enabled/disabled rows"""
+ if event == items.ItemChangedType.COMPLEX_MODE:
+ item = self.sender()
+ self.__updateRowsForItem(item)
+
+ def __updateRowsForItem(self, item):
+ """Update rows for item
+
+ :param item:
+ """
+ if not isinstance(item, ComplexIsosurface):
+ return
+
+ if item.getComplexMode() == items.ComplexMixIn.ComplexMode.NONE:
+ removed = self._colormapRow
+ added = self._colorRow
+ else:
+ removed = self._colorRow
+ added = self._colormapRow
+
+ # Remove unwanted rows
+ if removed in self.children():
+ self.removeRow(removed)
+
+ # Add required rows
+ if added not in self.children():
+ self.addRow(added, index=2)
+
+ def data(self, column, role):
+ if column == 0 and role == qt.Qt.DecorationRole:
+ item = self.item()
+ if (item is not None and
+ item.getComplexMode() != items.ComplexMixIn.ComplexMode.NONE):
+ return self._colormapRow.getColormapImage()
+
+ return super(ComplexIsosurfaceRow, self).data(column, role)
+
+
class AddIsosurfaceRow(BaseRow):
"""Class for Isosurface create button
@@ -1358,7 +1430,7 @@ class VolumeIsoSurfacesRow(StaticRow):
volume.sigIsosurfaceRemoved.connect(self._isosurfaceRemoved)
if isinstance(volume, items.ComplexMixIn):
- self.addRow(ComplexModeRow(volume))
+ self.addRow(ComplexModeRow(volume, "Complex Mode"))
for item in volume.getIsosurfaces():
self.addRow(nodeFromItem(item))
@@ -1581,6 +1653,8 @@ def nodeFromItem(item):
# Item with specific model row class
if isinstance(item, (items.GroupItem, items.GroupWithAxesItem)):
return GroupItemRow(item)
+ elif isinstance(item, ComplexIsosurface):
+ return ComplexIsosurfaceRow(item)
elif isinstance(item, Isosurface):
return IsosurfaceRow(item)
diff --git a/silx/gui/plot3d/items/_pick.py b/silx/gui/plot3d/items/_pick.py
index b35ef0d..8494723 100644
--- a/silx/gui/plot3d/items/_pick.py
+++ b/silx/gui/plot3d/items/_pick.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018 European Synchrotron Radiation Facility
+# Copyright (c) 2018-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
@@ -34,6 +34,7 @@ __date__ = "24/09/2018"
import logging
import numpy
+from ...plot.items._pick import PickingResult as _PickingResult
from ..scene import Viewport, Base
@@ -177,9 +178,8 @@ class PickContext(object):
return rayObject
-class PickingResult(object):
- """Class to access picking information in a 3D scene.
- """
+class PickingResult(_PickingResult):
+ """Class to access picking information in a 3D scene."""
def __init__(self, item, positions, indices=None, fetchdata=None):
"""Init
@@ -194,7 +194,8 @@ class PickingResult(object):
to provide an alternative function to access item data.
Default is to use `item.getData`.
"""
- self._item = item
+ super(PickingResult, self).__init__(item, indices)
+
self._objectPositions = numpy.array(
positions, copy=False, dtype=numpy.float)
@@ -205,36 +206,8 @@ class PickingResult(object):
self._scenePositions = None
self._ndcPositions = None
- if indices is None:
- self._indices = None
- else:
- self._indices = numpy.array(indices, copy=False, dtype=numpy.int)
-
self._fetchdata = fetchdata
- def getItem(self):
- """Returns the item this results corresponds to.
-
- :rtype: ~silx.gui.plot3d.items.Item3D
- """
- return self._item
-
- def getIndices(self, copy=True):
- """Returns indices of picked data.
-
- If data is 1D, it returns a numpy.ndarray, otherwise
- it returns a tuple with as many numpy.ndarray as there are
- dimensions in the data.
-
- :param bool copy: True (default) to get a copy,
- False to return internal arrays
- :rtype: Union[None,numpy.ndarray,List[numpy.ndarray]]
- """
- if self._indices is None:
- return None
- indices = numpy.array(self._indices, copy=copy)
- return indices if indices.ndim == 1 else tuple(indices)
-
def getData(self, copy=True):
"""Returns picked data values
diff --git a/silx/gui/plot3d/items/scatter.py b/silx/gui/plot3d/items/scatter.py
index e8ffee1..5fce629 100644
--- a/silx/gui/plot3d/items/scatter.py
+++ b/silx/gui/plot3d/items/scatter.py
@@ -234,6 +234,9 @@ class Scatter2D(DataItem3D, ColormapMixIn, SymbolMixIn,
}
"""Dict {visualization mode: property names used in this mode}"""
+ _SUPPORTED_SCATTER_VISUALIZATION = tuple(_VISUALIZATION_PROPERTIES.keys())
+ """Overrides supported Visualizations"""
+
def __init__(self, parent=None):
DataItem3D.__init__(self, parent=parent)
ColormapMixIn.__init__(self)
diff --git a/silx/gui/plot3d/items/volume.py b/silx/gui/plot3d/items/volume.py
index ae91e82..e0a2a1f 100644
--- a/silx/gui/plot3d/items/volume.py
+++ b/silx/gui/plot3d/items/volume.py
@@ -37,13 +37,14 @@ import numpy
from silx.math.combo import min_max
from silx.math.marchingcubes import MarchingCubes
+from silx.math.interpolate import interp3d
from ....utils.proxy import docstring
from ... import _glutils as glu
from ... import qt
from ...colors import rgba
-from ..scene import cutplane, primitives, transform, utils
+from ..scene import cutplane, function, primitives, transform, utils
from .core import BaseNodeItem, Item3D, ItemChangedType, Item3DChangedType
from .mixins import ColormapMixIn, ComplexMixIn, InterpolationMixIn, PlaneMixIn
@@ -301,6 +302,15 @@ class Isosurface(Item3D):
"""Return the color of this iso-surface (QColor)"""
return qt.QColor.fromRgbF(*self._color)
+ def _updateColor(self, color):
+ """Handle update of color
+
+ :param List[float] color: RGBA channels in [0, 1]
+ """
+ primitive = self._getScenePrimitive()
+ if len(primitive.children) != 0:
+ primitive.children[0].setAttribute('color', color)
+
def setColor(self, color):
"""Set the color of the iso-surface
@@ -310,15 +320,15 @@ class Isosurface(Item3D):
color = rgba(color)
if color != self._color:
self._color = color
- primitive = self._getScenePrimitive()
- if len(primitive.children) != 0:
- primitive.children[0].setAttribute('color', self._color)
+ self._updateColor(self._color)
self._updated(ItemChangedType.COLOR)
- def _updateScenePrimitive(self):
- """Update underlying mesh"""
- self._getScenePrimitive().children = []
+ def _computeIsosurface(self):
+ """Compute isosurface for current state.
+ :return: (vertices, normals, indices) arrays
+ :rtype: List[Union[None,numpy.ndarray]]
+ """
data = self.getData(copy=False)
if data is None:
@@ -349,24 +359,31 @@ class Isosurface(Item3D):
self._level = level
self._updated(Item3DChangedType.ISO_LEVEL)
- if not numpy.isfinite(self._level):
- return
+ if numpy.isfinite(self._level):
+ st = time.time()
+ vertices, normals, indices = MarchingCubes(
+ data,
+ isolevel=self._level)
+ _logger.info('Computed iso-surface in %f s.', time.time() - st)
- st = time.time()
- vertices, normals, indices = MarchingCubes(
- data,
- isolevel=self._level)
- _logger.info('Computed iso-surface in %f s.', time.time() - st)
+ if len(vertices) != 0:
+ return vertices, normals, indices
- if len(vertices) == 0:
- return
- else:
- mesh = primitives.Mesh3D(vertices,
- colors=self._color,
- normals=normals,
- mode='triangles',
- indices=indices)
- self._getScenePrimitive().children = [mesh]
+ return None, None, None
+
+ def _updateScenePrimitive(self):
+ """Update underlying mesh"""
+ self._getScenePrimitive().children = []
+
+ vertices, normals, indices = self._computeIsosurface()
+ if vertices is not None:
+ mesh = primitives.Mesh3D(vertices,
+ colors=self._color,
+ normals=normals,
+ mode='triangles',
+ indices=indices,
+ copy=False)
+ self._getScenePrimitive().children = [mesh]
def _pickFull(self, context):
"""Perform picking in this item at given widget position.
@@ -677,17 +694,39 @@ class ComplexCutPlane(CutPlane, ComplexMixIn):
super(ComplexCutPlane, self)._updated(event)
-class ComplexIsosurface(Isosurface):
+class ComplexIsosurface(Isosurface, ComplexMixIn, ColormapMixIn):
"""Class representing an iso-surface in a :class:`ComplexField3D` item.
:param parent: The DataItem3D this iso-surface belongs to
"""
+ _SUPPORTED_COMPLEX_MODES = \
+ (ComplexMixIn.ComplexMode.NONE,) + ComplexMixIn._SUPPORTED_COMPLEX_MODES
+ """Overrides supported ComplexMode"""
+
def __init__(self, parent):
- super(ComplexIsosurface, self).__init__(parent)
+ ComplexMixIn.__init__(self)
+ ColormapMixIn.__init__(self, function.Colormap())
+ Isosurface.__init__(self, parent=parent)
+ self.setComplexMode(self.ComplexMode.NONE)
+
+ def _updateColor(self, color):
+ """Handle update of color
+
+ :param List[float] color: RGBA channels in [0, 1]
+ """
+ primitive = self._getScenePrimitive()
+ if (len(primitive.children) != 0 and
+ isinstance(primitive.children[0], primitives.ColormapMesh3D)):
+ primitive.children[0].alpha = self._color[3]
+ else:
+ super(ComplexIsosurface, self)._updateColor(color)
def _syncDataWithParent(self):
"""Synchronize this instance data with that of its parent"""
+ if self.getComplexMode() != self.ComplexMode.NONE:
+ self._setRangeFromData(self.getColormappedData(copy=False))
+
parent = self.parent()
if parent is None:
self._data = None
@@ -702,6 +741,67 @@ class ComplexIsosurface(Isosurface):
self._syncDataWithParent()
super(ComplexIsosurface, self)._parentChanged(event)
+ def getColormappedData(self, copy=True):
+ """Return 3D dataset used to apply the colormap on the isosurface.
+
+ This depends on :meth:`getComplexMode`.
+
+ :param bool copy:
+ True (default) to get a copy,
+ False to get the internal data (DO NOT modify!)
+ :return: The data set (or None if not set)
+ :rtype: Union[numpy.ndarray,None]
+ """
+ if self.getComplexMode() == self.ComplexMode.NONE:
+ return None
+ else:
+ parent = self.parent()
+ if parent is None:
+ return None
+ else:
+ return parent.getData(mode=self.getComplexMode(), copy=copy)
+
+ def _updated(self, event=None):
+ """Handle update of the isosurface (and take care of mode change)
+
+ :param ItemChangedType event: The kind of update
+ """
+ if (event == ItemChangedType.COMPLEX_MODE and
+ self.getComplexMode() != self.ComplexMode.NONE):
+ self._setRangeFromData(self.getColormappedData(copy=False))
+
+ if event in (ItemChangedType.COMPLEX_MODE,
+ ItemChangedType.COLORMAP,
+ Item3DChangedType.INTERPOLATION):
+ self._updateScenePrimitive()
+ super(ComplexIsosurface, self)._updated(event)
+
+ def _updateScenePrimitive(self):
+ """Update underlying mesh"""
+ if self.getComplexMode() == self.ComplexMode.NONE:
+ super(ComplexIsosurface, self)._updateScenePrimitive()
+
+ else: # Specific display for colormapped isosurface
+ self._getScenePrimitive().children = []
+
+ values = self.getColormappedData(copy=False)
+ if values is not None:
+ vertices, normals, indices = self._computeIsosurface()
+ if vertices is not None:
+ values = interp3d(values, vertices, method='linear_omp')
+ # TODO reuse isosurface when only color changes...
+
+ mesh = primitives.ColormapMesh3D(
+ vertices,
+ value=values.reshape(-1, 1),
+ colormap=self._getSceneColormap(),
+ normal=normals,
+ mode='triangles',
+ indices=indices,
+ copy=False)
+ mesh.alpha = self._color[3]
+ self._getScenePrimitive().children = [mesh]
+
class ComplexField3D(ScalarField3D, ComplexMixIn):
"""3D complex field on a regular grid.
@@ -720,6 +820,7 @@ class ComplexField3D(ScalarField3D, ComplexMixIn):
@docstring(ComplexMixIn)
def setComplexMode(self, mode):
+ mode = ComplexMixIn.ComplexMode.from_value(mode)
if mode != self.getComplexMode():
self.clearIsosurfaces() # Reset isosurfaces
ComplexMixIn.setComplexMode(self, mode)
diff --git a/silx/gui/plot3d/scene/primitives.py b/silx/gui/plot3d/scene/primitives.py
index 08724ba..7db61e8 100644
--- a/silx/gui/plot3d/scene/primitives.py
+++ b/silx/gui/plot3d/scene/primitives.py
@@ -1874,6 +1874,8 @@ class ColormapMesh3D(Geometry):
}
""",
string.Template("""
+ uniform float alpha;
+
varying vec4 vCameraPosition;
varying vec3 vPosition;
varying vec3 vNormal;
@@ -1889,6 +1891,7 @@ class ColormapMesh3D(Geometry):
vec4 color = $colormapCall(vValue);
gl_FragColor = $lightingCall(color, vPosition, vNormal);
+ gl_FragColor.a *= alpha;
$scenePostCall(vCameraPosition);
}
@@ -1908,6 +1911,7 @@ class ColormapMesh3D(Geometry):
value=value,
copy=copy)
+ self._alpha = 1.0
self._lineWidth = 1.0
self._lineSmooth = True
self._culling = None
@@ -1922,6 +1926,10 @@ class ColormapMesh3D(Geometry):
converter=bool,
doc="Smooth line rendering enabled (bool, default: True)")
+ alpha = event.notifyProperty(
+ '_alpha', converter=float,
+ doc="Transparency of the mesh, float in [0, 1]")
+
@property
def culling(self):
"""Face culling (str)
@@ -1978,6 +1986,7 @@ class ColormapMesh3D(Geometry):
program.setUniformMatrix('transformMat',
ctx.objectToCamera.matrix,
safe=True)
+ gl.glUniform1f(program.uniforms['alpha'], self._alpha)
if self.drawMode in self._LINE_MODES:
gl.glLineWidth(self.lineWidth)
diff --git a/silx/gui/plot3d/tools/PositionInfoWidget.py b/silx/gui/plot3d/tools/PositionInfoWidget.py
index fc86a7f..52a6163 100644
--- a/silx/gui/plot3d/tools/PositionInfoWidget.py
+++ b/silx/gui/plot3d/tools/PositionInfoWidget.py
@@ -189,7 +189,7 @@ class PositionInfoWidget(qt.QWidget):
return # No picked item
item = picking.getItem()
- self._itemLabel.setText(item.getLabel())
+ self._itemLabel.setText(item.getName())
positions = picking.getPositions('scene', copy=False)
x, y, z = positions[0]
self._xLabel.setText("%g" % x)
diff --git a/silx/gui/qt/_utils.py b/silx/gui/qt/_utils.py
index 912f08c..f5915ae 100644
--- a/silx/gui/qt/_utils.py
+++ b/silx/gui/qt/_utils.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-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
@@ -29,21 +29,22 @@ __authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "30/11/2016"
-import sys
-from . import _qt as qt
+
+import sys as _sys
+from . import _qt
def supportedImageFormats():
"""Return a set of string of file format extensions supported by the
Qt runtime."""
- if sys.version_info[0] < 3 or qt.BINDING == 'PySide':
+ if _sys.version_info[0] < 3 or _qt.BINDING == 'PySide':
convert = str
- elif qt.BINDING == 'PySide2':
+ elif _qt.BINDING == 'PySide2':
def convert(data):
return str(data.data(), 'ascii')
else:
convert = lambda data: str(data, 'ascii')
- formats = qt.QImageReader.supportedImageFormats()
+ formats = _qt.QImageReader.supportedImageFormats()
return set([convert(data) for data in formats])
@@ -59,7 +60,7 @@ def silxGlobalThreadPool():
"""
global __globalThreadPoolInstance
if __globalThreadPoolInstance is None:
- tp = qt.QThreadPool()
+ tp = _qt.QThreadPool()
# This pointless command fixes a segfault with PyQt 5.9.1 on Windows
tp.setMaxThreadCount(tp.maxThreadCount())
__globalThreadPoolInstance = tp
diff --git a/silx/gui/test/test_colors.py b/silx/gui/test/test_colors.py
index 6e4fc73..12387a3 100644..100755
--- a/silx/gui/test/test_colors.py
+++ b/silx/gui/test/test_colors.py
@@ -39,28 +39,39 @@ from silx.gui.colors import Colormap
from silx.utils.exceptions import NotEditableError
-class TestRGBA(ParametricTestCase):
+class TestColor(ParametricTestCase):
"""Basic tests of rgba function"""
+ TEST_COLORS = { # name: (colors, expected values)
+ 'blue': ('blue', (0., 0., 1., 1.)),
+ '#010203': ('#010203', (1. / 255., 2. / 255., 3. / 255., 1.)),
+ '#01020304': ('#01020304', (1. / 255., 2. / 255., 3. / 255., 4. / 255.)),
+ '3 x uint8': (numpy.array((1, 255, 0), dtype=numpy.uint8),
+ (1 / 255., 1., 0., 1.)),
+ '4 x uint8': (numpy.array((1, 255, 0, 1), dtype=numpy.uint8),
+ (1 / 255., 1., 0., 1 / 255.)),
+ '3 x float overflow': ((3., 0.5, 1.), (1., 0.5, 1., 1.)),
+ }
+
def testRGBA(self):
""""Test rgba function with accepted values"""
- tests = { # name: (colors, expected values)
- 'blue': ('blue', (0., 0., 1., 1.)),
- '#010203': ('#010203', (1. / 255., 2. / 255., 3. / 255., 1.)),
- '#01020304': ('#01020304', (1. / 255., 2. / 255., 3. / 255., 4. / 255.)),
- '3 x uint8': (numpy.array((1, 255, 0), dtype=numpy.uint8),
- (1 / 255., 1., 0., 1.)),
- '4 x uint8': (numpy.array((1, 255, 0, 1), dtype=numpy.uint8),
- (1 / 255., 1., 0., 1 / 255.)),
- '3 x float overflow': ((3., 0.5, 1.), (1., 0.5, 1., 1.)),
- }
-
- for name, test in tests.items():
+ for name, test in self.TEST_COLORS.items():
color, expected = test
with self.subTest(msg=name):
result = colors.rgba(color)
self.assertEqual(result, expected)
+ def testQColor(self):
+ """"Test getQColor function with accepted values"""
+ for name, test in self.TEST_COLORS.items():
+ color, expected = test
+ with self.subTest(msg=name):
+ result = colors.asQColor(color)
+ self.assertAlmostEqual(result.redF(), expected[0], places=4)
+ self.assertAlmostEqual(result.greenF(), expected[1], places=4)
+ self.assertAlmostEqual(result.blueF(), expected[2], places=4)
+ self.assertAlmostEqual(result.alphaF(), expected[3], places=4)
+
class TestApplyColormapToData(ParametricTestCase):
"""Tests of applyColormapToData function"""
@@ -477,7 +488,7 @@ def suite():
test_suite = unittest.TestSuite()
loadTests = unittest.defaultTestLoader.loadTestsFromTestCase
test_suite.addTest(loadTests(TestApplyColormapToData))
- test_suite.addTest(loadTests(TestRGBA))
+ test_suite.addTest(loadTests(TestColor))
test_suite.addTest(loadTests(TestDictAPI))
test_suite.addTest(loadTests(TestObjectAPI))
test_suite.addTest(loadTests(TestPreferredColormaps))
diff --git a/silx/gui/utils/__init__.py b/silx/gui/utils/__init__.py
index 51c4fac..a4e442f 100644..100755
--- a/silx/gui/utils/__init__.py
+++ b/silx/gui/utils/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018 European Synchrotron Radiation Facility
+# Copyright (c) 2018-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
@@ -27,3 +27,33 @@
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "09/03/2018"
+
+
+import contextlib as _contextlib
+
+
+@_contextlib.contextmanager
+def blockSignals(*objs):
+ """Context manager blocking signals of QObjects.
+
+ It restores previous state when leaving.
+
+ :param qt.QObject objs: QObjects for which to block signals
+ """
+ blocked = [(obj, obj.blockSignals(True)) for obj in objs]
+ try:
+ yield
+ finally:
+ for obj, previous in blocked:
+ obj.blockSignals(previous)
+
+
+def getQEventName(eventType):
+ """
+ Returns the name of a QEvent.
+
+ :param Union[int,qt.QEvent] eventType: A QEvent or a QEvent type.
+ :returns: str
+ """
+ from . import qtutils
+ return qtutils.getQEventName(eventType)
diff --git a/silx/gui/utils/qtutils.py b/silx/gui/utils/qtutils.py
new file mode 100755
index 0000000..eb823a8
--- /dev/null
+++ b/silx/gui/utils/qtutils.py
@@ -0,0 +1,170 @@
+from silx.gui import qt
+
+
+QT_EVENT_NAMES = {
+ 0: "None",
+ 114: "ActionAdded",
+ 113: "ActionChanged",
+ 115: "ActionRemoved",
+ 99: "ActivationChange",
+ 121: "ApplicationActivate",
+ # ApplicationActivate: "ApplicationActivated",
+ 122: "ApplicationDeactivate",
+ 36: "ApplicationFontChange",
+ 37: "ApplicationLayoutDirectionChange",
+ 38: "ApplicationPaletteChange",
+ 214: "ApplicationStateChange",
+ 35: "ApplicationWindowIconChange",
+ 68: "ChildAdded",
+ 69: "ChildPolished",
+ 71: "ChildRemoved",
+ 40: "Clipboard",
+ 19: "Close",
+ 200: "CloseSoftwareInputPanel",
+ 178: "ContentsRectChange",
+ 82: "ContextMenu",
+ 183: "CursorChange",
+ 52: "DeferredDelete",
+ 60: "DragEnter",
+ 62: "DragLeave",
+ 61: "DragMove",
+ 63: "Drop",
+ 170: "DynamicPropertyChange",
+ 98: "EnabledChange",
+ 10: "Enter",
+ 150: "EnterEditFocus",
+ 124: "EnterWhatsThisMode",
+ 206: "Expose",
+ 116: "FileOpen",
+ 8: "FocusIn",
+ 9: "FocusOut",
+ 23: "FocusAboutToChange",
+ 97: "FontChange",
+ 198: "Gesture",
+ 202: "GestureOverride",
+ 188: "GrabKeyboard",
+ 186: "GrabMouse",
+ 159: "GraphicsSceneContextMenu",
+ 164: "GraphicsSceneDragEnter",
+ 166: "GraphicsSceneDragLeave",
+ 165: "GraphicsSceneDragMove",
+ 167: "GraphicsSceneDrop",
+ 163: "GraphicsSceneHelp",
+ 160: "GraphicsSceneHoverEnter",
+ 162: "GraphicsSceneHoverLeave",
+ 161: "GraphicsSceneHoverMove",
+ 158: "GraphicsSceneMouseDoubleClick",
+ 155: "GraphicsSceneMouseMove",
+ 156: "GraphicsSceneMousePress",
+ 157: "GraphicsSceneMouseRelease",
+ 182: "GraphicsSceneMove",
+ 181: "GraphicsSceneResize",
+ 168: "GraphicsSceneWheel",
+ 18: "Hide",
+ 27: "HideToParent",
+ 127: "HoverEnter",
+ 128: "HoverLeave",
+ 129: "HoverMove",
+ 96: "IconDrag",
+ 101: "IconTextChange",
+ 83: "InputMethod",
+ 207: "InputMethodQuery",
+ 169: "KeyboardLayoutChange",
+ 6: "KeyPress",
+ 7: "KeyRelease",
+ 89: "LanguageChange",
+ 90: "LayoutDirectionChange",
+ 76: "LayoutRequest",
+ 11: "Leave",
+ 151: "LeaveEditFocus",
+ 125: "LeaveWhatsThisMode",
+ 88: "LocaleChange",
+ 176: "NonClientAreaMouseButtonDblClick",
+ 174: "NonClientAreaMouseButtonPress",
+ 175: "NonClientAreaMouseButtonRelease",
+ 173: "NonClientAreaMouseMove",
+ 177: "MacSizeChange",
+ 43: "MetaCall",
+ 102: "ModifiedChange",
+ 4: "MouseButtonDblClick",
+ 2: "MouseButtonPress",
+ 3: "MouseButtonRelease",
+ 5: "MouseMove",
+ 109: "MouseTrackingChange",
+ 13: "Move",
+ 197: "NativeGesture",
+ 208: "OrientationChange",
+ 12: "Paint",
+ 39: "PaletteChange",
+ 131: "ParentAboutToChange",
+ 21: "ParentChange",
+ 212: "PlatformPanel",
+ 217: "PlatformSurface",
+ 75: "Polish",
+ 74: "PolishRequest",
+ 123: "QueryWhatsThis",
+ 106: "ReadOnlyChange",
+ 199: "RequestSoftwareInputPanel",
+ 14: "Resize",
+ 204: "ScrollPrepare",
+ 205: "Scroll",
+ 117: "Shortcut",
+ 51: "ShortcutOverride",
+ 17: "Show",
+ 26: "ShowToParent",
+ 50: "SockAct",
+ 192: "StateMachineSignal",
+ 193: "StateMachineWrapped",
+ 112: "StatusTip",
+ 100: "StyleChange",
+ 87: "TabletMove",
+ 92: "TabletPress",
+ 93: "TabletRelease",
+ 171: "TabletEnterProximity",
+ 172: "TabletLeaveProximity",
+ 219: "TabletTrackingChange",
+ 22: "ThreadChange",
+ 1: "Timer",
+ 120: "ToolBarChange",
+ 110: "ToolTip",
+ 184: "ToolTipChange",
+ 194: "TouchBegin",
+ 209: "TouchCancel",
+ 196: "TouchEnd",
+ 195: "TouchUpdate",
+ 189: "UngrabKeyboard",
+ 187: "UngrabMouse",
+ 78: "UpdateLater",
+ 77: "UpdateRequest",
+ 111: "WhatsThis",
+ 118: "WhatsThisClicked",
+ 31: "Wheel",
+ 132: "WinEventAct",
+ 24: "WindowActivate",
+ 103: "WindowBlocked",
+ 25: "WindowDeactivate",
+ 34: "WindowIconChange",
+ 105: "WindowStateChange",
+ 33: "WindowTitleChange",
+ 104: "WindowUnblocked",
+ 203: "WinIdChange",
+ 126: "ZOrderChange",
+ 65535: "MaxUser",
+}
+
+
+def getQEventName(eventType):
+ """
+ Returns the name of a QEvent.
+
+ :param Union[int,qt.QEvent] eventType: A QEvent or a QEvent type.
+ :returns: str
+ """
+ if isinstance(eventType, qt.QEvent):
+ eventType = eventType.type()
+ if 1000 <= eventType <= 65535:
+ return "User_%d" % eventType
+ name = QT_EVENT_NAMES.get(eventType, None)
+ if name is not None:
+ return name
+ return "Unknown_%d" % eventType
diff --git a/silx/gui/utils/test/__init__.py b/silx/gui/utils/test/__init__.py
index 9e50170..d500c05 100644..100755
--- a/silx/gui/utils/test/__init__.py
+++ b/silx/gui/utils/test/__init__.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2018 European Synchrotron Radiation Facility
+# Copyright (c) 2018-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
@@ -34,15 +34,21 @@ import unittest
from . import test_async
from . import test_image
+from . import test_qtutils
+from . import test_testutils
+from . import test
def suite():
"""Test suite for module silx.image.test"""
test_suite = unittest.TestSuite()
+ test_suite.addTest(test.suite())
test_suite.addTest(test_async.suite())
test_suite.addTest(test_image.suite())
+ test_suite.addTest(test_qtutils.suite())
+ test_suite.addTest(test_testutils.suite())
return test_suite
-if __name__ == '__main__':
- unittest.main(defaultTest='suite')
+if __name__ == "__main__":
+ unittest.main(defaultTest="suite")
diff --git a/silx/gui/utils/test/test.py b/silx/gui/utils/test/test.py
new file mode 100644
index 0000000..8bba852
--- /dev/null
+++ b/silx/gui/utils/test/test.py
@@ -0,0 +1,76 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 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.
+#
+# ###########################################################################*/
+"""Test of functions available in silx.gui.utils module."""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "01/08/2019"
+
+
+import unittest
+from silx.gui import qt
+from silx.gui.utils.testutils import TestCaseQt, SignalListener
+
+from silx.gui.utils import blockSignals
+
+
+class TestBlockSignals(TestCaseQt):
+ """Test blockSignals context manager"""
+
+ def _test(self, *objs):
+ """Test for provided objects"""
+ listener = SignalListener()
+ for obj in objs:
+ obj.objectNameChanged.connect(listener)
+ obj.setObjectName("received")
+
+ with blockSignals(*objs):
+ for obj in objs:
+ obj.setObjectName("silent")
+
+ self.assertEqual(listener.arguments(), [("received",)] * len(objs))
+
+ @unittest.skipUnless(qt.BINDING in ('PyQt5', 'PySide2'), 'Qt5 only test')
+ def testManyObjects(self):
+ """Test blockSignals with 2 QObjects"""
+ self._test(qt.QObject(), qt.QObject())
+
+ @unittest.skipUnless(qt.BINDING in ('PyQt5', 'PySide2'), 'Qt5 only test')
+ def testOneObject(self):
+ """Test blockSignals context manager with a single QObject"""
+ self._test(qt.QObject())
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(
+ TestBlockSignals))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/utils/test/test_qtutils.py b/silx/gui/utils/test/test_qtutils.py
new file mode 100755
index 0000000..043a0a6
--- /dev/null
+++ b/silx/gui/utils/test/test_qtutils.py
@@ -0,0 +1,75 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 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.
+#
+# ###########################################################################*/
+"""Test of functions available in silx.gui.utils module."""
+
+from __future__ import absolute_import
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "01/08/2019"
+
+
+import unittest
+from silx.gui import qt
+from silx.gui import utils
+from silx.gui.utils.testutils import TestCaseQt
+
+
+class TestQEventName(TestCaseQt):
+ """Test QEvent names"""
+
+ def testNoneType(self):
+ result = utils.getQEventName(0)
+ self.assertEqual(result, "None")
+
+ def testNoneEvent(self):
+ event = qt.QEvent(qt.QEvent.Type(0))
+ result = utils.getQEventName(event)
+ self.assertEqual(result, "None")
+
+ def testUserType(self):
+ result = utils.getQEventName(1050)
+ self.assertIn("User", result)
+ self.assertIn("1050", result)
+
+ def testQtUndefinedType(self):
+ result = utils.getQEventName(900)
+ self.assertIn("Unknown", result)
+ self.assertIn("900", result)
+
+ def testUndefinedType(self):
+ result = utils.getQEventName(70000)
+ self.assertIn("Unknown", result)
+ self.assertIn("70000", result)
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestQEventName))
+ return test_suite
+
+
+if __name__ == "__main__":
+ unittest.main(defaultTest="suite")
diff --git a/silx/gui/utils/test/test_testutils.py b/silx/gui/utils/test/test_testutils.py
new file mode 100644
index 0000000..8a58e6e
--- /dev/null
+++ b/silx/gui/utils/test/test_testutils.py
@@ -0,0 +1,55 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2017-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.
+#
+# ###########################################################################*/
+"""Test of testutils module."""
+
+__authors__ = ["T. Vincent"]
+__license__ = "MIT"
+__date__ = "16/01/2017"
+
+import unittest
+import sys
+
+from silx.gui import qt
+from ..testutils import TestCaseQt
+
+
+class TestOutcome(unittest.TestCase):
+ """Tests conversion of QImage to/from numpy array."""
+
+ @unittest.skipIf(sys.version_info.major <= 2, 'Python3 only')
+ def testNoneOutcome(self):
+ test = TestCaseQt()
+ test._currentTestSucceeded()
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ loader = unittest.defaultTestLoader.loadTestsFromTestCase
+ test_suite.addTest(loader(TestOutcome))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/utils/testutils.py b/silx/gui/utils/testutils.py
index d7f2f41..14dcc3f 100644
--- a/silx/gui/utils/testutils.py
+++ b/silx/gui/utils/testutils.py
@@ -155,7 +155,8 @@ class TestCaseQt(unittest.TestCase):
if hasattr(self, '_outcome'):
# For Python >= 3.4
result = self.defaultTestResult() # these 2 methods have no side effects
- self._feedErrorsToResult(result, self._outcome.errors)
+ if hasattr(self._outcome, 'errors'):
+ self._feedErrorsToResult(result, self._outcome.errors)
else:
# For Python < 3.4
result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups)
diff --git a/silx/gui/widgets/ColormapNameComboBox.py b/silx/gui/widgets/ColormapNameComboBox.py
new file mode 100644
index 0000000..fa8faf1
--- /dev/null
+++ b/silx/gui/widgets/ColormapNameComboBox.py
@@ -0,0 +1,166 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2004-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.
+#
+# ###########################################################################*/
+"""A QComboBox to display prefered colormaps
+"""
+
+from __future__ import division
+
+__authors__ = ["V.A. Sole", "T. Vincent", "H. Payno"]
+__license__ = "MIT"
+__date__ = "27/11/2018"
+
+
+import logging
+import numpy
+
+from .. import qt
+from .. import colors as colors_mdl
+
+_logger = logging.getLogger(__name__)
+
+
+_colormapIconPreview = {}
+
+
+class ColormapNameComboBox(qt.QComboBox):
+ def __init__(self, parent=None):
+ qt.QComboBox.__init__(self, parent)
+ self.__initItems()
+
+ LUT_NAME = qt.Qt.UserRole + 1
+ LUT_COLORS = qt.Qt.UserRole + 2
+
+ def __initItems(self):
+ for colormapName in colors_mdl.preferredColormaps():
+ index = self.count()
+ self.addItem(str.title(colormapName))
+ self.setItemIcon(index, self.getIconPreview(name=colormapName))
+ self.setItemData(index, colormapName, role=self.LUT_NAME)
+
+ def getIconPreview(self, name=None, colors=None):
+ """Return an icon preview from a LUT name.
+
+ This icons are cached into a global structure.
+
+ :param str name: Name of the LUT
+ :param numpy.ndarray colors: Colors identify the LUT
+ :rtype: qt.QIcon
+ """
+ if name is not None:
+ iconKey = name
+ else:
+ iconKey = tuple(colors)
+ icon = _colormapIconPreview.get(iconKey, None)
+ if icon is None:
+ icon = self.createIconPreview(name, colors)
+ _colormapIconPreview[iconKey] = icon
+ return icon
+
+ def createIconPreview(self, name=None, colors=None):
+ """Create and return an icon preview from a LUT name.
+
+ This icons are cached into a global structure.
+
+ :param str name: Name of the LUT
+ :param numpy.ndarray colors: Colors identify the LUT
+ :rtype: qt.QIcon
+ """
+ colormap = colors_mdl.Colormap(name)
+ size = 32
+ if name is not None:
+ lut = colormap.getNColors(size)
+ else:
+ lut = colors
+ if len(lut) > size:
+ # Down sample
+ step = int(len(lut) / size)
+ lut = lut[::step]
+ elif len(lut) < size:
+ # Over sample
+ indexes = numpy.arange(size) / float(size) * (len(lut) - 1)
+ indexes = indexes.astype("int")
+ lut = lut[indexes]
+ if lut is None or len(lut) == 0:
+ return qt.QIcon()
+
+ pixmap = qt.QPixmap(size, size)
+ painter = qt.QPainter(pixmap)
+ for i in range(size):
+ rgb = lut[i]
+ r, g, b = rgb[0], rgb[1], rgb[2]
+ painter.setPen(qt.QColor(r, g, b))
+ painter.drawPoint(qt.QPoint(i, 0))
+
+ painter.drawPixmap(0, 1, size, size - 1, pixmap, 0, 0, size, 1)
+ painter.end()
+
+ return qt.QIcon(pixmap)
+
+ def getCurrentName(self):
+ return self.itemData(self.currentIndex(), self.LUT_NAME)
+
+ def getCurrentColors(self):
+ return self.itemData(self.currentIndex(), self.LUT_COLORS)
+
+ def findLutName(self, name):
+ return self.findData(name, role=self.LUT_NAME)
+
+ def findLutColors(self, lut):
+ for index in range(self.count()):
+ if self.itemData(index, role=self.LUT_NAME) is not None:
+ continue
+ colors = self.itemData(index, role=self.LUT_COLORS)
+ if colors is None:
+ continue
+ if numpy.array_equal(colors, lut):
+ return index
+ return -1
+
+ def setCurrentLut(self, colormap):
+ name = colormap.getName()
+ if name is not None:
+ self._setCurrentName(name)
+ else:
+ lut = colormap.getColormapLUT()
+ self._setCurrentLut(lut)
+
+ def _setCurrentLut(self, lut):
+ index = self.findLutColors(lut)
+ if index == -1:
+ index = self.count()
+ self.addItem("Custom")
+ self.setItemIcon(index, self.getIconPreview(colors=lut))
+ self.setItemData(index, None, role=self.LUT_NAME)
+ self.setItemData(index, lut, role=self.LUT_COLORS)
+ self.setCurrentIndex(index)
+
+ def _setCurrentName(self, name):
+ index = self.findLutName(name)
+ if index < 0:
+ index = self.count()
+ self.addItem(str.title(name))
+ self.setItemIcon(index, self.getIconPreview(name=name))
+ self.setItemData(index, name, role=self.LUT_NAME)
+ self.setCurrentIndex(index)
diff --git a/silx/gui/widgets/FrameBrowser.py b/silx/gui/widgets/FrameBrowser.py
index b4f88fc..671991f 100644
--- a/silx/gui/widgets/FrameBrowser.py
+++ b/silx/gui/widgets/FrameBrowser.py
@@ -95,7 +95,7 @@ class FrameBrowser(qt.QWidget):
else:
first, last = 0, n
- self._lineEdit.setFixedWidth(self._lineEdit.fontMetrics().width('%05d' % last))
+ self._lineEdit.setFixedWidth(self._lineEdit.fontMetrics().boundingRect('%05d' % last).width())
validator = qt.QIntValidator(first, last, self._lineEdit)
self._lineEdit.setValidator(validator)
self._lineEdit.setText("%d" % first)
diff --git a/silx/gui/widgets/LegendIconWidget.py b/silx/gui/widgets/LegendIconWidget.py
new file mode 100755
index 0000000..1a403cb
--- /dev/null
+++ b/silx/gui/widgets/LegendIconWidget.py
@@ -0,0 +1,513 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 2004-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.
+#
+# ###########################################################################*/
+"""Widget displaying a symbol (marker symbol, line style and color) to identify
+an item displayed by a plot.
+"""
+
+__authors__ = ["V.A. Sole", "T. Rueter", "T. Vincent"]
+__license__ = "MIT"
+__data__ = "11/11/2019"
+
+
+import logging
+
+import numpy
+
+from .. import qt, colors
+
+
+_logger = logging.getLogger(__name__)
+
+
+# Build all symbols
+# Courtesy of the pyqtgraph project
+
+_Symbols = None
+""""Cache supported symbols as Qt paths"""
+
+
+_NoSymbols = (None, 'None', 'none', '', ' ')
+"""List of values resulting in no symbol being displayed for a curve"""
+
+
+_LineStyles = {
+ None: qt.Qt.NoPen,
+ 'None': qt.Qt.NoPen,
+ 'none': qt.Qt.NoPen,
+ '': qt.Qt.NoPen,
+ ' ': qt.Qt.NoPen,
+ '-': qt.Qt.SolidLine,
+ '--': qt.Qt.DashLine,
+ ':': qt.Qt.DotLine,
+ '-.': qt.Qt.DashDotLine
+}
+"""Conversion from matplotlib-like linestyle to Qt"""
+
+_NoLineStyle = (None, 'None', 'none', '', ' ')
+"""List of style values resulting in no line being displayed for a curve"""
+
+
+_colormapImage = {}
+"""Store cached pixmap"""
+# FIXME: Could be better to use a LRU dictionary
+
+_COLORMAP_PIXMAP_SIZE = 32
+"""Size of the cached pixmaps for the colormaps"""
+
+
+def _initSymbols():
+ """Init the cached symbol structure if not yet done."""
+ global _Symbols
+ if _Symbols is not None:
+ return
+
+ symbols = dict([(name, qt.QPainterPath())
+ for name in ['o', 's', 't', 'd', '+', 'x', '.', ',']])
+ symbols['o'].addEllipse(qt.QRectF(.1, .1, .8, .8))
+ symbols['.'].addEllipse(qt.QRectF(.3, .3, .4, .4))
+ symbols[','].addEllipse(qt.QRectF(.4, .4, .2, .2))
+ symbols['s'].addRect(qt.QRectF(.1, .1, .8, .8))
+
+ coords = {
+ 't': [(0.5, 0.), (.1, .8), (.9, .8)],
+ 'd': [(0.1, 0.5), (0.5, 0.), (0.9, 0.5), (0.5, 1.)],
+ '+': [(0.0, 0.40), (0.40, 0.40), (0.40, 0.), (0.60, 0.),
+ (0.60, 0.40), (1., 0.40), (1., 0.60), (0.60, 0.60),
+ (0.60, 1.), (0.40, 1.), (0.40, 0.60), (0., 0.60)],
+ 'x': [(0.0, 0.40), (0.40, 0.40), (0.40, 0.), (0.60, 0.),
+ (0.60, 0.40), (1., 0.40), (1., 0.60), (0.60, 0.60),
+ (0.60, 1.), (0.40, 1.), (0.40, 0.60), (0., 0.60)]
+ }
+ for s, c in coords.items():
+ symbols[s].moveTo(*c[0])
+ for x, y in c[1:]:
+ symbols[s].lineTo(x, y)
+ symbols[s].closeSubpath()
+ tr = qt.QTransform()
+ tr.rotate(45)
+ symbols['x'].translate(qt.QPointF(-0.5, -0.5))
+ symbols['x'] = tr.map(symbols['x'])
+ symbols['x'].translate(qt.QPointF(0.5, 0.5))
+
+ _Symbols = symbols
+
+
+class LegendIconWidget(qt.QWidget):
+ """Object displaying linestyle and symbol of plots.
+
+ :param QWidget parent: See :class:`QWidget`
+ """
+
+ def __init__(self, parent=None):
+ super(LegendIconWidget, self).__init__(parent)
+ _initSymbols()
+
+ # Visibilities
+ self.showLine = True
+ self.showSymbol = True
+ self.showColormap = True
+
+ # Line attributes
+ self.lineStyle = qt.Qt.NoPen
+ self.lineWidth = 1.
+ self.lineColor = qt.Qt.green
+
+ self.symbol = ''
+ # Symbol attributes
+ self.symbolStyle = qt.Qt.SolidPattern
+ self.symbolColor = qt.Qt.green
+ self.symbolOutlineBrush = qt.QBrush(qt.Qt.white)
+ self.symbolColormap = None
+ """Name or array of colors"""
+
+ self.colormap = None
+ """Name or array of colors"""
+
+ # Control widget size: sizeHint "is the only acceptable
+ # alternative, so the widget can never grow or shrink"
+ # (c.f. Qt Doc, enum QSizePolicy::Policy)
+ self.setSizePolicy(qt.QSizePolicy.Fixed,
+ qt.QSizePolicy.Fixed)
+
+ def sizeHint(self):
+ return qt.QSize(50, 15)
+
+ def setSymbol(self, symbol):
+ """Set the symbol"""
+ symbol = str(symbol)
+ if symbol not in _NoSymbols:
+ if symbol not in _Symbols:
+ raise ValueError("Unknown symbol: <%s>" % symbol)
+ self.symbol = symbol
+ self.update()
+
+ def setSymbolColor(self, color):
+ """
+ :param color: determines the symbol color
+ :type style: qt.QColor
+ """
+ self.symbolColor = qt.QColor(color)
+ self.update()
+
+ # Modify Line
+
+ def setLineColor(self, color):
+ self.lineColor = qt.QColor(color)
+ self.update()
+
+ def setLineWidth(self, width):
+ self.lineWidth = float(width)
+ self.update()
+
+ def setLineStyle(self, style):
+ """Set the linestyle.
+
+ Possible line styles:
+
+ - '', ' ', 'None': No line
+ - '-': solid
+ - '--': dashed
+ - ':': dotted
+ - '-.': dash and dot
+
+ :param str style: The linestyle to use
+ """
+ if style not in _LineStyles:
+ raise ValueError('Unknown style: %s', style)
+ self.lineStyle = _LineStyles[style]
+ self.update()
+
+ def _toLut(self, colormap):
+ """Returns an internal LUT object used by this widget to manage
+ a colormap LUT.
+
+ If the argument is a `Colormap` object, only the current state will be
+ displayed. The object itself will not be stored, and further changes
+ of this `Colormap` will not update this widget.
+
+ :param Union[str,numpy.ndarray,Colormap] colormap: The colormap to
+ display
+ :rtype: Union[None,str,numpy.ndarray]
+ """
+ if isinstance(colormap, colors.Colormap):
+ # Helper to allow to support Colormap objects
+ c = colormap.getName()
+ if c is None:
+ c = colormap.getNColors()
+ colormap = c
+
+ return colormap
+
+ def setColormap(self, colormap):
+ """Set the colormap to display
+
+ If the argument is a `Colormap` object, only the current state will be
+ displayed. The object itself will not be stored, and further changes
+ of this `Colormap` will not update this widget.
+
+ :param Union[str,numpy.ndarray,Colormap] colormap: The colormap to
+ display
+ """
+ colormap = self._toLut(colormap)
+
+ if colormap is None:
+ if self.colormap is None:
+ return
+ self.colormap = None
+ self.update()
+ return
+
+ if numpy.array_equal(self.colormap, colormap):
+ # This also works with strings
+ return
+
+ self.colormap = colormap
+ self.update()
+
+ def getColormap(self):
+ """Returns the used colormap.
+
+ If the argument was set with a `Colormap` object, this function will
+ returns the LUT, represented by a string name or by an array or colors.
+
+ :returns: Union[None,str,numpy.ndarray,Colormap]
+ """
+ return self.colormap
+
+ def setSymbolColormap(self, colormap):
+ """Set the colormap to display a symbol
+
+ If the argument is a `Colormap` object, only the current state will be
+ displayed. The object itself will not be stored, and further changes
+ of this `Colormap` will not update this widget.
+
+ :param Union[str,numpy.ndarray,Colormap] colormap: The colormap to
+ display
+ """
+ colormap = self._toLut(colormap)
+
+ if colormap is None:
+ if self.colormap is None:
+ return
+ self.symbolColormap = None
+ self.update()
+ return
+
+ if numpy.array_equal(self.symbolColormap, colormap):
+ # This also works with strings
+ return
+
+ self.symbolColormap = colormap
+ self.update()
+
+ def getSymbolColormap(self):
+ """Returns the used symbol colormap.
+
+ If the argument was set with a `Colormap` object, this function will
+ returns the LUT, represented by a string name or by an array or colors.
+
+ :returns: Union[None,str,numpy.ndarray,Colormap]
+ """
+ return self.colormap
+
+ # Paint
+
+ def paintEvent(self, event):
+ """
+ :param event: event
+ :type event: QPaintEvent
+ """
+ painter = qt.QPainter(self)
+ self.paint(painter, event.rect(), self.palette())
+
+ def paint(self, painter, rect, palette):
+ painter.save()
+ painter.setRenderHint(qt.QPainter.Antialiasing)
+ # Scale painter to the icon height
+ # current -> width = 2.5, height = 1.0
+ scale = float(self.height())
+ ratio = float(self.width()) / scale
+ symbolOffset = qt.QPointF(.5 * (ratio - 1.), 0.)
+ # Determine and scale offset
+ offset = qt.QPointF(float(rect.left()) / scale, float(rect.top()) / scale)
+
+ # Override color when disabled
+ if self.isEnabled():
+ overrideColor = None
+ else:
+ overrideColor = palette.color(qt.QPalette.Disabled,
+ qt.QPalette.WindowText)
+
+ # Draw BG rectangle (for debugging)
+ # bottomRight = qt.QPointF(
+ # float(rect.right())/scale,
+ # float(rect.bottom())/scale)
+ # painter.fillRect(qt.QRectF(offset, bottomRight),
+ # qt.QBrush(qt.Qt.green))
+
+ if self.showColormap:
+ if self.colormap is not None:
+ if self.isEnabled():
+ image = self.getColormapImage(self.colormap)
+ else:
+ image = self.getGrayedColormapImage(self.colormap)
+ pixmapRect = qt.QRect(0, 0, _COLORMAP_PIXMAP_SIZE, 1)
+ widthMargin = 0
+ halfHeight = 4
+ dest = qt.QRect(
+ rect.left() + widthMargin,
+ rect.center().y() - halfHeight + 1,
+ rect.width() - widthMargin * 2,
+ halfHeight * 2,
+ )
+ painter.drawImage(dest, image, pixmapRect)
+
+ painter.scale(scale, scale)
+
+ llist = []
+ if self.showLine:
+ linePath = qt.QPainterPath()
+ linePath.moveTo(0., 0.5)
+ linePath.lineTo(ratio, 0.5)
+ # linePath.lineTo(2.5, 0.5)
+ lineBrush = qt.QBrush(
+ self.lineColor if overrideColor is None else overrideColor)
+ linePen = qt.QPen(
+ lineBrush,
+ (self.lineWidth / self.height()),
+ self.lineStyle,
+ qt.Qt.FlatCap
+ )
+ llist.append((linePath, linePen, lineBrush))
+
+ isValidSymbol = (len(self.symbol) and
+ self.symbol not in _NoSymbols)
+ if self.showSymbol and isValidSymbol:
+ if self.symbolColormap is None:
+ # PITFALL ahead: Let this be a warning to others
+ # symbolPath = Symbols[self.symbol]
+ # Copy before translate! Dict is a mutable type
+ symbolPath = qt.QPainterPath(_Symbols[self.symbol])
+ symbolPath.translate(symbolOffset)
+ symbolBrush = qt.QBrush(
+ self.symbolColor if overrideColor is None else overrideColor,
+ self.symbolStyle)
+ symbolPen = qt.QPen(
+ self.symbolOutlineBrush, # Brush
+ 1. / self.height(), # Width
+ qt.Qt.SolidLine # Style
+ )
+ llist.append((symbolPath,
+ symbolPen,
+ symbolBrush))
+ else:
+ nbSymbols = int(ratio + 2)
+ for i in range(nbSymbols):
+ if self.isEnabled():
+ image = self.getColormapImage(self.symbolColormap)
+ else:
+ image = self.getGrayedColormapImage(self.symbolColormap)
+ pos = int((_COLORMAP_PIXMAP_SIZE / nbSymbols) * i)
+ pos = numpy.clip(pos, 0, _COLORMAP_PIXMAP_SIZE-1)
+ color = image.pixelColor(pos, 0)
+ delta = qt.QPointF(ratio * ((i - (nbSymbols-1)/2) / nbSymbols), 0)
+
+ symbolPath = qt.QPainterPath(_Symbols[self.symbol])
+ symbolPath.translate(symbolOffset + delta)
+ symbolBrush = qt.QBrush(color, self.symbolStyle)
+ symbolPen = qt.QPen(
+ self.symbolOutlineBrush, # Brush
+ 1. / self.height(), # Width
+ qt.Qt.SolidLine # Style
+ )
+ llist.append((symbolPath,
+ symbolPen,
+ symbolBrush))
+
+ # Draw
+ for path, pen, brush in llist:
+ path.translate(offset)
+ painter.setPen(pen)
+ painter.setBrush(brush)
+ painter.drawPath(path)
+
+ painter.restore()
+
+ # Helpers
+
+ @staticmethod
+ def isEmptySymbol(symbol):
+ """Returns True if this symbol description will result in an empty
+ symbol."""
+ return symbol in _NoSymbols
+
+ @staticmethod
+ def isEmptyLineStyle(lineStyle):
+ """Returns True if this line style description will result in an empty
+ line."""
+ return lineStyle in _NoLineStyle
+
+ @staticmethod
+ def _getColormapKey(colormap):
+ """
+ Returns the key used to store the image in the data storage
+ """
+ if isinstance(colormap, numpy.ndarray):
+ key = tuple(colormap)
+ else:
+ key = colormap
+ return key
+
+ @staticmethod
+ def getGrayedColormapImage(colormap):
+ """Return a grayed version image preview from a LUT name.
+
+ This images are cached into a global structure.
+
+ :param Union[str,numpy.ndarray] colormap: Description of the LUT
+ :rtype: qt.QImage
+ """
+ key = LegendIconWidget._getColormapKey(colormap)
+ grayKey = (key, "gray")
+ image = _colormapImage.get(grayKey, None)
+ if image is None:
+ image = LegendIconWidget.getColormapImage(colormap)
+ image = image.convertToFormat(qt.QImage.Format_Grayscale8)
+ _colormapImage[grayKey] = image
+ return image
+
+ @staticmethod
+ def getColormapImage(colormap):
+ """Return an image preview from a LUT name.
+
+ This images are cached into a global structure.
+
+ :param Union[str,numpy.ndarray] colormap: Description of the LUT
+ :rtype: qt.QImage
+ """
+ key = LegendIconWidget._getColormapKey(colormap)
+ image = _colormapImage.get(key, None)
+ if image is None:
+ image = LegendIconWidget.createColormapImage(colormap)
+ _colormapImage[key] = image
+ return image
+
+ @staticmethod
+ def createColormapImage(colormap):
+ """Create and return an icon preview from a LUT name.
+
+ This icons are cached into a global structure.
+
+ :param Union[str,numpy.ndarray] colormap: Description of the LUT
+ :rtype: qt.QImage
+ """
+ size = _COLORMAP_PIXMAP_SIZE
+ if isinstance(colormap, numpy.ndarray):
+ lut = colormap
+ if len(lut) > size:
+ # Down sample
+ step = int(len(lut) / size)
+ lut = lut[::step]
+ elif len(lut) < size:
+ # Over sample
+ indexes = numpy.arange(size) / float(size) * (len(lut) - 1)
+ indexes = indexes.astype("int")
+ lut = lut[indexes]
+ else:
+ colormap = colors.Colormap(colormap)
+ lut = colormap.getNColors(size)
+
+ if lut is None or len(lut) == 0:
+ return qt.QIcon()
+
+ pixmap = qt.QPixmap(size, 1)
+ painter = qt.QPainter(pixmap)
+ for i in range(size):
+ rgb = lut[i]
+ r, g, b = rgb[0], rgb[1], rgb[2]
+ painter.setPen(qt.QColor(r, g, b))
+ painter.drawPoint(qt.QPoint(i, 0))
+ painter.end()
+ return pixmap.toImage()
diff --git a/silx/gui/widgets/RangeSlider.py b/silx/gui/widgets/RangeSlider.py
index 0cf195c..c352147 100644
--- a/silx/gui/widgets/RangeSlider.py
+++ b/silx/gui/widgets/RangeSlider.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2018 European Synchrotron Radiation Facility
+# 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
@@ -466,7 +466,7 @@ class RangeSlider(qt.QWidget):
:param Union[numpy.ndarray,None] profile:
1D array of values to display
- :param Union[Colormap,str] colormap:
+ :param Union[~silx.gui.colors.Colormap,str] colormap:
The colormap name or object to convert profile values to colors
"""
if profile is None:
diff --git a/silx/image/bilinear.c b/silx/image/bilinear.c
deleted file mode 100644
index 85b293e..0000000
--- a/silx/image/bilinear.c
+++ /dev/null
@@ -1,24879 +0,0 @@
-/* Generated by Cython 0.29.11 */
-
-/* BEGIN: Cython Metadata
-{
- "distutils": {
- "depends": [],
- "language": "c",
- "name": "silx.image.bilinear",
- "sources": [
- "silx/image/bilinear.pyx"
- ]
- },
- "module_name": "silx.image.bilinear"
-}
-END: Cython Metadata */
-
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#ifndef Py_PYTHON_H
- #error Python headers needed to compile C extensions, please install development version of Python.
-#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03030000)
- #error Cython requires Python 2.6+ or Python 3.3+.
-#else
-#define CYTHON_ABI "0_29_11"
-#define CYTHON_HEX_VERSION 0x001D0BF0
-#define CYTHON_FUTURE_DIVISION 1
-#include <stddef.h>
-#ifndef offsetof
- #define offsetof(type, member) ( (size_t) & ((type*)0) -> member )
-#endif
-#if !defined(WIN32) && !defined(MS_WINDOWS)
- #ifndef __stdcall
- #define __stdcall
- #endif
- #ifndef __cdecl
- #define __cdecl
- #endif
- #ifndef __fastcall
- #define __fastcall
- #endif
-#endif
-#ifndef DL_IMPORT
- #define DL_IMPORT(t) t
-#endif
-#ifndef DL_EXPORT
- #define DL_EXPORT(t) t
-#endif
-#define __PYX_COMMA ,
-#ifndef HAVE_LONG_LONG
- #if PY_VERSION_HEX >= 0x02070000
- #define HAVE_LONG_LONG
- #endif
-#endif
-#ifndef PY_LONG_LONG
- #define PY_LONG_LONG LONG_LONG
-#endif
-#ifndef Py_HUGE_VAL
- #define Py_HUGE_VAL HUGE_VAL
-#endif
-#ifdef PYPY_VERSION
- #define CYTHON_COMPILING_IN_PYPY 1
- #define CYTHON_COMPILING_IN_PYSTON 0
- #define CYTHON_COMPILING_IN_CPYTHON 0
- #undef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 0
- #undef CYTHON_USE_PYTYPE_LOOKUP
- #define CYTHON_USE_PYTYPE_LOOKUP 0
- #if PY_VERSION_HEX < 0x03050000
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #elif !defined(CYTHON_USE_ASYNC_SLOTS)
- #define CYTHON_USE_ASYNC_SLOTS 1
- #endif
- #undef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 0
- #undef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 0
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #undef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 1
- #undef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 0
- #undef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 0
- #undef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 0
- #undef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 0
- #undef CYTHON_PEP489_MULTI_PHASE_INIT
- #define CYTHON_PEP489_MULTI_PHASE_INIT 0
- #undef CYTHON_USE_TP_FINALIZE
- #define CYTHON_USE_TP_FINALIZE 0
- #undef CYTHON_USE_DICT_VERSIONS
- #define CYTHON_USE_DICT_VERSIONS 0
- #undef CYTHON_USE_EXC_INFO_STACK
- #define CYTHON_USE_EXC_INFO_STACK 0
-#elif defined(PYSTON_VERSION)
- #define CYTHON_COMPILING_IN_PYPY 0
- #define CYTHON_COMPILING_IN_PYSTON 1
- #define CYTHON_COMPILING_IN_CPYTHON 0
- #ifndef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 1
- #endif
- #undef CYTHON_USE_PYTYPE_LOOKUP
- #define CYTHON_USE_PYTYPE_LOOKUP 0
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #undef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 0
- #ifndef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 1
- #endif
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #ifndef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 0
- #endif
- #ifndef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 1
- #endif
- #ifndef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 1
- #endif
- #undef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 0
- #undef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 0
- #undef CYTHON_PEP489_MULTI_PHASE_INIT
- #define CYTHON_PEP489_MULTI_PHASE_INIT 0
- #undef CYTHON_USE_TP_FINALIZE
- #define CYTHON_USE_TP_FINALIZE 0
- #undef CYTHON_USE_DICT_VERSIONS
- #define CYTHON_USE_DICT_VERSIONS 0
- #undef CYTHON_USE_EXC_INFO_STACK
- #define CYTHON_USE_EXC_INFO_STACK 0
-#else
- #define CYTHON_COMPILING_IN_PYPY 0
- #define CYTHON_COMPILING_IN_PYSTON 0
- #define CYTHON_COMPILING_IN_CPYTHON 1
- #ifndef CYTHON_USE_TYPE_SLOTS
- #define CYTHON_USE_TYPE_SLOTS 1
- #endif
- #if PY_VERSION_HEX < 0x02070000
- #undef CYTHON_USE_PYTYPE_LOOKUP
- #define CYTHON_USE_PYTYPE_LOOKUP 0
- #elif !defined(CYTHON_USE_PYTYPE_LOOKUP)
- #define CYTHON_USE_PYTYPE_LOOKUP 1
- #endif
- #if PY_MAJOR_VERSION < 3
- #undef CYTHON_USE_ASYNC_SLOTS
- #define CYTHON_USE_ASYNC_SLOTS 0
- #elif !defined(CYTHON_USE_ASYNC_SLOTS)
- #define CYTHON_USE_ASYNC_SLOTS 1
- #endif
- #if PY_VERSION_HEX < 0x02070000
- #undef CYTHON_USE_PYLONG_INTERNALS
- #define CYTHON_USE_PYLONG_INTERNALS 0
- #elif !defined(CYTHON_USE_PYLONG_INTERNALS)
- #define CYTHON_USE_PYLONG_INTERNALS 1
- #endif
- #ifndef CYTHON_USE_PYLIST_INTERNALS
- #define CYTHON_USE_PYLIST_INTERNALS 1
- #endif
- #ifndef CYTHON_USE_UNICODE_INTERNALS
- #define CYTHON_USE_UNICODE_INTERNALS 1
- #endif
- #if PY_VERSION_HEX < 0x030300F0
- #undef CYTHON_USE_UNICODE_WRITER
- #define CYTHON_USE_UNICODE_WRITER 0
- #elif !defined(CYTHON_USE_UNICODE_WRITER)
- #define CYTHON_USE_UNICODE_WRITER 1
- #endif
- #ifndef CYTHON_AVOID_BORROWED_REFS
- #define CYTHON_AVOID_BORROWED_REFS 0
- #endif
- #ifndef CYTHON_ASSUME_SAFE_MACROS
- #define CYTHON_ASSUME_SAFE_MACROS 1
- #endif
- #ifndef CYTHON_UNPACK_METHODS
- #define CYTHON_UNPACK_METHODS 1
- #endif
- #ifndef CYTHON_FAST_THREAD_STATE
- #define CYTHON_FAST_THREAD_STATE 1
- #endif
- #ifndef CYTHON_FAST_PYCALL
- #define CYTHON_FAST_PYCALL 1
- #endif
- #ifndef CYTHON_PEP489_MULTI_PHASE_INIT
- #define CYTHON_PEP489_MULTI_PHASE_INIT (PY_VERSION_HEX >= 0x03050000)
- #endif
- #ifndef CYTHON_USE_TP_FINALIZE
- #define CYTHON_USE_TP_FINALIZE (PY_VERSION_HEX >= 0x030400a1)
- #endif
- #ifndef CYTHON_USE_DICT_VERSIONS
- #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX >= 0x030600B1)
- #endif
- #ifndef CYTHON_USE_EXC_INFO_STACK
- #define CYTHON_USE_EXC_INFO_STACK (PY_VERSION_HEX >= 0x030700A3)
- #endif
-#endif
-#if !defined(CYTHON_FAST_PYCCALL)
-#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1)
-#endif
-#if CYTHON_USE_PYLONG_INTERNALS
- #include "longintrepr.h"
- #undef SHIFT
- #undef BASE
- #undef MASK
- #ifdef SIZEOF_VOID_P
- enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
- #endif
-#endif
-#ifndef __has_attribute
- #define __has_attribute(x) 0
-#endif
-#ifndef __has_cpp_attribute
- #define __has_cpp_attribute(x) 0
-#endif
-#ifndef CYTHON_RESTRICT
- #if defined(__GNUC__)
- #define CYTHON_RESTRICT __restrict__
- #elif defined(_MSC_VER) && _MSC_VER >= 1400
- #define CYTHON_RESTRICT __restrict
- #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- #define CYTHON_RESTRICT restrict
- #else
- #define CYTHON_RESTRICT
- #endif
-#endif
-#ifndef CYTHON_UNUSED
-# if defined(__GNUC__)
-# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
-# define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-# define CYTHON_UNUSED
-# endif
-# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER))
-# define CYTHON_UNUSED __attribute__ ((__unused__))
-# else
-# define CYTHON_UNUSED
-# endif
-#endif
-#ifndef CYTHON_MAYBE_UNUSED_VAR
-# if defined(__cplusplus)
- template<class T> void CYTHON_MAYBE_UNUSED_VAR( const T& ) { }
-# else
-# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x)
-# endif
-#endif
-#ifndef CYTHON_NCP_UNUSED
-# if CYTHON_COMPILING_IN_CPYTHON
-# define CYTHON_NCP_UNUSED
-# else
-# define CYTHON_NCP_UNUSED CYTHON_UNUSED
-# endif
-#endif
-#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None)
-#ifdef _MSC_VER
- #ifndef _MSC_STDINT_H_
- #if _MSC_VER < 1300
- typedef unsigned char uint8_t;
- typedef unsigned int uint32_t;
- #else
- typedef unsigned __int8 uint8_t;
- typedef unsigned __int32 uint32_t;
- #endif
- #endif
-#else
- #include <stdint.h>
-#endif
-#ifndef CYTHON_FALLTHROUGH
- #if defined(__cplusplus) && __cplusplus >= 201103L
- #if __has_cpp_attribute(fallthrough)
- #define CYTHON_FALLTHROUGH [[fallthrough]]
- #elif __has_cpp_attribute(clang::fallthrough)
- #define CYTHON_FALLTHROUGH [[clang::fallthrough]]
- #elif __has_cpp_attribute(gnu::fallthrough)
- #define CYTHON_FALLTHROUGH [[gnu::fallthrough]]
- #endif
- #endif
- #ifndef CYTHON_FALLTHROUGH
- #if __has_attribute(fallthrough)
- #define CYTHON_FALLTHROUGH __attribute__((fallthrough))
- #else
- #define CYTHON_FALLTHROUGH
- #endif
- #endif
- #if defined(__clang__ ) && defined(__apple_build_version__)
- #if __apple_build_version__ < 7000000
- #undef CYTHON_FALLTHROUGH
- #define CYTHON_FALLTHROUGH
- #endif
- #endif
-#endif
-
-#ifndef CYTHON_INLINE
- #if defined(__clang__)
- #define CYTHON_INLINE __inline__ __attribute__ ((__unused__))
- #elif defined(__GNUC__)
- #define CYTHON_INLINE __inline__
- #elif defined(_MSC_VER)
- #define CYTHON_INLINE __inline
- #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- #define CYTHON_INLINE inline
- #else
- #define CYTHON_INLINE
- #endif
-#endif
-
-#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag)
- #define Py_OptimizeFlag 0
-#endif
-#define __PYX_BUILD_PY_SSIZE_T "n"
-#define CYTHON_FORMAT_SSIZE_T "z"
-#if PY_MAJOR_VERSION < 3
- #define __Pyx_BUILTIN_MODULE_NAME "__builtin__"
- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
- PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
- #define __Pyx_DefaultClassType PyClass_Type
-#else
- #define __Pyx_BUILTIN_MODULE_NAME "builtins"
-#if PY_VERSION_HEX < 0x030800A4
- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
- PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
-#elif PY_VERSION_HEX >= 0x030800B2
- #define __Pyx_PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
- PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
-#else
- #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\
- PyCode_New(a, 0, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
-#endif
- #define __Pyx_DefaultClassType PyType_Type
-#endif
-#ifndef Py_TPFLAGS_CHECKTYPES
- #define Py_TPFLAGS_CHECKTYPES 0
-#endif
-#ifndef Py_TPFLAGS_HAVE_INDEX
- #define Py_TPFLAGS_HAVE_INDEX 0
-#endif
-#ifndef Py_TPFLAGS_HAVE_NEWBUFFER
- #define Py_TPFLAGS_HAVE_NEWBUFFER 0
-#endif
-#ifndef Py_TPFLAGS_HAVE_FINALIZE
- #define Py_TPFLAGS_HAVE_FINALIZE 0
-#endif
-#ifndef METH_STACKLESS
- #define METH_STACKLESS 0
-#endif
-#if PY_VERSION_HEX <= 0x030700A3 || !defined(METH_FASTCALL)
- #ifndef METH_FASTCALL
- #define METH_FASTCALL 0x80
- #endif
- typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs);
- typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args,
- Py_ssize_t nargs, PyObject *kwnames);
-#else
- #define __Pyx_PyCFunctionFast _PyCFunctionFast
- #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords
-#endif
-#if CYTHON_FAST_PYCCALL
-#define __Pyx_PyFastCFunction_Check(func)\
- ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS | METH_STACKLESS)))))
-#else
-#define __Pyx_PyFastCFunction_Check(func) 0
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc)
- #define PyObject_Malloc(s) PyMem_Malloc(s)
- #define PyObject_Free(p) PyMem_Free(p)
- #define PyObject_Realloc(p) PyMem_Realloc(p)
-#endif
-#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030400A1
- #define PyMem_RawMalloc(n) PyMem_Malloc(n)
- #define PyMem_RawRealloc(p, n) PyMem_Realloc(p, n)
- #define PyMem_RawFree(p) PyMem_Free(p)
-#endif
-#if CYTHON_COMPILING_IN_PYSTON
- #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co)
- #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno)
-#else
- #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0)
- #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno)
-#endif
-#if !CYTHON_FAST_THREAD_STATE || PY_VERSION_HEX < 0x02070000
- #define __Pyx_PyThreadState_Current PyThreadState_GET()
-#elif PY_VERSION_HEX >= 0x03060000
- #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet()
-#elif PY_VERSION_HEX >= 0x03000000
- #define __Pyx_PyThreadState_Current PyThreadState_GET()
-#else
- #define __Pyx_PyThreadState_Current _PyThreadState_Current
-#endif
-#if PY_VERSION_HEX < 0x030700A2 && !defined(PyThread_tss_create) && !defined(Py_tss_NEEDS_INIT)
-#include "pythread.h"
-#define Py_tss_NEEDS_INIT 0
-typedef int Py_tss_t;
-static CYTHON_INLINE int PyThread_tss_create(Py_tss_t *key) {
- *key = PyThread_create_key();
- return 0;
-}
-static CYTHON_INLINE Py_tss_t * PyThread_tss_alloc(void) {
- Py_tss_t *key = (Py_tss_t *)PyObject_Malloc(sizeof(Py_tss_t));
- *key = Py_tss_NEEDS_INIT;
- return key;
-}
-static CYTHON_INLINE void PyThread_tss_free(Py_tss_t *key) {
- PyObject_Free(key);
-}
-static CYTHON_INLINE int PyThread_tss_is_created(Py_tss_t *key) {
- return *key != Py_tss_NEEDS_INIT;
-}
-static CYTHON_INLINE void PyThread_tss_delete(Py_tss_t *key) {
- PyThread_delete_key(*key);
- *key = Py_tss_NEEDS_INIT;
-}
-static CYTHON_INLINE int PyThread_tss_set(Py_tss_t *key, void *value) {
- return PyThread_set_key_value(*key, value);
-}
-static CYTHON_INLINE void * PyThread_tss_get(Py_tss_t *key) {
- return PyThread_get_key_value(*key);
-}
-#endif
-#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized)
-#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n))
-#else
-#define __Pyx_PyDict_NewPresized(n) PyDict_New()
-#endif
-#if PY_MAJOR_VERSION >= 3 || CYTHON_FUTURE_DIVISION
- #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y)
- #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y)
-#else
- #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y)
- #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y)
-#endif
-#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030500A1 && CYTHON_USE_UNICODE_INTERNALS
-#define __Pyx_PyDict_GetItemStr(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash)
-#else
-#define __Pyx_PyDict_GetItemStr(dict, name) PyDict_GetItem(dict, name)
-#endif
-#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND)
- #define CYTHON_PEP393_ENABLED 1
- #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\
- 0 : _PyUnicode_Ready((PyObject *)(op)))
- #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u)
- #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i)
- #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u)
- #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u)
- #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u)
- #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i)
- #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch)
- #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u)))
-#else
- #define CYTHON_PEP393_ENABLED 0
- #define PyUnicode_1BYTE_KIND 1
- #define PyUnicode_2BYTE_KIND 2
- #define PyUnicode_4BYTE_KIND 4
- #define __Pyx_PyUnicode_READY(op) (0)
- #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u)
- #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i]))
- #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111)
- #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE))
- #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u))
- #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i]))
- #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch)
- #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u))
-#endif
-#if CYTHON_COMPILING_IN_PYPY
- #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b)
- #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b)
-#else
- #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b)
- #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\
- PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b))
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains)
- #define PyUnicode_Contains(u, s) PySequence_Contains(u, s)
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check)
- #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type)
-#endif
-#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format)
- #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt)
-#endif
-#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyString_Check(b) && !PyString_CheckExact(b)))) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b))
-#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b))
-#if PY_MAJOR_VERSION >= 3
- #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b)
-#else
- #define __Pyx_PyString_Format(a, b) PyString_Format(a, b)
-#endif
-#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII)
- #define PyObject_ASCII(o) PyObject_Repr(o)
-#endif
-#if PY_MAJOR_VERSION >= 3
- #define PyBaseString_Type PyUnicode_Type
- #define PyStringObject PyUnicodeObject
- #define PyString_Type PyUnicode_Type
- #define PyString_Check PyUnicode_Check
- #define PyString_CheckExact PyUnicode_CheckExact
- #define PyObject_Unicode PyObject_Str
-#endif
-#if PY_MAJOR_VERSION >= 3
- #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj)
- #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj)
-#else
- #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj))
- #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj))
-#endif
-#ifndef PySet_CheckExact
- #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type)
-#endif
-#if CYTHON_ASSUME_SAFE_MACROS
- #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq)
-#else
- #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq)
-#endif
-#if PY_MAJOR_VERSION >= 3
- #define PyIntObject PyLongObject
- #define PyInt_Type PyLong_Type
- #define PyInt_Check(op) PyLong_Check(op)
- #define PyInt_CheckExact(op) PyLong_CheckExact(op)
- #define PyInt_FromString PyLong_FromString
- #define PyInt_FromUnicode PyLong_FromUnicode
- #define PyInt_FromLong PyLong_FromLong
- #define PyInt_FromSize_t PyLong_FromSize_t
- #define PyInt_FromSsize_t PyLong_FromSsize_t
- #define PyInt_AsLong PyLong_AsLong
- #define PyInt_AS_LONG PyLong_AS_LONG
- #define PyInt_AsSsize_t PyLong_AsSsize_t
- #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
- #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
- #define PyNumber_Int PyNumber_Long
-#endif
-#if PY_MAJOR_VERSION >= 3
- #define PyBoolObject PyLongObject
-#endif
-#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY
- #ifndef PyUnicode_InternFromString
- #define PyUnicode_InternFromString(s) PyUnicode_FromString(s)
- #endif
-#endif
-#if PY_VERSION_HEX < 0x030200A4
- typedef long Py_hash_t;
- #define __Pyx_PyInt_FromHash_t PyInt_FromLong
- #define __Pyx_PyInt_AsHash_t PyInt_AsLong
-#else
- #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t
- #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t
-#endif
-#if PY_MAJOR_VERSION >= 3
- #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : (Py_INCREF(func), func))
-#else
- #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass)
-#endif
-#if CYTHON_USE_ASYNC_SLOTS
- #if PY_VERSION_HEX >= 0x030500B1
- #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods
- #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async)
- #else
- #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved))
- #endif
-#else
- #define __Pyx_PyType_AsAsync(obj) NULL
-#endif
-#ifndef __Pyx_PyAsyncMethodsStruct
- typedef struct {
- unaryfunc am_await;
- unaryfunc am_aiter;
- unaryfunc am_anext;
- } __Pyx_PyAsyncMethodsStruct;
-#endif
-
-#if defined(WIN32) || defined(MS_WINDOWS)
- #define _USE_MATH_DEFINES
-#endif
-#include <math.h>
-#ifdef NAN
-#define __PYX_NAN() ((float) NAN)
-#else
-static CYTHON_INLINE float __PYX_NAN() {
- float value;
- memset(&value, 0xFF, sizeof(value));
- return value;
-}
-#endif
-#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL)
-#define __Pyx_truncl trunc
-#else
-#define __Pyx_truncl truncl
-#endif
-
-
-#define __PYX_ERR(f_index, lineno, Ln_error) \
-{ \
- __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \
-}
-
-#ifndef __PYX_EXTERN_C
- #ifdef __cplusplus
- #define __PYX_EXTERN_C extern "C"
- #else
- #define __PYX_EXTERN_C extern
- #endif
-#endif
-
-#define __PYX_HAVE__silx__image__bilinear
-#define __PYX_HAVE_API__silx__image__bilinear
-/* Early includes */
-#include <math.h>
-#include "pythread.h"
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "pystate.h"
-#ifdef _OPENMP
-#include <omp.h>
-#endif /* _OPENMP */
-
-#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS)
-#define CYTHON_WITHOUT_ASSERTIONS
-#endif
-
-typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding;
- const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry;
-
-#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0
-#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0
-#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT (PY_MAJOR_VERSION >= 3 && __PYX_DEFAULT_STRING_ENCODING_IS_UTF8)
-#define __PYX_DEFAULT_STRING_ENCODING ""
-#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString
-#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize
-#define __Pyx_uchar_cast(c) ((unsigned char)c)
-#define __Pyx_long_cast(x) ((long)x)
-#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\
- (sizeof(type) < sizeof(Py_ssize_t)) ||\
- (sizeof(type) > sizeof(Py_ssize_t) &&\
- likely(v < (type)PY_SSIZE_T_MAX ||\
- v == (type)PY_SSIZE_T_MAX) &&\
- (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\
- v == (type)PY_SSIZE_T_MIN))) ||\
- (sizeof(type) == sizeof(Py_ssize_t) &&\
- (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\
- v == (type)PY_SSIZE_T_MAX))) )
-static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) {
- return (size_t) i < (size_t) limit;
-}
-#if defined (__cplusplus) && __cplusplus >= 201103L
- #include <cstdlib>
- #define __Pyx_sst_abs(value) std::abs(value)
-#elif SIZEOF_INT >= SIZEOF_SIZE_T
- #define __Pyx_sst_abs(value) abs(value)
-#elif SIZEOF_LONG >= SIZEOF_SIZE_T
- #define __Pyx_sst_abs(value) labs(value)
-#elif defined (_MSC_VER)
- #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value))
-#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
- #define __Pyx_sst_abs(value) llabs(value)
-#elif defined (__GNUC__)
- #define __Pyx_sst_abs(value) __builtin_llabs(value)
-#else
- #define __Pyx_sst_abs(value) ((value<0) ? -value : value)
-#endif
-static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*);
-static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length);
-#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s))
-#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l)
-#define __Pyx_PyBytes_FromString PyBytes_FromString
-#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize
-static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*);
-#if PY_MAJOR_VERSION < 3
- #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString
- #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize
-#else
- #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString
- #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize
-#endif
-#define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s))
-#define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s))
-#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s)
-#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s)
-#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s)
-#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s)
-#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s)
-static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) {
- const Py_UNICODE *u_end = u;
- while (*u_end++) ;
- return (size_t)(u_end - u - 1);
-}
-#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u))
-#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode
-#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode
-#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj)
-#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None)
-static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b);
-static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*);
-static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*);
-static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x);
-#define __Pyx_PySequence_Tuple(obj)\
- (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj))
-static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*);
-static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t);
-#if CYTHON_ASSUME_SAFE_MACROS
-#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x))
-#else
-#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x)
-#endif
-#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x))
-#if PY_MAJOR_VERSION >= 3
-#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x))
-#else
-#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x))
-#endif
-#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x))
-#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII
-static int __Pyx_sys_getdefaultencoding_not_ascii;
-static int __Pyx_init_sys_getdefaultencoding_params(void) {
- PyObject* sys;
- PyObject* default_encoding = NULL;
- PyObject* ascii_chars_u = NULL;
- PyObject* ascii_chars_b = NULL;
- const char* default_encoding_c;
- sys = PyImport_ImportModule("sys");
- if (!sys) goto bad;
- default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL);
- Py_DECREF(sys);
- if (!default_encoding) goto bad;
- default_encoding_c = PyBytes_AsString(default_encoding);
- if (!default_encoding_c) goto bad;
- if (strcmp(default_encoding_c, "ascii") == 0) {
- __Pyx_sys_getdefaultencoding_not_ascii = 0;
- } else {
- char ascii_chars[128];
- int c;
- for (c = 0; c < 128; c++) {
- ascii_chars[c] = c;
- }
- __Pyx_sys_getdefaultencoding_not_ascii = 1;
- ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL);
- if (!ascii_chars_u) goto bad;
- ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL);
- if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) {
- PyErr_Format(
- PyExc_ValueError,
- "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.",
- default_encoding_c);
- goto bad;
- }
- Py_DECREF(ascii_chars_u);
- Py_DECREF(ascii_chars_b);
- }
- Py_DECREF(default_encoding);
- return 0;
-bad:
- Py_XDECREF(default_encoding);
- Py_XDECREF(ascii_chars_u);
- Py_XDECREF(ascii_chars_b);
- return -1;
-}
-#endif
-#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3
-#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL)
-#else
-#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL)
-#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT
-static char* __PYX_DEFAULT_STRING_ENCODING;
-static int __Pyx_init_sys_getdefaultencoding_params(void) {
- PyObject* sys;
- PyObject* default_encoding = NULL;
- char* default_encoding_c;
- sys = PyImport_ImportModule("sys");
- if (!sys) goto bad;
- default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL);
- Py_DECREF(sys);
- if (!default_encoding) goto bad;
- default_encoding_c = PyBytes_AsString(default_encoding);
- if (!default_encoding_c) goto bad;
- __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c) + 1);
- if (!__PYX_DEFAULT_STRING_ENCODING) goto bad;
- strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c);
- Py_DECREF(default_encoding);
- return 0;
-bad:
- Py_XDECREF(default_encoding);
- return -1;
-}
-#endif
-#endif
-
-
-/* Test for GCC > 2.95 */
-#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)))
- #define likely(x) __builtin_expect(!!(x), 1)
- #define unlikely(x) __builtin_expect(!!(x), 0)
-#else /* !__GNUC__ or GCC < 2.95 */
- #define likely(x) (x)
- #define unlikely(x) (x)
-#endif /* __GNUC__ */
-static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; }
-
-static PyObject *__pyx_m = NULL;
-static PyObject *__pyx_d;
-static PyObject *__pyx_b;
-static PyObject *__pyx_cython_runtime = NULL;
-static PyObject *__pyx_empty_tuple;
-static PyObject *__pyx_empty_bytes;
-static PyObject *__pyx_empty_unicode;
-static int __pyx_lineno;
-static int __pyx_clineno = 0;
-static const char * __pyx_cfilenm= __FILE__;
-static const char *__pyx_filename;
-
-
-static const char *__pyx_f[] = {
- "silx/image/bilinear.pyx",
- "stringsource",
-};
-/* MemviewSliceStruct.proto */
-struct __pyx_memoryview_obj;
-typedef struct {
- struct __pyx_memoryview_obj *memview;
- char *data;
- Py_ssize_t shape[8];
- Py_ssize_t strides[8];
- Py_ssize_t suboffsets[8];
-} __Pyx_memviewslice;
-#define __Pyx_MemoryView_Len(m) (m.shape[0])
-
-/* Atomics.proto */
-#include <pythread.h>
-#ifndef CYTHON_ATOMICS
- #define CYTHON_ATOMICS 1
-#endif
-#define __pyx_atomic_int_type int
-#if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 ||\
- (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL >= 2)) &&\
- !defined(__i386__)
- #define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1)
- #define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1)
- #ifdef __PYX_DEBUG_ATOMICS
- #warning "Using GNU atomics"
- #endif
-#elif CYTHON_ATOMICS && defined(_MSC_VER) && 0
- #include <Windows.h>
- #undef __pyx_atomic_int_type
- #define __pyx_atomic_int_type LONG
- #define __pyx_atomic_incr_aligned(value, lock) InterlockedIncrement(value)
- #define __pyx_atomic_decr_aligned(value, lock) InterlockedDecrement(value)
- #ifdef __PYX_DEBUG_ATOMICS
- #pragma message ("Using MSVC atomics")
- #endif
-#elif CYTHON_ATOMICS && (defined(__ICC) || defined(__INTEL_COMPILER)) && 0
- #define __pyx_atomic_incr_aligned(value, lock) _InterlockedIncrement(value)
- #define __pyx_atomic_decr_aligned(value, lock) _InterlockedDecrement(value)
- #ifdef __PYX_DEBUG_ATOMICS
- #warning "Using Intel atomics"
- #endif
-#else
- #undef CYTHON_ATOMICS
- #define CYTHON_ATOMICS 0
- #ifdef __PYX_DEBUG_ATOMICS
- #warning "Not using atomics"
- #endif
-#endif
-typedef volatile __pyx_atomic_int_type __pyx_atomic_int;
-#if CYTHON_ATOMICS
- #define __pyx_add_acquisition_count(memview)\
- __pyx_atomic_incr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock)
- #define __pyx_sub_acquisition_count(memview)\
- __pyx_atomic_decr_aligned(__pyx_get_slice_count_pointer(memview), memview->lock)
-#else
- #define __pyx_add_acquisition_count(memview)\
- __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock)
- #define __pyx_sub_acquisition_count(memview)\
- __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock)
-#endif
-
-/* NoFastGil.proto */
-#define __Pyx_PyGILState_Ensure PyGILState_Ensure
-#define __Pyx_PyGILState_Release PyGILState_Release
-#define __Pyx_FastGIL_Remember()
-#define __Pyx_FastGIL_Forget()
-#define __Pyx_FastGilFuncInit()
-
-/* ForceInitThreads.proto */
-#ifndef __PYX_FORCE_INIT_THREADS
- #define __PYX_FORCE_INIT_THREADS 0
-#endif
-
-/* BufferFormatStructs.proto */
-#define IS_UNSIGNED(type) (((type) -1) > 0)
-struct __Pyx_StructField_;
-#define __PYX_BUF_FLAGS_PACKED_STRUCT (1 << 0)
-typedef struct {
- const char* name;
- struct __Pyx_StructField_* fields;
- size_t size;
- size_t arraysize[8];
- int ndim;
- char typegroup;
- char is_unsigned;
- int flags;
-} __Pyx_TypeInfo;
-typedef struct __Pyx_StructField_ {
- __Pyx_TypeInfo* type;
- const char* name;
- size_t offset;
-} __Pyx_StructField;
-typedef struct {
- __Pyx_StructField* field;
- size_t parent_offset;
-} __Pyx_BufFmt_StackElem;
-typedef struct {
- __Pyx_StructField root;
- __Pyx_BufFmt_StackElem* head;
- size_t fmt_offset;
- size_t new_count, enc_count;
- size_t struct_alignment;
- int is_complex;
- char enc_type;
- char new_packmode;
- char enc_packmode;
- char is_valid_array;
-} __Pyx_BufFmt_Context;
-
-
-/*--- Type declarations ---*/
-struct __pyx_obj_4silx_5image_8bilinear_BilinearImage;
-struct __pyx_array_obj;
-struct __pyx_MemviewEnum_obj;
-struct __pyx_memoryview_obj;
-struct __pyx_memoryviewslice_obj;
-
-/* "silx/image/bilinear.pyx":39
- *
- *
- * cdef class BilinearImage: # <<<<<<<<<<<<<<
- * """Bilinear interpolator for images ... or any data on a regular grid
- * """
- */
-struct __pyx_obj_4silx_5image_8bilinear_BilinearImage {
- PyObject_HEAD
- struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *__pyx_vtab;
- __Pyx_memviewslice data;
- float maxi;
- float mini;
- size_t width;
- size_t height;
-};
-
-
-/* "View.MemoryView":105
- *
- * @cname("__pyx_array")
- * cdef class array: # <<<<<<<<<<<<<<
- *
- * cdef:
- */
-struct __pyx_array_obj {
- PyObject_HEAD
- struct __pyx_vtabstruct_array *__pyx_vtab;
- char *data;
- Py_ssize_t len;
- char *format;
- int ndim;
- Py_ssize_t *_shape;
- Py_ssize_t *_strides;
- Py_ssize_t itemsize;
- PyObject *mode;
- PyObject *_format;
- void (*callback_free_data)(void *);
- int free_data;
- int dtype_is_object;
-};
-
-
-/* "View.MemoryView":279
- *
- * @cname('__pyx_MemviewEnum')
- * cdef class Enum(object): # <<<<<<<<<<<<<<
- * cdef object name
- * def __init__(self, name):
- */
-struct __pyx_MemviewEnum_obj {
- PyObject_HEAD
- PyObject *name;
-};
-
-
-/* "View.MemoryView":330
- *
- * @cname('__pyx_memoryview')
- * cdef class memoryview(object): # <<<<<<<<<<<<<<
- *
- * cdef object obj
- */
-struct __pyx_memoryview_obj {
- PyObject_HEAD
- struct __pyx_vtabstruct_memoryview *__pyx_vtab;
- PyObject *obj;
- PyObject *_size;
- PyObject *_array_interface;
- PyThread_type_lock lock;
- __pyx_atomic_int acquisition_count[2];
- __pyx_atomic_int *acquisition_count_aligned_p;
- Py_buffer view;
- int flags;
- int dtype_is_object;
- __Pyx_TypeInfo *typeinfo;
-};
-
-
-/* "View.MemoryView":961
- *
- * @cname('__pyx_memoryviewslice')
- * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<<
- * "Internal class for passing memoryview slices to Python"
- *
- */
-struct __pyx_memoryviewslice_obj {
- struct __pyx_memoryview_obj __pyx_base;
- __Pyx_memviewslice from_slice;
- PyObject *from_object;
- PyObject *(*to_object_func)(char *);
- int (*to_dtype_func)(char *, PyObject *);
-};
-
-
-
-/* "View.MemoryView":105
- *
- * @cname("__pyx_array")
- * cdef class array: # <<<<<<<<<<<<<<
- *
- * cdef:
- */
-
-struct __pyx_vtabstruct_array {
- PyObject *(*get_memview)(struct __pyx_array_obj *);
-};
-static struct __pyx_vtabstruct_array *__pyx_vtabptr_array;
-
-
-/* "silx/image/bilinear.pyx":39
- *
- *
- * cdef class BilinearImage: # <<<<<<<<<<<<<<
- * """Bilinear interpolator for images ... or any data on a regular grid
- * """
- */
-
-struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage {
- size_t (*coarse_local_maxi)(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *, size_t, int __pyx_skip_dispatch);
- size_t (*c_local_maxi)(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *, size_t);
- float (*c_funct)(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *, float, float);
-};
-static struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *__pyx_vtabptr_4silx_5image_8bilinear_BilinearImage;
-
-
-/* "View.MemoryView":330
- *
- * @cname('__pyx_memoryview')
- * cdef class memoryview(object): # <<<<<<<<<<<<<<
- *
- * cdef object obj
- */
-
-struct __pyx_vtabstruct_memoryview {
- char *(*get_item_pointer)(struct __pyx_memoryview_obj *, PyObject *);
- PyObject *(*is_slice)(struct __pyx_memoryview_obj *, PyObject *);
- PyObject *(*setitem_slice_assignment)(struct __pyx_memoryview_obj *, PyObject *, PyObject *);
- PyObject *(*setitem_slice_assign_scalar)(struct __pyx_memoryview_obj *, struct __pyx_memoryview_obj *, PyObject *);
- PyObject *(*setitem_indexed)(struct __pyx_memoryview_obj *, PyObject *, PyObject *);
- PyObject *(*convert_item_to_object)(struct __pyx_memoryview_obj *, char *);
- PyObject *(*assign_item_from_object)(struct __pyx_memoryview_obj *, char *, PyObject *);
-};
-static struct __pyx_vtabstruct_memoryview *__pyx_vtabptr_memoryview;
-
-
-/* "View.MemoryView":961
- *
- * @cname('__pyx_memoryviewslice')
- * cdef class _memoryviewslice(memoryview): # <<<<<<<<<<<<<<
- * "Internal class for passing memoryview slices to Python"
- *
- */
-
-struct __pyx_vtabstruct__memoryviewslice {
- struct __pyx_vtabstruct_memoryview __pyx_base;
-};
-static struct __pyx_vtabstruct__memoryviewslice *__pyx_vtabptr__memoryviewslice;
-
-/* --- Runtime support code (head) --- */
-/* Refnanny.proto */
-#ifndef CYTHON_REFNANNY
- #define CYTHON_REFNANNY 0
-#endif
-#if CYTHON_REFNANNY
- typedef struct {
- void (*INCREF)(void*, PyObject*, int);
- void (*DECREF)(void*, PyObject*, int);
- void (*GOTREF)(void*, PyObject*, int);
- void (*GIVEREF)(void*, PyObject*, int);
- void* (*SetupContext)(const char*, int, const char*);
- void (*FinishContext)(void**);
- } __Pyx_RefNannyAPIStruct;
- static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL;
- static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname);
- #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL;
-#ifdef WITH_THREAD
- #define __Pyx_RefNannySetupContext(name, acquire_gil)\
- if (acquire_gil) {\
- PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\
- __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\
- PyGILState_Release(__pyx_gilstate_save);\
- } else {\
- __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\
- }
-#else
- #define __Pyx_RefNannySetupContext(name, acquire_gil)\
- __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__)
-#endif
- #define __Pyx_RefNannyFinishContext()\
- __Pyx_RefNanny->FinishContext(&__pyx_refnanny)
- #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__)
- #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0)
- #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0)
- #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0)
- #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0)
-#else
- #define __Pyx_RefNannyDeclarations
- #define __Pyx_RefNannySetupContext(name, acquire_gil)
- #define __Pyx_RefNannyFinishContext()
- #define __Pyx_INCREF(r) Py_INCREF(r)
- #define __Pyx_DECREF(r) Py_DECREF(r)
- #define __Pyx_GOTREF(r)
- #define __Pyx_GIVEREF(r)
- #define __Pyx_XINCREF(r) Py_XINCREF(r)
- #define __Pyx_XDECREF(r) Py_XDECREF(r)
- #define __Pyx_XGOTREF(r)
- #define __Pyx_XGIVEREF(r)
-#endif
-#define __Pyx_XDECREF_SET(r, v) do {\
- PyObject *tmp = (PyObject *) r;\
- r = v; __Pyx_XDECREF(tmp);\
- } while (0)
-#define __Pyx_DECREF_SET(r, v) do {\
- PyObject *tmp = (PyObject *) r;\
- r = v; __Pyx_DECREF(tmp);\
- } while (0)
-#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0)
-#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
-
-/* PyObjectGetAttrStr.proto */
-#if CYTHON_USE_TYPE_SLOTS
-static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name);
-#else
-#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
-#endif
-
-/* GetBuiltinName.proto */
-static PyObject *__Pyx_GetBuiltinName(PyObject *name);
-
-/* RaiseDoubleKeywords.proto */
-static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name);
-
-/* ParseKeywords.proto */
-static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\
- PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\
- const char* function_name);
-
-/* RaiseArgTupleInvalid.proto */
-static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact,
- Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found);
-
-/* PyIntCompare.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyInt_EqObjC(PyObject *op1, PyObject *op2, long intval, long inplace);
-
-/* GetItemInt.proto */
-#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\
- (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\
- __Pyx_GetItemInt_Generic(o, to_py_func(i))))
-#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
- (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL))
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i,
- int wraparound, int boundscheck);
-#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\
- (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\
- __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\
- (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL))
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i,
- int wraparound, int boundscheck);
-static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j);
-static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i,
- int is_list, int wraparound, int boundscheck);
-
-/* PyFunctionFastCall.proto */
-#if CYTHON_FAST_PYCALL
-#define __Pyx_PyFunction_FastCall(func, args, nargs)\
- __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL)
-#if 1 || PY_VERSION_HEX < 0x030600B1
-static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs);
-#else
-#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs)
-#endif
-#define __Pyx_BUILD_ASSERT_EXPR(cond)\
- (sizeof(char [1 - 2*!(cond)]) - 1)
-#ifndef Py_MEMBER_SIZE
-#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
-#endif
- static size_t __pyx_pyframe_localsplus_offset = 0;
- #include "frameobject.h"
- #define __Pxy_PyFrame_Initialize_Offsets()\
- ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\
- (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus)))
- #define __Pyx_PyFrame_GetLocalsplus(frame)\
- (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset))
-#endif
-
-/* PyObjectCall.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
-static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw);
-#else
-#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw)
-#endif
-
-/* PyObjectCallMethO.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
-static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg);
-#endif
-
-/* PyObjectCallNoArg.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
-static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func);
-#else
-#define __Pyx_PyObject_CallNoArg(func) __Pyx_PyObject_Call(func, __pyx_empty_tuple, NULL)
-#endif
-
-/* PyCFunctionFastCall.proto */
-#if CYTHON_FAST_PYCCALL
-static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs);
-#else
-#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL)
-#endif
-
-/* PyObjectCallOneArg.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg);
-
-/* PyDictVersioning.proto */
-#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS
-#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1)
-#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag)
-#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\
- (version_var) = __PYX_GET_DICT_VERSION(dict);\
- (cache_var) = (value);
-#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\
- static PY_UINT64_T __pyx_dict_version = 0;\
- static PyObject *__pyx_dict_cached_value = NULL;\
- if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\
- (VAR) = __pyx_dict_cached_value;\
- } else {\
- (VAR) = __pyx_dict_cached_value = (LOOKUP);\
- __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\
- }\
-}
-static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj);
-static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj);
-static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version);
-#else
-#define __PYX_GET_DICT_VERSION(dict) (0)
-#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)
-#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP);
-#endif
-
-/* GetModuleGlobalName.proto */
-#if CYTHON_USE_DICT_VERSIONS
-#define __Pyx_GetModuleGlobalName(var, name) {\
- static PY_UINT64_T __pyx_dict_version = 0;\
- static PyObject *__pyx_dict_cached_value = NULL;\
- (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_d))) ?\
- (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\
- __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\
-}
-#define __Pyx_GetModuleGlobalNameUncached(var, name) {\
- PY_UINT64_T __pyx_dict_version;\
- PyObject *__pyx_dict_cached_value;\
- (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\
-}
-static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value);
-#else
-#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name)
-#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name)
-static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name);
-#endif
-
-/* MemviewSliceInit.proto */
-#define __Pyx_BUF_MAX_NDIMS %(BUF_MAX_NDIMS)d
-#define __Pyx_MEMVIEW_DIRECT 1
-#define __Pyx_MEMVIEW_PTR 2
-#define __Pyx_MEMVIEW_FULL 4
-#define __Pyx_MEMVIEW_CONTIG 8
-#define __Pyx_MEMVIEW_STRIDED 16
-#define __Pyx_MEMVIEW_FOLLOW 32
-#define __Pyx_IS_C_CONTIG 1
-#define __Pyx_IS_F_CONTIG 2
-static int __Pyx_init_memviewslice(
- struct __pyx_memoryview_obj *memview,
- int ndim,
- __Pyx_memviewslice *memviewslice,
- int memview_is_new_reference);
-static CYTHON_INLINE int __pyx_add_acquisition_count_locked(
- __pyx_atomic_int *acquisition_count, PyThread_type_lock lock);
-static CYTHON_INLINE int __pyx_sub_acquisition_count_locked(
- __pyx_atomic_int *acquisition_count, PyThread_type_lock lock);
-#define __pyx_get_slice_count_pointer(memview) (memview->acquisition_count_aligned_p)
-#define __pyx_get_slice_count(memview) (*__pyx_get_slice_count_pointer(memview))
-#define __PYX_INC_MEMVIEW(slice, have_gil) __Pyx_INC_MEMVIEW(slice, have_gil, __LINE__)
-#define __PYX_XDEC_MEMVIEW(slice, have_gil) __Pyx_XDEC_MEMVIEW(slice, have_gil, __LINE__)
-static CYTHON_INLINE void __Pyx_INC_MEMVIEW(__Pyx_memviewslice *, int, int);
-static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW(__Pyx_memviewslice *, int, int);
-
-/* PyThreadStateGet.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate;
-#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current;
-#define __Pyx_PyErr_Occurred() __pyx_tstate->curexc_type
-#else
-#define __Pyx_PyThreadState_declare
-#define __Pyx_PyThreadState_assign
-#define __Pyx_PyErr_Occurred() PyErr_Occurred()
-#endif
-
-/* PyErrFetchRestore.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL)
-#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb)
-#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb)
-#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb)
-#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb);
-static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#if CYTHON_COMPILING_IN_CPYTHON
-#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL))
-#else
-#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc)
-#endif
-#else
-#define __Pyx_PyErr_Clear() PyErr_Clear()
-#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc)
-#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb)
-#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb)
-#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb)
-#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb)
-#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb)
-#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb)
-#endif
-
-/* WriteUnraisableException.proto */
-static void __Pyx_WriteUnraisable(const char *name, int clineno,
- int lineno, const char *filename,
- int full_traceback, int nogil);
-
-/* RaiseTooManyValuesToUnpack.proto */
-static CYTHON_INLINE void __Pyx_RaiseTooManyValuesError(Py_ssize_t expected);
-
-/* RaiseNeedMoreValuesToUnpack.proto */
-static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index);
-
-/* IterFinish.proto */
-static CYTHON_INLINE int __Pyx_IterFinish(void);
-
-/* UnpackItemEndCheck.proto */
-static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected);
-
-/* PyObjectCall2Args.proto */
-static CYTHON_UNUSED PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2);
-
-/* RaiseException.proto */
-static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause);
-
-/* ArgTypeTest.proto */
-#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\
- ((likely((Py_TYPE(obj) == type) | (none_allowed && (obj == Py_None)))) ? 1 :\
- __Pyx__ArgTypeTest(obj, type, name, exact))
-static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact);
-
-/* IncludeStringH.proto */
-#include <string.h>
-
-/* BytesEquals.proto */
-static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals);
-
-/* UnicodeEquals.proto */
-static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals);
-
-/* StrEquals.proto */
-#if PY_MAJOR_VERSION >= 3
-#define __Pyx_PyString_Equals __Pyx_PyUnicode_Equals
-#else
-#define __Pyx_PyString_Equals __Pyx_PyBytes_Equals
-#endif
-
-/* None.proto */
-static CYTHON_INLINE Py_ssize_t __Pyx_div_Py_ssize_t(Py_ssize_t, Py_ssize_t);
-
-/* UnaryNegOverflows.proto */
-#define UNARY_NEG_WOULD_OVERFLOW(x)\
- (((x) < 0) & ((unsigned long)(x) == 0-(unsigned long)(x)))
-
-static CYTHON_UNUSED int __pyx_array_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/
-static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *); /*proto*/
-/* GetAttr.proto */
-static CYTHON_INLINE PyObject *__Pyx_GetAttr(PyObject *, PyObject *);
-
-/* ObjectGetItem.proto */
-#if CYTHON_USE_TYPE_SLOTS
-static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject* key);
-#else
-#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key)
-#endif
-
-/* decode_c_string_utf16.proto */
-static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16(const char *s, Py_ssize_t size, const char *errors) {
- int byteorder = 0;
- return PyUnicode_DecodeUTF16(s, size, errors, &byteorder);
-}
-static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16LE(const char *s, Py_ssize_t size, const char *errors) {
- int byteorder = -1;
- return PyUnicode_DecodeUTF16(s, size, errors, &byteorder);
-}
-static CYTHON_INLINE PyObject *__Pyx_PyUnicode_DecodeUTF16BE(const char *s, Py_ssize_t size, const char *errors) {
- int byteorder = 1;
- return PyUnicode_DecodeUTF16(s, size, errors, &byteorder);
-}
-
-/* decode_c_string.proto */
-static CYTHON_INLINE PyObject* __Pyx_decode_c_string(
- const char* cstring, Py_ssize_t start, Py_ssize_t stop,
- const char* encoding, const char* errors,
- PyObject* (*decode_func)(const char *s, Py_ssize_t size, const char *errors));
-
-/* PyErrExceptionMatches.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err)
-static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err);
-#else
-#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err)
-#endif
-
-/* GetAttr3.proto */
-static CYTHON_INLINE PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *);
-
-/* RaiseNoneIterError.proto */
-static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void);
-
-/* ExtTypeTest.proto */
-static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type);
-
-/* GetTopmostException.proto */
-#if CYTHON_USE_EXC_INFO_STACK
-static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate);
-#endif
-
-/* SaveResetException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb);
-#else
-#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb)
-#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb)
-#endif
-
-/* GetException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb)
-static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#else
-static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb);
-#endif
-
-/* SwapException.proto */
-#if CYTHON_FAST_THREAD_STATE
-#define __Pyx_ExceptionSwap(type, value, tb) __Pyx__ExceptionSwap(__pyx_tstate, type, value, tb)
-static CYTHON_INLINE void __Pyx__ExceptionSwap(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb);
-#else
-static CYTHON_INLINE void __Pyx_ExceptionSwap(PyObject **type, PyObject **value, PyObject **tb);
-#endif
-
-/* Import.proto */
-static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level);
-
-/* FastTypeChecks.proto */
-#if CYTHON_COMPILING_IN_CPYTHON
-#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type)
-static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b);
-static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type);
-static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2);
-#else
-#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type)
-#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type)
-#define __Pyx_PyErr_GivenExceptionMatches2(err, type1, type2) (PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2))
-#endif
-#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception)
-
-static CYTHON_UNUSED int __pyx_memoryview_getbuffer(PyObject *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /*proto*/
-/* ListCompAppend.proto */
-#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
-static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
- PyListObject* L = (PyListObject*) list;
- Py_ssize_t len = Py_SIZE(list);
- if (likely(L->allocated > len)) {
- Py_INCREF(x);
- PyList_SET_ITEM(list, len, x);
- Py_SIZE(list) = len+1;
- return 0;
- }
- return PyList_Append(list, x);
-}
-#else
-#define __Pyx_ListComp_Append(L,x) PyList_Append(L,x)
-#endif
-
-/* PyIntBinop.proto */
-#if !CYTHON_COMPILING_IN_PYPY
-static PyObject* __Pyx_PyInt_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check);
-#else
-#define __Pyx_PyInt_AddObjC(op1, op2, intval, inplace, zerodivision_check)\
- (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2))
-#endif
-
-/* ListExtend.proto */
-static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) {
-#if CYTHON_COMPILING_IN_CPYTHON
- PyObject* none = _PyList_Extend((PyListObject*)L, v);
- if (unlikely(!none))
- return -1;
- Py_DECREF(none);
- return 0;
-#else
- return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v);
-#endif
-}
-
-/* ListAppend.proto */
-#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS
-static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) {
- PyListObject* L = (PyListObject*) list;
- Py_ssize_t len = Py_SIZE(list);
- if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) {
- Py_INCREF(x);
- PyList_SET_ITEM(list, len, x);
- Py_SIZE(list) = len+1;
- return 0;
- }
- return PyList_Append(list, x);
-}
-#else
-#define __Pyx_PyList_Append(L,x) PyList_Append(L,x)
-#endif
-
-/* None.proto */
-static CYTHON_INLINE void __Pyx_RaiseUnboundLocalError(const char *varname);
-
-/* None.proto */
-static CYTHON_INLINE long __Pyx_div_long(long, long);
-
-/* ImportFrom.proto */
-static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name);
-
-/* HasAttr.proto */
-static CYTHON_INLINE int __Pyx_HasAttr(PyObject *, PyObject *);
-
-/* PyObject_GenericGetAttrNoDict.proto */
-#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000
-static CYTHON_INLINE PyObject* __Pyx_PyObject_GenericGetAttrNoDict(PyObject* obj, PyObject* attr_name);
-#else
-#define __Pyx_PyObject_GenericGetAttrNoDict PyObject_GenericGetAttr
-#endif
-
-/* PyObject_GenericGetAttr.proto */
-#if CYTHON_USE_TYPE_SLOTS && CYTHON_USE_PYTYPE_LOOKUP && PY_VERSION_HEX < 0x03070000
-static PyObject* __Pyx_PyObject_GenericGetAttr(PyObject* obj, PyObject* attr_name);
-#else
-#define __Pyx_PyObject_GenericGetAttr PyObject_GenericGetAttr
-#endif
-
-/* SetVTable.proto */
-static int __Pyx_SetVtable(PyObject *dict, void *vtable);
-
-/* SetupReduce.proto */
-static int __Pyx_setup_reduce(PyObject* type_obj);
-
-/* CLineInTraceback.proto */
-#ifdef CYTHON_CLINE_IN_TRACEBACK
-#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0)
-#else
-static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line);
-#endif
-
-/* CodeObjectCache.proto */
-typedef struct {
- PyCodeObject* code_object;
- int code_line;
-} __Pyx_CodeObjectCacheEntry;
-struct __Pyx_CodeObjectCache {
- int count;
- int max_count;
- __Pyx_CodeObjectCacheEntry* entries;
-};
-static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL};
-static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line);
-static PyCodeObject *__pyx_find_code_object(int code_line);
-static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object);
-
-/* AddTraceback.proto */
-static void __Pyx_AddTraceback(const char *funcname, int c_line,
- int py_line, const char *filename);
-
-#if PY_MAJOR_VERSION < 3
- static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
- static void __Pyx_ReleaseBuffer(Py_buffer *view);
-#else
- #define __Pyx_GetBuffer PyObject_GetBuffer
- #define __Pyx_ReleaseBuffer PyBuffer_Release
-#endif
-
-
-/* BufferStructDeclare.proto */
-typedef struct {
- Py_ssize_t shape, strides, suboffsets;
-} __Pyx_Buf_DimInfo;
-typedef struct {
- size_t refcount;
- Py_buffer pybuffer;
-} __Pyx_Buffer;
-typedef struct {
- __Pyx_Buffer *rcbuffer;
- char *data;
- __Pyx_Buf_DimInfo diminfo[8];
-} __Pyx_LocalBuf_ND;
-
-/* MemviewSliceIsContig.proto */
-static int __pyx_memviewslice_is_contig(const __Pyx_memviewslice mvs, char order, int ndim);
-
-/* OverlappingSlices.proto */
-static int __pyx_slices_overlap(__Pyx_memviewslice *slice1,
- __Pyx_memviewslice *slice2,
- int ndim, size_t itemsize);
-
-/* Capsule.proto */
-static CYTHON_INLINE PyObject *__pyx_capsule_create(void *p, const char *sig);
-
-/* CIntToPy.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value);
-
-/* CIntToPy.proto */
-static CYTHON_INLINE PyObject* __Pyx_PyInt_From_int(int value);
-
-/* MemviewDtypeToObject.proto */
-static CYTHON_INLINE PyObject *__pyx_memview_get_float(const char *itemp);
-static CYTHON_INLINE int __pyx_memview_set_float(const char *itemp, PyObject *obj);
-
-/* MemviewSliceCopyTemplate.proto */
-static __Pyx_memviewslice
-__pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
- const char *mode, int ndim,
- size_t sizeof_dtype, int contig_flag,
- int dtype_is_object);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE size_t __Pyx_PyInt_As_size_t(PyObject *);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *);
-
-/* CIntFromPy.proto */
-static CYTHON_INLINE char __Pyx_PyInt_As_char(PyObject *);
-
-/* IsLittleEndian.proto */
-static CYTHON_INLINE int __Pyx_Is_Little_Endian(void);
-
-/* BufferFormatCheck.proto */
-static const char* __Pyx_BufFmt_CheckString(__Pyx_BufFmt_Context* ctx, const char* ts);
-static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
- __Pyx_BufFmt_StackElem* stack,
- __Pyx_TypeInfo* type);
-
-/* TypeInfoCompare.proto */
-static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b);
-
-/* MemviewSliceValidateAndInit.proto */
-static int __Pyx_ValidateAndInit_memviewslice(
- int *axes_specs,
- int c_or_f_flag,
- int buf_flags,
- int ndim,
- __Pyx_TypeInfo *dtype,
- __Pyx_BufFmt_StackElem stack[],
- __Pyx_memviewslice *memviewslice,
- PyObject *original_obj);
-
-/* ObjectToMemviewSlice.proto */
-static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_d_dc_float(PyObject *, int writable_flag);
-
-/* ObjectToMemviewSlice.proto */
-static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_ds_float(PyObject *, int writable_flag);
-
-/* ObjectToMemviewSlice.proto */
-static CYTHON_INLINE __Pyx_memviewslice __Pyx_PyObject_to_MemoryviewSlice_dc_float(PyObject *, int writable_flag);
-
-/* CheckBinaryVersion.proto */
-static int __Pyx_check_binary_version(void);
-
-/* InitStrings.proto */
-static int __Pyx_InitStrings(__Pyx_StringTabEntry *t);
-
-static float __pyx_f_4silx_5image_8bilinear_13BilinearImage_c_funct(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, float __pyx_v_x, float __pyx_v_y); /* proto*/
-static size_t __pyx_f_4silx_5image_8bilinear_13BilinearImage_coarse_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_x, int __pyx_skip_dispatch); /* proto*/
-static size_t __pyx_f_4silx_5image_8bilinear_13BilinearImage_c_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_idx); /* proto*/
-static PyObject *__pyx_array_get_memview(struct __pyx_array_obj *__pyx_v_self); /* proto*/
-static char *__pyx_memoryview_get_item_pointer(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto*/
-static PyObject *__pyx_memoryview_is_slice(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj); /* proto*/
-static PyObject *__pyx_memoryview_setitem_slice_assignment(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_dst, PyObject *__pyx_v_src); /* proto*/
-static PyObject *__pyx_memoryview_setitem_slice_assign_scalar(struct __pyx_memoryview_obj *__pyx_v_self, struct __pyx_memoryview_obj *__pyx_v_dst, PyObject *__pyx_v_value); /* proto*/
-static PyObject *__pyx_memoryview_setitem_indexed(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto*/
-static PyObject *__pyx_memoryview_convert_item_to_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/
-static PyObject *__pyx_memoryview_assign_item_from_object(struct __pyx_memoryview_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/
-static PyObject *__pyx_memoryviewslice_convert_item_to_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp); /* proto*/
-static PyObject *__pyx_memoryviewslice_assign_item_from_object(struct __pyx_memoryviewslice_obj *__pyx_v_self, char *__pyx_v_itemp, PyObject *__pyx_v_value); /* proto*/
-
-/* Module declarations from 'cython.view' */
-
-/* Module declarations from 'cython' */
-
-/* Module declarations from 'libc.math' */
-
-/* Module declarations from 'silx.image.bilinear' */
-static PyTypeObject *__pyx_ptype_4silx_5image_8bilinear_BilinearImage = 0;
-static PyTypeObject *__pyx_array_type = 0;
-static PyTypeObject *__pyx_MemviewEnum_type = 0;
-static PyTypeObject *__pyx_memoryview_type = 0;
-static PyTypeObject *__pyx_memoryviewslice_type = 0;
-static PyObject *generic = 0;
-static PyObject *strided = 0;
-static PyObject *indirect = 0;
-static PyObject *contiguous = 0;
-static PyObject *indirect_contiguous = 0;
-static int __pyx_memoryview_thread_locks_used;
-static PyThread_type_lock __pyx_memoryview_thread_locks[8];
-static struct __pyx_array_obj *__pyx_array_new(PyObject *, Py_ssize_t, char *, char *, char *); /*proto*/
-static void *__pyx_align_pointer(void *, size_t); /*proto*/
-static PyObject *__pyx_memoryview_new(PyObject *, int, int, __Pyx_TypeInfo *); /*proto*/
-static CYTHON_INLINE int __pyx_memoryview_check(PyObject *); /*proto*/
-static PyObject *_unellipsify(PyObject *, int); /*proto*/
-static PyObject *assert_direct_dimensions(Py_ssize_t *, int); /*proto*/
-static struct __pyx_memoryview_obj *__pyx_memview_slice(struct __pyx_memoryview_obj *, PyObject *); /*proto*/
-static int __pyx_memoryview_slice_memviewslice(__Pyx_memviewslice *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int *, Py_ssize_t, Py_ssize_t, Py_ssize_t, int, int, int, int); /*proto*/
-static char *__pyx_pybuffer_index(Py_buffer *, char *, Py_ssize_t, Py_ssize_t); /*proto*/
-static int __pyx_memslice_transpose(__Pyx_memviewslice *); /*proto*/
-static PyObject *__pyx_memoryview_fromslice(__Pyx_memviewslice, int, PyObject *(*)(char *), int (*)(char *, PyObject *), int); /*proto*/
-static __Pyx_memviewslice *__pyx_memoryview_get_slice_from_memoryview(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/
-static void __pyx_memoryview_slice_copy(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/
-static PyObject *__pyx_memoryview_copy_object(struct __pyx_memoryview_obj *); /*proto*/
-static PyObject *__pyx_memoryview_copy_object_from_slice(struct __pyx_memoryview_obj *, __Pyx_memviewslice *); /*proto*/
-static Py_ssize_t abs_py_ssize_t(Py_ssize_t); /*proto*/
-static char __pyx_get_best_slice_order(__Pyx_memviewslice *, int); /*proto*/
-static void _copy_strided_to_strided(char *, Py_ssize_t *, char *, Py_ssize_t *, Py_ssize_t *, Py_ssize_t *, int, size_t); /*proto*/
-static void copy_strided_to_strided(__Pyx_memviewslice *, __Pyx_memviewslice *, int, size_t); /*proto*/
-static Py_ssize_t __pyx_memoryview_slice_get_size(__Pyx_memviewslice *, int); /*proto*/
-static Py_ssize_t __pyx_fill_contig_strides_array(Py_ssize_t *, Py_ssize_t *, Py_ssize_t, int, char); /*proto*/
-static void *__pyx_memoryview_copy_data_to_temp(__Pyx_memviewslice *, __Pyx_memviewslice *, char, int); /*proto*/
-static int __pyx_memoryview_err_extents(int, Py_ssize_t, Py_ssize_t); /*proto*/
-static int __pyx_memoryview_err_dim(PyObject *, char *, int); /*proto*/
-static int __pyx_memoryview_err(PyObject *, char *); /*proto*/
-static int __pyx_memoryview_copy_contents(__Pyx_memviewslice, __Pyx_memviewslice, int, int, int); /*proto*/
-static void __pyx_memoryview_broadcast_leading(__Pyx_memviewslice *, int, int); /*proto*/
-static void __pyx_memoryview_refcount_copying(__Pyx_memviewslice *, int, int, int); /*proto*/
-static void __pyx_memoryview_refcount_objects_in_slice_with_gil(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/
-static void __pyx_memoryview_refcount_objects_in_slice(char *, Py_ssize_t *, Py_ssize_t *, int, int); /*proto*/
-static void __pyx_memoryview_slice_assign_scalar(__Pyx_memviewslice *, int, size_t, void *, int); /*proto*/
-static void __pyx_memoryview__slice_assign_scalar(char *, Py_ssize_t *, Py_ssize_t *, int, size_t, void *); /*proto*/
-static PyObject *__pyx_unpickle_Enum__set_state(struct __pyx_MemviewEnum_obj *, PyObject *); /*proto*/
-static __Pyx_TypeInfo __Pyx_TypeInfo_float = { "float", NULL, sizeof(float), { 0 }, 0, 'R', 0, 0 };
-#define __Pyx_MODULE_NAME "silx.image.bilinear"
-extern int __pyx_module_is_main_silx__image__bilinear;
-int __pyx_module_is_main_silx__image__bilinear = 0;
-
-/* Implementation of 'silx.image.bilinear' */
-static PyObject *__pyx_builtin_round;
-static PyObject *__pyx_builtin_range;
-static PyObject *__pyx_builtin_TypeError;
-static PyObject *__pyx_builtin_ValueError;
-static PyObject *__pyx_builtin_MemoryError;
-static PyObject *__pyx_builtin_enumerate;
-static PyObject *__pyx_builtin_Ellipsis;
-static PyObject *__pyx_builtin_id;
-static PyObject *__pyx_builtin_IndexError;
-static const char __pyx_k_O[] = "O";
-static const char __pyx_k_c[] = "c";
-static const char __pyx_k_id[] = "id";
-static const char __pyx_k_MIT[] = "MIT";
-static const char __pyx_k_doc[] = "__doc__";
-static const char __pyx_k_dst[] = "dst";
-static const char __pyx_k_max[] = "max";
-static const char __pyx_k_min[] = "min";
-static const char __pyx_k_new[] = "__new__";
-static const char __pyx_k_obj[] = "obj";
-static const char __pyx_k_src[] = "src";
-static const char __pyx_k_base[] = "base";
-static const char __pyx_k_data[] = "data";
-static const char __pyx_k_date[] = "__date__";
-static const char __pyx_k_dict[] = "__dict__";
-static const char __pyx_k_main[] = "__main__";
-static const char __pyx_k_mean[] = "mean";
-static const char __pyx_k_mode[] = "mode";
-static const char __pyx_k_name[] = "name";
-static const char __pyx_k_ndim[] = "ndim";
-static const char __pyx_k_pack[] = "pack";
-static const char __pyx_k_size[] = "size";
-static const char __pyx_k_step[] = "step";
-static const char __pyx_k_stop[] = "stop";
-static const char __pyx_k_test[] = "__test__";
-static const char __pyx_k_ASCII[] = "ASCII";
-static const char __pyx_k_array[] = "array";
-static const char __pyx_k_class[] = "__class__";
-static const char __pyx_k_coord[] = "coord";
-static const char __pyx_k_debug[] = "debug";
-static const char __pyx_k_dtype[] = "dtype";
-static const char __pyx_k_empty[] = "empty";
-static const char __pyx_k_error[] = "error";
-static const char __pyx_k_flags[] = "flags";
-static const char __pyx_k_numpy[] = "numpy";
-static const char __pyx_k_range[] = "range";
-static const char __pyx_k_ravel[] = "ravel";
-static const char __pyx_k_round[] = "round";
-static const char __pyx_k_shape[] = "shape";
-static const char __pyx_k_start[] = "start";
-static const char __pyx_k_zeros[] = "zeros";
-static const char __pyx_k_encode[] = "encode";
-static const char __pyx_k_format[] = "format";
-static const char __pyx_k_import[] = "__import__";
-static const char __pyx_k_logger[] = "logger";
-static const char __pyx_k_method[] = "method";
-static const char __pyx_k_name_2[] = "__name__";
-static const char __pyx_k_pickle[] = "pickle";
-static const char __pyx_k_reduce[] = "__reduce__";
-static const char __pyx_k_struct[] = "struct";
-static const char __pyx_k_unpack[] = "unpack";
-static const char __pyx_k_update[] = "update";
-static const char __pyx_k_asarray[] = "asarray";
-static const char __pyx_k_authors[] = "__authors__";
-static const char __pyx_k_float32[] = "float32";
-static const char __pyx_k_fortran[] = "fortran";
-static const char __pyx_k_license[] = "__license__";
-static const char __pyx_k_logging[] = "logging";
-static const char __pyx_k_memview[] = "memview";
-static const char __pyx_k_reshape[] = "reshape";
-static const char __pyx_k_warning[] = "warning";
-static const char __pyx_k_Ellipsis[] = "Ellipsis";
-static const char __pyx_k_getstate[] = "__getstate__";
-static const char __pyx_k_itemsize[] = "itemsize";
-static const char __pyx_k_pyx_type[] = "__pyx_type";
-static const char __pyx_k_setstate[] = "__setstate__";
-static const char __pyx_k_J_Kieffer[] = "J. Kieffer";
-static const char __pyx_k_TypeError[] = "TypeError";
-static const char __pyx_k_enumerate[] = "enumerate";
-static const char __pyx_k_getLogger[] = "getLogger";
-static const char __pyx_k_linewidth[] = "linewidth";
-static const char __pyx_k_pyx_state[] = "__pyx_state";
-static const char __pyx_k_reduce_ex[] = "__reduce_ex__";
-static const char __pyx_k_15_09_2016[] = "15/09/2016";
-static const char __pyx_k_IndexError[] = "IndexError";
-static const char __pyx_k_ValueError[] = "ValueError";
-static const char __pyx_k_pyx_result[] = "__pyx_result";
-static const char __pyx_k_pyx_vtable[] = "__pyx_vtable__";
-static const char __pyx_k_MemoryError[] = "MemoryError";
-static const char __pyx_k_PickleError[] = "PickleError";
-static const char __pyx_k_pyx_checksum[] = "__pyx_checksum";
-static const char __pyx_k_stringsource[] = "stringsource";
-static const char __pyx_k_BilinearImage[] = "BilinearImage";
-static const char __pyx_k_pyx_getbuffer[] = "__pyx_getbuffer";
-static const char __pyx_k_reduce_cython[] = "__reduce_cython__";
-static const char __pyx_k_View_MemoryView[] = "View.MemoryView";
-static const char __pyx_k_allocate_buffer[] = "allocate_buffer";
-static const char __pyx_k_dtype_is_object[] = "dtype_is_object";
-static const char __pyx_k_pyx_PickleError[] = "__pyx_PickleError";
-static const char __pyx_k_setstate_cython[] = "__setstate_cython__";
-static const char __pyx_k_ascontiguousarray[] = "ascontiguousarray";
-static const char __pyx_k_coarse_local_maxi[] = "coarse_local_maxi";
-static const char __pyx_k_pyx_unpickle_Enum[] = "__pyx_unpickle_Enum";
-static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
-static const char __pyx_k_strided_and_direct[] = "<strided and direct>";
-static const char __pyx_k_strided_and_indirect[] = "<strided and indirect>";
-static const char __pyx_k_contiguous_and_direct[] = "<contiguous and direct>";
-static const char __pyx_k_MemoryView_of_r_object[] = "<MemoryView of %r object>";
-static const char __pyx_k_MemoryView_of_r_at_0x_x[] = "<MemoryView of %r at 0x%x>";
-static const char __pyx_k_contiguous_and_indirect[] = "<contiguous and indirect>";
-static const char __pyx_k_Cannot_index_with_type_s[] = "Cannot index with type '%s'";
-static const char __pyx_k_Invalid_shape_in_axis_d_d[] = "Invalid shape in axis %d: %d.";
-static const char __pyx_k_itemsize_0_for_cython_array[] = "itemsize <= 0 for cython.array";
-static const char __pyx_k_unable_to_allocate_array_data[] = "unable to allocate array data.";
-static const char __pyx_k_strided_and_direct_or_indirect[] = "<strided and direct or indirect>";
-static const char __pyx_k_Bilinear_interpolator_peak_finde[] = "Bilinear interpolator, peak finder, line-profile for images";
-static const char __pyx_k_Buffer_view_does_not_expose_stri[] = "Buffer view does not expose strides";
-static const char __pyx_k_Can_only_create_a_buffer_that_is[] = "Can only create a buffer that is contiguous in memory.";
-static const char __pyx_k_Cannot_assign_to_read_only_memor[] = "Cannot assign to read-only memoryview";
-static const char __pyx_k_Cannot_create_writable_memory_vi[] = "Cannot create writable memory view from read-only memoryview";
-static const char __pyx_k_Empty_shape_tuple_for_cython_arr[] = "Empty shape tuple for cython.array";
-static const char __pyx_k_Failed_to_find_root_using_second[] = "Failed to find root using second order expansion";
-static const char __pyx_k_Incompatible_checksums_s_vs_0xb0[] = "Incompatible checksums (%s vs 0xb068931 = (name))";
-static const char __pyx_k_Indirect_dimensions_not_supporte[] = "Indirect dimensions not supported";
-static const char __pyx_k_Invalid_mode_expected_c_or_fortr[] = "Invalid mode, expected 'c' or 'fortran', got %s";
-static const char __pyx_k_Out_of_bounds_on_buffer_access_a[] = "Out of bounds on buffer access (axis %d)";
-static const char __pyx_k_Singular_determinant_Hessian_und[] = "Singular determinant, Hessian undefined";
-static const char __pyx_k_Source_and_destination_points_ar[] = "Source and destination points are the same";
-static const char __pyx_k_Unable_to_convert_item_to_object[] = "Unable to convert item to object";
-static const char __pyx_k_got_differing_extents_in_dimensi[] = "got differing extents in dimension %d (got %d and %d)";
-static const char __pyx_k_no_default___reduce___due_to_non[] = "no default __reduce__ due to non-trivial __cinit__";
-static const char __pyx_k_unable_to_allocate_shape_and_str[] = "unable to allocate shape and strides.";
-static PyObject *__pyx_kp_u_15_09_2016;
-static PyObject *__pyx_n_s_ASCII;
-static PyObject *__pyx_n_s_BilinearImage;
-static PyObject *__pyx_kp_u_Bilinear_interpolator_peak_finde;
-static PyObject *__pyx_kp_s_Buffer_view_does_not_expose_stri;
-static PyObject *__pyx_kp_s_Can_only_create_a_buffer_that_is;
-static PyObject *__pyx_kp_s_Cannot_assign_to_read_only_memor;
-static PyObject *__pyx_kp_s_Cannot_create_writable_memory_vi;
-static PyObject *__pyx_kp_s_Cannot_index_with_type_s;
-static PyObject *__pyx_n_s_Ellipsis;
-static PyObject *__pyx_kp_s_Empty_shape_tuple_for_cython_arr;
-static PyObject *__pyx_kp_u_Failed_to_find_root_using_second;
-static PyObject *__pyx_kp_s_Incompatible_checksums_s_vs_0xb0;
-static PyObject *__pyx_n_s_IndexError;
-static PyObject *__pyx_kp_s_Indirect_dimensions_not_supporte;
-static PyObject *__pyx_kp_s_Invalid_mode_expected_c_or_fortr;
-static PyObject *__pyx_kp_s_Invalid_shape_in_axis_d_d;
-static PyObject *__pyx_kp_u_J_Kieffer;
-static PyObject *__pyx_n_u_MIT;
-static PyObject *__pyx_n_s_MemoryError;
-static PyObject *__pyx_kp_s_MemoryView_of_r_at_0x_x;
-static PyObject *__pyx_kp_s_MemoryView_of_r_object;
-static PyObject *__pyx_n_b_O;
-static PyObject *__pyx_kp_s_Out_of_bounds_on_buffer_access_a;
-static PyObject *__pyx_n_s_PickleError;
-static PyObject *__pyx_kp_u_Singular_determinant_Hessian_und;
-static PyObject *__pyx_kp_u_Source_and_destination_points_ar;
-static PyObject *__pyx_n_s_TypeError;
-static PyObject *__pyx_kp_s_Unable_to_convert_item_to_object;
-static PyObject *__pyx_n_s_ValueError;
-static PyObject *__pyx_n_s_View_MemoryView;
-static PyObject *__pyx_n_s_allocate_buffer;
-static PyObject *__pyx_n_s_array;
-static PyObject *__pyx_n_s_asarray;
-static PyObject *__pyx_n_s_ascontiguousarray;
-static PyObject *__pyx_n_s_authors;
-static PyObject *__pyx_n_s_base;
-static PyObject *__pyx_n_s_c;
-static PyObject *__pyx_n_u_c;
-static PyObject *__pyx_n_s_class;
-static PyObject *__pyx_n_s_cline_in_traceback;
-static PyObject *__pyx_n_s_coarse_local_maxi;
-static PyObject *__pyx_kp_s_contiguous_and_direct;
-static PyObject *__pyx_kp_s_contiguous_and_indirect;
-static PyObject *__pyx_n_s_coord;
-static PyObject *__pyx_n_s_data;
-static PyObject *__pyx_n_s_date;
-static PyObject *__pyx_n_s_debug;
-static PyObject *__pyx_n_s_dict;
-static PyObject *__pyx_n_s_doc;
-static PyObject *__pyx_n_s_dst;
-static PyObject *__pyx_n_s_dtype;
-static PyObject *__pyx_n_s_dtype_is_object;
-static PyObject *__pyx_n_s_empty;
-static PyObject *__pyx_n_s_encode;
-static PyObject *__pyx_n_s_enumerate;
-static PyObject *__pyx_n_s_error;
-static PyObject *__pyx_n_s_flags;
-static PyObject *__pyx_n_s_float32;
-static PyObject *__pyx_n_s_format;
-static PyObject *__pyx_n_s_fortran;
-static PyObject *__pyx_n_u_fortran;
-static PyObject *__pyx_n_s_getLogger;
-static PyObject *__pyx_n_s_getstate;
-static PyObject *__pyx_kp_s_got_differing_extents_in_dimensi;
-static PyObject *__pyx_n_s_id;
-static PyObject *__pyx_n_s_import;
-static PyObject *__pyx_n_s_itemsize;
-static PyObject *__pyx_kp_s_itemsize_0_for_cython_array;
-static PyObject *__pyx_n_s_license;
-static PyObject *__pyx_n_s_linewidth;
-static PyObject *__pyx_n_s_logger;
-static PyObject *__pyx_n_s_logging;
-static PyObject *__pyx_n_s_main;
-static PyObject *__pyx_n_s_max;
-static PyObject *__pyx_n_u_mean;
-static PyObject *__pyx_n_s_memview;
-static PyObject *__pyx_n_s_method;
-static PyObject *__pyx_n_s_min;
-static PyObject *__pyx_n_s_mode;
-static PyObject *__pyx_n_s_name;
-static PyObject *__pyx_n_s_name_2;
-static PyObject *__pyx_n_s_ndim;
-static PyObject *__pyx_n_s_new;
-static PyObject *__pyx_kp_s_no_default___reduce___due_to_non;
-static PyObject *__pyx_n_s_numpy;
-static PyObject *__pyx_n_s_obj;
-static PyObject *__pyx_n_s_pack;
-static PyObject *__pyx_n_s_pickle;
-static PyObject *__pyx_n_s_pyx_PickleError;
-static PyObject *__pyx_n_s_pyx_checksum;
-static PyObject *__pyx_n_s_pyx_getbuffer;
-static PyObject *__pyx_n_s_pyx_result;
-static PyObject *__pyx_n_s_pyx_state;
-static PyObject *__pyx_n_s_pyx_type;
-static PyObject *__pyx_n_s_pyx_unpickle_Enum;
-static PyObject *__pyx_n_s_pyx_vtable;
-static PyObject *__pyx_n_s_range;
-static PyObject *__pyx_n_s_ravel;
-static PyObject *__pyx_n_s_reduce;
-static PyObject *__pyx_n_s_reduce_cython;
-static PyObject *__pyx_n_s_reduce_ex;
-static PyObject *__pyx_n_s_reshape;
-static PyObject *__pyx_n_s_round;
-static PyObject *__pyx_n_s_setstate;
-static PyObject *__pyx_n_s_setstate_cython;
-static PyObject *__pyx_n_s_shape;
-static PyObject *__pyx_n_s_size;
-static PyObject *__pyx_n_s_src;
-static PyObject *__pyx_n_s_start;
-static PyObject *__pyx_n_s_step;
-static PyObject *__pyx_n_s_stop;
-static PyObject *__pyx_kp_s_strided_and_direct;
-static PyObject *__pyx_kp_s_strided_and_direct_or_indirect;
-static PyObject *__pyx_kp_s_strided_and_indirect;
-static PyObject *__pyx_kp_s_stringsource;
-static PyObject *__pyx_n_s_struct;
-static PyObject *__pyx_n_s_test;
-static PyObject *__pyx_kp_s_unable_to_allocate_array_data;
-static PyObject *__pyx_kp_s_unable_to_allocate_shape_and_str;
-static PyObject *__pyx_n_s_unpack;
-static PyObject *__pyx_n_s_update;
-static PyObject *__pyx_n_s_warning;
-static PyObject *__pyx_n_s_zeros;
-static int __pyx_pf_4silx_5image_8bilinear_13BilinearImage___cinit__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_data); /* proto */
-static void __pyx_pf_4silx_5image_8bilinear_13BilinearImage_2__dealloc__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4__call__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_6opp_f(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_8local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_10coarse_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_x); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_12map_coordinates(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coordinates); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_14profile_line(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_src, PyObject *__pyx_v_dst, int __pyx_v_linewidth, PyObject *__pyx_v_method); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4data___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4maxi___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4mini___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_5width___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_6height___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_16__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_18__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */
-static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer); /* proto */
-static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_2__getbuffer__(struct __pyx_array_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */
-static void __pyx_array___pyx_pf_15View_dot_MemoryView_5array_4__dealloc__(struct __pyx_array_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_5array_7memview___get__(struct __pyx_array_obj *__pyx_v_self); /* proto */
-static Py_ssize_t __pyx_array___pyx_pf_15View_dot_MemoryView_5array_6__len__(struct __pyx_array_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_8__getattr__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_attr); /* proto */
-static PyObject *__pyx_array___pyx_pf_15View_dot_MemoryView_5array_10__getitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item); /* proto */
-static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array_12__setitem__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_item, PyObject *__pyx_v_value); /* proto */
-static PyObject *__pyx_pf___pyx_array___reduce_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_array_2__setstate_cython__(CYTHON_UNUSED struct __pyx_array_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */
-static int __pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum___init__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v_name); /* proto */
-static PyObject *__pyx_MemviewEnum___pyx_pf_15View_dot_MemoryView_4Enum_2__repr__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_MemviewEnum___reduce_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_MemviewEnum_2__setstate_cython__(struct __pyx_MemviewEnum_obj *__pyx_v_self, PyObject *__pyx_v___pyx_state); /* proto */
-static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview___cinit__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_obj, int __pyx_v_flags, int __pyx_v_dtype_is_object); /* proto */
-static void __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_2__dealloc__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_4__getitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index); /* proto */
-static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_6__setitem__(struct __pyx_memoryview_obj *__pyx_v_self, PyObject *__pyx_v_index, PyObject *__pyx_v_value); /* proto */
-static int __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_8__getbuffer__(struct __pyx_memoryview_obj *__pyx_v_self, Py_buffer *__pyx_v_info, int __pyx_v_flags); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_1T___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4base___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_5shape___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_7strides___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_10suboffsets___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4ndim___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_8itemsize___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_6nbytes___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_10memoryview_4size___get__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static Py_ssize_t __pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_10__len__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_12__repr__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_14__str__(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_16is_c_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_18is_f_contig(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_20copy(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_memoryview___pyx_pf_15View_dot_MemoryView_10memoryview_22copy_fortran(struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_memoryview___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_memoryview_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryview_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */
-static void __pyx_memoryviewslice___pyx_pf_15View_dot_MemoryView_16_memoryviewslice___dealloc__(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView_16_memoryviewslice_4base___get__(struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_memoryviewslice___reduce_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self); /* proto */
-static PyObject *__pyx_pf___pyx_memoryviewslice_2__setstate_cython__(CYTHON_UNUSED struct __pyx_memoryviewslice_obj *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state); /* proto */
-static PyObject *__pyx_pf_15View_dot_MemoryView___pyx_unpickle_Enum(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v___pyx_type, long __pyx_v___pyx_checksum, PyObject *__pyx_v___pyx_state); /* proto */
-static PyObject *__pyx_tp_new_4silx_5image_8bilinear_BilinearImage(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new_array(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new_Enum(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new_memoryview(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_tp_new__memoryviewslice(PyTypeObject *t, PyObject *a, PyObject *k); /*proto*/
-static PyObject *__pyx_int_0;
-static PyObject *__pyx_int_1;
-static PyObject *__pyx_int_2;
-static PyObject *__pyx_int_184977713;
-static PyObject *__pyx_int_neg_1;
-static PyObject *__pyx_tuple_;
-static PyObject *__pyx_tuple__2;
-static PyObject *__pyx_tuple__3;
-static PyObject *__pyx_tuple__4;
-static PyObject *__pyx_tuple__5;
-static PyObject *__pyx_tuple__6;
-static PyObject *__pyx_tuple__7;
-static PyObject *__pyx_tuple__8;
-static PyObject *__pyx_tuple__9;
-static PyObject *__pyx_slice__17;
-static PyObject *__pyx_tuple__10;
-static PyObject *__pyx_tuple__11;
-static PyObject *__pyx_tuple__12;
-static PyObject *__pyx_tuple__13;
-static PyObject *__pyx_tuple__14;
-static PyObject *__pyx_tuple__15;
-static PyObject *__pyx_tuple__16;
-static PyObject *__pyx_tuple__18;
-static PyObject *__pyx_tuple__19;
-static PyObject *__pyx_tuple__20;
-static PyObject *__pyx_tuple__21;
-static PyObject *__pyx_tuple__22;
-static PyObject *__pyx_tuple__23;
-static PyObject *__pyx_tuple__24;
-static PyObject *__pyx_tuple__25;
-static PyObject *__pyx_tuple__26;
-static PyObject *__pyx_codeobj__27;
-/* Late includes */
-
-/* "silx/image/bilinear.pyx":51
- * cdef float c_funct(self, float, float) nogil
- *
- * def __cinit__(self, data not None): # <<<<<<<<<<<<<<
- * """Constructor
- *
- */
-
-/* Python wrapper */
-static int __pyx_pw_4silx_5image_8bilinear_13BilinearImage_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_pw_4silx_5image_8bilinear_13BilinearImage_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
- PyObject *__pyx_v_data = 0;
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
- {
- static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_data,0};
- PyObject* values[1] = {0};
- if (unlikely(__pyx_kwds)) {
- Py_ssize_t kw_args;
- const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
- switch (pos_args) {
- case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- CYTHON_FALLTHROUGH;
- case 0: break;
- default: goto __pyx_L5_argtuple_error;
- }
- kw_args = PyDict_Size(__pyx_kwds);
- switch (pos_args) {
- case 0:
- if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_data)) != 0)) kw_args--;
- else goto __pyx_L5_argtuple_error;
- }
- if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(0, 51, __pyx_L3_error)
- }
- } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
- goto __pyx_L5_argtuple_error;
- } else {
- values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- }
- __pyx_v_data = values[0];
- }
- goto __pyx_L4_argument_unpacking_done;
- __pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__cinit__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 51, __pyx_L3_error)
- __pyx_L3_error:;
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __Pyx_RefNannyFinishContext();
- return -1;
- __pyx_L4_argument_unpacking_done:;
- if (unlikely(((PyObject *)__pyx_v_data) == Py_None)) {
- PyErr_Format(PyExc_TypeError, "Argument '%.200s' must not be None", "data"); __PYX_ERR(0, 51, __pyx_L1_error)
- }
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage___cinit__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), __pyx_v_data);
-
- /* function exit code */
- goto __pyx_L0;
- __pyx_L1_error:;
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static int __pyx_pf_4silx_5image_8bilinear_13BilinearImage___cinit__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_data) {
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- int __pyx_t_3;
- size_t __pyx_t_4;
- PyObject *__pyx_t_5 = NULL;
- float __pyx_t_6;
- PyObject *__pyx_t_7 = NULL;
- PyObject *__pyx_t_8 = NULL;
- __Pyx_memviewslice __pyx_t_9 = { 0, 0, { 0 }, { 0 }, { 0 } };
- __Pyx_RefNannySetupContext("__cinit__", 0);
-
- /* "silx/image/bilinear.pyx":56
- * :param data: image as a 2D array
- * """
- * assert data.ndim == 2 # <<<<<<<<<<<<<<
- * self.height = data.shape[0]
- * self.width = data.shape[1]
- */
- #ifndef CYTHON_WITHOUT_ASSERTIONS
- if (unlikely(!Py_OptimizeFlag)) {
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_n_s_ndim); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 56, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyInt_EqObjC(__pyx_t_1, __pyx_int_2, 2, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 56, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_3 = __Pyx_PyObject_IsTrue(__pyx_t_2); if (unlikely(__pyx_t_3 < 0)) __PYX_ERR(0, 56, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- if (unlikely(!__pyx_t_3)) {
- PyErr_SetNone(PyExc_AssertionError);
- __PYX_ERR(0, 56, __pyx_L1_error)
- }
- }
- #endif
-
- /* "silx/image/bilinear.pyx":57
- * """
- * assert data.ndim == 2
- * self.height = data.shape[0] # <<<<<<<<<<<<<<
- * self.width = data.shape[1]
- * self.maxi = data.max()
- */
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 57, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_t_2, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 57, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_4 = __Pyx_PyInt_As_size_t(__pyx_t_1); if (unlikely((__pyx_t_4 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 57, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_self->height = __pyx_t_4;
-
- /* "silx/image/bilinear.pyx":58
- * assert data.ndim == 2
- * self.height = data.shape[0]
- * self.width = data.shape[1] # <<<<<<<<<<<<<<
- * self.maxi = data.max()
- * self.mini = data.min()
- */
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_n_s_shape); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 58, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_GetItemInt(__pyx_t_1, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 58, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_4 = __Pyx_PyInt_As_size_t(__pyx_t_2); if (unlikely((__pyx_t_4 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 58, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_v_self->width = __pyx_t_4;
-
- /* "silx/image/bilinear.pyx":59
- * self.height = data.shape[0]
- * self.width = data.shape[1]
- * self.maxi = data.max() # <<<<<<<<<<<<<<
- * self.mini = data.min()
- * self.data = numpy.ascontiguousarray(data, dtype=numpy.float32)
- */
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_n_s_max); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 59, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) {
- __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1);
- if (likely(__pyx_t_5)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_5);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_1, function);
- }
- }
- __pyx_t_2 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_6 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_6 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 59, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_v_self->maxi = __pyx_t_6;
-
- /* "silx/image/bilinear.pyx":60
- * self.width = data.shape[1]
- * self.maxi = data.max()
- * self.mini = data.min() # <<<<<<<<<<<<<<
- * self.data = numpy.ascontiguousarray(data, dtype=numpy.float32)
- *
- */
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_n_s_min); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 60, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_1))) {
- __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_1);
- if (likely(__pyx_t_5)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_5);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_1, function);
- }
- }
- __pyx_t_2 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_6 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_6 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 60, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_v_self->mini = __pyx_t_6;
-
- /* "silx/image/bilinear.pyx":61
- * self.maxi = data.max()
- * self.mini = data.min()
- * self.data = numpy.ascontiguousarray(data, dtype=numpy.float32) # <<<<<<<<<<<<<<
- *
- * def __dealloc__(self):
- */
- __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_numpy); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_INCREF(__pyx_v_data);
- __Pyx_GIVEREF(__pyx_v_data);
- PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_v_data);
- __pyx_t_5 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_numpy); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_7);
- __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_float32); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
- if (PyDict_SetItem(__pyx_t_5, __pyx_n_s_dtype, __pyx_t_8) < 0) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_2, __pyx_t_5); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_8);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_9 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_float(__pyx_t_8, PyBUF_WRITABLE); if (unlikely(!__pyx_t_9.memview)) __PYX_ERR(0, 61, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
- __PYX_XDEC_MEMVIEW(&__pyx_v_self->data, 0);
- __pyx_v_self->data = __pyx_t_9;
- __pyx_t_9.memview = NULL;
- __pyx_t_9.data = NULL;
-
- /* "silx/image/bilinear.pyx":51
- * cdef float c_funct(self, float, float) nogil
- *
- * def __cinit__(self, data not None): # <<<<<<<<<<<<<<
- * """Constructor
- *
- */
-
- /* function exit code */
- __pyx_r = 0;
- goto __pyx_L0;
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_7);
- __Pyx_XDECREF(__pyx_t_8);
- __PYX_XDEC_MEMVIEW(&__pyx_t_9, 1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":63
- * self.data = numpy.ascontiguousarray(data, dtype=numpy.float32)
- *
- * def __dealloc__(self): # <<<<<<<<<<<<<<
- * self.data = None
- *
- */
-
-/* Python wrapper */
-static void __pyx_pw_4silx_5image_8bilinear_13BilinearImage_3__dealloc__(PyObject *__pyx_v_self); /*proto*/
-static void __pyx_pw_4silx_5image_8bilinear_13BilinearImage_3__dealloc__(PyObject *__pyx_v_self) {
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__dealloc__ (wrapper)", 0);
- __pyx_pf_4silx_5image_8bilinear_13BilinearImage_2__dealloc__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
-}
-
-static void __pyx_pf_4silx_5image_8bilinear_13BilinearImage_2__dealloc__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- __Pyx_RefNannyDeclarations
- __Pyx_memviewslice __pyx_t_1 = { 0, 0, { 0 }, { 0 }, { 0 } };
- __Pyx_RefNannySetupContext("__dealloc__", 0);
-
- /* "silx/image/bilinear.pyx":64
- *
- * def __dealloc__(self):
- * self.data = None # <<<<<<<<<<<<<<
- *
- * def __call__(self, coord):
- */
- __pyx_t_1 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_float(Py_None, PyBUF_WRITABLE); if (unlikely(!__pyx_t_1.memview)) __PYX_ERR(0, 64, __pyx_L1_error)
- __PYX_XDEC_MEMVIEW(&__pyx_v_self->data, 0);
- __pyx_v_self->data = __pyx_t_1;
- __pyx_t_1.memview = NULL;
- __pyx_t_1.data = NULL;
-
- /* "silx/image/bilinear.pyx":63
- * self.data = numpy.ascontiguousarray(data, dtype=numpy.float32)
- *
- * def __dealloc__(self): # <<<<<<<<<<<<<<
- * self.data = None
- *
- */
-
- /* function exit code */
- goto __pyx_L0;
- __pyx_L1_error:;
- __PYX_XDEC_MEMVIEW(&__pyx_t_1, 1);
- __Pyx_WriteUnraisable("silx.image.bilinear.BilinearImage.__dealloc__", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0);
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
-}
-
-/* "silx/image/bilinear.pyx":66
- * self.data = None
- *
- * def __call__(self, coord): # <<<<<<<<<<<<<<
- * """Function f((y, x)) where f is a continuous function
- * made from the image and (y,x)=(row, column) is the pixel coordinates
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_4__call__[] = "Function f((y, x)) where f is a continuous function\n made from the image and (y,x)=(row, column) is the pixel coordinates\n in natural C-order\n\n :param x: 2-tuple of float (row, column)\n :return: Interpolated signal from the image\n ";
-#if CYTHON_COMPILING_IN_CPYTHON
-struct wrapperbase __pyx_wrapperbase_4silx_5image_8bilinear_13BilinearImage_4__call__;
-#endif
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_5__call__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
- PyObject *__pyx_v_coord = 0;
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__call__ (wrapper)", 0);
- {
- static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_coord,0};
- PyObject* values[1] = {0};
- if (unlikely(__pyx_kwds)) {
- Py_ssize_t kw_args;
- const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
- switch (pos_args) {
- case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- CYTHON_FALLTHROUGH;
- case 0: break;
- default: goto __pyx_L5_argtuple_error;
- }
- kw_args = PyDict_Size(__pyx_kwds);
- switch (pos_args) {
- case 0:
- if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_coord)) != 0)) kw_args--;
- else goto __pyx_L5_argtuple_error;
- }
- if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__call__") < 0)) __PYX_ERR(0, 66, __pyx_L3_error)
- }
- } else if (PyTuple_GET_SIZE(__pyx_args) != 1) {
- goto __pyx_L5_argtuple_error;
- } else {
- values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- }
- __pyx_v_coord = values[0];
- }
- goto __pyx_L4_argument_unpacking_done;
- __pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__call__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 66, __pyx_L3_error)
- __pyx_L3_error:;
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __Pyx_RefNannyFinishContext();
- return NULL;
- __pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_4__call__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), __pyx_v_coord);
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4__call__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- float __pyx_t_2;
- float __pyx_t_3;
- __Pyx_RefNannySetupContext("__call__", 0);
-
- /* "silx/image/bilinear.pyx":74
- * :return: Interpolated signal from the image
- * """
- * return self.c_funct(coord[1], coord[0]) # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_coord, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 74, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_coord, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 74, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = PyFloat_FromDouble(((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_funct(__pyx_v_self, __pyx_t_2, __pyx_t_3)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":66
- * self.data = None
- *
- * def __call__(self, coord): # <<<<<<<<<<<<<<
- * """Function f((y, x)) where f is a continuous function
- * made from the image and (y,x)=(row, column) is the pixel coordinates
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__call__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":78
- * @cython.boundscheck(False)
- * @cython.wraparound(False)
- * cdef float c_funct(self, float x, float y) nogil: # <<<<<<<<<<<<<<
- * """Function f(x, y) where f is a continuous function
- * made from the image.
- */
-
-static float __pyx_f_4silx_5image_8bilinear_13BilinearImage_c_funct(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, float __pyx_v_x, float __pyx_v_y) {
- float __pyx_v_d0;
- float __pyx_v_d1;
- int __pyx_v_i0;
- int __pyx_v_i1;
- int __pyx_v_j0;
- int __pyx_v_j1;
- float __pyx_v_x0;
- float __pyx_v_x1;
- float __pyx_v_y0;
- float __pyx_v_y1;
- float __pyx_v_res;
- float __pyx_r;
- double __pyx_t_1;
- double __pyx_t_2;
- float __pyx_t_3;
- double __pyx_t_4;
- int __pyx_t_5;
- int __pyx_t_6;
- Py_ssize_t __pyx_t_7;
- Py_ssize_t __pyx_t_8;
- Py_ssize_t __pyx_t_9;
- Py_ssize_t __pyx_t_10;
- Py_ssize_t __pyx_t_11;
- Py_ssize_t __pyx_t_12;
- Py_ssize_t __pyx_t_13;
- Py_ssize_t __pyx_t_14;
- Py_ssize_t __pyx_t_15;
- Py_ssize_t __pyx_t_16;
- Py_ssize_t __pyx_t_17;
- Py_ssize_t __pyx_t_18;
- Py_ssize_t __pyx_t_19;
- Py_ssize_t __pyx_t_20;
- Py_ssize_t __pyx_t_21;
- Py_ssize_t __pyx_t_22;
- Py_ssize_t __pyx_t_23;
- Py_ssize_t __pyx_t_24;
-
- /* "silx/image/bilinear.pyx":89
- * """
- * cdef:
- * float d0 = min(max(y, 0.0), (self.height - 1.0)) # <<<<<<<<<<<<<<
- * float d1 = min(max(x, 0.0), (self.width - 1.0))
- * int i0, i1, j0, j1
- */
- __pyx_t_1 = (__pyx_v_self->height - 1.0);
- __pyx_t_2 = 0.0;
- __pyx_t_3 = __pyx_v_y;
- if (((__pyx_t_2 > __pyx_t_3) != 0)) {
- __pyx_t_4 = __pyx_t_2;
- } else {
- __pyx_t_4 = __pyx_t_3;
- }
- __pyx_t_2 = __pyx_t_4;
- if (((__pyx_t_1 < __pyx_t_2) != 0)) {
- __pyx_t_4 = __pyx_t_1;
- } else {
- __pyx_t_4 = __pyx_t_2;
- }
- __pyx_v_d0 = __pyx_t_4;
-
- /* "silx/image/bilinear.pyx":90
- * cdef:
- * float d0 = min(max(y, 0.0), (self.height - 1.0))
- * float d1 = min(max(x, 0.0), (self.width - 1.0)) # <<<<<<<<<<<<<<
- * int i0, i1, j0, j1
- * float x0, x1, y0, y1, res
- */
- __pyx_t_4 = (__pyx_v_self->width - 1.0);
- __pyx_t_1 = 0.0;
- __pyx_t_3 = __pyx_v_x;
- if (((__pyx_t_1 > __pyx_t_3) != 0)) {
- __pyx_t_2 = __pyx_t_1;
- } else {
- __pyx_t_2 = __pyx_t_3;
- }
- __pyx_t_1 = __pyx_t_2;
- if (((__pyx_t_4 < __pyx_t_1) != 0)) {
- __pyx_t_2 = __pyx_t_4;
- } else {
- __pyx_t_2 = __pyx_t_1;
- }
- __pyx_v_d1 = __pyx_t_2;
-
- /* "silx/image/bilinear.pyx":94
- * float x0, x1, y0, y1, res
- *
- * x0 = floor(d0) # <<<<<<<<<<<<<<
- * x1 = ceil(d0)
- * y0 = floor(d1)
- */
- __pyx_v_x0 = floor(__pyx_v_d0);
-
- /* "silx/image/bilinear.pyx":95
- *
- * x0 = floor(d0)
- * x1 = ceil(d0) # <<<<<<<<<<<<<<
- * y0 = floor(d1)
- * y1 = ceil(d1)
- */
- __pyx_v_x1 = ceil(__pyx_v_d0);
-
- /* "silx/image/bilinear.pyx":96
- * x0 = floor(d0)
- * x1 = ceil(d0)
- * y0 = floor(d1) # <<<<<<<<<<<<<<
- * y1 = ceil(d1)
- * i0 = < int > x0
- */
- __pyx_v_y0 = floor(__pyx_v_d1);
-
- /* "silx/image/bilinear.pyx":97
- * x1 = ceil(d0)
- * y0 = floor(d1)
- * y1 = ceil(d1) # <<<<<<<<<<<<<<
- * i0 = < int > x0
- * i1 = < int > x1
- */
- __pyx_v_y1 = ceil(__pyx_v_d1);
-
- /* "silx/image/bilinear.pyx":98
- * y0 = floor(d1)
- * y1 = ceil(d1)
- * i0 = < int > x0 # <<<<<<<<<<<<<<
- * i1 = < int > x1
- * j0 = < int > y0
- */
- __pyx_v_i0 = ((int)__pyx_v_x0);
-
- /* "silx/image/bilinear.pyx":99
- * y1 = ceil(d1)
- * i0 = < int > x0
- * i1 = < int > x1 # <<<<<<<<<<<<<<
- * j0 = < int > y0
- * j1 = < int > y1
- */
- __pyx_v_i1 = ((int)__pyx_v_x1);
-
- /* "silx/image/bilinear.pyx":100
- * i0 = < int > x0
- * i1 = < int > x1
- * j0 = < int > y0 # <<<<<<<<<<<<<<
- * j1 = < int > y1
- * if (i0 == i1) and (j0 == j1):
- */
- __pyx_v_j0 = ((int)__pyx_v_y0);
-
- /* "silx/image/bilinear.pyx":101
- * i1 = < int > x1
- * j0 = < int > y0
- * j1 = < int > y1 # <<<<<<<<<<<<<<
- * if (i0 == i1) and (j0 == j1):
- * res = self.data[i0, j0]
- */
- __pyx_v_j1 = ((int)__pyx_v_y1);
-
- /* "silx/image/bilinear.pyx":102
- * j0 = < int > y0
- * j1 = < int > y1
- * if (i0 == i1) and (j0 == j1): # <<<<<<<<<<<<<<
- * res = self.data[i0, j0]
- * elif i0 == i1:
- */
- __pyx_t_6 = ((__pyx_v_i0 == __pyx_v_i1) != 0);
- if (__pyx_t_6) {
- } else {
- __pyx_t_5 = __pyx_t_6;
- goto __pyx_L4_bool_binop_done;
- }
- __pyx_t_6 = ((__pyx_v_j0 == __pyx_v_j1) != 0);
- __pyx_t_5 = __pyx_t_6;
- __pyx_L4_bool_binop_done:;
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":103
- * j1 = < int > y1
- * if (i0 == i1) and (j0 == j1):
- * res = self.data[i0, j0] # <<<<<<<<<<<<<<
- * elif i0 == i1:
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 103, __pyx_L1_error)}
- __pyx_t_7 = __pyx_v_i0;
- __pyx_t_8 = __pyx_v_j0;
- __pyx_v_res = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_7 * __pyx_v_self->data.strides[0]) )) + __pyx_t_8)) )));
-
- /* "silx/image/bilinear.pyx":102
- * j0 = < int > y0
- * j1 = < int > y1
- * if (i0 == i1) and (j0 == j1): # <<<<<<<<<<<<<<
- * res = self.data[i0, j0]
- * elif i0 == i1:
- */
- goto __pyx_L3;
- }
-
- /* "silx/image/bilinear.pyx":104
- * if (i0 == i1) and (j0 == j1):
- * res = self.data[i0, j0]
- * elif i0 == i1: # <<<<<<<<<<<<<<
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- * elif j0 == j1:
- */
- __pyx_t_5 = ((__pyx_v_i0 == __pyx_v_i1) != 0);
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":105
- * res = self.data[i0, j0]
- * elif i0 == i1:
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0)) # <<<<<<<<<<<<<<
- * elif j0 == j1:
- * res = (self.data[i0, j0] * (x1 - d0)) + (self.data[i1, j0] * (d0 - x0))
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 105, __pyx_L1_error)}
- __pyx_t_9 = __pyx_v_i0;
- __pyx_t_10 = __pyx_v_j0;
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 105, __pyx_L1_error)}
- __pyx_t_11 = __pyx_v_i0;
- __pyx_t_12 = __pyx_v_j1;
- __pyx_v_res = (((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_9 * __pyx_v_self->data.strides[0]) )) + __pyx_t_10)) ))) * (__pyx_v_y1 - __pyx_v_d1)) + ((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_11 * __pyx_v_self->data.strides[0]) )) + __pyx_t_12)) ))) * (__pyx_v_d1 - __pyx_v_y0)));
-
- /* "silx/image/bilinear.pyx":104
- * if (i0 == i1) and (j0 == j1):
- * res = self.data[i0, j0]
- * elif i0 == i1: # <<<<<<<<<<<<<<
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- * elif j0 == j1:
- */
- goto __pyx_L3;
- }
-
- /* "silx/image/bilinear.pyx":106
- * elif i0 == i1:
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- * elif j0 == j1: # <<<<<<<<<<<<<<
- * res = (self.data[i0, j0] * (x1 - d0)) + (self.data[i1, j0] * (d0 - x0))
- * else:
- */
- __pyx_t_5 = ((__pyx_v_j0 == __pyx_v_j1) != 0);
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":107
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- * elif j0 == j1:
- * res = (self.data[i0, j0] * (x1 - d0)) + (self.data[i1, j0] * (d0 - x0)) # <<<<<<<<<<<<<<
- * else:
- * res = (self.data[i0, j0] * (x1 - d0) * (y1 - d1)) \
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 107, __pyx_L1_error)}
- __pyx_t_13 = __pyx_v_i0;
- __pyx_t_14 = __pyx_v_j0;
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 107, __pyx_L1_error)}
- __pyx_t_15 = __pyx_v_i1;
- __pyx_t_16 = __pyx_v_j0;
- __pyx_v_res = (((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_13 * __pyx_v_self->data.strides[0]) )) + __pyx_t_14)) ))) * (__pyx_v_x1 - __pyx_v_d0)) + ((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_15 * __pyx_v_self->data.strides[0]) )) + __pyx_t_16)) ))) * (__pyx_v_d0 - __pyx_v_x0)));
-
- /* "silx/image/bilinear.pyx":106
- * elif i0 == i1:
- * res = (self.data[i0, j0] * (y1 - d1)) + (self.data[i0, j1] * (d1 - y0))
- * elif j0 == j1: # <<<<<<<<<<<<<<
- * res = (self.data[i0, j0] * (x1 - d0)) + (self.data[i1, j0] * (d0 - x0))
- * else:
- */
- goto __pyx_L3;
- }
-
- /* "silx/image/bilinear.pyx":112
- * + (self.data[i1, j0] * (d0 - x0) * (y1 - d1)) \
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \
- * + (self.data[i1, j1] * (d0 - x0) * (d1 - y0)) # <<<<<<<<<<<<<<
- * return res
- *
- */
- /*else*/ {
-
- /* "silx/image/bilinear.pyx":109
- * res = (self.data[i0, j0] * (x1 - d0)) + (self.data[i1, j0] * (d0 - x0))
- * else:
- * res = (self.data[i0, j0] * (x1 - d0) * (y1 - d1)) \ # <<<<<<<<<<<<<<
- * + (self.data[i1, j0] * (d0 - x0) * (y1 - d1)) \
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 109, __pyx_L1_error)}
- __pyx_t_17 = __pyx_v_i0;
- __pyx_t_18 = __pyx_v_j0;
-
- /* "silx/image/bilinear.pyx":110
- * else:
- * res = (self.data[i0, j0] * (x1 - d0) * (y1 - d1)) \
- * + (self.data[i1, j0] * (d0 - x0) * (y1 - d1)) \ # <<<<<<<<<<<<<<
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \
- * + (self.data[i1, j1] * (d0 - x0) * (d1 - y0))
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 110, __pyx_L1_error)}
- __pyx_t_19 = __pyx_v_i1;
- __pyx_t_20 = __pyx_v_j0;
-
- /* "silx/image/bilinear.pyx":111
- * res = (self.data[i0, j0] * (x1 - d0) * (y1 - d1)) \
- * + (self.data[i1, j0] * (d0 - x0) * (y1 - d1)) \
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \ # <<<<<<<<<<<<<<
- * + (self.data[i1, j1] * (d0 - x0) * (d1 - y0))
- * return res
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 111, __pyx_L1_error)}
- __pyx_t_21 = __pyx_v_i0;
- __pyx_t_22 = __pyx_v_j1;
-
- /* "silx/image/bilinear.pyx":112
- * + (self.data[i1, j0] * (d0 - x0) * (y1 - d1)) \
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \
- * + (self.data[i1, j1] * (d0 - x0) * (d1 - y0)) # <<<<<<<<<<<<<<
- * return res
- *
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 112, __pyx_L1_error)}
- __pyx_t_23 = __pyx_v_i1;
- __pyx_t_24 = __pyx_v_j1;
- __pyx_v_res = ((((((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_17 * __pyx_v_self->data.strides[0]) )) + __pyx_t_18)) ))) * (__pyx_v_x1 - __pyx_v_d0)) * (__pyx_v_y1 - __pyx_v_d1)) + (((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_19 * __pyx_v_self->data.strides[0]) )) + __pyx_t_20)) ))) * (__pyx_v_d0 - __pyx_v_x0)) * (__pyx_v_y1 - __pyx_v_d1))) + (((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_21 * __pyx_v_self->data.strides[0]) )) + __pyx_t_22)) ))) * (__pyx_v_x1 - __pyx_v_d0)) * (__pyx_v_d1 - __pyx_v_y0))) + (((*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_23 * __pyx_v_self->data.strides[0]) )) + __pyx_t_24)) ))) * (__pyx_v_d0 - __pyx_v_x0)) * (__pyx_v_d1 - __pyx_v_y0)));
- }
- __pyx_L3:;
-
- /* "silx/image/bilinear.pyx":113
- * + (self.data[i0, j1] * (x1 - d0) * (d1 - y0)) \
- * + (self.data[i1, j1] * (d0 - x0) * (d1 - y0))
- * return res # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __pyx_r = __pyx_v_res;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":78
- * @cython.boundscheck(False)
- * @cython.wraparound(False)
- * cdef float c_funct(self, float x, float y) nogil: # <<<<<<<<<<<<<<
- * """Function f(x, y) where f is a continuous function
- * made from the image.
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_WriteUnraisable("silx.image.bilinear.BilinearImage.c_funct", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
- __pyx_r = 0;
- __pyx_L0:;
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":117
- * @cython.boundscheck(False)
- * @cython.wraparound(False)
- * def opp_f(self, coord): # <<<<<<<<<<<<<<
- * """Function -f((y,x)) for peak finding via minimizer.
- *
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_7opp_f(PyObject *__pyx_v_self, PyObject *__pyx_v_coord); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_6opp_f[] = "BilinearImage.opp_f(self, coord)\nFunction -f((y,x)) for peak finding via minimizer.\n\n Gives large number outside the boundaries to return into the image\n\n :param x: 2-tuple of float in natural C order, i.e (row, column)\n :return: Negative interpolated signal from the image\n ";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_7opp_f(PyObject *__pyx_v_self, PyObject *__pyx_v_coord) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("opp_f (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_6opp_f(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), ((PyObject *)__pyx_v_coord));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_6opp_f(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord) {
- float __pyx_v_d0;
- float __pyx_v_d1;
- float __pyx_v_res;
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- PyObject *(*__pyx_t_4)(PyObject *);
- float __pyx_t_5;
- float __pyx_t_6;
- int __pyx_t_7;
- __Pyx_RefNannySetupContext("opp_f", 0);
-
- /* "silx/image/bilinear.pyx":127
- * cdef:
- * float d0, d1, res
- * d0, d1 = coord # <<<<<<<<<<<<<<
- * if d0 < 0:
- * res = self.mini + d0
- */
- if ((likely(PyTuple_CheckExact(__pyx_v_coord))) || (PyList_CheckExact(__pyx_v_coord))) {
- PyObject* sequence = __pyx_v_coord;
- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
- if (unlikely(size != 2)) {
- if (size > 2) __Pyx_RaiseTooManyValuesError(2);
- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(0, 127, __pyx_L1_error)
- }
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- if (likely(PyTuple_CheckExact(sequence))) {
- __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0);
- __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1);
- } else {
- __pyx_t_1 = PyList_GET_ITEM(sequence, 0);
- __pyx_t_2 = PyList_GET_ITEM(sequence, 1);
- }
- __Pyx_INCREF(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_2);
- #else
- __pyx_t_1 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- #endif
- } else {
- Py_ssize_t index = -1;
- __pyx_t_3 = PyObject_GetIter(__pyx_v_coord); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 127, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
- index = 0; __pyx_t_1 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_1)) goto __pyx_L3_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_1);
- index = 1; __pyx_t_2 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_2)) goto __pyx_L3_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_2);
- if (__Pyx_IternextUnpackEndCheck(__pyx_t_4(__pyx_t_3), 2) < 0) __PYX_ERR(0, 127, __pyx_L1_error)
- __pyx_t_4 = NULL;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L4_unpacking_done;
- __pyx_L3_unpacking_failed:;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_4 = NULL;
- if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
- __PYX_ERR(0, 127, __pyx_L1_error)
- __pyx_L4_unpacking_done:;
- }
- __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_6 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_6 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 127, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_v_d0 = __pyx_t_5;
- __pyx_v_d1 = __pyx_t_6;
-
- /* "silx/image/bilinear.pyx":128
- * float d0, d1, res
- * d0, d1 = coord
- * if d0 < 0: # <<<<<<<<<<<<<<
- * res = self.mini + d0
- * elif d1 < 0:
- */
- __pyx_t_7 = ((__pyx_v_d0 < 0.0) != 0);
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":129
- * d0, d1 = coord
- * if d0 < 0:
- * res = self.mini + d0 # <<<<<<<<<<<<<<
- * elif d1 < 0:
- * res = self.mini + d1
- */
- __pyx_v_res = (__pyx_v_self->mini + __pyx_v_d0);
-
- /* "silx/image/bilinear.pyx":128
- * float d0, d1, res
- * d0, d1 = coord
- * if d0 < 0: # <<<<<<<<<<<<<<
- * res = self.mini + d0
- * elif d1 < 0:
- */
- goto __pyx_L5;
- }
-
- /* "silx/image/bilinear.pyx":130
- * if d0 < 0:
- * res = self.mini + d0
- * elif d1 < 0: # <<<<<<<<<<<<<<
- * res = self.mini + d1
- * elif d0 > (self.height - 1):
- */
- __pyx_t_7 = ((__pyx_v_d1 < 0.0) != 0);
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":131
- * res = self.mini + d0
- * elif d1 < 0:
- * res = self.mini + d1 # <<<<<<<<<<<<<<
- * elif d0 > (self.height - 1):
- * res = self.mini - d0 + self.height - 1
- */
- __pyx_v_res = (__pyx_v_self->mini + __pyx_v_d1);
-
- /* "silx/image/bilinear.pyx":130
- * if d0 < 0:
- * res = self.mini + d0
- * elif d1 < 0: # <<<<<<<<<<<<<<
- * res = self.mini + d1
- * elif d0 > (self.height - 1):
- */
- goto __pyx_L5;
- }
-
- /* "silx/image/bilinear.pyx":132
- * elif d1 < 0:
- * res = self.mini + d1
- * elif d0 > (self.height - 1): # <<<<<<<<<<<<<<
- * res = self.mini - d0 + self.height - 1
- * elif d1 > self.width - 1:
- */
- __pyx_t_7 = ((__pyx_v_d0 > (__pyx_v_self->height - 1)) != 0);
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":133
- * res = self.mini + d1
- * elif d0 > (self.height - 1):
- * res = self.mini - d0 + self.height - 1 # <<<<<<<<<<<<<<
- * elif d1 > self.width - 1:
- * res = self.mini - d1 + self.width - 1
- */
- __pyx_v_res = (((__pyx_v_self->mini - __pyx_v_d0) + __pyx_v_self->height) - 1.0);
-
- /* "silx/image/bilinear.pyx":132
- * elif d1 < 0:
- * res = self.mini + d1
- * elif d0 > (self.height - 1): # <<<<<<<<<<<<<<
- * res = self.mini - d0 + self.height - 1
- * elif d1 > self.width - 1:
- */
- goto __pyx_L5;
- }
-
- /* "silx/image/bilinear.pyx":134
- * elif d0 > (self.height - 1):
- * res = self.mini - d0 + self.height - 1
- * elif d1 > self.width - 1: # <<<<<<<<<<<<<<
- * res = self.mini - d1 + self.width - 1
- * else:
- */
- __pyx_t_7 = ((__pyx_v_d1 > (__pyx_v_self->width - 1)) != 0);
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":135
- * res = self.mini - d0 + self.height - 1
- * elif d1 > self.width - 1:
- * res = self.mini - d1 + self.width - 1 # <<<<<<<<<<<<<<
- * else:
- * res = self.c_funct(d1, d0)
- */
- __pyx_v_res = (((__pyx_v_self->mini - __pyx_v_d1) + __pyx_v_self->width) - 1.0);
-
- /* "silx/image/bilinear.pyx":134
- * elif d0 > (self.height - 1):
- * res = self.mini - d0 + self.height - 1
- * elif d1 > self.width - 1: # <<<<<<<<<<<<<<
- * res = self.mini - d1 + self.width - 1
- * else:
- */
- goto __pyx_L5;
- }
-
- /* "silx/image/bilinear.pyx":137
- * res = self.mini - d1 + self.width - 1
- * else:
- * res = self.c_funct(d1, d0) # <<<<<<<<<<<<<<
- * return - res
- *
- */
- /*else*/ {
- __pyx_v_res = ((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_funct(__pyx_v_self, __pyx_v_d1, __pyx_v_d0);
- }
- __pyx_L5:;
-
- /* "silx/image/bilinear.pyx":138
- * else:
- * res = self.c_funct(d1, d0)
- * return - res # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_2 = PyFloat_FromDouble((-__pyx_v_res)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 138, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_r = __pyx_t_2;
- __pyx_t_2 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":117
- * @cython.boundscheck(False)
- * @cython.wraparound(False)
- * def opp_f(self, coord): # <<<<<<<<<<<<<<
- * """Function -f((y,x)) for peak finding via minimizer.
- *
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_3);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.opp_f", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":143
- * @cython.wraparound(False)
- * @cython.cdivision(True)
- * def local_maxi(self, coord): # <<<<<<<<<<<<<<
- * """Return the nearest local maximum ... with sub-pixel refinement
- *
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_9local_maxi(PyObject *__pyx_v_self, PyObject *__pyx_v_coord); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_8local_maxi[] = "BilinearImage.local_maxi(self, coord)\nReturn the nearest local maximum ... with sub-pixel refinement\n\n Nearest maximum search:\n steepest ascent\n\n Sub-pixel refinement:\n Second order Taylor expansion of the function;\n At the maximum, the first derivative is null\n delta = x-i = -Inverse[Hessian].gradient\n if Hessian is singular or \\|delta\\|>1: use a center of mass.\n\n :param coord: 2-tuple of scalar (row, column)\n :return: 2-tuple of float with the nearest local maximum\n ";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_9local_maxi(PyObject *__pyx_v_self, PyObject *__pyx_v_coord) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("local_maxi (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_8local_maxi(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), ((PyObject *)__pyx_v_coord));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_8local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coord) {
- int __pyx_v_res;
- int __pyx_v_current0;
- int __pyx_v_current1;
- int __pyx_v_i0;
- int __pyx_v_i1;
- float __pyx_v_tmp;
- float __pyx_v_sum0;
- float __pyx_v_sum1;
- float __pyx_v_sum;
- float __pyx_v_a00;
- float __pyx_v_a01;
- float __pyx_v_a02;
- float __pyx_v_a10;
- float __pyx_v_a11;
- float __pyx_v_a12;
- float __pyx_v_a20;
- float __pyx_v_a21;
- float __pyx_v_a22;
- float __pyx_v_d00;
- float __pyx_v_d11;
- float __pyx_v_d01;
- float __pyx_v_denom;
- float __pyx_v_delta0;
- float __pyx_v_delta1;
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- size_t __pyx_t_4;
- int __pyx_t_5;
- int __pyx_t_6;
- Py_ssize_t __pyx_t_7;
- Py_ssize_t __pyx_t_8;
- Py_ssize_t __pyx_t_9;
- Py_ssize_t __pyx_t_10;
- Py_ssize_t __pyx_t_11;
- Py_ssize_t __pyx_t_12;
- Py_ssize_t __pyx_t_13;
- Py_ssize_t __pyx_t_14;
- Py_ssize_t __pyx_t_15;
- Py_ssize_t __pyx_t_16;
- Py_ssize_t __pyx_t_17;
- Py_ssize_t __pyx_t_18;
- Py_ssize_t __pyx_t_19;
- Py_ssize_t __pyx_t_20;
- Py_ssize_t __pyx_t_21;
- Py_ssize_t __pyx_t_22;
- Py_ssize_t __pyx_t_23;
- Py_ssize_t __pyx_t_24;
- long __pyx_t_25;
- long __pyx_t_26;
- int __pyx_t_27;
- long __pyx_t_28;
- long __pyx_t_29;
- int __pyx_t_30;
- Py_ssize_t __pyx_t_31;
- Py_ssize_t __pyx_t_32;
- __Pyx_RefNannySetupContext("local_maxi", 0);
-
- /* "silx/image/bilinear.pyx":161
- * int res, current0, current1
- * int i0, i1
- * float tmp, sum0 = 0, sum1 = 0, sum = 0 # <<<<<<<<<<<<<<
- * float a00, a01, a02, a10, a11, a12, a20, a21, a22
- * float d00, d11, d01, denom, delta0, delta1
- */
- __pyx_v_sum0 = 0.0;
- __pyx_v_sum1 = 0.0;
- __pyx_v_sum = 0.0;
-
- /* "silx/image/bilinear.pyx":164
- * float a00, a01, a02, a10, a11, a12, a20, a21, a22
- * float d00, d11, d01, denom, delta0, delta1
- * res = self.c_local_maxi(round(coord[0]) * self.width + round(coord[1])) # <<<<<<<<<<<<<<
- *
- * current0 = res // self.width
- */
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_coord, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_round, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyInt_FromSize_t(__pyx_v_self->width); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyNumber_Multiply(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_coord, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_builtin_round, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = PyNumber_Add(__pyx_t_3, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_4 = __Pyx_PyInt_As_size_t(__pyx_t_1); if (unlikely((__pyx_t_4 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 164, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_res = ((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_local_maxi(__pyx_v_self, __pyx_t_4);
-
- /* "silx/image/bilinear.pyx":166
- * res = self.c_local_maxi(round(coord[0]) * self.width + round(coord[1]))
- *
- * current0 = res // self.width # <<<<<<<<<<<<<<
- * current1 = res % self.width
- * if (current0 > 0) and (current0 < self.height - 1) and (current1 > 0) and (current1 < self.width - 1):
- */
- __pyx_v_current0 = (__pyx_v_res / __pyx_v_self->width);
-
- /* "silx/image/bilinear.pyx":167
- *
- * current0 = res // self.width
- * current1 = res % self.width # <<<<<<<<<<<<<<
- * if (current0 > 0) and (current0 < self.height - 1) and (current1 > 0) and (current1 < self.width - 1):
- * # Use second order polynomial Taylor expansion
- */
- __pyx_v_current1 = (__pyx_v_res % __pyx_v_self->width);
-
- /* "silx/image/bilinear.pyx":168
- * current0 = res // self.width
- * current1 = res % self.width
- * if (current0 > 0) and (current0 < self.height - 1) and (current1 > 0) and (current1 < self.width - 1): # <<<<<<<<<<<<<<
- * # Use second order polynomial Taylor expansion
- * a00 = self.data[current0 - 1, current1 - 1]
- */
- __pyx_t_6 = ((__pyx_v_current0 > 0) != 0);
- if (__pyx_t_6) {
- } else {
- __pyx_t_5 = __pyx_t_6;
- goto __pyx_L4_bool_binop_done;
- }
- __pyx_t_6 = ((__pyx_v_current0 < (__pyx_v_self->height - 1)) != 0);
- if (__pyx_t_6) {
- } else {
- __pyx_t_5 = __pyx_t_6;
- goto __pyx_L4_bool_binop_done;
- }
- __pyx_t_6 = ((__pyx_v_current1 > 0) != 0);
- if (__pyx_t_6) {
- } else {
- __pyx_t_5 = __pyx_t_6;
- goto __pyx_L4_bool_binop_done;
- }
- __pyx_t_6 = ((__pyx_v_current1 < (__pyx_v_self->width - 1)) != 0);
- __pyx_t_5 = __pyx_t_6;
- __pyx_L4_bool_binop_done:;
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":170
- * if (current0 > 0) and (current0 < self.height - 1) and (current1 > 0) and (current1 < self.width - 1):
- * # Use second order polynomial Taylor expansion
- * a00 = self.data[current0 - 1, current1 - 1] # <<<<<<<<<<<<<<
- * a01 = self.data[current0 - 1, current1 ]
- * a02 = self.data[current0 - 1, current1 + 1]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 170, __pyx_L1_error)}
- __pyx_t_7 = (__pyx_v_current0 - 1);
- __pyx_t_8 = (__pyx_v_current1 - 1);
- __pyx_v_a00 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_7 * __pyx_v_self->data.strides[0]) )) + __pyx_t_8)) )));
-
- /* "silx/image/bilinear.pyx":171
- * # Use second order polynomial Taylor expansion
- * a00 = self.data[current0 - 1, current1 - 1]
- * a01 = self.data[current0 - 1, current1 ] # <<<<<<<<<<<<<<
- * a02 = self.data[current0 - 1, current1 + 1]
- * a10 = self.data[current0 , current1 - 1]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 171, __pyx_L1_error)}
- __pyx_t_9 = (__pyx_v_current0 - 1);
- __pyx_t_10 = __pyx_v_current1;
- __pyx_v_a01 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_9 * __pyx_v_self->data.strides[0]) )) + __pyx_t_10)) )));
-
- /* "silx/image/bilinear.pyx":172
- * a00 = self.data[current0 - 1, current1 - 1]
- * a01 = self.data[current0 - 1, current1 ]
- * a02 = self.data[current0 - 1, current1 + 1] # <<<<<<<<<<<<<<
- * a10 = self.data[current0 , current1 - 1]
- * a11 = self.data[current0 , current1 ]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 172, __pyx_L1_error)}
- __pyx_t_11 = (__pyx_v_current0 - 1);
- __pyx_t_12 = (__pyx_v_current1 + 1);
- __pyx_v_a02 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_11 * __pyx_v_self->data.strides[0]) )) + __pyx_t_12)) )));
-
- /* "silx/image/bilinear.pyx":173
- * a01 = self.data[current0 - 1, current1 ]
- * a02 = self.data[current0 - 1, current1 + 1]
- * a10 = self.data[current0 , current1 - 1] # <<<<<<<<<<<<<<
- * a11 = self.data[current0 , current1 ]
- * a12 = self.data[current0 , current1 + 1]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 173, __pyx_L1_error)}
- __pyx_t_13 = __pyx_v_current0;
- __pyx_t_14 = (__pyx_v_current1 - 1);
- __pyx_v_a10 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_13 * __pyx_v_self->data.strides[0]) )) + __pyx_t_14)) )));
-
- /* "silx/image/bilinear.pyx":174
- * a02 = self.data[current0 - 1, current1 + 1]
- * a10 = self.data[current0 , current1 - 1]
- * a11 = self.data[current0 , current1 ] # <<<<<<<<<<<<<<
- * a12 = self.data[current0 , current1 + 1]
- * a20 = self.data[current0 + 1, current1 - 1]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 174, __pyx_L1_error)}
- __pyx_t_15 = __pyx_v_current0;
- __pyx_t_16 = __pyx_v_current1;
- __pyx_v_a11 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_15 * __pyx_v_self->data.strides[0]) )) + __pyx_t_16)) )));
-
- /* "silx/image/bilinear.pyx":175
- * a10 = self.data[current0 , current1 - 1]
- * a11 = self.data[current0 , current1 ]
- * a12 = self.data[current0 , current1 + 1] # <<<<<<<<<<<<<<
- * a20 = self.data[current0 + 1, current1 - 1]
- * a21 = self.data[current0 + 1, current1 ]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 175, __pyx_L1_error)}
- __pyx_t_17 = __pyx_v_current0;
- __pyx_t_18 = (__pyx_v_current1 + 1);
- __pyx_v_a12 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_17 * __pyx_v_self->data.strides[0]) )) + __pyx_t_18)) )));
-
- /* "silx/image/bilinear.pyx":176
- * a11 = self.data[current0 , current1 ]
- * a12 = self.data[current0 , current1 + 1]
- * a20 = self.data[current0 + 1, current1 - 1] # <<<<<<<<<<<<<<
- * a21 = self.data[current0 + 1, current1 ]
- * a22 = self.data[current0 + 1, current1 - 1]
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 176, __pyx_L1_error)}
- __pyx_t_19 = (__pyx_v_current0 + 1);
- __pyx_t_20 = (__pyx_v_current1 - 1);
- __pyx_v_a20 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_19 * __pyx_v_self->data.strides[0]) )) + __pyx_t_20)) )));
-
- /* "silx/image/bilinear.pyx":177
- * a12 = self.data[current0 , current1 + 1]
- * a20 = self.data[current0 + 1, current1 - 1]
- * a21 = self.data[current0 + 1, current1 ] # <<<<<<<<<<<<<<
- * a22 = self.data[current0 + 1, current1 - 1]
- * d00 = a12 - 2.0 * a11 + a10
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 177, __pyx_L1_error)}
- __pyx_t_21 = (__pyx_v_current0 + 1);
- __pyx_t_22 = __pyx_v_current1;
- __pyx_v_a21 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_21 * __pyx_v_self->data.strides[0]) )) + __pyx_t_22)) )));
-
- /* "silx/image/bilinear.pyx":178
- * a20 = self.data[current0 + 1, current1 - 1]
- * a21 = self.data[current0 + 1, current1 ]
- * a22 = self.data[current0 + 1, current1 - 1] # <<<<<<<<<<<<<<
- * d00 = a12 - 2.0 * a11 + a10
- * d11 = a21 - 2.0 * a11 + a01
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 178, __pyx_L1_error)}
- __pyx_t_23 = (__pyx_v_current0 + 1);
- __pyx_t_24 = (__pyx_v_current1 - 1);
- __pyx_v_a22 = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_23 * __pyx_v_self->data.strides[0]) )) + __pyx_t_24)) )));
-
- /* "silx/image/bilinear.pyx":179
- * a21 = self.data[current0 + 1, current1 ]
- * a22 = self.data[current0 + 1, current1 - 1]
- * d00 = a12 - 2.0 * a11 + a10 # <<<<<<<<<<<<<<
- * d11 = a21 - 2.0 * a11 + a01
- * d01 = (a00 - a02 - a20 + a22) / 4.0
- */
- __pyx_v_d00 = ((__pyx_v_a12 - (2.0 * __pyx_v_a11)) + __pyx_v_a10);
-
- /* "silx/image/bilinear.pyx":180
- * a22 = self.data[current0 + 1, current1 - 1]
- * d00 = a12 - 2.0 * a11 + a10
- * d11 = a21 - 2.0 * a11 + a01 # <<<<<<<<<<<<<<
- * d01 = (a00 - a02 - a20 + a22) / 4.0
- * denom = 2.0 * (d00 * d11 - d01 * d01)
- */
- __pyx_v_d11 = ((__pyx_v_a21 - (2.0 * __pyx_v_a11)) + __pyx_v_a01);
-
- /* "silx/image/bilinear.pyx":181
- * d00 = a12 - 2.0 * a11 + a10
- * d11 = a21 - 2.0 * a11 + a01
- * d01 = (a00 - a02 - a20 + a22) / 4.0 # <<<<<<<<<<<<<<
- * denom = 2.0 * (d00 * d11 - d01 * d01)
- * if abs(denom) < 1e-10:
- */
- __pyx_v_d01 = (((double)(((__pyx_v_a00 - __pyx_v_a02) - __pyx_v_a20) + __pyx_v_a22)) / 4.0);
-
- /* "silx/image/bilinear.pyx":182
- * d11 = a21 - 2.0 * a11 + a01
- * d01 = (a00 - a02 - a20 + a22) / 4.0
- * denom = 2.0 * (d00 * d11 - d01 * d01) # <<<<<<<<<<<<<<
- * if abs(denom) < 1e-10:
- * logger.debug("Singular determinant, Hessian undefined")
- */
- __pyx_v_denom = (2.0 * ((__pyx_v_d00 * __pyx_v_d11) - (__pyx_v_d01 * __pyx_v_d01)));
-
- /* "silx/image/bilinear.pyx":183
- * d01 = (a00 - a02 - a20 + a22) / 4.0
- * denom = 2.0 * (d00 * d11 - d01 * d01)
- * if abs(denom) < 1e-10: # <<<<<<<<<<<<<<
- * logger.debug("Singular determinant, Hessian undefined")
- * else:
- */
- __pyx_t_5 = ((fabsf(__pyx_v_denom) < 1e-10) != 0);
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":184
- * denom = 2.0 * (d00 * d11 - d01 * d01)
- * if abs(denom) < 1e-10:
- * logger.debug("Singular determinant, Hessian undefined") # <<<<<<<<<<<<<<
- * else:
- * delta0 = ((a12 - a10) * d01 + (a01 - a21) * d11) / denom
- */
- __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_logger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 184, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_debug); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 184, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
- __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
- if (likely(__pyx_t_2)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
- __Pyx_INCREF(__pyx_t_2);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_3, function);
- }
- }
- __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_2, __pyx_kp_u_Singular_determinant_Hessian_und) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_kp_u_Singular_determinant_Hessian_und);
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 184, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/image/bilinear.pyx":183
- * d01 = (a00 - a02 - a20 + a22) / 4.0
- * denom = 2.0 * (d00 * d11 - d01 * d01)
- * if abs(denom) < 1e-10: # <<<<<<<<<<<<<<
- * logger.debug("Singular determinant, Hessian undefined")
- * else:
- */
- goto __pyx_L8;
- }
-
- /* "silx/image/bilinear.pyx":186
- * logger.debug("Singular determinant, Hessian undefined")
- * else:
- * delta0 = ((a12 - a10) * d01 + (a01 - a21) * d11) / denom # <<<<<<<<<<<<<<
- * delta1 = ((a10 - a12) * d00 + (a21 - a01) * d01) / denom
- * if abs(delta0) <= 1.0 and abs(delta1) <= 1.0:
- */
- /*else*/ {
- __pyx_v_delta0 = ((((__pyx_v_a12 - __pyx_v_a10) * __pyx_v_d01) + ((__pyx_v_a01 - __pyx_v_a21) * __pyx_v_d11)) / __pyx_v_denom);
-
- /* "silx/image/bilinear.pyx":187
- * else:
- * delta0 = ((a12 - a10) * d01 + (a01 - a21) * d11) / denom
- * delta1 = ((a10 - a12) * d00 + (a21 - a01) * d01) / denom # <<<<<<<<<<<<<<
- * if abs(delta0) <= 1.0 and abs(delta1) <= 1.0:
- * # Result is OK if lower than 0.5.
- */
- __pyx_v_delta1 = ((((__pyx_v_a10 - __pyx_v_a12) * __pyx_v_d00) + ((__pyx_v_a21 - __pyx_v_a01) * __pyx_v_d01)) / __pyx_v_denom);
-
- /* "silx/image/bilinear.pyx":188
- * delta0 = ((a12 - a10) * d01 + (a01 - a21) * d11) / denom
- * delta1 = ((a10 - a12) * d00 + (a21 - a01) * d01) / denom
- * if abs(delta0) <= 1.0 and abs(delta1) <= 1.0: # <<<<<<<<<<<<<<
- * # Result is OK if lower than 0.5.
- * return (delta0 + float(current0), delta1 + float(current1))
- */
- __pyx_t_6 = ((fabsf(__pyx_v_delta0) <= 1.0) != 0);
- if (__pyx_t_6) {
- } else {
- __pyx_t_5 = __pyx_t_6;
- goto __pyx_L10_bool_binop_done;
- }
- __pyx_t_6 = ((fabsf(__pyx_v_delta1) <= 1.0) != 0);
- __pyx_t_5 = __pyx_t_6;
- __pyx_L10_bool_binop_done:;
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":190
- * if abs(delta0) <= 1.0 and abs(delta1) <= 1.0:
- * # Result is OK if lower than 0.5.
- * return (delta0 + float(current0), delta1 + float(current1)) # <<<<<<<<<<<<<<
- * else:
- * logger.debug("Failed to find root using second order expansion")
- */
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyFloat_FromDouble((__pyx_v_delta0 + ((double)__pyx_v_current0))); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 190, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyFloat_FromDouble((__pyx_v_delta1 + ((double)__pyx_v_current1))); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 190, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 190, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_GIVEREF(__pyx_t_1);
- PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1);
- __Pyx_GIVEREF(__pyx_t_3);
- PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
- __pyx_t_1 = 0;
- __pyx_t_3 = 0;
- __pyx_r = __pyx_t_2;
- __pyx_t_2 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":188
- * delta0 = ((a12 - a10) * d01 + (a01 - a21) * d11) / denom
- * delta1 = ((a10 - a12) * d00 + (a21 - a01) * d01) / denom
- * if abs(delta0) <= 1.0 and abs(delta1) <= 1.0: # <<<<<<<<<<<<<<
- * # Result is OK if lower than 0.5.
- * return (delta0 + float(current0), delta1 + float(current1))
- */
- }
-
- /* "silx/image/bilinear.pyx":192
- * return (delta0 + float(current0), delta1 + float(current1))
- * else:
- * logger.debug("Failed to find root using second order expansion") # <<<<<<<<<<<<<<
- * # refinement of the position by a simple center of mass of the last valid region used
- * for i0 in range(current0 - 1, current0 + 2):
- */
- /*else*/ {
- __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_logger); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 192, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_debug); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 192, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_1))) {
- __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_1);
- if (likely(__pyx_t_3)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_3);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_1, function);
- }
- }
- __pyx_t_2 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_1, __pyx_t_3, __pyx_kp_u_Failed_to_find_root_using_second) : __Pyx_PyObject_CallOneArg(__pyx_t_1, __pyx_kp_u_Failed_to_find_root_using_second);
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 192, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- }
- }
- __pyx_L8:;
-
- /* "silx/image/bilinear.pyx":194
- * logger.debug("Failed to find root using second order expansion")
- * # refinement of the position by a simple center of mass of the last valid region used
- * for i0 in range(current0 - 1, current0 + 2): # <<<<<<<<<<<<<<
- * for i1 in range(current1 - 1, current1 + 2):
- * tmp = self.data[i0, i1]
- */
- __pyx_t_25 = (__pyx_v_current0 + 2);
- __pyx_t_26 = __pyx_t_25;
- for (__pyx_t_27 = (__pyx_v_current0 - 1); __pyx_t_27 < __pyx_t_26; __pyx_t_27+=1) {
- __pyx_v_i0 = __pyx_t_27;
-
- /* "silx/image/bilinear.pyx":195
- * # refinement of the position by a simple center of mass of the last valid region used
- * for i0 in range(current0 - 1, current0 + 2):
- * for i1 in range(current1 - 1, current1 + 2): # <<<<<<<<<<<<<<
- * tmp = self.data[i0, i1]
- * sum0 += tmp * i0
- */
- __pyx_t_28 = (__pyx_v_current1 + 2);
- __pyx_t_29 = __pyx_t_28;
- for (__pyx_t_30 = (__pyx_v_current1 - 1); __pyx_t_30 < __pyx_t_29; __pyx_t_30+=1) {
- __pyx_v_i1 = __pyx_t_30;
-
- /* "silx/image/bilinear.pyx":196
- * for i0 in range(current0 - 1, current0 + 2):
- * for i1 in range(current1 - 1, current1 + 2):
- * tmp = self.data[i0, i1] # <<<<<<<<<<<<<<
- * sum0 += tmp * i0
- * sum1 += tmp * i1
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 196, __pyx_L1_error)}
- __pyx_t_31 = __pyx_v_i0;
- __pyx_t_32 = __pyx_v_i1;
- __pyx_v_tmp = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_31 * __pyx_v_self->data.strides[0]) )) + __pyx_t_32)) )));
-
- /* "silx/image/bilinear.pyx":197
- * for i1 in range(current1 - 1, current1 + 2):
- * tmp = self.data[i0, i1]
- * sum0 += tmp * i0 # <<<<<<<<<<<<<<
- * sum1 += tmp * i1
- * sum += tmp
- */
- __pyx_v_sum0 = (__pyx_v_sum0 + (__pyx_v_tmp * __pyx_v_i0));
-
- /* "silx/image/bilinear.pyx":198
- * tmp = self.data[i0, i1]
- * sum0 += tmp * i0
- * sum1 += tmp * i1 # <<<<<<<<<<<<<<
- * sum += tmp
- * if sum > 0:
- */
- __pyx_v_sum1 = (__pyx_v_sum1 + (__pyx_v_tmp * __pyx_v_i1));
-
- /* "silx/image/bilinear.pyx":199
- * sum0 += tmp * i0
- * sum1 += tmp * i1
- * sum += tmp # <<<<<<<<<<<<<<
- * if sum > 0:
- * return (sum0 / sum, sum1 / sum)
- */
- __pyx_v_sum = (__pyx_v_sum + __pyx_v_tmp);
- }
- }
-
- /* "silx/image/bilinear.pyx":200
- * sum1 += tmp * i1
- * sum += tmp
- * if sum > 0: # <<<<<<<<<<<<<<
- * return (sum0 / sum, sum1 / sum)
- *
- */
- __pyx_t_5 = ((__pyx_v_sum > 0.0) != 0);
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":201
- * sum += tmp
- * if sum > 0:
- * return (sum0 / sum, sum1 / sum) # <<<<<<<<<<<<<<
- *
- * return (float(current0), float(current1))
- */
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_2 = PyFloat_FromDouble((__pyx_v_sum0 / __pyx_v_sum)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 201, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_1 = PyFloat_FromDouble((__pyx_v_sum1 / __pyx_v_sum)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 201, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 201, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_2);
- PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2);
- __Pyx_GIVEREF(__pyx_t_1);
- PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_1);
- __pyx_t_2 = 0;
- __pyx_t_1 = 0;
- __pyx_r = __pyx_t_3;
- __pyx_t_3 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":200
- * sum1 += tmp * i1
- * sum += tmp
- * if sum > 0: # <<<<<<<<<<<<<<
- * return (sum0 / sum, sum1 / sum)
- *
- */
- }
-
- /* "silx/image/bilinear.pyx":168
- * current0 = res // self.width
- * current1 = res % self.width
- * if (current0 > 0) and (current0 < self.height - 1) and (current1 > 0) and (current1 < self.width - 1): # <<<<<<<<<<<<<<
- * # Use second order polynomial Taylor expansion
- * a00 = self.data[current0 - 1, current1 - 1]
- */
- }
-
- /* "silx/image/bilinear.pyx":203
- * return (sum0 / sum, sum1 / sum)
- *
- * return (float(current0), float(current1)) # <<<<<<<<<<<<<<
- *
- * cpdef size_t coarse_local_maxi(self, size_t x):
- */
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_3 = PyFloat_FromDouble(((double)__pyx_v_current0)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 203, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_1 = PyFloat_FromDouble(((double)__pyx_v_current1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 203, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 203, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_GIVEREF(__pyx_t_3);
- PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3);
- __Pyx_GIVEREF(__pyx_t_1);
- PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_1);
- __pyx_t_3 = 0;
- __pyx_t_1 = 0;
- __pyx_r = __pyx_t_2;
- __pyx_t_2 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":143
- * @cython.wraparound(False)
- * @cython.cdivision(True)
- * def local_maxi(self, coord): # <<<<<<<<<<<<<<
- * """Return the nearest local maximum ... with sub-pixel refinement
- *
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_3);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.local_maxi", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":205
- * return (float(current0), float(current1))
- *
- * cpdef size_t coarse_local_maxi(self, size_t x): # <<<<<<<<<<<<<<
- * """Return the nearest local maximum ... without sub-pixel refinement
- *
- */
-
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_11coarse_local_maxi(PyObject *__pyx_v_self, PyObject *__pyx_arg_x); /*proto*/
-static size_t __pyx_f_4silx_5image_8bilinear_13BilinearImage_coarse_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_x, int __pyx_skip_dispatch) {
- size_t __pyx_r;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- PyObject *__pyx_t_4 = NULL;
- PyObject *__pyx_t_5 = NULL;
- size_t __pyx_t_6;
- __Pyx_RefNannySetupContext("coarse_local_maxi", 0);
- /* Check if called by wrapper */
- if (unlikely(__pyx_skip_dispatch)) ;
- /* Check if overridden in Python */
- else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || (Py_TYPE(((PyObject *)__pyx_v_self))->tp_flags & (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {
- #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS
- static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT;
- if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) {
- PY_UINT64_T __pyx_type_dict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self));
- #endif
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_coarse_local_maxi); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 205, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- if (!PyCFunction_Check(__pyx_t_1) || (PyCFunction_GET_FUNCTION(__pyx_t_1) != (PyCFunction)(void*)__pyx_pw_4silx_5image_8bilinear_13BilinearImage_11coarse_local_maxi)) {
- __pyx_t_3 = __Pyx_PyInt_FromSize_t(__pyx_v_x); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 205, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_INCREF(__pyx_t_1);
- __pyx_t_4 = __pyx_t_1; __pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
- __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4);
- if (likely(__pyx_t_5)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
- __Pyx_INCREF(__pyx_t_5);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_4, function);
- }
- }
- __pyx_t_2 = (__pyx_t_5) ? __Pyx_PyObject_Call2Args(__pyx_t_4, __pyx_t_5, __pyx_t_3) : __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_3);
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 205, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_6 = __Pyx_PyInt_As_size_t(__pyx_t_2); if (unlikely((__pyx_t_6 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 205, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_r = __pyx_t_6;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- goto __pyx_L0;
- }
- #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS
- __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self));
- __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self));
- if (unlikely(__pyx_type_dict_guard != __pyx_tp_dict_version)) {
- __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT;
- }
- #endif
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS
- }
- #endif
- }
-
- /* "silx/image/bilinear.pyx":211
- * :return: local maximum index
- * """
- * return self.c_local_maxi(x) # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __pyx_r = ((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_local_maxi(__pyx_v_self, __pyx_v_x);
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":205
- * return (float(current0), float(current1))
- *
- * cpdef size_t coarse_local_maxi(self, size_t x): # <<<<<<<<<<<<<<
- * """Return the nearest local maximum ... without sub-pixel refinement
- *
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_3);
- __Pyx_XDECREF(__pyx_t_4);
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_WriteUnraisable("silx.image.bilinear.BilinearImage.coarse_local_maxi", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 0);
- __pyx_r = 0;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_11coarse_local_maxi(PyObject *__pyx_v_self, PyObject *__pyx_arg_x); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_10coarse_local_maxi[] = "BilinearImage.coarse_local_maxi(self, size_t x) -> size_t\nReturn the nearest local maximum ... without sub-pixel refinement\n\n :param idx: start index (=row*width+column)\n :return: local maximum index\n ";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_11coarse_local_maxi(PyObject *__pyx_v_self, PyObject *__pyx_arg_x) {
- size_t __pyx_v_x;
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("coarse_local_maxi (wrapper)", 0);
- assert(__pyx_arg_x); {
- __pyx_v_x = __Pyx_PyInt_As_size_t(__pyx_arg_x); if (unlikely((__pyx_v_x == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 205, __pyx_L3_error)
- }
- goto __pyx_L4_argument_unpacking_done;
- __pyx_L3_error:;
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.coarse_local_maxi", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __Pyx_RefNannyFinishContext();
- return NULL;
- __pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_10coarse_local_maxi(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), ((size_t)__pyx_v_x));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_10coarse_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_x) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("coarse_local_maxi", 0);
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_FromSize_t(__pyx_f_4silx_5image_8bilinear_13BilinearImage_coarse_local_maxi(__pyx_v_self, __pyx_v_x, 1)); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 205, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.coarse_local_maxi", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":216
- * @cython.wraparound(False)
- * @cython.cdivision(True)
- * cdef size_t c_local_maxi(self, size_t idx) nogil: # <<<<<<<<<<<<<<
- * """Return the nearest local maximum without sub-pixel refinement
- *
- */
-
-static size_t __pyx_f_4silx_5image_8bilinear_13BilinearImage_c_local_maxi(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, size_t __pyx_v_idx) {
- int __pyx_v_current0;
- int __pyx_v_current1;
- int __pyx_v_i0;
- int __pyx_v_i1;
- int __pyx_v_start0;
- int __pyx_v_stop0;
- int __pyx_v_start1;
- int __pyx_v_stop1;
- int __pyx_v_new0;
- int __pyx_v_new1;
- float __pyx_v_tmp;
- float __pyx_v_value;
- float __pyx_v_old_value;
- size_t __pyx_r;
- Py_ssize_t __pyx_t_1;
- Py_ssize_t __pyx_t_2;
- int __pyx_t_3;
- int __pyx_t_4;
- int __pyx_t_5;
- long __pyx_t_6;
- long __pyx_t_7;
- long __pyx_t_8;
- size_t __pyx_t_9;
- size_t __pyx_t_10;
- int __pyx_t_11;
- int __pyx_t_12;
- int __pyx_t_13;
- int __pyx_t_14;
- Py_ssize_t __pyx_t_15;
- Py_ssize_t __pyx_t_16;
- int __pyx_t_17;
- int __pyx_t_18;
-
- /* "silx/image/bilinear.pyx":225
- * """
- * cdef:
- * int current0 = idx // self.width # <<<<<<<<<<<<<<
- * int current1 = idx % self.width
- * int i0, i1, start0, stop0, start1, stop1, new0, new1
- */
- __pyx_v_current0 = (__pyx_v_idx / __pyx_v_self->width);
-
- /* "silx/image/bilinear.pyx":226
- * cdef:
- * int current0 = idx // self.width
- * int current1 = idx % self.width # <<<<<<<<<<<<<<
- * int i0, i1, start0, stop0, start1, stop1, new0, new1
- * float tmp, value, old_value
- */
- __pyx_v_current1 = (__pyx_v_idx % __pyx_v_self->width);
-
- /* "silx/image/bilinear.pyx":230
- * float tmp, value, old_value
- *
- * value = self.data[current0, current1] # <<<<<<<<<<<<<<
- * old_value = value - 1.0
- * new0, new1 = current0, current1
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 230, __pyx_L1_error)}
- __pyx_t_1 = __pyx_v_current0;
- __pyx_t_2 = __pyx_v_current1;
- __pyx_v_value = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_1 * __pyx_v_self->data.strides[0]) )) + __pyx_t_2)) )));
-
- /* "silx/image/bilinear.pyx":231
- *
- * value = self.data[current0, current1]
- * old_value = value - 1.0 # <<<<<<<<<<<<<<
- * new0, new1 = current0, current1
- *
- */
- __pyx_v_old_value = (__pyx_v_value - 1.0);
-
- /* "silx/image/bilinear.pyx":232
- * value = self.data[current0, current1]
- * old_value = value - 1.0
- * new0, new1 = current0, current1 # <<<<<<<<<<<<<<
- *
- * while value > old_value:
- */
- __pyx_t_3 = __pyx_v_current0;
- __pyx_t_4 = __pyx_v_current1;
- __pyx_v_new0 = __pyx_t_3;
- __pyx_v_new1 = __pyx_t_4;
-
- /* "silx/image/bilinear.pyx":234
- * new0, new1 = current0, current1
- *
- * while value > old_value: # <<<<<<<<<<<<<<
- * old_value = value
- * start0 = max(0, current0 - 1)
- */
- while (1) {
- __pyx_t_5 = ((__pyx_v_value > __pyx_v_old_value) != 0);
- if (!__pyx_t_5) break;
-
- /* "silx/image/bilinear.pyx":235
- *
- * while value > old_value:
- * old_value = value # <<<<<<<<<<<<<<
- * start0 = max(0, current0 - 1)
- * stop0 = min(self.height, current0 + 2)
- */
- __pyx_v_old_value = __pyx_v_value;
-
- /* "silx/image/bilinear.pyx":236
- * while value > old_value:
- * old_value = value
- * start0 = max(0, current0 - 1) # <<<<<<<<<<<<<<
- * stop0 = min(self.height, current0 + 2)
- * start1 = max(0, current1 - 1)
- */
- __pyx_t_6 = (__pyx_v_current0 - 1);
- __pyx_t_7 = 0;
- if (((__pyx_t_6 > __pyx_t_7) != 0)) {
- __pyx_t_8 = __pyx_t_6;
- } else {
- __pyx_t_8 = __pyx_t_7;
- }
- __pyx_v_start0 = __pyx_t_8;
-
- /* "silx/image/bilinear.pyx":237
- * old_value = value
- * start0 = max(0, current0 - 1)
- * stop0 = min(self.height, current0 + 2) # <<<<<<<<<<<<<<
- * start1 = max(0, current1 - 1)
- * stop1 = min(self.width, current1 + 2)
- */
- __pyx_t_8 = (__pyx_v_current0 + 2);
- __pyx_t_9 = __pyx_v_self->height;
- if (((__pyx_t_8 < __pyx_t_9) != 0)) {
- __pyx_t_10 = __pyx_t_8;
- } else {
- __pyx_t_10 = __pyx_t_9;
- }
- __pyx_v_stop0 = __pyx_t_10;
-
- /* "silx/image/bilinear.pyx":238
- * start0 = max(0, current0 - 1)
- * stop0 = min(self.height, current0 + 2)
- * start1 = max(0, current1 - 1) # <<<<<<<<<<<<<<
- * stop1 = min(self.width, current1 + 2)
- * for i0 in range(start0, stop0):
- */
- __pyx_t_8 = (__pyx_v_current1 - 1);
- __pyx_t_6 = 0;
- if (((__pyx_t_8 > __pyx_t_6) != 0)) {
- __pyx_t_7 = __pyx_t_8;
- } else {
- __pyx_t_7 = __pyx_t_6;
- }
- __pyx_v_start1 = __pyx_t_7;
-
- /* "silx/image/bilinear.pyx":239
- * stop0 = min(self.height, current0 + 2)
- * start1 = max(0, current1 - 1)
- * stop1 = min(self.width, current1 + 2) # <<<<<<<<<<<<<<
- * for i0 in range(start0, stop0):
- * for i1 in range(start1, stop1):
- */
- __pyx_t_7 = (__pyx_v_current1 + 2);
- __pyx_t_10 = __pyx_v_self->width;
- if (((__pyx_t_7 < __pyx_t_10) != 0)) {
- __pyx_t_9 = __pyx_t_7;
- } else {
- __pyx_t_9 = __pyx_t_10;
- }
- __pyx_v_stop1 = __pyx_t_9;
-
- /* "silx/image/bilinear.pyx":240
- * start1 = max(0, current1 - 1)
- * stop1 = min(self.width, current1 + 2)
- * for i0 in range(start0, stop0): # <<<<<<<<<<<<<<
- * for i1 in range(start1, stop1):
- * tmp = self.data[i0, i1]
- */
- __pyx_t_4 = __pyx_v_stop0;
- __pyx_t_3 = __pyx_t_4;
- for (__pyx_t_11 = __pyx_v_start0; __pyx_t_11 < __pyx_t_3; __pyx_t_11+=1) {
- __pyx_v_i0 = __pyx_t_11;
-
- /* "silx/image/bilinear.pyx":241
- * stop1 = min(self.width, current1 + 2)
- * for i0 in range(start0, stop0):
- * for i1 in range(start1, stop1): # <<<<<<<<<<<<<<
- * tmp = self.data[i0, i1]
- * if tmp > value:
- */
- __pyx_t_12 = __pyx_v_stop1;
- __pyx_t_13 = __pyx_t_12;
- for (__pyx_t_14 = __pyx_v_start1; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) {
- __pyx_v_i1 = __pyx_t_14;
-
- /* "silx/image/bilinear.pyx":242
- * for i0 in range(start0, stop0):
- * for i1 in range(start1, stop1):
- * tmp = self.data[i0, i1] # <<<<<<<<<<<<<<
- * if tmp > value:
- * new0, new1 = i0, i1
- */
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 242, __pyx_L1_error)}
- __pyx_t_15 = __pyx_v_i0;
- __pyx_t_16 = __pyx_v_i1;
- __pyx_v_tmp = (*((float *) ( /* dim=1 */ ((char *) (((float *) ( /* dim=0 */ (__pyx_v_self->data.data + __pyx_t_15 * __pyx_v_self->data.strides[0]) )) + __pyx_t_16)) )));
-
- /* "silx/image/bilinear.pyx":243
- * for i1 in range(start1, stop1):
- * tmp = self.data[i0, i1]
- * if tmp > value: # <<<<<<<<<<<<<<
- * new0, new1 = i0, i1
- * value = tmp
- */
- __pyx_t_5 = ((__pyx_v_tmp > __pyx_v_value) != 0);
- if (__pyx_t_5) {
-
- /* "silx/image/bilinear.pyx":244
- * tmp = self.data[i0, i1]
- * if tmp > value:
- * new0, new1 = i0, i1 # <<<<<<<<<<<<<<
- * value = tmp
- * current0, current1 = new0, new1
- */
- __pyx_t_17 = __pyx_v_i0;
- __pyx_t_18 = __pyx_v_i1;
- __pyx_v_new0 = __pyx_t_17;
- __pyx_v_new1 = __pyx_t_18;
-
- /* "silx/image/bilinear.pyx":245
- * if tmp > value:
- * new0, new1 = i0, i1
- * value = tmp # <<<<<<<<<<<<<<
- * current0, current1 = new0, new1
- * return self.width * current0 + current1
- */
- __pyx_v_value = __pyx_v_tmp;
-
- /* "silx/image/bilinear.pyx":243
- * for i1 in range(start1, stop1):
- * tmp = self.data[i0, i1]
- * if tmp > value: # <<<<<<<<<<<<<<
- * new0, new1 = i0, i1
- * value = tmp
- */
- }
- }
- }
-
- /* "silx/image/bilinear.pyx":246
- * new0, new1 = i0, i1
- * value = tmp
- * current0, current1 = new0, new1 # <<<<<<<<<<<<<<
- * return self.width * current0 + current1
- *
- */
- __pyx_t_4 = __pyx_v_new0;
- __pyx_t_3 = __pyx_v_new1;
- __pyx_v_current0 = __pyx_t_4;
- __pyx_v_current1 = __pyx_t_3;
- }
-
- /* "silx/image/bilinear.pyx":247
- * value = tmp
- * current0, current1 = new0, new1
- * return self.width * current0 + current1 # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __pyx_r = ((__pyx_v_self->width * __pyx_v_current0) + __pyx_v_current1);
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":216
- * @cython.wraparound(False)
- * @cython.cdivision(True)
- * cdef size_t c_local_maxi(self, size_t idx) nogil: # <<<<<<<<<<<<<<
- * """Return the nearest local maximum without sub-pixel refinement
- *
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_WriteUnraisable("silx.image.bilinear.BilinearImage.c_local_maxi", __pyx_clineno, __pyx_lineno, __pyx_filename, 1, 1);
- __pyx_r = 0;
- __pyx_L0:;
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":250
- *
- * @cython.boundscheck(False)
- * def map_coordinates(self, coordinates): # <<<<<<<<<<<<<<
- * """Map coordinates of the array on the image
- *
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_13map_coordinates(PyObject *__pyx_v_self, PyObject *__pyx_v_coordinates); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_12map_coordinates[] = "BilinearImage.map_coordinates(self, coordinates)\nMap coordinates of the array on the image\n\n :param coordinates: 2-tuple of array of the same size (row_array, column_array)\n :return: array of values at given coordinates\n ";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_13map_coordinates(PyObject *__pyx_v_self, PyObject *__pyx_v_coordinates) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("map_coordinates (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_12map_coordinates(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), ((PyObject *)__pyx_v_coordinates));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_12map_coordinates(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_coordinates) {
- __Pyx_memviewslice __pyx_v_d0 = { 0, 0, { 0 }, { 0 }, { 0 } };
- __Pyx_memviewslice __pyx_v_d1 = { 0, 0, { 0 }, { 0 }, { 0 } };
- __Pyx_memviewslice __pyx_v_res = { 0, 0, { 0 }, { 0 }, { 0 } };
- size_t __pyx_v_size;
- size_t __pyx_v_i;
- PyObject *__pyx_v_shape = NULL;
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- size_t __pyx_t_3;
- PyObject *__pyx_t_4 = NULL;
- PyObject *__pyx_t_5 = NULL;
- PyObject *__pyx_t_6 = NULL;
- __Pyx_memviewslice __pyx_t_7 = { 0, 0, { 0 }, { 0 }, { 0 } };
- int __pyx_t_8;
- size_t __pyx_t_9;
- size_t __pyx_t_10;
- size_t __pyx_t_11;
- size_t __pyx_t_12;
- size_t __pyx_t_13;
- __Pyx_RefNannySetupContext("map_coordinates", 0);
-
- /* "silx/image/bilinear.pyx":259
- * float[:] d0, d1, res
- * size_t size, i
- * shape = coordinates[0].shape # <<<<<<<<<<<<<<
- * size = coordinates[0].size
- * d0 = numpy.ascontiguousarray(coordinates[0].ravel(), dtype=numpy.float32)
- */
- __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_coordinates, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 259, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_shape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 259, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_shape = __pyx_t_2;
- __pyx_t_2 = 0;
-
- /* "silx/image/bilinear.pyx":260
- * size_t size, i
- * shape = coordinates[0].shape
- * size = coordinates[0].size # <<<<<<<<<<<<<<
- * d0 = numpy.ascontiguousarray(coordinates[0].ravel(), dtype=numpy.float32)
- * d1 = numpy.ascontiguousarray(coordinates[1].ravel(), dtype=numpy.float32)
- */
- __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_coordinates, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 260, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_size); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 260, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_3 = __Pyx_PyInt_As_size_t(__pyx_t_1); if (unlikely((__pyx_t_3 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 260, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_size = __pyx_t_3;
-
- /* "silx/image/bilinear.pyx":261
- * shape = coordinates[0].shape
- * size = coordinates[0].size
- * d0 = numpy.ascontiguousarray(coordinates[0].ravel(), dtype=numpy.float32) # <<<<<<<<<<<<<<
- * d1 = numpy.ascontiguousarray(coordinates[1].ravel(), dtype=numpy.float32)
- * assert size == d1.size
- */
- __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_4 = __Pyx_GetItemInt(__pyx_v_coordinates, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_ravel); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
- __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5);
- if (likely(__pyx_t_4)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
- __Pyx_INCREF(__pyx_t_4);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_5, function);
- }
- }
- __pyx_t_1 = (__pyx_t_4) ? __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_t_4) : __Pyx_PyObject_CallNoArg(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_GIVEREF(__pyx_t_1);
- PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1);
- __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_numpy); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_float32); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_6) < 0) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_ds_float(__pyx_t_6, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 261, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_v_d0 = __pyx_t_7;
- __pyx_t_7.memview = NULL;
- __pyx_t_7.data = NULL;
-
- /* "silx/image/bilinear.pyx":262
- * size = coordinates[0].size
- * d0 = numpy.ascontiguousarray(coordinates[0].ravel(), dtype=numpy.float32)
- * d1 = numpy.ascontiguousarray(coordinates[1].ravel(), dtype=numpy.float32) # <<<<<<<<<<<<<<
- * assert size == d1.size
- * res = numpy.empty(size, dtype=numpy.float32)
- */
- __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_numpy); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_ascontiguousarray); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_5 = __Pyx_GetItemInt(__pyx_v_coordinates, 1, long, 1, __Pyx_PyInt_From_long, 0, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_ravel); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
- __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_2);
- if (likely(__pyx_t_5)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
- __Pyx_INCREF(__pyx_t_5);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_2, function);
- }
- }
- __pyx_t_6 = (__pyx_t_5) ? __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_5) : __Pyx_PyObject_CallNoArg(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_n_s_numpy); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_n_s_float32); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_dtype, __pyx_t_4) < 0) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_1, __pyx_t_2, __pyx_t_6); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_ds_float(__pyx_t_4, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 262, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_v_d1 = __pyx_t_7;
- __pyx_t_7.memview = NULL;
- __pyx_t_7.data = NULL;
-
- /* "silx/image/bilinear.pyx":263
- * d0 = numpy.ascontiguousarray(coordinates[0].ravel(), dtype=numpy.float32)
- * d1 = numpy.ascontiguousarray(coordinates[1].ravel(), dtype=numpy.float32)
- * assert size == d1.size # <<<<<<<<<<<<<<
- * res = numpy.empty(size, dtype=numpy.float32)
- * with nogil:
- */
- #ifndef CYTHON_WITHOUT_ASSERTIONS
- if (unlikely(!Py_OptimizeFlag)) {
- __pyx_t_4 = __Pyx_PyInt_FromSize_t(__pyx_v_size); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_6 = __pyx_memoryview_fromslice(__pyx_v_d1, 1, (PyObject *(*)(char *)) __pyx_memview_get_float, (int (*)(char *, PyObject *)) __pyx_memview_set_float, 0);; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_size); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_6 = PyObject_RichCompare(__pyx_t_4, __pyx_t_2, Py_EQ); __Pyx_XGOTREF(__pyx_t_6); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_8 = __Pyx_PyObject_IsTrue(__pyx_t_6); if (unlikely(__pyx_t_8 < 0)) __PYX_ERR(0, 263, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- if (unlikely(!__pyx_t_8)) {
- PyErr_SetNone(PyExc_AssertionError);
- __PYX_ERR(0, 263, __pyx_L1_error)
- }
- }
- #endif
-
- /* "silx/image/bilinear.pyx":264
- * d1 = numpy.ascontiguousarray(coordinates[1].ravel(), dtype=numpy.float32)
- * assert size == d1.size
- * res = numpy.empty(size, dtype=numpy.float32) # <<<<<<<<<<<<<<
- * with nogil:
- * for i in range(size):
- */
- __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_numpy); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_empty); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyInt_FromSize_t(__pyx_v_size); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __Pyx_GIVEREF(__pyx_t_6);
- PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_6);
- __pyx_t_6 = 0;
- __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_float32); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- if (PyDict_SetItem(__pyx_t_6, __pyx_n_s_dtype, __pyx_t_5) < 0) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_t_5 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_4, __pyx_t_6); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_7 = __Pyx_PyObject_to_MemoryviewSlice_ds_float(__pyx_t_5, PyBUF_WRITABLE); if (unlikely(!__pyx_t_7.memview)) __PYX_ERR(0, 264, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __pyx_v_res = __pyx_t_7;
- __pyx_t_7.memview = NULL;
- __pyx_t_7.data = NULL;
-
- /* "silx/image/bilinear.pyx":265
- * assert size == d1.size
- * res = numpy.empty(size, dtype=numpy.float32)
- * with nogil: # <<<<<<<<<<<<<<
- * for i in range(size):
- * res[i] = self.c_funct(d1[i], d0[i])
- */
- {
- #ifdef WITH_THREAD
- PyThreadState *_save;
- Py_UNBLOCK_THREADS
- __Pyx_FastGIL_Remember();
- #endif
- /*try:*/ {
-
- /* "silx/image/bilinear.pyx":266
- * res = numpy.empty(size, dtype=numpy.float32)
- * with nogil:
- * for i in range(size): # <<<<<<<<<<<<<<
- * res[i] = self.c_funct(d1[i], d0[i])
- * return numpy.asarray(res).reshape(shape)
- */
- __pyx_t_3 = __pyx_v_size;
- __pyx_t_9 = __pyx_t_3;
- for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_9; __pyx_t_10+=1) {
- __pyx_v_i = __pyx_t_10;
-
- /* "silx/image/bilinear.pyx":267
- * with nogil:
- * for i in range(size):
- * res[i] = self.c_funct(d1[i], d0[i]) # <<<<<<<<<<<<<<
- * return numpy.asarray(res).reshape(shape)
- *
- */
- __pyx_t_11 = __pyx_v_i;
- __pyx_t_12 = __pyx_v_i;
- __pyx_t_13 = __pyx_v_i;
- *((float *) ( /* dim=0 */ (__pyx_v_res.data + __pyx_t_13 * __pyx_v_res.strides[0]) )) = ((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_funct(__pyx_v_self, (*((float *) ( /* dim=0 */ (__pyx_v_d1.data + __pyx_t_11 * __pyx_v_d1.strides[0]) ))), (*((float *) ( /* dim=0 */ (__pyx_v_d0.data + __pyx_t_12 * __pyx_v_d0.strides[0]) ))));
- }
- }
-
- /* "silx/image/bilinear.pyx":265
- * assert size == d1.size
- * res = numpy.empty(size, dtype=numpy.float32)
- * with nogil: # <<<<<<<<<<<<<<
- * for i in range(size):
- * res[i] = self.c_funct(d1[i], d0[i])
- */
- /*finally:*/ {
- /*normal exit:*/{
- #ifdef WITH_THREAD
- __Pyx_FastGIL_Forget();
- Py_BLOCK_THREADS
- #endif
- goto __pyx_L5;
- }
- __pyx_L5:;
- }
- }
-
- /* "silx/image/bilinear.pyx":268
- * for i in range(size):
- * res[i] = self.c_funct(d1[i], d0[i])
- * return numpy.asarray(res).reshape(shape) # <<<<<<<<<<<<<<
- *
- * @cython.boundscheck(False)
- */
- __Pyx_XDECREF(__pyx_r);
- __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_n_s_numpy); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_asarray); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- __pyx_t_4 = __pyx_memoryview_fromslice(__pyx_v_res, 1, (PyObject *(*)(char *)) __pyx_memview_get_float, (int (*)(char *, PyObject *)) __pyx_memview_set_float, 0);; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_4);
- __pyx_t_1 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
- __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_2);
- if (likely(__pyx_t_1)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
- __Pyx_INCREF(__pyx_t_1);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_2, function);
- }
- }
- __pyx_t_6 = (__pyx_t_1) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_1, __pyx_t_4) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_4);
- __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
- __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
- if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_6);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_reshape); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
- __pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_2))) {
- __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_2);
- if (likely(__pyx_t_6)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
- __Pyx_INCREF(__pyx_t_6);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_2, function);
- }
- }
- __pyx_t_5 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_6, __pyx_v_shape) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_v_shape);
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 268, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_r = __pyx_t_5;
- __pyx_t_5 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":250
- *
- * @cython.boundscheck(False)
- * def map_coordinates(self, coordinates): # <<<<<<<<<<<<<<
- * """Map coordinates of the array on the image
- *
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_4);
- __Pyx_XDECREF(__pyx_t_5);
- __Pyx_XDECREF(__pyx_t_6);
- __PYX_XDEC_MEMVIEW(&__pyx_t_7, 1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.map_coordinates", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __PYX_XDEC_MEMVIEW(&__pyx_v_d0, 1);
- __PYX_XDEC_MEMVIEW(&__pyx_v_d1, 1);
- __PYX_XDEC_MEMVIEW(&__pyx_v_res, 1);
- __Pyx_XDECREF(__pyx_v_shape);
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":271
- *
- * @cython.boundscheck(False)
- * def profile_line(self, src, dst, int linewidth=1, method='mean'): # <<<<<<<<<<<<<<
- * """Return the mean or sum of intensity profile of an image measured
- * along a scan line.
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_15profile_line(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_14profile_line[] = "BilinearImage.profile_line(self, src, dst, int linewidth=1, method=u'mean')\nReturn the mean or sum of intensity profile of an image measured\n along a scan line.\n\n :param src: The start point of the scan line.\n :type src: 2-tuple of numeric scalar\n :param dst: The end point of the scan line.\n The destination point is included in the profile,\n in contrast to standard numpy indexing.\n :type dst: 2-tuple of numeric scalar\n :param int linewidth: Width of the scanline (unit image pixel).\n :param str method: 'mean' or 'sum' depending if we want to compute the\n mean intensity along the line or the sum.\n :return: The intensity profile along the scan line.\n The length of the profile is the ceil of the computed length\n of the scan line.\n :rtype: 1d array\n\n Inspired from skimage\n ";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_15profile_line(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
- PyObject *__pyx_v_src = 0;
- PyObject *__pyx_v_dst = 0;
- int __pyx_v_linewidth;
- PyObject *__pyx_v_method = 0;
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("profile_line (wrapper)", 0);
- {
- static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_src,&__pyx_n_s_dst,&__pyx_n_s_linewidth,&__pyx_n_s_method,0};
- PyObject* values[4] = {0,0,0,0};
- values[3] = ((PyObject *)__pyx_n_u_mean);
- if (unlikely(__pyx_kwds)) {
- Py_ssize_t kw_args;
- const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
- switch (pos_args) {
- case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
- CYTHON_FALLTHROUGH;
- case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
- CYTHON_FALLTHROUGH;
- case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
- CYTHON_FALLTHROUGH;
- case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- CYTHON_FALLTHROUGH;
- case 0: break;
- default: goto __pyx_L5_argtuple_error;
- }
- kw_args = PyDict_Size(__pyx_kwds);
- switch (pos_args) {
- case 0:
- if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_src)) != 0)) kw_args--;
- else goto __pyx_L5_argtuple_error;
- CYTHON_FALLTHROUGH;
- case 1:
- if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_dst)) != 0)) kw_args--;
- else {
- __Pyx_RaiseArgtupleInvalid("profile_line", 0, 2, 4, 1); __PYX_ERR(0, 271, __pyx_L3_error)
- }
- CYTHON_FALLTHROUGH;
- case 2:
- if (kw_args > 0) {
- PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_linewidth);
- if (value) { values[2] = value; kw_args--; }
- }
- CYTHON_FALLTHROUGH;
- case 3:
- if (kw_args > 0) {
- PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_method);
- if (value) { values[3] = value; kw_args--; }
- }
- }
- if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "profile_line") < 0)) __PYX_ERR(0, 271, __pyx_L3_error)
- }
- } else {
- switch (PyTuple_GET_SIZE(__pyx_args)) {
- case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
- CYTHON_FALLTHROUGH;
- case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
- CYTHON_FALLTHROUGH;
- case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
- values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- break;
- default: goto __pyx_L5_argtuple_error;
- }
- }
- __pyx_v_src = values[0];
- __pyx_v_dst = values[1];
- if (values[2]) {
- __pyx_v_linewidth = __Pyx_PyInt_As_int(values[2]); if (unlikely((__pyx_v_linewidth == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 271, __pyx_L3_error)
- } else {
- __pyx_v_linewidth = ((int)1);
- }
- __pyx_v_method = values[3];
- }
- goto __pyx_L4_argument_unpacking_done;
- __pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("profile_line", 0, 2, 4, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 271, __pyx_L3_error)
- __pyx_L3_error:;
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.profile_line", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __Pyx_RefNannyFinishContext();
- return NULL;
- __pyx_L4_argument_unpacking_done:;
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_14profile_line(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), __pyx_v_src, __pyx_v_dst, __pyx_v_linewidth, __pyx_v_method);
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_14profile_line(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, PyObject *__pyx_v_src, PyObject *__pyx_v_dst, int __pyx_v_linewidth, PyObject *__pyx_v_method) {
- float __pyx_v_src_row;
- float __pyx_v_src_col;
- float __pyx_v_dst_row;
- float __pyx_v_dst_col;
- float __pyx_v_d_row;
- float __pyx_v_d_col;
- float __pyx_v_length;
- float __pyx_v_col_width;
- float __pyx_v_row_width;
- float __pyx_v_sum;
- float __pyx_v_row;
- float __pyx_v_col;
- float __pyx_v_new_row;
- float __pyx_v_new_col;
- int __pyx_v_lengt;
- int __pyx_v_i;
- int __pyx_v_j;
- int __pyx_v_cnt;
- __Pyx_memviewslice __pyx_v_result = { 0, 0, { 0 }, { 0 }, { 0 } };
- PyObject *__pyx_v_compute_mean = NULL;
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- PyObject *__pyx_t_2 = NULL;
- PyObject *__pyx_t_3 = NULL;
- PyObject *(*__pyx_t_4)(PyObject *);
- float __pyx_t_5;
- float __pyx_t_6;
- int __pyx_t_7;
- int __pyx_t_8;
- PyObject *__pyx_t_9 = NULL;
- PyObject *__pyx_t_10 = NULL;
- __Pyx_memviewslice __pyx_t_11 = { 0, 0, { 0 }, { 0 }, { 0 } };
- int __pyx_t_12;
- int __pyx_t_13;
- int __pyx_t_14;
- int __pyx_t_15;
- int __pyx_t_16;
- int __pyx_t_17;
- Py_ssize_t __pyx_t_18;
- Py_ssize_t __pyx_t_19;
- __Pyx_RefNannySetupContext("profile_line", 0);
-
- /* "silx/image/bilinear.pyx":296
- * int lengt, i, j, cnt
- * float[::1] result
- * src_row, src_col = src # <<<<<<<<<<<<<<
- * dst_row, dst_col = dst
- * if (src_row == dst_row) and (src_col == dst_col):
- */
- if ((likely(PyTuple_CheckExact(__pyx_v_src))) || (PyList_CheckExact(__pyx_v_src))) {
- PyObject* sequence = __pyx_v_src;
- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
- if (unlikely(size != 2)) {
- if (size > 2) __Pyx_RaiseTooManyValuesError(2);
- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(0, 296, __pyx_L1_error)
- }
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- if (likely(PyTuple_CheckExact(sequence))) {
- __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0);
- __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1);
- } else {
- __pyx_t_1 = PyList_GET_ITEM(sequence, 0);
- __pyx_t_2 = PyList_GET_ITEM(sequence, 1);
- }
- __Pyx_INCREF(__pyx_t_1);
- __Pyx_INCREF(__pyx_t_2);
- #else
- __pyx_t_1 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 296, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 296, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- #endif
- } else {
- Py_ssize_t index = -1;
- __pyx_t_3 = PyObject_GetIter(__pyx_v_src); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 296, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
- index = 0; __pyx_t_1 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_1)) goto __pyx_L3_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_1);
- index = 1; __pyx_t_2 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_2)) goto __pyx_L3_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_2);
- if (__Pyx_IternextUnpackEndCheck(__pyx_t_4(__pyx_t_3), 2) < 0) __PYX_ERR(0, 296, __pyx_L1_error)
- __pyx_t_4 = NULL;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L4_unpacking_done;
- __pyx_L3_unpacking_failed:;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_4 = NULL;
- if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
- __PYX_ERR(0, 296, __pyx_L1_error)
- __pyx_L4_unpacking_done:;
- }
- __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_6 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_6 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 296, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_v_src_row = __pyx_t_5;
- __pyx_v_src_col = __pyx_t_6;
-
- /* "silx/image/bilinear.pyx":297
- * float[::1] result
- * src_row, src_col = src
- * dst_row, dst_col = dst # <<<<<<<<<<<<<<
- * if (src_row == dst_row) and (src_col == dst_col):
- * logger.warning("Source and destination points are the same")
- */
- if ((likely(PyTuple_CheckExact(__pyx_v_dst))) || (PyList_CheckExact(__pyx_v_dst))) {
- PyObject* sequence = __pyx_v_dst;
- Py_ssize_t size = __Pyx_PySequence_SIZE(sequence);
- if (unlikely(size != 2)) {
- if (size > 2) __Pyx_RaiseTooManyValuesError(2);
- else if (size >= 0) __Pyx_RaiseNeedMoreValuesError(size);
- __PYX_ERR(0, 297, __pyx_L1_error)
- }
- #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
- if (likely(PyTuple_CheckExact(sequence))) {
- __pyx_t_2 = PyTuple_GET_ITEM(sequence, 0);
- __pyx_t_1 = PyTuple_GET_ITEM(sequence, 1);
- } else {
- __pyx_t_2 = PyList_GET_ITEM(sequence, 0);
- __pyx_t_1 = PyList_GET_ITEM(sequence, 1);
- }
- __Pyx_INCREF(__pyx_t_2);
- __Pyx_INCREF(__pyx_t_1);
- #else
- __pyx_t_2 = PySequence_ITEM(sequence, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 297, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_1 = PySequence_ITEM(sequence, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 297, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- #endif
- } else {
- Py_ssize_t index = -1;
- __pyx_t_3 = PyObject_GetIter(__pyx_v_dst); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 297, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext;
- index = 0; __pyx_t_2 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_2)) goto __pyx_L5_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_2);
- index = 1; __pyx_t_1 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_1)) goto __pyx_L5_unpacking_failed;
- __Pyx_GOTREF(__pyx_t_1);
- if (__Pyx_IternextUnpackEndCheck(__pyx_t_4(__pyx_t_3), 2) < 0) __PYX_ERR(0, 297, __pyx_L1_error)
- __pyx_t_4 = NULL;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- goto __pyx_L6_unpacking_done;
- __pyx_L5_unpacking_failed:;
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_4 = NULL;
- if (__Pyx_IterFinish() == 0) __Pyx_RaiseNeedMoreValuesError(index);
- __PYX_ERR(0, 297, __pyx_L1_error)
- __pyx_L6_unpacking_done:;
- }
- __pyx_t_6 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_6 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 297, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_5 = __pyx_PyFloat_AsFloat(__pyx_t_1); if (unlikely((__pyx_t_5 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 297, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_v_dst_row = __pyx_t_6;
- __pyx_v_dst_col = __pyx_t_5;
-
- /* "silx/image/bilinear.pyx":298
- * src_row, src_col = src
- * dst_row, dst_col = dst
- * if (src_row == dst_row) and (src_col == dst_col): # <<<<<<<<<<<<<<
- * logger.warning("Source and destination points are the same")
- * return numpy.array([self.c_funct(src_col, src_row)])
- */
- __pyx_t_8 = ((__pyx_v_src_row == __pyx_v_dst_row) != 0);
- if (__pyx_t_8) {
- } else {
- __pyx_t_7 = __pyx_t_8;
- goto __pyx_L8_bool_binop_done;
- }
- __pyx_t_8 = ((__pyx_v_src_col == __pyx_v_dst_col) != 0);
- __pyx_t_7 = __pyx_t_8;
- __pyx_L8_bool_binop_done:;
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":299
- * dst_row, dst_col = dst
- * if (src_row == dst_row) and (src_col == dst_col):
- * logger.warning("Source and destination points are the same") # <<<<<<<<<<<<<<
- * return numpy.array([self.c_funct(src_col, src_row)])
- * d_row = dst_row - src_row
- */
- __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_logger); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 299, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_warning); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 299, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
- __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
- if (likely(__pyx_t_2)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
- __Pyx_INCREF(__pyx_t_2);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_3, function);
- }
- }
- __pyx_t_1 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_2, __pyx_kp_u_Source_and_destination_points_ar) : __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_kp_u_Source_and_destination_points_ar);
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 299, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
-
- /* "silx/image/bilinear.pyx":300
- * if (src_row == dst_row) and (src_col == dst_col):
- * logger.warning("Source and destination points are the same")
- * return numpy.array([self.c_funct(src_col, src_row)]) # <<<<<<<<<<<<<<
- * d_row = dst_row - src_row
- * d_col = dst_col - src_col
- */
- __Pyx_XDECREF(__pyx_r);
- __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_numpy); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 300, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_array); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 300, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __pyx_t_3 = PyFloat_FromDouble(((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_funct(__pyx_v_self, __pyx_v_src_col, __pyx_v_src_row)); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 300, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_9 = PyList_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 300, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __Pyx_GIVEREF(__pyx_t_3);
- PyList_SET_ITEM(__pyx_t_9, 0, __pyx_t_3);
- __pyx_t_3 = 0;
- __pyx_t_3 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
- __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_2);
- if (likely(__pyx_t_3)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
- __Pyx_INCREF(__pyx_t_3);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_2, function);
- }
- }
- __pyx_t_1 = (__pyx_t_3) ? __Pyx_PyObject_Call2Args(__pyx_t_2, __pyx_t_3, __pyx_t_9) : __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_9);
- __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 300, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":298
- * src_row, src_col = src
- * dst_row, dst_col = dst
- * if (src_row == dst_row) and (src_col == dst_col): # <<<<<<<<<<<<<<
- * logger.warning("Source and destination points are the same")
- * return numpy.array([self.c_funct(src_col, src_row)])
- */
- }
-
- /* "silx/image/bilinear.pyx":301
- * logger.warning("Source and destination points are the same")
- * return numpy.array([self.c_funct(src_col, src_row)])
- * d_row = dst_row - src_row # <<<<<<<<<<<<<<
- * d_col = dst_col - src_col
- *
- */
- __pyx_v_d_row = (__pyx_v_dst_row - __pyx_v_src_row);
-
- /* "silx/image/bilinear.pyx":302
- * return numpy.array([self.c_funct(src_col, src_row)])
- * d_row = dst_row - src_row
- * d_col = dst_col - src_col # <<<<<<<<<<<<<<
- *
- * # Offsets to deal with linewidth
- */
- __pyx_v_d_col = (__pyx_v_dst_col - __pyx_v_src_col);
-
- /* "silx/image/bilinear.pyx":305
- *
- * # Offsets to deal with linewidth
- * length = sqrt(d_row * d_row + d_col * d_col) # <<<<<<<<<<<<<<
- * row_width = d_col / length
- * col_width = - d_row / length
- */
- __pyx_v_length = sqrt(((__pyx_v_d_row * __pyx_v_d_row) + (__pyx_v_d_col * __pyx_v_d_col)));
-
- /* "silx/image/bilinear.pyx":306
- * # Offsets to deal with linewidth
- * length = sqrt(d_row * d_row + d_col * d_col)
- * row_width = d_col / length # <<<<<<<<<<<<<<
- * col_width = - d_row / length
- *
- */
- if (unlikely(__pyx_v_length == 0)) {
- PyErr_SetString(PyExc_ZeroDivisionError, "float division");
- __PYX_ERR(0, 306, __pyx_L1_error)
- }
- __pyx_v_row_width = (__pyx_v_d_col / __pyx_v_length);
-
- /* "silx/image/bilinear.pyx":307
- * length = sqrt(d_row * d_row + d_col * d_col)
- * row_width = d_col / length
- * col_width = - d_row / length # <<<<<<<<<<<<<<
- *
- * lengt = <int> ceil(length + 1)
- */
- __pyx_t_5 = (-__pyx_v_d_row);
- if (unlikely(__pyx_v_length == 0)) {
- PyErr_SetString(PyExc_ZeroDivisionError, "float division");
- __PYX_ERR(0, 307, __pyx_L1_error)
- }
- __pyx_v_col_width = (__pyx_t_5 / __pyx_v_length);
-
- /* "silx/image/bilinear.pyx":309
- * col_width = - d_row / length
- *
- * lengt = <int> ceil(length + 1) # <<<<<<<<<<<<<<
- * d_row /= <float> (lengt -1)
- * d_col /= <float> (lengt -1)
- */
- __pyx_v_lengt = ((int)ceil((__pyx_v_length + 1.0)));
-
- /* "silx/image/bilinear.pyx":310
- *
- * lengt = <int> ceil(length + 1)
- * d_row /= <float> (lengt -1) # <<<<<<<<<<<<<<
- * d_col /= <float> (lengt -1)
- *
- */
- __pyx_t_5 = ((float)(__pyx_v_lengt - 1));
- if (unlikely(__pyx_t_5 == 0)) {
- PyErr_SetString(PyExc_ZeroDivisionError, "float division");
- __PYX_ERR(0, 310, __pyx_L1_error)
- }
- __pyx_v_d_row = (__pyx_v_d_row / __pyx_t_5);
-
- /* "silx/image/bilinear.pyx":311
- * lengt = <int> ceil(length + 1)
- * d_row /= <float> (lengt -1)
- * d_col /= <float> (lengt -1) # <<<<<<<<<<<<<<
- *
- * result = numpy.zeros(lengt, dtype=numpy.float32)
- */
- __pyx_t_5 = ((float)(__pyx_v_lengt - 1));
- if (unlikely(__pyx_t_5 == 0)) {
- PyErr_SetString(PyExc_ZeroDivisionError, "float division");
- __PYX_ERR(0, 311, __pyx_L1_error)
- }
- __pyx_v_d_col = (__pyx_v_d_col / __pyx_t_5);
-
- /* "silx/image/bilinear.pyx":313
- * d_col /= <float> (lengt -1)
- *
- * result = numpy.zeros(lengt, dtype=numpy.float32) # <<<<<<<<<<<<<<
- *
- * # Offset position to the center of the bottom pixels of the profile
- */
- __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_zeros); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_2);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_lengt); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = PyTuple_New(1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __Pyx_GIVEREF(__pyx_t_1);
- PyTuple_SET_ITEM(__pyx_t_9, 0, __pyx_t_1);
- __pyx_t_1 = 0;
- __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_n_s_numpy); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_float32); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- if (PyDict_SetItem(__pyx_t_1, __pyx_n_s_dtype, __pyx_t_10) < 0) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_9, __pyx_t_1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_dc_float(__pyx_t_10, PyBUF_WRITABLE); if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 313, __pyx_L1_error)
- __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0;
- __pyx_v_result = __pyx_t_11;
- __pyx_t_11.memview = NULL;
- __pyx_t_11.data = NULL;
-
- /* "silx/image/bilinear.pyx":316
- *
- * # Offset position to the center of the bottom pixels of the profile
- * src_row -= row_width * (linewidth - 1) / 2. # <<<<<<<<<<<<<<
- * src_col -= col_width * (linewidth - 1) / 2.
- *
- */
- __pyx_v_src_row = (__pyx_v_src_row - (((double)(__pyx_v_row_width * (__pyx_v_linewidth - 1))) / 2.));
-
- /* "silx/image/bilinear.pyx":317
- * # Offset position to the center of the bottom pixels of the profile
- * src_row -= row_width * (linewidth - 1) / 2.
- * src_col -= col_width * (linewidth - 1) / 2. # <<<<<<<<<<<<<<
- *
- * compute_mean = (method == 'mean')
- */
- __pyx_v_src_col = (__pyx_v_src_col - (((double)(__pyx_v_col_width * (__pyx_v_linewidth - 1))) / 2.));
-
- /* "silx/image/bilinear.pyx":319
- * src_col -= col_width * (linewidth - 1) / 2.
- *
- * compute_mean = (method == 'mean') # <<<<<<<<<<<<<<
- * with nogil:
- * for i in range(lengt):
- */
- __pyx_t_10 = PyObject_RichCompare(__pyx_v_method, __pyx_n_u_mean, Py_EQ); __Pyx_XGOTREF(__pyx_t_10); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 319, __pyx_L1_error)
- __pyx_v_compute_mean = __pyx_t_10;
- __pyx_t_10 = 0;
-
- /* "silx/image/bilinear.pyx":320
- *
- * compute_mean = (method == 'mean')
- * with nogil: # <<<<<<<<<<<<<<
- * for i in range(lengt):
- * sum = 0
- */
- {
- #ifdef WITH_THREAD
- PyThreadState *_save;
- Py_UNBLOCK_THREADS
- __Pyx_FastGIL_Remember();
- #endif
- /*try:*/ {
-
- /* "silx/image/bilinear.pyx":321
- * compute_mean = (method == 'mean')
- * with nogil:
- * for i in range(lengt): # <<<<<<<<<<<<<<
- * sum = 0
- * cnt = 0
- */
- __pyx_t_12 = __pyx_v_lengt;
- __pyx_t_13 = __pyx_t_12;
- for (__pyx_t_14 = 0; __pyx_t_14 < __pyx_t_13; __pyx_t_14+=1) {
- __pyx_v_i = __pyx_t_14;
-
- /* "silx/image/bilinear.pyx":322
- * with nogil:
- * for i in range(lengt):
- * sum = 0 # <<<<<<<<<<<<<<
- * cnt = 0
- *
- */
- __pyx_v_sum = 0.0;
-
- /* "silx/image/bilinear.pyx":323
- * for i in range(lengt):
- * sum = 0
- * cnt = 0 # <<<<<<<<<<<<<<
- *
- * row = src_row + i * d_row
- */
- __pyx_v_cnt = 0;
-
- /* "silx/image/bilinear.pyx":325
- * cnt = 0
- *
- * row = src_row + i * d_row # <<<<<<<<<<<<<<
- * col = src_col + i * d_col
- *
- */
- __pyx_v_row = (__pyx_v_src_row + (__pyx_v_i * __pyx_v_d_row));
-
- /* "silx/image/bilinear.pyx":326
- *
- * row = src_row + i * d_row
- * col = src_col + i * d_col # <<<<<<<<<<<<<<
- *
- * for j in range(linewidth):
- */
- __pyx_v_col = (__pyx_v_src_col + (__pyx_v_i * __pyx_v_d_col));
-
- /* "silx/image/bilinear.pyx":328
- * col = src_col + i * d_col
- *
- * for j in range(linewidth): # <<<<<<<<<<<<<<
- * new_row = row + j * row_width
- * new_col = col + j * col_width
- */
- __pyx_t_15 = __pyx_v_linewidth;
- __pyx_t_16 = __pyx_t_15;
- for (__pyx_t_17 = 0; __pyx_t_17 < __pyx_t_16; __pyx_t_17+=1) {
- __pyx_v_j = __pyx_t_17;
-
- /* "silx/image/bilinear.pyx":329
- *
- * for j in range(linewidth):
- * new_row = row + j * row_width # <<<<<<<<<<<<<<
- * new_col = col + j * col_width
- * if ((new_col >= 0) and (new_col < self.width) and
- */
- __pyx_v_new_row = (__pyx_v_row + (__pyx_v_j * __pyx_v_row_width));
-
- /* "silx/image/bilinear.pyx":330
- * for j in range(linewidth):
- * new_row = row + j * row_width
- * new_col = col + j * col_width # <<<<<<<<<<<<<<
- * if ((new_col >= 0) and (new_col < self.width) and
- * (new_row >= 0) and (new_row < self.height)):
- */
- __pyx_v_new_col = (__pyx_v_col + (__pyx_v_j * __pyx_v_col_width));
-
- /* "silx/image/bilinear.pyx":331
- * new_row = row + j * row_width
- * new_col = col + j * col_width
- * if ((new_col >= 0) and (new_col < self.width) and # <<<<<<<<<<<<<<
- * (new_row >= 0) and (new_row < self.height)):
- * cnt = cnt + 1
- */
- __pyx_t_8 = ((__pyx_v_new_col >= 0.0) != 0);
- if (__pyx_t_8) {
- } else {
- __pyx_t_7 = __pyx_t_8;
- goto __pyx_L18_bool_binop_done;
- }
- __pyx_t_8 = ((__pyx_v_new_col < __pyx_v_self->width) != 0);
- if (__pyx_t_8) {
- } else {
- __pyx_t_7 = __pyx_t_8;
- goto __pyx_L18_bool_binop_done;
- }
-
- /* "silx/image/bilinear.pyx":332
- * new_col = col + j * col_width
- * if ((new_col >= 0) and (new_col < self.width) and
- * (new_row >= 0) and (new_row < self.height)): # <<<<<<<<<<<<<<
- * cnt = cnt + 1
- * sum = sum + self.c_funct(new_col, new_row)
- */
- __pyx_t_8 = ((__pyx_v_new_row >= 0.0) != 0);
- if (__pyx_t_8) {
- } else {
- __pyx_t_7 = __pyx_t_8;
- goto __pyx_L18_bool_binop_done;
- }
- __pyx_t_8 = ((__pyx_v_new_row < __pyx_v_self->height) != 0);
- __pyx_t_7 = __pyx_t_8;
- __pyx_L18_bool_binop_done:;
-
- /* "silx/image/bilinear.pyx":331
- * new_row = row + j * row_width
- * new_col = col + j * col_width
- * if ((new_col >= 0) and (new_col < self.width) and # <<<<<<<<<<<<<<
- * (new_row >= 0) and (new_row < self.height)):
- * cnt = cnt + 1
- */
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":333
- * if ((new_col >= 0) and (new_col < self.width) and
- * (new_row >= 0) and (new_row < self.height)):
- * cnt = cnt + 1 # <<<<<<<<<<<<<<
- * sum = sum + self.c_funct(new_col, new_row)
- * if cnt:
- */
- __pyx_v_cnt = (__pyx_v_cnt + 1);
-
- /* "silx/image/bilinear.pyx":334
- * (new_row >= 0) and (new_row < self.height)):
- * cnt = cnt + 1
- * sum = sum + self.c_funct(new_col, new_row) # <<<<<<<<<<<<<<
- * if cnt:
- * if compute_mean is True:
- */
- __pyx_v_sum = (__pyx_v_sum + ((struct __pyx_vtabstruct_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self->__pyx_vtab)->c_funct(__pyx_v_self, __pyx_v_new_col, __pyx_v_new_row));
-
- /* "silx/image/bilinear.pyx":331
- * new_row = row + j * row_width
- * new_col = col + j * col_width
- * if ((new_col >= 0) and (new_col < self.width) and # <<<<<<<<<<<<<<
- * (new_row >= 0) and (new_row < self.height)):
- * cnt = cnt + 1
- */
- }
- }
-
- /* "silx/image/bilinear.pyx":335
- * cnt = cnt + 1
- * sum = sum + self.c_funct(new_col, new_row)
- * if cnt: # <<<<<<<<<<<<<<
- * if compute_mean is True:
- * result[i] += sum / cnt
- */
- __pyx_t_7 = (__pyx_v_cnt != 0);
- if (__pyx_t_7) {
-
- /* "silx/image/bilinear.pyx":336
- * sum = sum + self.c_funct(new_col, new_row)
- * if cnt:
- * if compute_mean is True: # <<<<<<<<<<<<<<
- * result[i] += sum / cnt
- * else:
- */
- __pyx_t_7 = (__pyx_v_compute_mean == Py_True);
- __pyx_t_8 = (__pyx_t_7 != 0);
- if (__pyx_t_8) {
-
- /* "silx/image/bilinear.pyx":337
- * if cnt:
- * if compute_mean is True:
- * result[i] += sum / cnt # <<<<<<<<<<<<<<
- * else:
- * result[i] += sum
- */
- if (unlikely(__pyx_v_cnt == 0)) {
- #ifdef WITH_THREAD
- PyGILState_STATE __pyx_gilstate_save = __Pyx_PyGILState_Ensure();
- #endif
- PyErr_SetString(PyExc_ZeroDivisionError, "float division");
- #ifdef WITH_THREAD
- __Pyx_PyGILState_Release(__pyx_gilstate_save);
- #endif
- __PYX_ERR(0, 337, __pyx_L11_error)
- }
- __pyx_t_18 = __pyx_v_i;
- if (__pyx_t_18 < 0) __pyx_t_18 += __pyx_v_result.shape[0];
- *((float *) ( /* dim=0 */ ((char *) (((float *) __pyx_v_result.data) + __pyx_t_18)) )) += (__pyx_v_sum / ((float)__pyx_v_cnt));
-
- /* "silx/image/bilinear.pyx":336
- * sum = sum + self.c_funct(new_col, new_row)
- * if cnt:
- * if compute_mean is True: # <<<<<<<<<<<<<<
- * result[i] += sum / cnt
- * else:
- */
- goto __pyx_L23;
- }
-
- /* "silx/image/bilinear.pyx":339
- * result[i] += sum / cnt
- * else:
- * result[i] += sum # <<<<<<<<<<<<<<
- *
- * # Ensures the result is exported as numpy array and not memory view.
- */
- /*else*/ {
- __pyx_t_19 = __pyx_v_i;
- if (__pyx_t_19 < 0) __pyx_t_19 += __pyx_v_result.shape[0];
- *((float *) ( /* dim=0 */ ((char *) (((float *) __pyx_v_result.data) + __pyx_t_19)) )) += __pyx_v_sum;
- }
- __pyx_L23:;
-
- /* "silx/image/bilinear.pyx":335
- * cnt = cnt + 1
- * sum = sum + self.c_funct(new_col, new_row)
- * if cnt: # <<<<<<<<<<<<<<
- * if compute_mean is True:
- * result[i] += sum / cnt
- */
- }
- }
- }
-
- /* "silx/image/bilinear.pyx":320
- *
- * compute_mean = (method == 'mean')
- * with nogil: # <<<<<<<<<<<<<<
- * for i in range(lengt):
- * sum = 0
- */
- /*finally:*/ {
- /*normal exit:*/{
- #ifdef WITH_THREAD
- __Pyx_FastGIL_Forget();
- Py_BLOCK_THREADS
- #endif
- goto __pyx_L12;
- }
- __pyx_L11_error: {
- #ifdef WITH_THREAD
- __Pyx_FastGIL_Forget();
- Py_BLOCK_THREADS
- #endif
- goto __pyx_L1_error;
- }
- __pyx_L12:;
- }
- }
-
- /* "silx/image/bilinear.pyx":342
- *
- * # Ensures the result is exported as numpy array and not memory view.
- * return numpy.asarray(result) # <<<<<<<<<<<<<<
- */
- __Pyx_XDECREF(__pyx_r);
- __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_n_s_numpy); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 342, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_asarray); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 342, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_9);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_result, 1, (PyObject *(*)(char *)) __pyx_memview_get_float, (int (*)(char *, PyObject *)) __pyx_memview_set_float, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 342, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_t_2 = NULL;
- if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_9))) {
- __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_9);
- if (likely(__pyx_t_2)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_9);
- __Pyx_INCREF(__pyx_t_2);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_9, function);
- }
- }
- __pyx_t_10 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_9, __pyx_t_2, __pyx_t_1) : __Pyx_PyObject_CallOneArg(__pyx_t_9, __pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 342, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_10);
- __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
- __pyx_r = __pyx_t_10;
- __pyx_t_10 = 0;
- goto __pyx_L0;
-
- /* "silx/image/bilinear.pyx":271
- *
- * @cython.boundscheck(False)
- * def profile_line(self, src, dst, int linewidth=1, method='mean'): # <<<<<<<<<<<<<<
- * """Return the mean or sum of intensity profile of an image measured
- * along a scan line.
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_XDECREF(__pyx_t_2);
- __Pyx_XDECREF(__pyx_t_3);
- __Pyx_XDECREF(__pyx_t_9);
- __Pyx_XDECREF(__pyx_t_10);
- __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.profile_line", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __PYX_XDEC_MEMVIEW(&__pyx_v_result, 1);
- __Pyx_XDECREF(__pyx_v_compute_mean);
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":43
- * """
- * cdef:
- * readonly float[:, ::1] data # <<<<<<<<<<<<<<
- * readonly float maxi, mini
- * readonly size_t width, height
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4data_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4data_1__get__(PyObject *__pyx_v_self) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_4data___get__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4data___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__get__", 0);
- __Pyx_XDECREF(__pyx_r);
- if (unlikely(!__pyx_v_self->data.memview)) {PyErr_SetString(PyExc_AttributeError,"Memoryview is not initialized");__PYX_ERR(0, 43, __pyx_L1_error)}
- __pyx_t_1 = __pyx_memoryview_fromslice(__pyx_v_self->data, 2, (PyObject *(*)(char *)) __pyx_memview_get_float, (int (*)(char *, PyObject *)) __pyx_memview_set_float, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 43, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.data.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":44
- * cdef:
- * readonly float[:, ::1] data
- * readonly float maxi, mini # <<<<<<<<<<<<<<
- * readonly size_t width, height
- *
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4maxi_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4maxi_1__get__(PyObject *__pyx_v_self) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_4maxi___get__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4maxi___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__get__", 0);
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->maxi); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 44, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.maxi.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4mini_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_4mini_1__get__(PyObject *__pyx_v_self) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_4mini___get__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_4mini___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__get__", 0);
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = PyFloat_FromDouble(__pyx_v_self->mini); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 44, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.mini.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "silx/image/bilinear.pyx":45
- * readonly float[:, ::1] data
- * readonly float maxi, mini
- * readonly size_t width, height # <<<<<<<<<<<<<<
- *
- * cpdef size_t coarse_local_maxi(self, size_t)
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_5width_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_5width_1__get__(PyObject *__pyx_v_self) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_5width___get__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_5width___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__get__", 0);
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_FromSize_t(__pyx_v_self->width); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.width.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_6height_1__get__(PyObject *__pyx_v_self); /*proto*/
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_6height_1__get__(PyObject *__pyx_v_self) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__get__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_6height___get__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_6height___get__(struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__get__", 0);
- __Pyx_XDECREF(__pyx_r);
- __pyx_t_1 = __Pyx_PyInt_FromSize_t(__pyx_v_self->height); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 45, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __pyx_r = __pyx_t_1;
- __pyx_t_1 = 0;
- goto __pyx_L0;
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.height.__get__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __pyx_L0:;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "(tree fragment)":1
- * def __reduce_cython__(self): # <<<<<<<<<<<<<<
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- * def __setstate_cython__(self, __pyx_state):
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_17__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_16__reduce_cython__[] = "BilinearImage.__reduce_cython__(self)";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_17__reduce_cython__(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__reduce_cython__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_16__reduce_cython__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_16__reduce_cython__(CYTHON_UNUSED struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__reduce_cython__", 0);
-
- /* "(tree fragment)":2
- * def __reduce_cython__(self):
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<<
- * def __setstate_cython__(self, __pyx_state):
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- */
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple_, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 2, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_Raise(__pyx_t_1, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(1, 2, __pyx_L1_error)
-
- /* "(tree fragment)":1
- * def __reduce_cython__(self): # <<<<<<<<<<<<<<
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- * def __setstate_cython__(self, __pyx_state):
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__reduce_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "(tree fragment)":3
- * def __reduce_cython__(self):
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<<
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- */
-
-/* Python wrapper */
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_19__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state); /*proto*/
-static char __pyx_doc_4silx_5image_8bilinear_13BilinearImage_18__setstate_cython__[] = "BilinearImage.__setstate_cython__(self, __pyx_state)";
-static PyObject *__pyx_pw_4silx_5image_8bilinear_13BilinearImage_19__setstate_cython__(PyObject *__pyx_v_self, PyObject *__pyx_v___pyx_state) {
- PyObject *__pyx_r = 0;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__setstate_cython__ (wrapper)", 0);
- __pyx_r = __pyx_pf_4silx_5image_8bilinear_13BilinearImage_18__setstate_cython__(((struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *)__pyx_v_self), ((PyObject *)__pyx_v___pyx_state));
-
- /* function exit code */
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static PyObject *__pyx_pf_4silx_5image_8bilinear_13BilinearImage_18__setstate_cython__(CYTHON_UNUSED struct __pyx_obj_4silx_5image_8bilinear_BilinearImage *__pyx_v_self, CYTHON_UNUSED PyObject *__pyx_v___pyx_state) {
- PyObject *__pyx_r = NULL;
- __Pyx_RefNannyDeclarations
- PyObject *__pyx_t_1 = NULL;
- __Pyx_RefNannySetupContext("__setstate_cython__", 0);
-
- /* "(tree fragment)":4
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- * def __setstate_cython__(self, __pyx_state):
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__") # <<<<<<<<<<<<<<
- */
- __pyx_t_1 = __Pyx_PyObject_Call(__pyx_builtin_TypeError, __pyx_tuple__2, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(1, 4, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_1);
- __Pyx_Raise(__pyx_t_1, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
- __PYX_ERR(1, 4, __pyx_L1_error)
-
- /* "(tree fragment)":3
- * def __reduce_cython__(self):
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- * def __setstate_cython__(self, __pyx_state): # <<<<<<<<<<<<<<
- * raise TypeError("no default __reduce__ due to non-trivial __cinit__")
- */
-
- /* function exit code */
- __pyx_L1_error:;
- __Pyx_XDECREF(__pyx_t_1);
- __Pyx_AddTraceback("silx.image.bilinear.BilinearImage.__setstate_cython__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __pyx_r = NULL;
- __Pyx_XGIVEREF(__pyx_r);
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-/* "View.MemoryView":122
- * cdef bint dtype_is_object
- *
- * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<<
- * mode="c", bint allocate_buffer=True):
- *
- */
-
-/* Python wrapper */
-static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static int __pyx_array___cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
- PyObject *__pyx_v_shape = 0;
- Py_ssize_t __pyx_v_itemsize;
- PyObject *__pyx_v_format = 0;
- PyObject *__pyx_v_mode = 0;
- int __pyx_v_allocate_buffer;
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- __Pyx_RefNannySetupContext("__cinit__ (wrapper)", 0);
- {
- static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_shape,&__pyx_n_s_itemsize,&__pyx_n_s_format,&__pyx_n_s_mode,&__pyx_n_s_allocate_buffer,0};
- PyObject* values[5] = {0,0,0,0,0};
- values[3] = ((PyObject *)__pyx_n_s_c);
- if (unlikely(__pyx_kwds)) {
- Py_ssize_t kw_args;
- const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
- switch (pos_args) {
- case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
- CYTHON_FALLTHROUGH;
- case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
- CYTHON_FALLTHROUGH;
- case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
- CYTHON_FALLTHROUGH;
- case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
- CYTHON_FALLTHROUGH;
- case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- CYTHON_FALLTHROUGH;
- case 0: break;
- default: goto __pyx_L5_argtuple_error;
- }
- kw_args = PyDict_Size(__pyx_kwds);
- switch (pos_args) {
- case 0:
- if (likely((values[0] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_shape)) != 0)) kw_args--;
- else goto __pyx_L5_argtuple_error;
- CYTHON_FALLTHROUGH;
- case 1:
- if (likely((values[1] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_itemsize)) != 0)) kw_args--;
- else {
- __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 1); __PYX_ERR(1, 122, __pyx_L3_error)
- }
- CYTHON_FALLTHROUGH;
- case 2:
- if (likely((values[2] = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_format)) != 0)) kw_args--;
- else {
- __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, 2); __PYX_ERR(1, 122, __pyx_L3_error)
- }
- CYTHON_FALLTHROUGH;
- case 3:
- if (kw_args > 0) {
- PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_mode);
- if (value) { values[3] = value; kw_args--; }
- }
- CYTHON_FALLTHROUGH;
- case 4:
- if (kw_args > 0) {
- PyObject* value = __Pyx_PyDict_GetItemStr(__pyx_kwds, __pyx_n_s_allocate_buffer);
- if (value) { values[4] = value; kw_args--; }
- }
- }
- if (unlikely(kw_args > 0)) {
- if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "__cinit__") < 0)) __PYX_ERR(1, 122, __pyx_L3_error)
- }
- } else {
- switch (PyTuple_GET_SIZE(__pyx_args)) {
- case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
- CYTHON_FALLTHROUGH;
- case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
- CYTHON_FALLTHROUGH;
- case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
- values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
- values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
- break;
- default: goto __pyx_L5_argtuple_error;
- }
- }
- __pyx_v_shape = ((PyObject*)values[0]);
- __pyx_v_itemsize = __Pyx_PyIndex_AsSsize_t(values[1]); if (unlikely((__pyx_v_itemsize == (Py_ssize_t)-1) && PyErr_Occurred())) __PYX_ERR(1, 122, __pyx_L3_error)
- __pyx_v_format = values[2];
- __pyx_v_mode = values[3];
- if (values[4]) {
- __pyx_v_allocate_buffer = __Pyx_PyObject_IsTrue(values[4]); if (unlikely((__pyx_v_allocate_buffer == (int)-1) && PyErr_Occurred())) __PYX_ERR(1, 123, __pyx_L3_error)
- } else {
-
- /* "View.MemoryView":123
- *
- * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None,
- * mode="c", bint allocate_buffer=True): # <<<<<<<<<<<<<<
- *
- * cdef int idx
- */
- __pyx_v_allocate_buffer = ((int)1);
- }
- }
- goto __pyx_L4_argument_unpacking_done;
- __pyx_L5_argtuple_error:;
- __Pyx_RaiseArgtupleInvalid("__cinit__", 0, 3, 5, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(1, 122, __pyx_L3_error)
- __pyx_L3_error:;
- __Pyx_AddTraceback("View.MemoryView.array.__cinit__", __pyx_clineno, __pyx_lineno, __pyx_filename);
- __Pyx_RefNannyFinishContext();
- return -1;
- __pyx_L4_argument_unpacking_done:;
- if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_shape), (&PyTuple_Type), 1, "shape", 1))) __PYX_ERR(1, 122, __pyx_L1_error)
- if (unlikely(((PyObject *)__pyx_v_format) == Py_None)) {
- PyErr_Format(PyExc_TypeError, "Argument '%.200s' must not be None", "format"); __PYX_ERR(1, 122, __pyx_L1_error)
- }
- __pyx_r = __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(((struct __pyx_array_obj *)__pyx_v_self), __pyx_v_shape, __pyx_v_itemsize, __pyx_v_format, __pyx_v_mode, __pyx_v_allocate_buffer);
-
- /* "View.MemoryView":122
- * cdef bint dtype_is_object
- *
- * def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None, # <<<<<<<<<<<<<<
- * mode="c", bint allocate_buffer=True):
- *
- */
-
- /* function exit code */
- goto __pyx_L0;
- __pyx_L1_error:;
- __pyx_r = -1;
- __pyx_L0:;
- __Pyx_RefNannyFinishContext();
- return __pyx_r;
-}
-
-static int __pyx_array___pyx_pf_15View_dot_MemoryView_5array___cinit__(struct __pyx_array_obj *__pyx_v_self, PyObject *__pyx_v_shape, Py_ssize_t __pyx_v_itemsize, PyObject *__pyx_v_format, PyObject *__pyx_v_mode, int __pyx_v_allocate_buffer) {
- int __pyx_v_idx;
- Py_ssize_t __pyx_v_i;
- Py_ssize_t __pyx_v_dim;
- PyObject **__pyx_v_p;
- char __pyx_v_order;
- int __pyx_r;
- __Pyx_RefNannyDeclarations
- Py_ssize_t __pyx_t_1;
- int __pyx_t_2;
- PyObject *__pyx_t_3 = NULL;
- int __pyx_t_4;
- PyObject *__pyx_t_5 = NULL;
- PyObject *__pyx_t_6 = NULL;
- char *__pyx_t_7;
- int __pyx_t_8;
- Py_ssize_t __pyx_t_9;
- PyObject *__pyx_t_10 = NULL;
- Py_ssize_t __pyx_t_11;
- __Pyx_RefNannySetupContext("__cinit__", 0);
- __Pyx_INCREF(__pyx_v_format);
-
- /* "View.MemoryView":129
- * cdef PyObject **p
- *
- * self.ndim = <int> len(shape) # <<<<<<<<<<<<<<
- * self.itemsize = itemsize
- *
- */
- if (unlikely(__pyx_v_shape == Py_None)) {
- PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()");
- __PYX_ERR(1, 129, __pyx_L1_error)
- }
- __pyx_t_1 = PyTuple_GET_SIZE(__pyx_v_shape); if (unlikely(__pyx_t_1 == ((Py_ssize_t)-1))) __PYX_ERR(1, 129, __pyx_L1_error)
- __pyx_v_self->ndim = ((int)__pyx_t_1);
-
- /* "View.MemoryView":130
- *
- * self.ndim = <int> len(shape)
- * self.itemsize = itemsize # <<<<<<<<<<<<<<
- *
- * if not self.ndim:
- */
- __pyx_v_self->itemsize = __pyx_v_itemsize;
-
- /* "View.MemoryView":132
- * self.itemsize = itemsize
- *
- * if not self.ndim: # <<<<<<<<<<<<<<
- * raise ValueError("Empty shape tuple for cython.array")
- *
- */
- __pyx_t_2 = ((!(__pyx_v_self->ndim != 0)) != 0);
- if (unlikely(__pyx_t_2)) {
-
- /* "View.MemoryView":133
- *
- * if not self.ndim:
- * raise ValueError("Empty shape tuple for cython.array") # <<<<<<<<<<<<<<
- *
- * if itemsize <= 0:
- */
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__3, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 133, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_Raise(__pyx_t_3, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 133, __pyx_L1_error)
-
- /* "View.MemoryView":132
- * self.itemsize = itemsize
- *
- * if not self.ndim: # <<<<<<<<<<<<<<
- * raise ValueError("Empty shape tuple for cython.array")
- *
- */
- }
-
- /* "View.MemoryView":135
- * raise ValueError("Empty shape tuple for cython.array")
- *
- * if itemsize <= 0: # <<<<<<<<<<<<<<
- * raise ValueError("itemsize <= 0 for cython.array")
- *
- */
- __pyx_t_2 = ((__pyx_v_itemsize <= 0) != 0);
- if (unlikely(__pyx_t_2)) {
-
- /* "View.MemoryView":136
- *
- * if itemsize <= 0:
- * raise ValueError("itemsize <= 0 for cython.array") # <<<<<<<<<<<<<<
- *
- * if not isinstance(format, bytes):
- */
- __pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_ValueError, __pyx_tuple__4, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 136, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_Raise(__pyx_t_3, 0, 0, 0);
- __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
- __PYX_ERR(1, 136, __pyx_L1_error)
-
- /* "View.MemoryView":135
- * raise ValueError("Empty shape tuple for cython.array")
- *
- * if itemsize <= 0: # <<<<<<<<<<<<<<
- * raise ValueError("itemsize <= 0 for cython.array")
- *
- */
- }
-
- /* "View.MemoryView":138
- * raise ValueError("itemsize <= 0 for cython.array")
- *
- * if not isinstance(format, bytes): # <<<<<<<<<<<<<<
- * format = format.encode('ASCII')
- * self._format = format # keep a reference to the byte string
- */
- __pyx_t_2 = PyBytes_Check(__pyx_v_format);
- __pyx_t_4 = ((!(__pyx_t_2 != 0)) != 0);
- if (__pyx_t_4) {
-
- /* "View.MemoryView":139
- *
- * if not isinstance(format, bytes):
- * format = format.encode('ASCII') # <<<<<<<<<<<<<<
- * self._format = format # keep a reference to the byte string
- * self.format = self._format
- */
- __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_format, __pyx_n_s_encode); if (unlikely(!__pyx_t_5)) __PYX_ERR(1, 139, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_5);
- __pyx_t_6 = NULL;
- if (CYTHON_UNPACK_METHODS && likely(PyMethod_Check(__pyx_t_5))) {
- __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_5);
- if (likely(__pyx_t_6)) {
- PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
- __Pyx_INCREF(__pyx_t_6);
- __Pyx_INCREF(function);
- __Pyx_DECREF_SET(__pyx_t_5, function);
- }
- }
- __pyx_t_3 = (__pyx_t_6) ? __Pyx_PyObject_Call2Args(__pyx_t_5, __pyx_t_6, __pyx_n_s_ASCII) : __Pyx_PyObject_CallOneArg(__pyx_t_5, __pyx_n_s_ASCII);
- __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
- if (unlikely(!__pyx_t_3)) __PYX_ERR(1, 139, __pyx_L1_error)
- __Pyx_GOTREF(__pyx_t_3);
- __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
- __Pyx_DECREF_SET(__pyx_v_format, __pyx_t_3);
- __pyx_t_3 = 0;
-
- /* "View.MemoryView":138
- * raise ValueError("itemsize <= 0 for cython.array")
- *
- * if not isinstance(format, bytes): # <<<<<<<<<<<<<<
- * format = format.encode('ASCII')
- * self._format = format # keep a reference to the byte string
- */
- }
-
- /* "View.MemoryView":140
- * if not isinstance(format, bytes):
- * format = format.encode('ASCII')
- * self._format = format # keep a reference to the byte string # <<<<<<<<<<<<<<
- * self.format = self._format
- *
- */
- if (!(likely(PyBytes_CheckExact(__pyx_v_