summaryrefslogtreecommitdiff
path: root/silx/gui/plot/StatsWidget.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/plot/StatsWidget.py')
-rw-r--r--silx/gui/plot/StatsWidget.py1618
1 files changed, 0 insertions, 1618 deletions
diff --git a/silx/gui/plot/StatsWidget.py b/silx/gui/plot/StatsWidget.py
deleted file mode 100644
index 5e2dc58..0000000
--- a/silx/gui/plot/StatsWidget.py
+++ /dev/null
@@ -1,1618 +0,0 @@
-# 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.
-#
-# ###########################################################################*/
-"""
-Module containing widgets displaying stats from items of a plot.
-"""
-
-__authors__ = ["H. Payno"]
-__license__ = "MIT"
-__date__ = "24/07/2018"
-
-
-from collections import OrderedDict
-from contextlib import contextmanager
-import logging
-import weakref
-import functools
-import numpy
-import enum
-from silx.utils.proxy import docstring
-from silx.utils.enum import Enum as _Enum
-from silx.gui import qt
-from silx.gui import icons
-from silx.gui.plot import stats as statsmdl
-from silx.gui.widgets.TableWidget import TableWidget
-from silx.gui.plot.stats.statshandler import StatsHandler, StatFormatter
-from silx.gui.plot.items.core import ItemChangedType
-from silx.gui.widgets.FlowLayout import FlowLayout
-from . import PlotWidget
-from . import items as plotitems
-
-
-_logger = logging.getLogger(__name__)
-
-
-@enum.unique
-class UpdateMode(_Enum):
- AUTO = 'auto'
- MANUAL = 'manual'
-
-
-# Helper class to handle specific calls to PlotWidget and SceneWidget
-
-
-class _Wrapper(qt.QObject):
- """Base class for connection with PlotWidget and SceneWidget.
-
- This class is used when no PlotWidget or SceneWidget is connected.
-
- :param plot: The plot to be used
- """
-
- sigItemAdded = qt.Signal(object)
- """Signal emitted when a new item is added.
-
- It provides the added item.
- """
-
- sigItemRemoved = qt.Signal(object)
- """Signal emitted when an item is (about to be) removed.
-
- It provides the removed item.
- """
-
- sigCurrentChanged = qt.Signal(object)
- """Signal emitted when the current item has changed.
-
- It provides the current item.
- """
-
- sigVisibleDataChanged = qt.Signal()
- """Signal emitted when the visible data area has changed"""
-
- def __init__(self, plot=None):
- super(_Wrapper, self).__init__(parent=None)
- self._plotRef = None if plot is None else weakref.ref(plot)
-
- def getPlot(self):
- """Returns the plot attached to this widget"""
- return None if self._plotRef is None else self._plotRef()
-
- def getItems(self):
- """Returns the list of items in the plot
-
- :rtype: List[object]
- """
- return ()
-
- def getSelectedItems(self):
- """Returns the list of selected items in the plot
-
- :rtype: List[object]
- """
- return ()
-
- def setCurrentItem(self, item):
- """Set the current/active item in the plot
-
- :param item: The plot item to set as active/current
- """
- pass
-
- def getLabel(self, item):
- """Returns the label of the given item.
-
- :param item:
- :rtype: str
- """
- return ''
-
- def getKind(self, item):
- """Returns the kind of an item or None if not supported
-
- :param item:
- :rtype: Union[str,None]
- """
- return None
-
-
-class _PlotWidgetWrapper(_Wrapper):
- """Class handling PlotWidget specific calls and signal connections
-
- See :class:`._Wrapper` for documentation
-
- :param PlotWidget plot:
- """
-
- def __init__(self, plot):
- assert isinstance(plot, PlotWidget)
- super(_PlotWidgetWrapper, self).__init__(plot)
- plot.sigItemAdded.connect(self.sigItemAdded.emit)
- plot.sigItemAboutToBeRemoved.connect(self.sigItemRemoved.emit)
- plot.sigActiveCurveChanged.connect(self._activeCurveChanged)
- plot.sigActiveImageChanged.connect(self._activeImageChanged)
- plot.sigActiveScatterChanged.connect(self._activeScatterChanged)
- plot.sigPlotSignal.connect(self._limitsChanged)
-
- def _activeChanged(self, kind):
- """Handle change of active curve/image/scatter"""
- plot = self.getPlot()
- if plot is not None:
- item = plot._getActiveItem(kind=kind)
- if item is None or self.getKind(item) is not None:
- self.sigCurrentChanged.emit(item)
-
- def _activeCurveChanged(self, previous, current):
- self._activeChanged(kind='curve')
-
- def _activeImageChanged(self, previous, current):
- self._activeChanged(kind='image')
-
- def _activeScatterChanged(self, previous, current):
- self._activeChanged(kind='scatter')
-
- def _limitsChanged(self, event):
- """Handle change of plot area limits."""
- if event['event'] == 'limitsChanged':
- self.sigVisibleDataChanged.emit()
-
- def getItems(self):
- plot = self.getPlot()
- return () if plot is None else plot._getItems()
-
- def getSelectedItems(self):
- plot = self.getPlot()
- items = []
- if plot is not None:
- for kind in plot._ACTIVE_ITEM_KINDS:
- item = plot._getActiveItem(kind=kind)
- if item is not None:
- items.append(item)
- return tuple(items)
-
- def setCurrentItem(self, item):
- plot = self.getPlot()
- if plot is not None:
- kind = self.getKind(item)
- if kind in plot._ACTIVE_ITEM_KINDS:
- if plot._getActiveItem(kind) != item:
- plot._setActiveItem(kind, item.getLegend())
-
- def getLabel(self, item):
- return item.getLegend()
-
- def getKind(self, item):
- if isinstance(item, plotitems.Curve):
- return 'curve'
- elif isinstance(item, plotitems.ImageData):
- return 'image'
- elif isinstance(item, plotitems.Scatter):
- return 'scatter'
- elif isinstance(item, plotitems.Histogram):
- return 'histogram'
- else:
- return None
-
-
-class _SceneWidgetWrapper(_Wrapper):
- """Class handling SceneWidget specific calls and signal connections
-
- See :class:`._Wrapper` for documentation
-
- :param SceneWidget plot:
- """
-
- def __init__(self, plot):
- # Lazy-import to avoid circular imports
- from ..plot3d.SceneWidget import SceneWidget
-
- assert isinstance(plot, SceneWidget)
- super(_SceneWidgetWrapper, self).__init__(plot)
- plot.getSceneGroup().sigItemAdded.connect(self.sigItemAdded)
- plot.getSceneGroup().sigItemRemoved.connect(self.sigItemRemoved)
- plot.selection().sigCurrentChanged.connect(self._currentChanged)
- # sigVisibleDataChanged is never emitted
-
- def _currentChanged(self, current, previous):
- self.sigCurrentChanged.emit(current)
-
- def getItems(self):
- plot = self.getPlot()
- return () if plot is None else tuple(plot.getSceneGroup().visit())
-
- def getSelectedItems(self):
- plot = self.getPlot()
- return () if plot is None else (plot.selection().getCurrentItem(),)
-
- def setCurrentItem(self, item):
- plot = self.getPlot()
- if plot is not None:
- plot.selection().setCurrentItem(item)
-
- def getLabel(self, item):
- return item.getLabel()
-
- def getKind(self, item):
- from ..plot3d import items as plot3ditems
-
- if isinstance(item, (plot3ditems.ImageData,
- plot3ditems.ScalarField3D)):
- return 'image'
- elif isinstance(item, (plot3ditems.Scatter2D,
- plot3ditems.Scatter3D)):
- return 'scatter'
- else:
- return None
-
-
-class _ScalarFieldViewWrapper(_Wrapper):
- """Class handling ScalarFieldView specific calls and signal connections
-
- See :class:`._Wrapper` for documentation
-
- :param SceneWidget plot:
- """
-
- def __init__(self, plot):
- # Lazy-import to avoid circular imports
- from ..plot3d.ScalarFieldView import ScalarFieldView
- from ..plot3d.items import ScalarField3D
-
- assert isinstance(plot, ScalarFieldView)
- super(_ScalarFieldViewWrapper, self).__init__(plot)
- self._item = ScalarField3D()
- self._dataChanged()
- plot.sigDataChanged.connect(self._dataChanged)
- # sigItemAdded, sigItemRemoved, sigVisibleDataChanged are never emitted
-
- def _dataChanged(self):
- plot = self.getPlot()
- if plot is not None:
- self._item.setData(plot.getData(copy=False), copy=False)
- self.sigCurrentChanged.emit(self._item)
-
- def getItems(self):
- plot = self.getPlot()
- return () if plot is None else (self._item,)
-
- def getSelectedItems(self):
- return self.getItems()
-
- def setCurrentItem(self, item):
- pass
-
- def getLabel(self, item):
- return 'Data'
-
- def getKind(self, item):
- return 'image'
-
-
-class _Container(object):
- """Class to contain a plot item.
-
- This is apparently needed for compatibility with PySide2,
-
- :param QObject obj:
- """
- def __init__(self, obj):
- self._obj = obj
-
- def __call__(self):
- return self._obj
-
-
-class _StatsWidgetBase(object):
- """
- Base class for all widgets which want to display statistics
- """
-
- def __init__(self, statsOnVisibleData, displayOnlyActItem):
- self._displayOnlyActItem = displayOnlyActItem
- self._statsOnVisibleData = statsOnVisibleData
- self._statsHandler = None
- self._updateMode = UpdateMode.AUTO
-
- self.__default_skipped_events = (
- ItemChangedType.ALPHA,
- ItemChangedType.COLOR,
- ItemChangedType.COLORMAP,
- ItemChangedType.SYMBOL,
- ItemChangedType.SYMBOL_SIZE,
- ItemChangedType.LINE_WIDTH,
- ItemChangedType.LINE_STYLE,
- ItemChangedType.LINE_BG_COLOR,
- ItemChangedType.FILL,
- ItemChangedType.HIGHLIGHTED_COLOR,
- ItemChangedType.HIGHLIGHTED_STYLE,
- ItemChangedType.TEXT,
- ItemChangedType.OVERLAY,
- ItemChangedType.VISUALIZATION_MODE,
- )
-
- self._plotWrapper = _Wrapper()
- self._dealWithPlotConnection(create=True)
-
- def setPlot(self, plot):
- """Define the plot to interact with
-
- :param Union[PlotWidget,SceneWidget,None] plot:
- The plot containing the items on which statistics are applied
- """
- try:
- import OpenGL
- except ImportError:
- has_opengl = False
- else:
- has_opengl = True
- from ..plot3d.SceneWidget import SceneWidget # Lazy import
- self._dealWithPlotConnection(create=False)
- self.clear()
- if plot is None:
- self._plotWrapper = _Wrapper()
- elif isinstance(plot, PlotWidget):
- self._plotWrapper = _PlotWidgetWrapper(plot)
- else:
- if has_opengl is True:
- if isinstance(plot, SceneWidget):
- self._plotWrapper = _SceneWidgetWrapper(plot)
- else: # Expect a ScalarFieldView
- self._plotWrapper = _ScalarFieldViewWrapper(plot)
- else:
- _logger.warning('OpenGL not installed, %s not managed' % ('SceneWidget qnd ScalarFieldView'))
- self._dealWithPlotConnection(create=True)
-
- 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
- """
- if statsHandler is None:
- statsHandler = StatsHandler(statFormatters=())
- elif isinstance(statsHandler, (list, tuple)):
- statsHandler = StatsHandler(statsHandler)
- assert isinstance(statsHandler, StatsHandler)
-
- self._statsHandler = statsHandler
-
- def getStatsHandler(self):
- """Returns the :class:`StatsHandler` in use.
-
- :rtype: StatsHandler
- """
- return self._statsHandler
-
- def getPlot(self):
- """Returns the plot attached to this widget
-
- :rtype: Union[PlotWidget,SceneWidget,None]
- """
- return self._plotWrapper.getPlot()
-
- def _dealWithPlotConnection(self, create=True):
- """Manage connection to plot signals
-
- Note: connection on Item are managed by _addItem and _removeItem methods
- """
- connections = [] # List of (signal, slot) to connect/disconnect
- if self._statsOnVisibleData:
- connections.append(
- (self._plotWrapper.sigVisibleDataChanged, self._updateAllStats))
-
- if self._displayOnlyActItem:
- connections.append(
- (self._plotWrapper.sigCurrentChanged, self._updateItemObserve))
- else:
- connections += [
- (self._plotWrapper.sigItemAdded, self._addItem),
- (self._plotWrapper.sigItemRemoved, self._removeItem),
- (self._plotWrapper.sigCurrentChanged, self._plotCurrentChanged)]
-
- for signal, slot in connections:
- if create:
- signal.connect(slot)
- else:
- signal.disconnect(slot)
-
- def _updateItemObserve(self, *args):
- """Reload table depending on mode"""
- raise NotImplementedError('Base class')
-
- def _updateStats(self, item):
- """Update displayed information for given plot item
-
- :param item: The plot item
- """
- raise NotImplementedError('Base class')
-
- def _updateAllStats(self):
- """Update stats for all rows in the table"""
- raise NotImplementedError('Base class')
-
- def setDisplayOnlyActiveItem(self, displayOnlyActItem):
- """Toggle display off all items or only the active/selected one
-
- :param bool displayOnlyActItem:
- True if we want to only show active item
- """
- self._displayOnlyActItem = displayOnlyActItem
-
- def setStatsOnVisibleData(self, b):
- """Toggle computation of statistics on whole data or only visible ones.
-
- .. warning:: When visible data is activated we will process to a simple
- filtering of visible data by the user. The filtering is a
- simple data sub-sampling. No interpolation is made to fit
- data to boundaries.
-
- :param bool b: True if we want to apply statistics only on visible data
- """
- if self._statsOnVisibleData != b:
- self._dealWithPlotConnection(create=False)
- self._statsOnVisibleData = b
- self._dealWithPlotConnection(create=True)
- self._updateAllStats()
-
- def _addItem(self, item):
- """Add a plot item to the table
-
- If item is not supported, it is ignored.
-
- :param item: The plot item
- :returns: True if the item is added to the widget.
- :rtype: bool
- """
- raise NotImplementedError('Base class')
-
- def _removeItem(self, item):
- """Remove table items corresponding to given plot item from the table.
-
- :param item: The plot item
- """
- raise NotImplementedError('Base class')
-
- def _plotCurrentChanged(self, current):
- """Handle change of current item and update selection in table
-
- :param current:
- """
- raise NotImplementedError('Base class')
-
- def clear(self):
- """clear GUI"""
- pass
-
- def _skipPlotItemChangedEvent(self, event):
- """
-
- :param ItemChangedtype event: event to filter or not
- :return: True if we want to ignore this ItemChangedtype
- :rtype: bool
- """
- return event in self.__default_skipped_events
-
- def setUpdateMode(self, mode):
- """Set the way to update the displayed statistics.
-
- :param mode: mode requested for update
- :type mode: Union[str,UpdateMode]
- """
- mode = UpdateMode.from_value(mode)
- if mode != self._updateMode:
- self._updateMode = mode
- self._updateModeHasChanged()
-
- def getUpdateMode(self):
- """Returns update mode (See :meth:`setUpdateMode`).
-
- :return: update mode
- :rtype: UpdateMode
- """
- return self._updateMode
-
- def _updateModeHasChanged(self):
- """callback when the update mode has changed"""
- pass
-
-
-class StatsTable(_StatsWidgetBase, TableWidget):
- """
- TableWidget displaying for each curves contained by the Plot some
- information:
-
- * legend
- * minimal value
- * maximal value
- * standard deviation (std)
-
- :param QWidget parent: The widget's parent.
- :param Union[PlotWidget,SceneWidget] plot:
- :class:`PlotWidget` or :class:`SceneWidget` instance on which to operate
- """
-
- _LEGEND_HEADER_DATA = 'legend'
- _KIND_HEADER_DATA = 'kind'
-
- sigUpdateModeChanged = qt.Signal(object)
- """Signal emitted when the update mode changed"""
-
- def __init__(self, parent=None, plot=None):
- TableWidget.__init__(self, parent)
- _StatsWidgetBase.__init__(self, statsOnVisibleData=False,
- displayOnlyActItem=False)
-
- # Init for _displayOnlyActItem == False
- assert self._displayOnlyActItem is False
- self.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
- self.setSelectionMode(qt.QAbstractItemView.SingleSelection)
- self.currentItemChanged.connect(self._currentItemChanged)
-
- self.setRowCount(0)
- self.setColumnCount(2)
-
- # Init headers
- headerItem = qt.QTableWidgetItem('Legend')
- headerItem.setData(qt.Qt.UserRole, self._LEGEND_HEADER_DATA)
- self.setHorizontalHeaderItem(0, headerItem)
- headerItem = qt.QTableWidgetItem('Kind')
- headerItem.setData(qt.Qt.UserRole, self._KIND_HEADER_DATA)
- self.setHorizontalHeaderItem(1, headerItem)
-
- self.setSortingEnabled(True)
- self.setPlot(plot)
-
- @contextmanager
- def _disableSorting(self):
- """Context manager that disables table sorting
-
- Previous state is restored when leaving
- """
- sorting = self.isSortingEnabled()
- if sorting:
- self.setSortingEnabled(False)
- yield
- if sorting:
- self.setSortingEnabled(sorting)
-
- 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
- """
- self._removeAllItems()
- _StatsWidgetBase.setStats(self, statsHandler)
-
- self.setRowCount(0)
- self.setColumnCount(len(self._statsHandler.stats) + 2) # + legend and kind
-
- for index, stat in enumerate(self._statsHandler.stats.values()):
- headerItem = qt.QTableWidgetItem(stat.name.capitalize())
- headerItem.setData(qt.Qt.UserRole, stat.name)
- if stat.description is not None:
- headerItem.setToolTip(stat.description)
- self.setHorizontalHeaderItem(2 + index, headerItem)
-
- horizontalHeader = self.horizontalHeader()
- if hasattr(horizontalHeader, 'setSectionResizeMode'): # Qt5
- horizontalHeader.setSectionResizeMode(qt.QHeaderView.ResizeToContents)
- else: # Qt4
- horizontalHeader.setResizeMode(qt.QHeaderView.ResizeToContents)
-
- self._updateItemObserve()
-
- def setPlot(self, plot):
- """Define the plot to interact with
-
- :param Union[PlotWidget,SceneWidget,None] plot:
- The plot containing the items on which statistics are applied
- """
- _StatsWidgetBase.setPlot(self, plot)
- self._updateItemObserve()
-
- def clear(self):
- """Define the plot to interact with
-
- :param Union[PlotWidget,SceneWidget,None] plot:
- The plot containing the items on which statistics are applied
- """
- self._removeAllItems()
-
- 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
- if self._displayOnlyActItem: # Only selected
- items = self._plotWrapper.getSelectedItems()
- else: # All items
- items = self._plotWrapper.getItems()
-
- # Add items to the plot
- for item in items:
- self._addItem(item)
-
- def _plotCurrentChanged(self, current):
- """Handle change of current item and update selection in table
-
- :param current:
- """
- row = self._itemToRow(current)
- if row is None:
- if self.currentRow() >= 0:
- self.setCurrentCell(-1, -1)
- elif row != self.currentRow():
- self.setCurrentCell(row, 0)
-
- def _tableItemToItem(self, tableItem):
- """Find the plot item corresponding to a table item
-
- :param QTableWidgetItem tableItem:
- :rtype: QObject
- """
- container = tableItem.data(qt.Qt.UserRole)
- return container()
-
- def _itemToRow(self, item):
- """Find the row corresponding to a plot item
-
- :param item: The plot item
- :return: The corresponding row index
- :rtype: Union[int,None]
- """
- for row in range(self.rowCount()):
- tableItem = self.item(row, 0)
- if self._tableItemToItem(tableItem) == item:
- return row
- return None
-
- def _itemToTableItems(self, item):
- """Find all table items corresponding to a plot item
-
- :param item: The plot item
- :return: An ordered dict of column name to QTableWidgetItem mapping
- for the given plot item.
- :rtype: OrderedDict
- """
- result = OrderedDict()
- row = self._itemToRow(item)
- if row is not None:
- for column in range(self.columnCount()):
- tableItem = self.item(row, column)
- if self._tableItemToItem(tableItem) != item:
- _logger.error("Table item/plot item mismatch")
- else:
- header = self.horizontalHeaderItem(column)
- name = header.data(qt.Qt.UserRole)
- result[name] = tableItem
- return result
-
- def _plotItemChanged(self, event):
- """Handle modifications of the items.
-
- :param event:
- """
- if self.getUpdateMode() is UpdateMode.MANUAL:
- return
- if self._skipPlotItemChangedEvent(event) is True:
- return
- else:
- item = self.sender()
- self._updateStats(item)
- # deal with stat items visibility
- if event is ItemChangedType.VISIBLE:
- if len(self._itemToTableItems(item).items()) > 0:
- item_0 = list(self._itemToTableItems(item).values())[0]
- row_index = item_0.row()
- self.setRowHidden(row_index, not item.isVisible())
-
- def _addItem(self, item):
- """Add a plot item to the table
-
- If item is not supported, it is ignored.
-
- :param item: The plot item
- :returns: True if the item is added to the widget.
- :rtype: bool
- """
- if self._itemToRow(item) is not None:
- _logger.info("Item already present in the table")
- self._updateStats(item)
- return True
-
- kind = self._plotWrapper.getKind(item)
- if kind not in statsmdl.BASIC_COMPATIBLE_KINDS:
- _logger.info("Item has not a supported type: %s", item)
- return False
-
- # Prepare table items
- tableItems = [
- qt.QTableWidgetItem(), # Legend
- qt.QTableWidgetItem()] # Kind
-
- for column in range(2, self.columnCount()):
- header = self.horizontalHeaderItem(column)
- name = header.data(qt.Qt.UserRole)
-
- formatter = self._statsHandler.formatters[name]
- if formatter:
- tableItem = formatter.tabWidgetItemClass()
- else:
- tableItem = qt.QTableWidgetItem()
-
- tooltip = self._statsHandler.stats[name].getToolTip(kind=kind)
- if tooltip is not None:
- tableItem.setToolTip(tooltip)
-
- tableItems.append(tableItem)
-
- # Disable sorting while adding table items
- with self._disableSorting():
- # Add a row to the table
- self.setRowCount(self.rowCount() + 1)
-
- # Add table items to the last row
- row = self.rowCount() - 1
- for column, tableItem in enumerate(tableItems):
- tableItem.setData(qt.Qt.UserRole, _Container(item))
- tableItem.setFlags(
- qt.Qt.ItemIsEnabled | qt.Qt.ItemIsSelectable)
- self.setItem(row, column, tableItem)
-
- # Update table items content
- self._updateStats(item)
-
- # Listen for item changes
- # Using queued connection to avoid issue with sender
- # being that of the signal calling the signal
- item.sigItemChanged.connect(self._plotItemChanged,
- qt.Qt.QueuedConnection)
-
- return True
-
- def _removeItem(self, item):
- """Remove table items corresponding to given plot item from the table.
-
- :param item: The plot item
- """
- row = self._itemToRow(item)
- if row is None:
- kind = self._plotWrapper.getKind(item)
- if kind in statsmdl.BASIC_COMPATIBLE_KINDS:
- _logger.error("Removing item that is not in table: %s", str(item))
- return
- item.sigItemChanged.disconnect(self._plotItemChanged)
- self.removeRow(row)
-
- def _removeAllItems(self):
- """Remove content of the table"""
- for row in range(self.rowCount()):
- tableItem = self.item(row, 0)
- item = self._tableItemToItem(tableItem)
- item.sigItemChanged.disconnect(self._plotItemChanged)
- self.clearContents()
- self.setRowCount(0)
-
- def _updateStats(self, item):
- """Update displayed information for given plot item
-
- :param item: The plot item
- """
- if item is None:
- return
- plot = self.getPlot()
- if plot is None:
- _logger.info("Plot not available")
- return
-
- row = self._itemToRow(item)
- if row is None:
- _logger.error("This item is not in the table: %s", str(item))
- return
-
- statsHandler = self.getStatsHandler()
- if statsHandler is not None:
- stats = statsHandler.calculate(
- item, plot, self._statsOnVisibleData)
- else:
- stats = {}
-
- with self._disableSorting():
- for name, tableItem in self._itemToTableItems(item).items():
- if name == self._LEGEND_HEADER_DATA:
- text = self._plotWrapper.getLabel(item)
- tableItem.setText(text)
- elif name == self._KIND_HEADER_DATA:
- tableItem.setText(self._plotWrapper.getKind(item))
- else:
- value = stats.get(name)
- if value is None:
- _logger.error("Value not found for: %s", name)
- tableItem.setText('-')
- else:
- tableItem.setText(str(value))
-
- def _updateAllStats(self, is_request=False):
- """Update stats for all rows in the table
-
- :param bool is_request: True if come from a manual request
- """
- if self.getUpdateMode() is UpdateMode.MANUAL and not is_request:
- return
- with self._disableSorting():
- for row in range(self.rowCount()):
- tableItem = self.item(row, 0)
- item = self._tableItemToItem(tableItem)
- self._updateStats(item)
-
- def _currentItemChanged(self, current, previous):
- """Handle change of selection in table and sync plot selection
-
- :param QTableWidgetItem current:
- :param QTableWidgetItem previous:
- """
- if current and current.row() >= 0:
- item = self._tableItemToItem(current)
- self._plotWrapper.setCurrentItem(item)
-
- def setDisplayOnlyActiveItem(self, displayOnlyActItem):
- """Toggle display off all items or only the active/selected one
-
- :param bool displayOnlyActItem:
- True if we want to only show active item
- """
- if self._displayOnlyActItem == displayOnlyActItem:
- return
- self._dealWithPlotConnection(create=False)
- if not self._displayOnlyActItem:
- self.currentItemChanged.disconnect(self._currentItemChanged)
-
- _StatsWidgetBase.setDisplayOnlyActiveItem(self, displayOnlyActItem)
-
- self._updateItemObserve()
- self._dealWithPlotConnection(create=True)
-
- if not self._displayOnlyActItem:
- self.currentItemChanged.connect(self._currentItemChanged)
- self.setSelectionMode(qt.QAbstractItemView.SingleSelection)
- else:
- self.setSelectionMode(qt.QAbstractItemView.NoSelection)
-
- def _updateModeHasChanged(self):
- self.sigUpdateModeChanged.emit(self._updateMode)
-
-
-class UpdateModeWidget(qt.QWidget):
- """Widget used to select the mode of update"""
- sigUpdateModeChanged = qt.Signal(object)
- """signal emitted when the mode for update changed"""
- sigUpdateRequested = qt.Signal()
- """signal emitted when an manual request for example is activate"""
-
- def __init__(self, parent=None):
- qt.QWidget.__init__(self, parent)
- self.setLayout(qt.QHBoxLayout())
- self._buttonGrp = qt.QButtonGroup(parent=self)
- self._buttonGrp.setExclusive(True)
-
- spacer = qt.QSpacerItem(20, 20,
- qt.QSizePolicy.Expanding,
- qt.QSizePolicy.Minimum)
- self.layout().addItem(spacer)
-
- self._autoRB = qt.QRadioButton('auto', parent=self)
- self.layout().addWidget(self._autoRB)
- self._buttonGrp.addButton(self._autoRB)
-
- self._manualRB = qt.QRadioButton('manual', parent=self)
- self.layout().addWidget(self._manualRB)
- self._buttonGrp.addButton(self._manualRB)
- self._manualRB.setChecked(True)
-
- refresh_icon = icons.getQIcon('view-refresh')
- self._updatePB = qt.QPushButton(refresh_icon, '', parent=self)
- self.layout().addWidget(self._updatePB)
-
- # connect signal / SLOT
- self._updatePB.clicked.connect(self._updateRequested)
- self._manualRB.toggled.connect(self._manualButtonToggled)
- self._autoRB.toggled.connect(self._autoButtonToggled)
-
- def _manualButtonToggled(self, checked):
- if checked:
- self.setUpdateMode(UpdateMode.MANUAL)
- self.sigUpdateModeChanged.emit(self.getUpdateMode())
-
- def _autoButtonToggled(self, checked):
- if checked:
- self.setUpdateMode(UpdateMode.AUTO)
- self.sigUpdateModeChanged.emit(self.getUpdateMode())
-
- def _updateRequested(self):
- if self.getUpdateMode() is UpdateMode.MANUAL:
- self.sigUpdateRequested.emit()
-
- def setUpdateMode(self, mode):
- """Set the way to update the displayed statistics.
-
- :param mode: mode requested for update
- :type mode: Union[str,UpdateMode]
- """
- mode = UpdateMode.from_value(mode)
-
- if mode is UpdateMode.AUTO:
- if not self._autoRB.isChecked():
- self._autoRB.setChecked(True)
- elif mode is UpdateMode.MANUAL:
- if not self._manualRB.isChecked():
- self._manualRB.setChecked(True)
- else:
- raise ValueError('mode', mode, 'is not recognized')
-
- def getUpdateMode(self):
- """Returns update mode (See :meth:`setUpdateMode`).
-
- :return: the active update mode
- :rtype: UpdateMode
- """
- if self._manualRB.isChecked():
- return UpdateMode.MANUAL
- elif self._autoRB.isChecked():
- return UpdateMode.AUTO
- else:
- raise RuntimeError("No mode selected")
-
- def showRadioButtons(self, show):
- """show / hide the QRadioButtons
-
- :param bool show: if True make RadioButton visible
- """
- self._autoRB.setVisible(show)
- self._manualRB.setVisible(show)
-
-
-class _OptionsWidget(qt.QToolBar):
-
- def __init__(self, parent=None, updateMode=None, displayOnlyActItem=False):
- assert updateMode is not None
- qt.QToolBar.__init__(self, parent)
- self.setIconSize(qt.QSize(16, 16))
-
- action = qt.QAction(self)
- action.setIcon(icons.getQIcon("stats-active-items"))
- action.setText("Active items only")
- action.setToolTip("Display stats for active items only.")
- action.setCheckable(True)
- action.setChecked(displayOnlyActItem)
- self.__displayActiveItems = action
-
- action = qt.QAction(self)
- action.setIcon(icons.getQIcon("stats-whole-items"))
- action.setText("All items")
- action.setToolTip("Display stats for all available items.")
- action.setCheckable(True)
- self.__displayWholeItems = action
-
- action = qt.QAction(self)
- action.setIcon(icons.getQIcon("stats-visible-data"))
- action.setText("Use the visible data range")
- action.setToolTip("Use the visible data range.<br/>"
- "If activated the data is filtered to only use"
- "visible data of the plot."
- "The filtering is a data sub-sampling."
- "No interpolation is made to fit data to"
- "boundaries.")
- action.setCheckable(True)
- self.__useVisibleData = action
-
- action = qt.QAction(self)
- action.setIcon(icons.getQIcon("stats-whole-data"))
- action.setText("Use the full data range")
- action.setToolTip("Use the full data range.")
- action.setCheckable(True)
- action.setChecked(True)
- self.__useWholeData = action
-
- self.addAction(self.__displayWholeItems)
- self.addAction(self.__displayActiveItems)
- self.addSeparator()
- self.addAction(self.__useVisibleData)
- self.addAction(self.__useWholeData)
-
- self.itemSelection = qt.QActionGroup(self)
- self.itemSelection.setExclusive(True)
- self.itemSelection.addAction(self.__displayActiveItems)
- self.itemSelection.addAction(self.__displayWholeItems)
-
- self.dataRangeSelection = qt.QActionGroup(self)
- self.dataRangeSelection.setExclusive(True)
- self.dataRangeSelection.addAction(self.__useWholeData)
- self.dataRangeSelection.addAction(self.__useVisibleData)
-
- self.__updateStatsAction = qt.QAction(self)
- self.__updateStatsAction.setIcon(icons.getQIcon("view-refresh"))
- self.__updateStatsAction.setText("update statistics")
- self.__updateStatsAction.setToolTip("update statistics")
- self.__updateStatsAction.setCheckable(False)
- self._updateStatsSep = self.addSeparator()
- self.addAction(self.__updateStatsAction)
-
- self._setUpdateMode(mode=updateMode)
-
- # expose API
- self.sigUpdateStats = self.__updateStatsAction.triggered
-
- def isActiveItemMode(self):
- return self.itemSelection.checkedAction() is self.__displayActiveItems
-
- def setDisplayActiveItems(self, only_active):
- self.__displayActiveItems.setChecked(only_active)
- self.__displayWholeItems.setChecked(not only_active)
-
- def isVisibleDataRangeMode(self):
- return self.dataRangeSelection.checkedAction() is self.__useVisibleData
-
- def setVisibleDataRangeModeEnabled(self, enabled):
- """Enable/Disable the visible data range mode
-
- :param bool enabled: True to allow user to choose
- stats on visible data
- """
- self.__useVisibleData.setEnabled(enabled)
- if not enabled:
- self.__useWholeData.setChecked(True)
-
- def _setUpdateMode(self, mode):
- self.__updateStatsAction.setVisible(mode == UpdateMode.MANUAL)
- self._updateStatsSep.setVisible(mode == UpdateMode.MANUAL)
-
- def getUpdateStatsAction(self):
- """
-
- :return: the action for the automatic mode
- :rtype: QAction
- """
- return self.__updateStatsAction
-
-
-class StatsWidget(qt.QWidget):
- """
- Widget displaying a set of :class:`Stat` to be displayed on a
- :class:`StatsTable` and to be apply on items contained in the :class:`Plot`
- Also contains options to:
-
- * compute statistics on all the data or on visible data only
- * show statistics of all items or only the active one
-
- :param QWidget parent: Qt parent
- :param Union[PlotWidget,SceneWidget] plot:
- The plot containing items on which we want statistics.
- :param StatsHandler stats:
- Set the statistics to be displayed and how to format them using
- """
-
- sigVisibilityChanged = qt.Signal(bool)
- """Signal emitted when the visibility of this widget changes.
-
- It Provides the visibility of the widget.
- """
-
- NUMBER_FORMAT = '{0:.3f}'
-
- def __init__(self, parent=None, plot=None, stats=None):
- qt.QWidget.__init__(self, parent)
- self.setLayout(qt.QVBoxLayout())
- self.layout().setContentsMargins(0, 0, 0, 0)
- self._options = _OptionsWidget(parent=self, updateMode=UpdateMode.MANUAL)
- self.layout().addWidget(self._options)
- self._statsTable = StatsTable(parent=self, plot=plot)
- self._statsTable.setDisplayOnlyActiveItem(self._options.isActiveItemMode())
- self._options._setUpdateMode(mode=self._statsTable.getUpdateMode())
- self.setStats(stats)
-
- self.layout().addWidget(self._statsTable)
-
- old = self._statsTable.blockSignals(True)
- self._options.itemSelection.triggered.connect(
- self._optSelectionChanged)
- self._options.dataRangeSelection.triggered.connect(
- self._optDataRangeChanged)
- self._optDataRangeChanged()
- self._statsTable.blockSignals(old)
-
- self._statsTable.sigUpdateModeChanged.connect(self._options._setUpdateMode)
- callback = functools.partial(self._getStatsTable()._updateAllStats, is_request=True)
- self._options.sigUpdateStats.connect(callback)
-
- def _getStatsTable(self):
- """Returns the :class:`StatsTable` used by this widget.
-
- :rtype: StatsTable
- """
- return self._statsTable
-
- def showEvent(self, event):
- self.sigVisibilityChanged.emit(True)
- qt.QWidget.showEvent(self, event)
-
- def hideEvent(self, event):
- self.sigVisibilityChanged.emit(False)
- qt.QWidget.hideEvent(self, event)
-
- def _optSelectionChanged(self, action=None):
- self._getStatsTable().setDisplayOnlyActiveItem(
- self._options.isActiveItemMode())
-
- def _optDataRangeChanged(self, action=None):
- self._getStatsTable().setStatsOnVisibleData(
- self._options.isVisibleDataRangeMode())
-
- # Proxy methods
-
- @docstring(StatsTable)
- def setStats(self, statsHandler):
- return self._getStatsTable().setStats(statsHandler=statsHandler)
-
- @docstring(StatsTable)
- def setPlot(self, plot):
- self._options.setVisibleDataRangeModeEnabled(
- plot is None or isinstance(plot, PlotWidget))
- return self._getStatsTable().setPlot(plot=plot)
-
- @docstring(StatsTable)
- def getPlot(self):
- return self._getStatsTable().getPlot()
-
- @docstring(StatsTable)
- def setDisplayOnlyActiveItem(self, displayOnlyActItem):
- old = self._options.blockSignals(True)
- # update the options
- self._options.setDisplayActiveItems(displayOnlyActItem)
- self._options.blockSignals(old)
- return self._getStatsTable().setDisplayOnlyActiveItem(
- displayOnlyActItem=displayOnlyActItem)
-
- @docstring(StatsTable)
- def setStatsOnVisibleData(self, b):
- return self._getStatsTable().setStatsOnVisibleData(b=b)
-
- @docstring(StatsTable)
- def getUpdateMode(self):
- return self._statsTable.getUpdateMode()
-
- @docstring(StatsTable)
- def setUpdateMode(self, mode):
- self._statsTable.setUpdateMode(mode)
-
-
-DEFAULT_STATS = StatsHandler((
- (statsmdl.StatMin(), StatFormatter()),
- statsmdl.StatCoordMin(),
- (statsmdl.StatMax(), StatFormatter()),
- statsmdl.StatCoordMax(),
- statsmdl.StatCOM(),
- (('mean', numpy.mean), StatFormatter()),
- (('std', numpy.std), StatFormatter()),
-))
-
-
-class BasicStatsWidget(StatsWidget):
- """
- Widget defining a simple set of :class:`Stat` to be displayed on a
- :class:`StatsWidget`.
-
- :param QWidget parent: Qt parent
- :param PlotWidget plot:
- The plot containing items on which we want statistics.
- :param StatsHandler stats:
- Set the statistics to be displayed and how to format them using
-
- .. snapshotqt:: img/BasicStatsWidget.png
- :width: 300px
- :align: center
-
- from silx.gui.plot import Plot1D
- from silx.gui.plot.StatsWidget import BasicStatsWidget
-
- plot = Plot1D()
- x = range(100)
- y = x
- plot.addCurve(x, y, legend='curve_0')
- plot.setActiveCurve('curve_0')
-
- widget = BasicStatsWidget(plot=plot)
- widget.show()
- """
- def __init__(self, parent=None, plot=None):
- StatsWidget.__init__(self, parent=parent, plot=plot,
- stats=DEFAULT_STATS)
-
-
-class _BaseLineStatsWidget(_StatsWidgetBase, qt.QWidget):
- """
- Widget made to display stats into a QLayout with couple (QLabel, QLineEdit)
- created for each stats.
- The layout can be defined prior of adding any statistic.
-
- :param QWidget parent: Qt parent
- :param Union[PlotWidget,SceneWidget] plot:
- The plot containing items on which we want statistics.
- :param str kind: the kind of plotitems we want to display
- :param StatsHandler stats:
- Set the statistics to be displayed and how to format them using
- :param bool statsOnVisibleData: compute statistics for the whole data or
- only visible ones.
- """
-
- sigUpdateModeChanged = qt.Signal(object)
- """Signal emitted when the update mode changed"""
-
- def __init__(self, parent=None, plot=None, kind='curve', stats=None,
- statsOnVisibleData=False):
- self._item_kind = kind
- """The item displayed"""
- self._statQlineEdit = {}
- """list of legends actually displayed"""
- self._n_statistics_per_line = 4
- """number of statistics displayed per line in the grid layout"""
- qt.QWidget.__init__(self, parent)
- _StatsWidgetBase.__init__(self,
- statsOnVisibleData=statsOnVisibleData,
- displayOnlyActItem=True)
- self.setLayout(self._createLayout())
- self.setPlot(plot)
- if stats is not None:
- self.setStats(stats)
-
- def _addItemForStatistic(self, statistic):
- assert isinstance(statistic, statsmdl.StatBase)
- assert statistic.name in self._statsHandler.stats
-
- self.layout().setSpacing(2)
- self.layout().setContentsMargins(2, 2, 2, 2)
-
- if isinstance(self.layout(), qt.QGridLayout):
- parent = self
- else:
- widget = qt.QWidget(parent=self)
- parent = widget
-
- qLabel = qt.QLabel(statistic.name + ':', parent=parent)
- qLineEdit = qt.QLineEdit('', parent=parent)
- qLineEdit.setReadOnly(True)
-
- self._addStatsWidgetsToLayout(qLabel=qLabel, qLineEdit=qLineEdit)
- self._statQlineEdit[statistic.name] = qLineEdit
-
- def setPlot(self, plot):
- """Define the plot to interact with
-
- :param Union[PlotWidget,SceneWidget,None] plot:
- The plot containing the items on which statistics are applied
- """
- _StatsWidgetBase.setPlot(self, plot)
- self._updateAllStats()
-
- def _addStatsWidgetsToLayout(self, qLabel, qLineEdit):
- raise NotImplementedError('Base class')
-
- 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
- """
- _StatsWidgetBase.setStats(self, statsHandler)
- for statName, stat in list(self._statsHandler.stats.items()):
- self._addItemForStatistic(stat)
- self._updateAllStats()
-
- def _activeItemChanged(self, kind, previous, current):
- if self.getUpdateMode() is UpdateMode.MANUAL:
- return
- if kind == self._item_kind:
- self._updateAllStats()
-
- def _updateAllStats(self):
- plot = self.getPlot()
- if plot is not None:
- _items = self._plotWrapper.getSelectedItems()
-
- def kind_filter(_item):
- return self._plotWrapper.getKind(_item) == self.getKind()
- items = list(filter(kind_filter, _items))
- assert len(items) in (0, 1)
- if len(items) is 1:
- self._setItem(items[0])
-
- def setKind(self, kind):
- """Change the kind of active item to display
- :param str kind: kind of item to display information for ('curve' ...)
- """
- if self._item_kind != kind:
- self._item_kind = kind
- self._updateItemObserve()
-
- def getKind(self):
- """
- :return: kind of item we want to compute statistic for
- :rtype: str
- """
- return self._item_kind
-
- def _setItem(self, item):
- if item is None:
- for stat_name, stat_widget in self._statQlineEdit.items():
- stat_widget.setText('')
- elif (self._statsHandler is not None and len(
- self._statsHandler.stats) > 0):
- plot = self.getPlot()
- if plot is not None:
- statsValDict = self._statsHandler.calculate(item,
- plot,
- self._statsOnVisibleData)
- for statName, statVal in list(statsValDict.items()):
- self._statQlineEdit[statName].setText(statVal)
-
- def _updateItemObserve(self, *argv):
- if self.getUpdateMode() is UpdateMode.MANUAL:
- return
- assert self._displayOnlyActItem
- _items = self._plotWrapper.getSelectedItems()
-
- def kind_filter(_item):
- return self._plotWrapper.getKind(_item) == self.getKind()
- items = list(filter(kind_filter, _items))
- assert len(items) in (0, 1)
- _item = items[0] if len(items) is 1 else None
- self._setItem(_item)
-
- def _createLayout(self):
- """create an instance of the main QLayout"""
- raise NotImplementedError('Base class')
-
- def _addItem(self, item):
- raise NotImplementedError('Display only the active item')
-
- def _removeItem(self, item):
- raise NotImplementedError('Display only the active item')
-
- def _plotCurrentChanged(selfself, current):
- raise NotImplementedError('Display only the active item')
-
- def _updateModeHasChanged(self):
- self.sigUpdateModeChanged.emit(self._updateMode)
-
-
-class _BasicLineStatsWidget(_BaseLineStatsWidget):
- def __init__(self, parent=None, plot=None, kind='curve',
- stats=DEFAULT_STATS, statsOnVisibleData=False):
- _BaseLineStatsWidget.__init__(self, parent=parent, kind=kind,
- plot=plot, stats=stats,
- statsOnVisibleData=statsOnVisibleData)
-
- def _createLayout(self):
- return FlowLayout()
-
- def _addStatsWidgetsToLayout(self, qLabel, qLineEdit):
- # create a mother widget to make sure both qLabel & qLineEdit will
- # always be displayed side by side
- widget = qt.QWidget(parent=self)
- widget.setLayout(qt.QHBoxLayout())
- widget.layout().setSpacing(0)
- widget.layout().setContentsMargins(0, 0, 0, 0)
-
- widget.layout().addWidget(qLabel)
- widget.layout().addWidget(qLineEdit)
-
- self.layout().addWidget(widget)
-
- def _addOptionsWidget(self, widget):
- self.layout().addWidget(widget)
-
-
-class BasicLineStatsWidget(qt.QWidget):
- """
- Widget defining a simple set of :class:`Stat` to be displayed on a
- :class:`LineStatsWidget`.
-
- :param QWidget parent: Qt parent
- :param Union[PlotWidget,SceneWidget] plot:
- The plot containing items on which we want statistics.
- :param str kind: the kind of plotitems we want to display
- :param StatsHandler stats:
- Set the statistics to be displayed and how to format them using
- :param bool statsOnVisibleData: compute statistics for the whole data or
- only visible ones.
- """
- def __init__(self, parent=None, plot=None, kind='curve',
- stats=DEFAULT_STATS, statsOnVisibleData=False):
- qt.QWidget.__init__(self, parent)
- self.setLayout(qt.QHBoxLayout())
- self.layout().setSpacing(0)
- self.layout().setContentsMargins(0, 0, 0, 0)
- self._lineStatsWidget = _BasicLineStatsWidget(parent=self, plot=plot,
- kind=kind, stats=stats,
- statsOnVisibleData=statsOnVisibleData)
- self.layout().addWidget(self._lineStatsWidget)
-
- self._options = UpdateModeWidget()
- self._options.setUpdateMode(self._lineStatsWidget.getUpdateMode())
- self._options.showRadioButtons(False)
- self.layout().addWidget(self._options)
-
- # connect Signal ? SLOT
- self._lineStatsWidget.sigUpdateModeChanged.connect(self._options.setUpdateMode)
- self._options.sigUpdateModeChanged.connect(self._lineStatsWidget.setUpdateMode)
- self._options.sigUpdateRequested.connect(self._lineStatsWidget._updateAllStats)
-
- def showControl(self, visible):
- self._options.setVisible(visible)
-
- # Proxy methods
-
- @docstring(_BasicLineStatsWidget)
- def setUpdateMode(self, mode):
- self._lineStatsWidget.setUpdateMode(mode=mode)
-
- @docstring(_BasicLineStatsWidget)
- def getUpdateMode(self):
- return self._lineStatsWidget.getUpdateMode()
-
- @docstring(_BasicLineStatsWidget)
- def setPlot(self, plot):
- self._lineStatsWidget.setPlot(plot=plot)
-
- @docstring(_BasicLineStatsWidget)
- def setStats(self, statsHandler):
- self._lineStatsWidget.setStats(statsHandler=statsHandler)
-
- @docstring(_BasicLineStatsWidget)
- def setKind(self, kind):
- self._lineStatsWidget.setKind(kind=kind)
-
- @docstring(_BasicLineStatsWidget)
- def getKind(self):
- return self._lineStatsWidget.getKind()
-
- @docstring(_BasicLineStatsWidget)
- def setStatsOnVisibleData(self, b):
- self._lineStatsWidget.setStatsOnVisibleData(b)
-
- @docstring(UpdateModeWidget)
- def showRadioButtons(self, show):
- self._options.showRadioButtons(show=show)
-
-
-class _BasicGridStatsWidget(_BaseLineStatsWidget):
- def __init__(self, parent=None, plot=None, kind='curve',
- stats=DEFAULT_STATS, statsOnVisibleData=False,
- statsPerLine=4):
- _BaseLineStatsWidget.__init__(self, parent=parent, kind=kind,
- plot=plot, stats=stats,
- statsOnVisibleData=statsOnVisibleData)
- self._n_statistics_per_line = statsPerLine
-
- def _addStatsWidgetsToLayout(self, qLabel, qLineEdit):
- column = len(self._statQlineEdit) % self._n_statistics_per_line
- row = len(self._statQlineEdit) // self._n_statistics_per_line
- self.layout().addWidget(qLabel, row, column * 2)
- self.layout().addWidget(qLineEdit, row, column * 2 + 1)
-
- def _createLayout(self):
- return qt.QGridLayout()
-
-
-class BasicGridStatsWidget(qt.QWidget):
- """
- pymca design like widget
-
- :param QWidget parent: Qt parent
- :param Union[PlotWidget,SceneWidget] plot:
- The plot containing items on which we want statistics.
- :param StatsHandler stats:
- Set the statistics to be displayed and how to format them using
- :param str kind: the kind of plotitems we want to display
- :param bool statsOnVisibleData: compute statistics for the whole data or
- only visible ones.
- :param int statsPerLine: number of statistic to be displayed per line
-
- .. snapshotqt:: img/_BasicGridStatsWidget.png
- :width: 600px
- :align: center
-
- from silx.gui.plot import Plot1D
- from silx.gui.plot.StatsWidget import _BasicGridStatsWidget
-
- plot = Plot1D()
- x = range(100)
- y = x
- plot.addCurve(x, y, legend='curve_0')
- plot.setActiveCurve('curve_0')
-
- widget = _BasicGridStatsWidget(plot=plot, kind='curve')
- widget.show()
- """
-
- def __init__(self, parent=None, plot=None, kind='curve',
- stats=DEFAULT_STATS, statsOnVisibleData=False):
- qt.QWidget.__init__(self, parent)
- self.setLayout(qt.QVBoxLayout())
- self.layout().setSpacing(0)
- self.layout().setContentsMargins(0, 0, 0, 0)
-
- self._options = UpdateModeWidget()
- self._options.showRadioButtons(False)
- self.layout().addWidget(self._options)
-
- self._lineStatsWidget = _BasicGridStatsWidget(parent=self, plot=plot,
- kind=kind, stats=stats,
- statsOnVisibleData=statsOnVisibleData)
- self.layout().addWidget(self._lineStatsWidget)
-
- # tune options
- self._options.setUpdateMode(self._lineStatsWidget.getUpdateMode())
-
- # connect Signal ? SLOT
- self._lineStatsWidget.sigUpdateModeChanged.connect(self._options.setUpdateMode)
- self._options.sigUpdateModeChanged.connect(self._lineStatsWidget.setUpdateMode)
- self._options.sigUpdateRequested.connect(self._lineStatsWidget._updateAllStats)
-
- def showControl(self, visible):
- self._options.setVisible(visible)
-
- @docstring(_BasicGridStatsWidget)
- def setUpdateMode(self, mode):
- self._lineStatsWidget.setUpdateMode(mode=mode)
-
- @docstring(_BasicGridStatsWidget)
- def getUpdateMode(self):
- return self._lineStatsWidget.getUpdateMode()
-
- @docstring(_BasicGridStatsWidget)
- def setPlot(self, plot):
- self._lineStatsWidget.setPlot(plot=plot)
-
- @docstring(_BasicGridStatsWidget)
- def setStats(self, statsHandler):
- self._lineStatsWidget.setStats(statsHandler=statsHandler)
-
- @docstring(_BasicGridStatsWidget)
- def setKind(self, kind):
- self._lineStatsWidget.setKind(kind=kind)
-
- @docstring(_BasicGridStatsWidget)
- def getKind(self):
- return self._lineStatsWidget.getKind()
-
- @docstring(_BasicGridStatsWidget)
- def setStatsOnVisibleData(self, b):
- self._lineStatsWidget.setStatsOnVisibleData(b)
-
- @docstring(UpdateModeWidget)
- def showRadioButtons(self, show):
- self._options.showRadioButtons(show=show)