Source code for silx.gui.plot3d.tools.PositionInfoWidget
# coding: utf-8
# /*##########################################################################
#
# Copyright (c) 2018-2021 European Synchrotron Radiation Facility
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
"""This module provides a widget that displays data values of a SceneWidget.
"""
from __future__ import absolute_import
__authors__ = ["T. Vincent"]
__license__ = "MIT"
__date__ = "01/10/2018"
import logging
import weakref
from ... import qt
from .. import actions
from .. import items
from ..items import volume
from ..SceneWidget import SceneWidget
_logger = logging.getLogger(__name__)
[docs]class PositionInfoWidget(qt.QWidget):
"""Widget displaying information about picked position
:param QWidget parent: See :class:`QWidget`
"""
def __init__(self, parent=None):
super(PositionInfoWidget, self).__init__(parent)
self._sceneWidgetRef = None
self.setToolTip("Double-click on a data point to show its value")
layout = qt.QBoxLayout(qt.QBoxLayout.LeftToRight, self)
self._xLabel = self._addInfoField('X')
self._yLabel = self._addInfoField('Y')
self._zLabel = self._addInfoField('Z')
self._dataLabel = self._addInfoField('Data')
self._itemLabel = self._addInfoField('Item')
layout.addStretch(1)
self._action = actions.mode.PickingModeAction(parent=self)
self._action.setText('Selection')
self._action.setToolTip(
'Toggle selection information update with left button click')
self._action.sigSceneClicked.connect(self.pick)
self._action.changed.connect(self.__actionChanged)
self._action.setChecked(False) # Disabled by default
self.__actionChanged() # Sync action/widget
def __actionChanged(self):
"""Handle toggle action change signal"""
if self.toggleAction().isChecked() != self.isEnabled():
self.setEnabled(self.toggleAction().isChecked())
[docs] def toggleAction(self):
"""The action to toggle the picking mode.
:rtype: QAction
"""
return self._action
def _addInfoField(self, label):
"""Add a description: info widget to this widget
:param str label: Description label
:return: The QLabel used to display the info
:rtype: QLabel
"""
subLayout = qt.QHBoxLayout()
subLayout.setContentsMargins(0, 0, 0, 0)
subLayout.addWidget(qt.QLabel(label + ':'))
widget = qt.QLabel('-')
widget.setAlignment(qt.Qt.AlignLeft | qt.Qt.AlignVCenter)
widget.setTextInteractionFlags(qt.Qt.TextSelectableByMouse)
widget.setMinimumWidth(widget.fontMetrics().width('#######'))
subLayout.addWidget(widget)
subLayout.addStretch(1)
layout = self.layout()
layout.addLayout(subLayout)
return widget
[docs] def getSceneWidget(self):
"""Returns the associated :class:`SceneWidget` or None.
:rtype: Union[None,~silx.gui.plot3d.SceneWidget.SceneWidget]
"""
if self._sceneWidgetRef is None:
return None
else:
return self._sceneWidgetRef()
[docs] def setSceneWidget(self, widget):
"""Set the associated :class:`SceneWidget`
:param ~silx.gui.plot3d.SceneWidget.SceneWidget widget:
3D scene for which to display information
"""
if widget is not None and not isinstance(widget, SceneWidget):
raise ValueError("widget must be a SceneWidget or None")
self._sceneWidgetRef = None if widget is None else weakref.ref(widget)
self.toggleAction().setPlot3DWidget(widget)
[docs] def clear(self):
"""Clean-up displayed values"""
for widget in (self._xLabel, self._yLabel, self._zLabel,
self._dataLabel, self._itemLabel):
widget.setText('-')
_SUPPORTED_ITEMS = (items.Scatter3D,
items.Scatter2D,
items.ImageData,
items.ImageRgba,
items.HeightMapData,
items.HeightMapRGBA,
items.Mesh,
items.Box,
items.Cylinder,
items.Hexagon,
volume.CutPlane,
volume.Isosurface)
"""Type of items that are picked"""
def _isSupportedItem(self, item):
"""Returns True if item is of supported type
:param Item3D item: The Item3D to check
:rtype: bool
"""
return isinstance(item, self._SUPPORTED_ITEMS)
[docs] def pick(self, x, y):
"""Pick items in the associated SceneWidget and display result
Only the closest point is displayed.
:param int x: X coordinate in pixel in the SceneWidget
:param int y: Y coordinate in pixel in the SceneWidget
"""
self.clear()
sceneWidget = self.getSceneWidget()
if sceneWidget is None: # No associated widget
_logger.info('Picking without associated SceneWidget')
return
# Find closest (and latest in the tree) supported item
closestNdcZ = float('inf')
picking = None
for result in sceneWidget.pickItems(x, y,
condition=self._isSupportedItem):
ndcZ = result.getPositions('ndc', copy=False)[0, 2]
if ndcZ <= closestNdcZ:
closestNdcZ = ndcZ
picking = result
if picking is None:
return # No picked item
item = picking.getItem()
self._itemLabel.setText(item.getLabel())
positions = picking.getPositions('scene', copy=False)
x, y, z = positions[0]
self._xLabel.setText("%g" % x)
self._yLabel.setText("%g" % y)
self._zLabel.setText("%g" % z)
data = picking.getData(copy=False)
if data is not None:
data = data[0]
if hasattr(data, '__len__'):
text = ' '.join(["%.3g"] * len(data)) % tuple(data)
else:
text = "%g" % data
self._dataLabel.setText(text)
[docs] def updateInfo(self):
"""Update information according to cursor position"""
widget = self.getSceneWidget()
if widget is None:
_logger.info('Update without associated SceneWidget')
self.clear()
return
position = widget.mapFromGlobal(qt.QCursor.pos())
self.pick(position.x(), position.y())