Skip to content

Commit 2eabc24

Browse files
authored
Merge pull request #236 from zhujun98/add_meter_bar_to_plot_area
Add meter bar to plot area
2 parents fa7fd14 + 17a1473 commit 2eabc24

17 files changed

+180
-102
lines changed

extra_foam/gui/image_tool/azimuthal_integ_1d_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class AzimuthalInteg1dPlot(PlotWidgetF):
2323
"""
2424
def __init__(self, *, parent=None):
2525
"""Initialization."""
26-
super().__init__(parent=parent, show_indicator=True)
26+
super().__init__(parent=parent)
2727

2828
x_label, y_label = plot_labels[AnalysisType.AZIMUTHAL_INTEG]
2929
self.setLabel('bottom', x_label)

extra_foam/gui/image_tool/corrected_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class RoiProjPlot(PlotWidgetF):
3131
"""
3232
def __init__(self, *, parent=None):
3333
"""Initialization."""
34-
super().__init__(parent=parent, show_indicator=True)
34+
super().__init__(parent=parent)
3535

3636
x_label, y_label = plot_labels[AnalysisType.ROI_PROJ]
3737
self.setLabel('bottom', x_label)

extra_foam/gui/plot_widgets/graphics_widgets.py

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,13 @@ class PlotArea(pg.GraphicsWidget):
185185
# Emitted when the ViewBox X range has changed
186186
sigXRangeChanged = pyqtSignal(object, object)
187187

188-
def __init__(self, name=None, parent=None):
188+
cross_toggled_sgn = pyqtSignal(bool)
189+
190+
_METER_ROW = 0
191+
_TITLE_ROW = 1
192+
193+
def __init__(self, name=None, *,
194+
enable_meter=True, enable_transform=True, parent=None):
189195
super().__init__(parent=parent)
190196

191197
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
@@ -200,9 +206,13 @@ def __init__(self, name=None, parent=None):
200206

201207
self._legend = None
202208
self._axes = {}
209+
self._meter = pg.LabelItem(
210+
'', size='11pt', justify='left', color='6A3D9A', parent=self)
203211
self._title = pg.LabelItem('', size='11pt', parent=self)
204212

205213
# context menu
214+
self._show_cross_cb = QCheckBox("Cross cursor")
215+
206216
self._show_x_grid_cb = QCheckBox("Show X Grid")
207217
self._show_y_grid_cb = QCheckBox("Show Y Grid")
208218
self._grid_opacity_sld = QSlider(Qt.Horizontal)
@@ -215,7 +225,10 @@ def __init__(self, name=None, parent=None):
215225
self._log_y_cb = QCheckBox("Log Y")
216226

217227
self._menu = None
218-
self._enable_log_menu = True
228+
self._enable_transform = enable_transform
229+
self._enable_meter = enable_meter
230+
231+
self._show_meter = False
219232

220233
self._layout = QGraphicsGridLayout()
221234

@@ -229,13 +242,11 @@ def initUI(self):
229242
layout.setHorizontalSpacing(0)
230243
layout.setVerticalSpacing(0)
231244

232-
layout.addItem(self._title, 0, 1)
233-
layout.addItem(self._vb, 2, 1)
234-
235-
self._initAxisItems()
236-
self.setTitle()
245+
layout.addItem(self._meter, self._METER_ROW, 1)
246+
layout.addItem(self._title, self._TITLE_ROW, 1)
247+
layout.addItem(self._vb, 3, 1)
237248

238-
for i in range(4):
249+
for i in range(5):
239250
layout.setRowPreferredHeight(i, 0)
240251
layout.setRowMinimumHeight(i, 0)
241252
layout.setRowSpacing(i, 0)
@@ -252,13 +263,19 @@ def initUI(self):
252263

253264
self.setLayout(layout)
254265

266+
self._initAxisItems()
267+
self.setTitle()
268+
self.showMeter(self._show_meter)
269+
255270
self._initContextMenu()
256271

257272
def initConnections(self):
258273
self._vb.sigRangeChanged.connect(self.range_changed_sgn)
259274
self._vb.sigXRangeChanged.connect(self.sigXRangeChanged)
260275
self._vb.sigYRangeChanged.connect(self.sigYRangeChanged)
261276

277+
self._show_cross_cb.toggled.connect(self._onShowCrossChanged)
278+
262279
self._show_x_grid_cb.toggled.connect(self._onShowGridChanged)
263280
self._show_y_grid_cb.toggled.connect(self._onShowGridChanged)
264281
self._grid_opacity_sld.sliderReleased.connect(self._onShowGridChanged)
@@ -268,11 +285,17 @@ def initConnections(self):
268285

269286
def _initContextMenu(self):
270287
self._menu = [
288+
QMenu("Meter"),
271289
QMenu("Grid"),
272290
QMenu("Transform")
273291
]
274292

275-
grid_menu = self._menu[0]
293+
meter_menu = self._menu[0]
294+
cross_act = QWidgetAction(meter_menu)
295+
cross_act.setDefaultWidget(self._show_cross_cb)
296+
meter_menu.addAction(cross_act)
297+
298+
grid_menu = self._menu[1]
276299
show_x_act = QWidgetAction(grid_menu)
277300
show_x_act.setDefaultWidget(self._show_x_grid_cb)
278301
grid_menu.addAction(show_x_act)
@@ -288,7 +311,7 @@ def _initContextMenu(self):
288311
opacity_act.setDefaultWidget(widget)
289312
grid_menu.addAction(opacity_act)
290313

291-
transform_menu = self._menu[1]
314+
transform_menu = self._menu[2]
292315
log_x_act = QWidgetAction(transform_menu)
293316
log_x_act.setDefaultWidget(self._log_x_cb)
294317
transform_menu.addAction(log_x_act)
@@ -297,10 +320,10 @@ def _initContextMenu(self):
297320
transform_menu.addAction(log_y_act)
298321

299322
def _initAxisItems(self):
300-
for orient, pos in (('top', (1, 1)),
301-
('bottom', (3, 1)),
302-
('left', (2, 0)),
303-
('right', (2, 2))):
323+
for orient, pos in (('top', (2, 1)),
324+
('bottom', (4, 1)),
325+
('left', (3, 0)),
326+
('right', (3, 2))):
304327
axis = pg.AxisItem(orientation=orient, parent=self)
305328

306329
axis.linkToView(self._vb)
@@ -320,6 +343,11 @@ def clearAllPlotItems(self):
320343
# TODO: introduce a method which set empty data
321344
item.setData([], [])
322345

346+
@pyqtSlot(bool)
347+
def _onShowCrossChanged(self, state):
348+
self.showMeter(state)
349+
self.cross_toggled_sgn.emit(state)
350+
323351
@pyqtSlot()
324352
def _onShowGridChanged(self):
325353
alpha = self._grid_opacity_sld.value()
@@ -385,12 +413,13 @@ def removeAllItems(self):
385413

386414
def getContextMenus(self, event):
387415
"""Override."""
388-
if self._enable_log_menu:
389-
return self._menu
390-
return self._menu[:-1]
391-
392-
def enableLogMenu(self, enable):
393-
self._enable_log_menu = enable
416+
start = 0
417+
end = len(self._menu)
418+
if not self._enable_transform:
419+
end -= 1
420+
if not self._enable_meter:
421+
start += 1
422+
return self._menu[start:end]
394423

395424
def getAxis(self, axis):
396425
"""Return the specified AxisItem.
@@ -449,18 +478,47 @@ def showLabel(self, axis, show=True):
449478
"""
450479
self.getAxis(axis).showLabel(show)
451480

481+
def showMeter(self, show=True):
482+
"""Show or hide the meter bar.
483+
484+
:param bool show: whether to show the meter bar.
485+
"""
486+
row = self._METER_ROW
487+
if not show:
488+
self._meter.setMaximumHeight(0)
489+
self._layout.setRowFixedHeight(row, 0)
490+
self._meter.setVisible(False)
491+
else:
492+
self._meter.setMaximumHeight(30)
493+
self._layout.setRowFixedHeight(row, 30)
494+
self._meter.setVisible(True)
495+
496+
self._show_meter = show
497+
498+
def setMeter(self, pos):
499+
"""Set the meter of the plot."""
500+
if not self._show_meter:
501+
return
502+
503+
if pos is None:
504+
self._meter.setText("")
505+
else:
506+
x, y = pos
507+
self._meter.setText(f"x = {x}, y = {y}")
508+
452509
def setTitle(self, title=None, **args):
453510
"""Set the title of the plot.
454511
455512
:param str title: text to display along the axis. HTML allowed.
456513
"""
514+
row = self._TITLE_ROW
457515
if title is None:
458516
self._title.setMaximumHeight(0)
459-
self._layout.setRowFixedHeight(0, 0)
517+
self._layout.setRowFixedHeight(row, 0)
460518
self._title.setVisible(False)
461519
else:
462520
self._title.setMaximumHeight(30)
463-
self._layout.setRowFixedHeight(0, 30)
521+
self._layout.setRowFixedHeight(row, 30)
464522
self._title.setText(title, **args)
465523
self._title.setVisible(True)
466524

@@ -472,3 +530,6 @@ def invertY(self, *args, **kwargs):
472530

473531
def invertX(self, *args, **kwargs):
474532
self._vb.invertX(*args, **kwargs)
533+
534+
def mapSceneToView(self, *args, **kwargs):
535+
return self._vb.mapSceneToView(*args, **kwargs)

extra_foam/gui/plot_widgets/image_view_base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ def __init__(self, *,
8181
if has_roi:
8282
self._initializeROIs(roi_position, roi_size)
8383

84-
self._plot_widget = PlotWidgetF()
85-
self._plot_widget.disableLogMenu()
84+
self._plot_widget = PlotWidgetF(enable_meter=False,
85+
enable_transform=False)
8686

8787
self._cached_title = None
8888
# use the public interface for caching

extra_foam/gui/plot_widgets/plot_widget_base.py

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import numpy as np
1313

14-
from PyQt5.QtCore import pyqtSignal, QTimer
14+
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QTimer
1515
from PyQt5.QtWidgets import QSizePolicy
1616

1717
from .. import pyqtgraph as pg
@@ -40,7 +40,9 @@ class PlotWidgetF(pg.GraphicsView):
4040
sigTransformChanged = pyqtSignal(object)
4141

4242
def __init__(self, parent=None, *,
43-
background='default', show_indicator=False, **kargs):
43+
background='default',
44+
enable_meter=True,
45+
enable_transform=True):
4446
"""Initialization."""
4547
super().__init__(parent, background=background)
4648

@@ -49,23 +51,20 @@ def __init__(self, parent=None, *,
4951

5052
self._title = ""
5153

52-
self._plot_area = PlotArea(**kargs)
54+
self._plot_area = PlotArea(enable_meter=enable_meter,
55+
enable_transform=enable_transform)
5356
self.setCentralWidget(self._plot_area)
57+
self._plot_area.cross_toggled_sgn.connect(self.onCrossToggled)
5458

55-
# TODO: improve indicator implementation
56-
# Move Indicator to PlotArea
57-
self._show_indicator = show_indicator
58-
if show_indicator:
59+
self._v_line = None
60+
self._h_line = None
61+
if enable_meter:
5962
self._v_line = pg.InfiniteLine(angle=90, movable=False)
6063
self._h_line = pg.InfiniteLine(angle=0, movable=False)
61-
self._indicator = pg.TextItem(color=FColor.k)
6264
self._v_line.hide()
6365
self._h_line.hide()
64-
self._indicator.hide()
6566
self._plot_area.addItem(self._v_line, ignore_bounds=True)
6667
self._plot_area.addItem(self._h_line, ignore_bounds=True)
67-
self._plot_area.scene().addItem(self._indicator)
68-
6968
# rateLimit should be fast enough to be able to capture
7069
# the leaveEvent
7170
self._proxy = pg.SignalProxy(self._plot_area.scene().sigMouseMoved,
@@ -218,39 +217,24 @@ def showLegend(self):
218217
"""Show legend."""
219218
self._plot_area.showLegend(True)
220219

221-
def disableLogMenu(self):
222-
"""Disable log X/Y context menu."""
223-
self._plot_area.enableLogMenu(False)
224-
225220
def viewRangeChanged(self, view, range):
226221
self.sigRangeChanged.emit(self, range)
227222

228-
def onMouseMoved(self, ev):
229-
pos = ev[0]
230-
y_shift = 45 # move text to the top of the mouse cursor
231-
self._indicator.setPos(pos.x(), pos.y() - y_shift)
232-
233-
# TODO: improve
234-
m_pos = self._plot_area._vb.mapSceneToView(pos)
235-
x, y = m_pos.x(), m_pos.y()
236-
self._v_line.setPos(x)
237-
self._h_line.setPos(y)
238-
239-
self._indicator.setText(f"x={x}\ny={y}")
240-
241-
def enterEvent(self, ev):
242-
"""Override."""
243-
if self._show_indicator:
223+
@pyqtSlot(bool)
224+
def onCrossToggled(self, state):
225+
if state:
244226
self._v_line.show()
245227
self._h_line.show()
246-
self._indicator.show()
247-
248-
def leaveEvent(self, ev):
249-
"""Override."""
250-
if self._show_indicator:
228+
else:
251229
self._v_line.hide()
252230
self._h_line.hide()
253-
self._indicator.hide()
231+
232+
def onMouseMoved(self, pos):
233+
m_pos = self._plot_area.mapSceneToView(pos[0])
234+
x, y = m_pos.x(), m_pos.y()
235+
self._v_line.setPos(x)
236+
self._h_line.setPos(y)
237+
self._plot_area.setMeter((x, y))
254238

255239
def closeEvent(self, event):
256240
"""Override."""

0 commit comments

Comments
 (0)