summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-01-30 11:47:01 +0100
committerAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-01-30 11:47:01 +0100
commit867a81e9d35da6d95a11deaf0deb679e58abed66 (patch)
tree5ad6620b7e0f75c12144508e4252825f0b3a7fc3
parent4b9a78d3afad181b195ccfe5bf7f6b7c8fb6aa50 (diff)
parent33ed2a64c92b0311ae35456c016eb284e426afc2 (diff)
Update upstream source from tag 'upstream/0.12.0+dfsg'
Update to upstream version '0.12.0+dfsg' with Debian dir 3ea2a979401866ff2d55ac0090bf496c85038fcb
-rw-r--r--CHANGELOG.rst16
-rw-r--r--PKG-INFO2
-rw-r--r--doc/source/modules/gui/icons.rst18
-rw-r--r--examples/dropZones.py4
-rw-r--r--examples/fileDialog.py4
-rw-r--r--examples/plotStats.py3
-rw-r--r--silx.egg-info/PKG-INFO2
-rw-r--r--silx/app/view/main.py16
-rw-r--r--silx/gui/data/DataViewer.py2
-rw-r--r--silx/gui/dialog/ColormapDialog.py9
-rw-r--r--silx/gui/fit/FitWidget.py10
-rwxr-xr-xsilx/gui/plot/PlotWidget.py3
-rw-r--r--silx/gui/plot/ProfileMainWindow.py3
-rw-r--r--silx/gui/plot/StatsWidget.py33
-rwxr-xr-xsilx/gui/plot/backends/BackendMatplotlib.py23
-rw-r--r--silx/gui/plot/items/shape.py2
-rw-r--r--silx/gui/plot/tools/profile/_BaseProfileToolBar.py2
-rw-r--r--silx/gui/plot3d/tools/PositionInfoWidget.py2
-rw-r--r--silx/math/fit/fitmanager.py36
-rw-r--r--silx/math/fit/test/test_fitmanager.py87
-rw-r--r--silx/sx/_plot.py2
-rw-r--r--version.py4
22 files changed, 192 insertions, 91 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4fe299b..0777568 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,8 +1,8 @@
Change Log
==========
-0.12.0rc0: 2019/12/16
----------------------
+0.12.0: 2020/01/09
+------------------
Python 2.7 is no longer officially supported (even if tests pass and most of the library should work).
@@ -11,6 +11,7 @@ Python 2.7 is no longer officially supported (even if tests pass and most of the
* Added: keep the same axes selection when changing dataset except for the stack view (PR #2701, #2780)
* Added a Description column in the browsing tree to display NeXus title or name (PR #2804)
* Added support of URL as filename (PR #2750)
+ * Behavior changed: no longer lock HDF5 files by default, can be changed with `--hdf5-file-locking` option (PR #2861)
* `silx.gui`:
@@ -21,8 +22,8 @@ Python 2.7 is no longer officially supported (even if tests pass and most of the
* Added right axis support to `PlotWidget` marker items (PR #2744)
* Added `BoundingRect` `PlotWidget` item (PR #2823)
* Added more markers to `PlotWidget` items using symbols (PR #2792)
- * Improved and fixed `PlotWidget` and backends rendering and picking to guarantee rendering order of items (PR #2602, #2694, #2726, #2728, #2730, #2731, #2732, #2734, #2746, #2800, #2822, #2829)
- * Improved `RegionOfInterest`: Added `sigItemChanged` signal, renamed `get|setLabel` to `get|setName` (PR #2684, #2729, #2794, #2803)
+ * Improved and fixed `PlotWidget` and backends rendering and picking to guarantee rendering order of items (PR #2602, #2694, #2726, #2728, #2730, #2731, #2732, #2734, #2746, #2800, #2822, #2829, #2851, #2853)
+ * Improved `RegionOfInterest`: Added `sigItemChanged` signal, renamed `get|setLabel` to `get|setName` (PR #2684, #2729, #2794, #2803, #2860)
* Improved `StackView`: Allow to save dataset to HDF5 (PR #2813)
* `silx.gui.plot3d`:
@@ -37,7 +38,7 @@ Python 2.7 is no longer officially supported (even if tests pass and most of the
* Added `silx.gui.utils.blockSignals` context manager (PR #2697, #2702)
* Added `silx.gui.utils.qtutils.getQEventName` function (PR #2725)
* Added `silx.gui.colors.asQColor` function (PR #2753)
- * Minor fixes (PR #2662, #2667, #2674, #2719, #2724, #2747, #2757, #2760, #2766, #2789, #2798, #2799, #2805, #2811, #2832, #2834)
+ * Minor fixes (PR #2662, #2667, #2674, #2719, #2724, #2747, #2757, #2760, #2766, #2789, #2798, #2799, #2805, #2811, #2832, #2834, #2839, #2849, #2852, #2857, #2864, #2867)
* `silx.opencl`:
@@ -54,6 +55,7 @@ Python 2.7 is no longer officially supported (even if tests pass and most of the
* Added `silx.image.utils.gaussian_kernel` function (PR #2782)
* Improved `silx.image.shapes.Polygon` argument check (PR #2761)
* Fixed and improved `silx.math.fft` with FFTW backend (PR #2751)
+ * Fixed support of not finite data in fit manager (PR #2868)
* `silx.io`:
@@ -66,7 +68,9 @@ Python 2.7 is no longer officially supported (even if tests pass and most of the
* Added `Cython` as a build dependency (PR #2795, #2807, #2808)
* Added Debian 10 packaging (PR #2670, #2672, #2666, #2686, #2706)
- * Improvements: documentation (PR #2673, #2680, #2679, #2772, #2759, #2779, #2801, #2802, #2833), testing tools (PR #2704, #2796, #2818), `bootstrap.py` script (PR #2727, #2733)
+ * Improved documentation (PR #2673, #2680, #2679, #2772, #2759, #2779, #2801, #2802, #2833, #2857, #2869)
+ * Improved testing tools (PR #2704, #2796, #2818)
+ * Improved `bootstrap.py` script (PR #2727, #2733)
0.11.0: 2019/07/03
diff --git a/PKG-INFO b/PKG-INFO
index 9c1e298..1c225b2 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: silx
-Version: 0.12.0b0
+Version: 0.12.0
Summary: Software library for X-ray data analysis
Home-page: http://www.silx.org/
Author: data analysis unit
diff --git a/doc/source/modules/gui/icons.rst b/doc/source/modules/gui/icons.rst
index dbd58b4..ba7d89b 100644
--- a/doc/source/modules/gui/icons.rst
+++ b/doc/source/modules/gui/icons.rst
@@ -109,6 +109,18 @@ Available icons
- cube-top
* - |cube|
- cube
+ * - |description-description|
+ - description-description
+ * - |description-error|
+ - description-error
+ * - |description-name|
+ - description-name
+ * - |description-program|
+ - description-program
+ * - |description-title|
+ - description-title
+ * - |description-value|
+ - description-value
* - |document-open|
- document-open
* - |document-print|
@@ -393,6 +405,12 @@ Available icons
.. |cube-rotate| image:: ../../../../silx/resources/gui/icons/cube-rotate.png
.. |cube-top| image:: ../../../../silx/resources/gui/icons/cube-top.png
.. |cube| image:: ../../../../silx/resources/gui/icons/cube.png
+.. |description-description| image:: ../../../../silx/resources/gui/icons/description-description.png
+.. |description-error| image:: ../../../../silx/resources/gui/icons/description-error.png
+.. |description-name| image:: ../../../../silx/resources/gui/icons/description-name.png
+.. |description-program| image:: ../../../../silx/resources/gui/icons/description-program.png
+.. |description-title| image:: ../../../../silx/resources/gui/icons/description-title.png
+.. |description-value| image:: ../../../../silx/resources/gui/icons/description-value.png
.. |document-open| image:: ../../../../silx/resources/gui/icons/document-open.png
.. |document-print| image:: ../../../../silx/resources/gui/icons/document-print.png
.. |document-save| image:: ../../../../silx/resources/gui/icons/document-save.png
diff --git a/examples/dropZones.py b/examples/dropZones.py
index d0d16b5..27d9df8 100644
--- a/examples/dropZones.py
+++ b/examples/dropZones.py
@@ -2,7 +2,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
@@ -39,7 +39,7 @@ from silx.gui import qt
from silx.gui.plot.PlotWidget import PlotWidget
_logger = logging.getLogger(__name__)
-logging.basicConfig(level=logging.DEBUG)
+logging.basicConfig()
class DropPlotWidget(PlotWidget):
diff --git a/examples/fileDialog.py b/examples/fileDialog.py
index 82e6798..40191bb 100644
--- a/examples/fileDialog.py
+++ b/examples/fileDialog.py
@@ -2,7 +2,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
@@ -41,7 +41,7 @@ from silx.gui.dialog.DataFileDialog import DataFileDialog
import silx.io
-logging.basicConfig(level=logging.DEBUG)
+logging.basicConfig()
class Mode(enum.Enum):
diff --git a/examples/plotStats.py b/examples/plotStats.py
index 3929697..5f6e768 100644
--- a/examples/plotStats.py
+++ b/examples/plotStats.py
@@ -131,7 +131,7 @@ def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--update-mode',
- default='manual',
+ default='auto',
help='update mode to display (manual or auto)')
options = parser.parse_args(argv[1:])
@@ -167,4 +167,5 @@ def main(argv):
if __name__ == '__main__':
+ import sys
main(sys.argv)
diff --git a/silx.egg-info/PKG-INFO b/silx.egg-info/PKG-INFO
index 9c1e298..1c225b2 100644
--- a/silx.egg-info/PKG-INFO
+++ b/silx.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: silx
-Version: 0.12.0b0
+Version: 0.12.0
Summary: Software library for X-ray data analysis
Home-page: http://www.silx.org/
Author: data analysis unit
diff --git a/silx/app/view/main.py b/silx/app/view/main.py
index 90b8b17..8139175 100644
--- a/silx/app/view/main.py
+++ b/silx/app/view/main.py
@@ -1,6 +1,6 @@
# 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
@@ -27,10 +27,11 @@ __authors__ = ["V. Valls"]
__license__ = "MIT"
__date__ = "17/01/2019"
-import sys
import argparse
import logging
+import os
import signal
+import sys
_logger = logging.getLogger(__name__)
@@ -61,6 +62,12 @@ def createParser():
action="store_true",
default=False,
help='Start the application using new fresh user preferences')
+ parser.add_argument(
+ '--hdf5-file-locking',
+ dest="hdf5_file_locking",
+ action="store_true",
+ default=False,
+ help='Start the application with HDF5 file locking enabled (it is disabled by default)')
return parser
@@ -73,6 +80,11 @@ def mainQt(options):
# Import most of the things here to be sure to use the right logging level
#
+ # This needs to be done prior to load HDF5
+ hdf5_file_locking = 'TRUE' if options.hdf5_file_locking else 'FALSE'
+ _logger.info('Set HDF5_USE_FILE_LOCKING=%s', hdf5_file_locking)
+ os.environ['HDF5_USE_FILE_LOCKING'] = hdf5_file_locking
+
try:
# it should be loaded before h5py
import hdf5plugin # noqa
diff --git a/silx/gui/data/DataViewer.py b/silx/gui/data/DataViewer.py
index 67db5f9..bad4362 100644
--- a/silx/gui/data/DataViewer.py
+++ b/silx/gui/data/DataViewer.py
@@ -221,7 +221,7 @@ class DataViewer(qt.QFrame):
self.__numpySelection.setSelection(
previousSelection, previousPermutation)
except ValueError as e:
- _logger.error("Not restoring selection because: %s", e)
+ _logger.info("Not restoring selection because: %s", e)
if hasattr(data, "shape"):
isVisible = not (len(axisNames) == 1 and len(data.shape) == 1)
diff --git a/silx/gui/dialog/ColormapDialog.py b/silx/gui/dialog/ColormapDialog.py
index ed15947..dddec4c 100644
--- a/silx/gui/dialog/ColormapDialog.py
+++ b/silx/gui/dialog/ColormapDialog.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2018 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
@@ -463,6 +463,7 @@ class ColormapDialog(qt.QDialog):
color='black',
symbol='o',
linestyle='-',
+ z=2,
resetzoom=False)
scale = self._plot.getXAxis().getScale()
@@ -702,7 +703,8 @@ class ColormapDialog(qt.QDialog):
legend="Histogram",
color='gray',
align='center',
- fill=True)
+ fill=True,
+ z=1)
self._updateMinMaxData()
def getColormap(self):
@@ -753,7 +755,8 @@ class ColormapDialog(qt.QDialog):
legend="Range",
color='gray',
align='center',
- fill=True)
+ fill=True,
+ z=1)
self._dataRange = minimum, positiveMin, maximum
self._updateMinMaxData()
diff --git a/silx/gui/fit/FitWidget.py b/silx/gui/fit/FitWidget.py
index 78230b1..c3804e1 100644
--- a/silx/gui/fit/FitWidget.py
+++ b/silx/gui/fit/FitWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2004-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -315,8 +315,8 @@ class FitWidget(qt.QWidget):
configuration.update(self.configure())
def setdata(self, x, y, sigmay=None, xmin=None, xmax=None):
- warnings.warning("Method renamed to setData",
- DeprecationWarning)
+ warnings.warn("Method renamed to setData",
+ DeprecationWarning)
self.setData(x, y, sigmay, xmin, xmax)
def setData(self, x, y, sigmay=None, xmin=None, xmax=None):
@@ -525,8 +525,8 @@ class FitWidget(qt.QWidget):
self._emitSignal(ddict)
def startfit(self):
- warnings.warning("Method renamed to startFit",
- DeprecationWarning)
+ warnings.warn("Method renamed to startFit",
+ DeprecationWarning)
self.startFit()
def startFit(self):
diff --git a/silx/gui/plot/PlotWidget.py b/silx/gui/plot/PlotWidget.py
index 49e444a..e47249e 100755
--- a/silx/gui/plot/PlotWidget.py
+++ b/silx/gui/plot/PlotWidget.py
@@ -624,8 +624,7 @@ class PlotWidget(qt.QMainWindow):
# Add item to plot
self._content[key] = item
item._setPlot(self)
- if item.isVisible():
- self._itemRequiresUpdate(item)
+ self._itemRequiresUpdate(item)
if isinstance(item, items.DATA_ITEMS):
self._invalidateDataRange() # TODO handle this automatically
diff --git a/silx/gui/plot/ProfileMainWindow.py b/silx/gui/plot/ProfileMainWindow.py
index 39830d8..aaedd1c 100644
--- a/silx/gui/plot/ProfileMainWindow.py
+++ b/silx/gui/plot/ProfileMainWindow.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2017-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2017-2020 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
@@ -85,6 +85,7 @@ class ProfileMainWindow(qt.QMainWindow):
self._plot2D.setParent(None) # necessary to avoid widget destruction
if self._plot1D is None:
self._plot1D = Plot1D(backend=self._backend)
+ self._plot1D.setDataMargins(yMinMargin=0.1, yMaxMargin=0.1)
self._plot1D.setGraphYLabel('Profile')
self._plot1D.setGraphXLabel('')
self.setCentralWidget(self._plot1D)
diff --git a/silx/gui/plot/StatsWidget.py b/silx/gui/plot/StatsWidget.py
index 80bc05d..52b7e5c 100644
--- a/silx/gui/plot/StatsWidget.py
+++ b/silx/gui/plot/StatsWidget.py
@@ -424,7 +424,7 @@ class _StatsWidgetBase(object):
if self._displayOnlyActItem:
connections.append(
- (self._plotWrapper.sigCurrentChanged, self._updateItemObserve))
+ (self._plotWrapper.sigCurrentChanged, self._updateCurrentItem))
else:
connections += [
(self._plotWrapper.sigItemAdded, self._addItem),
@@ -441,6 +441,11 @@ class _StatsWidgetBase(object):
"""Reload table depending on mode"""
raise NotImplementedError('Base class')
+ def _updateCurrentItem(self, *args):
+ """specific callback for the sigCurrentChanged and with the
+ _displayOnlyActItem option."""
+ raise NotImplementedError('Base class')
+
def _updateStats(self, item):
"""Update displayed information for given plot item
@@ -643,8 +648,6 @@ class StatsTable(_StatsWidgetBase, TableWidget):
def _updateItemObserve(self, *args):
"""Reload table depending on mode"""
- if self.getUpdateMode() is UpdateMode.MANUAL:
- return
self._removeAllItems()
# Get selected or all items from the plot
@@ -657,6 +660,27 @@ class StatsTable(_StatsWidgetBase, TableWidget):
for item in items:
self._addItem(item)
+ def _updateCurrentItem(self, *args):
+ """specific callback for the sigCurrentChanged and with the
+ _displayOnlyActItem option.
+
+ Behavior: create the tableItems if does not exists.
+ If exists, update it only when we are in 'auto' mode"""
+ if self.getUpdateMode() is UpdateMode.MANUAL:
+ # when sigCurrentChanged is giving the current item
+ if len(args) > 0 and isinstance(args[0], (plotitems.Curve, plotitems.Histogram, plotitems.ImageData, plotitems.Scatter)):
+ item = args[0]
+ tableItems = self._itemToTableItems(item)
+ # if the table does not exists yet
+ if len(tableItems) == 0:
+ self._updateItemObserve()
+ else:
+ # in this case no current item
+ self._updateItemObserve(args)
+ else:
+ # auto mode
+ self._updateItemObserve(args)
+
def _plotCurrentChanged(self, current):
"""Handle change of current item and update selection in table
@@ -1392,6 +1416,9 @@ class _BaseLineStatsWidget(_StatsWidgetBase, qt.QWidget):
_item = items[0] if len(items) is 1 else None
self._setItem(_item)
+ def _updateCurrentItem(self):
+ self._updateItemObserve()
+
def _createLayout(self):
"""create an instance of the main QLayout"""
raise NotImplementedError('Base class')
diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index 075f6aa..2336494 100755
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -1094,13 +1094,16 @@ class BackendMatplotlib(BackendBase.BackendBase):
# Data <-> Pixel coordinates conversion
- def _mplQtYAxisCoordConversion(self, y):
+ def _mplQtYAxisCoordConversion(self, y, asint=True):
"""Qt origin (top) to/from matplotlib origin (bottom) conversion.
+ :param y:
+ :param bool asint: True to cast to int, False to keep as float
+
:rtype: float
"""
- height = self.fig.get_window_extent().height
- return height - y
+ value = self.fig.get_window_extent().height - y
+ return int(value) if asint else value
def dataToPixel(self, x, y, axis):
ax = self.ax2 if axis == "right" else self.ax
@@ -1109,7 +1112,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
xPixel, yPixel = pixels.T
# Convert from matplotlib origin (bottom) to Qt origin (top)
- yPixel = self._mplQtYAxisCoordConversion(yPixel)
+ yPixel = self._mplQtYAxisCoordConversion(yPixel, asint=False)
return xPixel, yPixel
@@ -1117,7 +1120,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
ax = self.ax2 if axis == "right" else self.ax
# Convert from Qt origin (top) to matplotlib origin (bottom)
- y = self._mplQtYAxisCoordConversion(y)
+ y = self._mplQtYAxisCoordConversion(y, asint=False)
inv = ax.transData.inverted()
x, y = inv.transform_point((x, y))
@@ -1126,10 +1129,10 @@ class BackendMatplotlib(BackendBase.BackendBase):
def getPlotBoundsInPixels(self):
bbox = self.ax.get_window_extent()
# Warning this is not returning int...
- return (bbox.xmin,
- self._mplQtYAxisCoordConversion(bbox.ymax),
- bbox.width,
- bbox.height)
+ return (int(bbox.xmin),
+ self._mplQtYAxisCoordConversion(bbox.ymax, asint=True),
+ int(bbox.width),
+ int(bbox.height))
def setAxesDisplayed(self, displayed):
"""Display or not the axes.
@@ -1263,7 +1266,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
def _onMouseMove(self, event):
if self._graphCursor:
lineh, linev = self._graphCursor
- if event.inaxes != self.ax and lineh.get_visible():
+ if event.inaxes not in (self.ax, self.ax2) and lineh.get_visible():
lineh.set_visible(False)
linev.set_visible(False)
self._plot._setDirtyPlot(overlayOnly=True)
diff --git a/silx/gui/plot/items/shape.py b/silx/gui/plot/items/shape.py
index e6dc529..8176be1 100644
--- a/silx/gui/plot/items/shape.py
+++ b/silx/gui/plot/items/shape.py
@@ -197,6 +197,8 @@ class BoundingRect(Item, YAxisMixIn):
self._updated(ItemChangedType.DATA)
def _getBounds(self):
+ if self.__bounds is None:
+ return None
plot = self.getPlot()
if plot is not None:
xPositive = plot.getXAxis()._isLogarithmic()
diff --git a/silx/gui/plot/tools/profile/_BaseProfileToolBar.py b/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
index ced81da..75bb4c6 100644
--- a/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
+++ b/silx/gui/plot/tools/profile/_BaseProfileToolBar.py
@@ -231,7 +231,7 @@ class _BaseProfileToolBar(qt.QToolBar):
profilePlot.addCurve(
xProfile, values, legend='Profile', color=self._color)
- self._showDefaultProfileWindow()
+ self._showDefaultProfileWindow()
def _showDefaultProfileWindow(self):
"""If profile window was created by this toolbar,
diff --git a/silx/gui/plot3d/tools/PositionInfoWidget.py b/silx/gui/plot3d/tools/PositionInfoWidget.py
index 52a6163..fc86a7f 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.getName())
+ self._itemLabel.setText(item.getLabel())
positions = picking.getPositions('scene', copy=False)
x, y, z = positions[0]
self._xLabel.setText("%g" % x)
diff --git a/silx/math/fit/fitmanager.py b/silx/math/fit/fitmanager.py
index f62dedb..2dc63a1 100644
--- a/silx/math/fit/fitmanager.py
+++ b/silx/math/fit/fitmanager.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*#########################################################################
#
-# Copyright (c) 2004-2018 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2020 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
@@ -411,8 +411,9 @@ class FitManager(object):
6: 'SUM',
7: 'IGNORE'}
- xwork = self.xdata
- ywork = self.ydata
+ # Filter-out not finite data
+ xwork = self.xdata[self._finite_mask]
+ ywork = self.ydata[self._finite_mask]
# estimate the background
bg_params, bg_constraints = self.estimate_bkg(xwork, ywork)
@@ -516,8 +517,8 @@ class FitManager(object):
from a list of parameter dictionaries, if field ``code`` is not set
to ``"IGNORE"``.
"""
- if x is None:
- x = self.xdata
+ x = self.xdata if x is None else numpy.array(x, copy=False)
+
if paramlist is None:
paramlist = self.fit_results
active_params = []
@@ -528,8 +529,18 @@ class FitManager(object):
else:
active_params.append(param['estimation'])
- newdata = self.fitfunction(numpy.array(x), *active_params)
- return newdata
+ # Mask x with not finite (support nD x)
+ finite_mask = numpy.all(numpy.isfinite(x), axis=tuple(range(1, x.ndim)))
+
+ if numpy.all(finite_mask): # All values are finite: fast path
+ return self.fitfunction(numpy.array(x, copy=True), *active_params)
+
+ else: # Only run fitfunction on finite data and complete result with NaNs
+ # Create result with same number as elements as x, filling holes with NaNs
+ result = numpy.full((x.shape[0],), numpy.nan, dtype=numpy.float64)
+ result[finite_mask] = self.fitfunction(
+ numpy.array(x[finite_mask], copy=True), *active_params)
+ return result
def get_estimation(self):
"""Return the list of fit parameter names."""
@@ -750,6 +761,10 @@ class FitManager(object):
self.ydata = self.ydata[bool_array]
self.sigmay = self.sigmay[bool_array] if sigmay is not None else None
+ self._finite_mask = numpy.logical_and(
+ numpy.all(numpy.isfinite(self.xdata), axis=tuple(range(1, self.xdata.ndim))),
+ numpy.isfinite(self.ydata))
+
def enableweight(self):
"""This method can be called to set :attr:`sigmay`. If :attr:`sigmay0` was filled with
actual uncertainties in :meth:`setdata`, use these values.
@@ -822,13 +837,14 @@ class FitManager(object):
param_val.append(param['estimation'])
param_constraints.append([param['code'], param['cons1'], param['cons2']])
- ywork = self.ydata
-
+ # Filter-out not finite data
+ ywork = self.ydata[self._finite_mask]
+ xwork = self.xdata[self._finite_mask]
try:
params, covariance_matrix, infodict = leastsq(
self.fitfunction, # bg + actual model function
- self.xdata, ywork, param_val,
+ xwork, ywork, param_val,
sigma=self.sigmay,
constraints=param_constraints,
model_deriv=self.theories[self.selectedtheory].derivative,
diff --git a/silx/math/fit/test/test_fitmanager.py b/silx/math/fit/test/test_fitmanager.py
index 38c4802..7a643cb 100644
--- a/silx/math/fit/test/test_fitmanager.py
+++ b/silx/math/fit/test/test_fitmanager.py
@@ -1,6 +1,6 @@
# coding: utf-8
# /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2020 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,7 @@ from silx.math.fit import bgtheories
from silx.math.fit.fittheory import FitTheory
from silx.math.fit.functions import sum_gauss, sum_stepdown, sum_stepup
+from silx.utils.testutils import ParametricTestCase
from silx.test.utils import temp_dir
custom_function_definition = """
@@ -110,7 +111,7 @@ def _order_of_magnitude(x):
return numpy.log10(x).round()
-class TestFitmanager(unittest.TestCase):
+class TestFitmanager(ParametricTestCase):
"""
Unit tests of multi-peak functions.
"""
@@ -132,40 +133,54 @@ class TestFitmanager(unittest.TestCase):
linear_bg = 2.65 * x + 13
y = linear_bg + sum_gauss(x, *p)
- # Fitting
- fit = fitmanager.FitManager()
- fit.setdata(x=x, y=y)
- fit.loadtheories(fittheories)
- # Use one of the default fit functions
- fit.settheory('Gaussians')
- fit.setbackground('Linear')
- fit.estimate()
- fit.runfit()
-
- # fit.fit_results[]
-
- # first 2 parameters are related to the linear background
- self.assertEqual(fit.fit_results[0]["name"], "Constant")
- self.assertAlmostEqual(fit.fit_results[0]["fitresult"], 13)
- self.assertEqual(fit.fit_results[1]["name"], "Slope")
- self.assertAlmostEqual(fit.fit_results[1]["fitresult"], 2.65)
-
- for i, param in enumerate(fit.fit_results[2:]):
- param_number = i // 3 + 1
- if i % 3 == 0:
- self.assertEqual(param["name"],
- "Height%d" % param_number)
- elif i % 3 == 1:
- self.assertEqual(param["name"],
- "Position%d" % param_number)
- elif i % 3 == 2:
- self.assertEqual(param["name"],
- "FWHM%d" % param_number)
-
- self.assertAlmostEqual(param["fitresult"],
- p[i])
- self.assertAlmostEqual(_order_of_magnitude(param["estimation"]),
- _order_of_magnitude(p[i]))
+ y_with_nans = numpy.array(y)
+ y_with_nans[::10] = numpy.nan
+
+ x_with_nans = numpy.array(x)
+ x_with_nans[5::15] = numpy.nan
+
+ tests = {
+ 'all finite': (x, y),
+ 'y with NaNs': (x, y_with_nans),
+ 'x with NaNs': (x_with_nans, y),
+ }
+
+ for name, (xdata, ydata) in tests.items():
+ with self.subTest(name=name):
+ # Fitting
+ fit = fitmanager.FitManager()
+ fit.setdata(x=xdata, y=ydata)
+ fit.loadtheories(fittheories)
+ # Use one of the default fit functions
+ fit.settheory('Gaussians')
+ fit.setbackground('Linear')
+ fit.estimate()
+ fit.runfit()
+
+ # fit.fit_results[]
+
+ # first 2 parameters are related to the linear background
+ self.assertEqual(fit.fit_results[0]["name"], "Constant")
+ self.assertAlmostEqual(fit.fit_results[0]["fitresult"], 13)
+ self.assertEqual(fit.fit_results[1]["name"], "Slope")
+ self.assertAlmostEqual(fit.fit_results[1]["fitresult"], 2.65)
+
+ for i, param in enumerate(fit.fit_results[2:]):
+ param_number = i // 3 + 1
+ if i % 3 == 0:
+ self.assertEqual(param["name"],
+ "Height%d" % param_number)
+ elif i % 3 == 1:
+ self.assertEqual(param["name"],
+ "Position%d" % param_number)
+ elif i % 3 == 2:
+ self.assertEqual(param["name"],
+ "FWHM%d" % param_number)
+
+ self.assertAlmostEqual(param["fitresult"],
+ p[i])
+ self.assertAlmostEqual(_order_of_magnitude(param["estimation"]),
+ _order_of_magnitude(p[i]))
def testLoadCustomFitFunction(self):
"""Test FitManager using a custom fit function defined in an external
diff --git a/silx/sx/_plot.py b/silx/sx/_plot.py
index 9ef52a1..74ebe84 100644
--- a/silx/sx/_plot.py
+++ b/silx/sx/_plot.py
@@ -548,7 +548,7 @@ class _GInputHandler(roi.InteractiveRegionOfInterestManager):
"""
if isinstance(roi, roi_items.PointROI):
# Only handle points
- roi.setLabel('%d' % len(self.__selections))
+ roi.setName('%d' % len(self.__selections))
self.__updateSelection(roi)
roi.sigRegionChanged.connect(self.__regionChanged)
diff --git a/version.py b/version.py
index a7a2cd6..58be1b2 100644
--- a/version.py
+++ b/version.py
@@ -2,7 +2,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2015-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2015-2020 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
@@ -69,7 +69,7 @@ RELEASE_LEVEL_VALUE = {"dev": 0,
MAJOR = 0
MINOR = 12
MICRO = 0
-RELEV = "rc" # <16
+RELEV = "final" # <16
SERIAL = 0 # <16
date = __date__