diff --git a/pydm/tests/widgets/test_baseplot.py b/pydm/tests/widgets/test_baseplot.py index 81cf98dce..cc0538e5d 100644 --- a/pydm/tests/widgets/test_baseplot.py +++ b/pydm/tests/widgets/test_baseplot.py @@ -132,9 +132,9 @@ def test_baseplot_multiple_y_axes(qtbot): assert base_plot.plotItem.axes["Test Axis 3"]["item"].orientation == "left" # Verify the curves got assigned to the correct axes - assert base_plot.plotItem.curvesPerAxis["Test Axis 1"] == 2 - assert base_plot.plotItem.curvesPerAxis["Test Axis 2"] == 1 - assert base_plot.plotItem.curvesPerAxis["Test Axis 3"] == 1 + assert len(base_plot.plotItem.axes["Test Axis 1"]["item"]._curves) == 2 + assert len(base_plot.plotItem.axes["Test Axis 2"]["item"]._curves) == 1 + assert len(base_plot.plotItem.axes["Test Axis 3"]["item"]._curves) == 1 def test_baseplot_no_added_y_axes(qtbot): @@ -224,10 +224,10 @@ def test_timeplot_add_multiple_axes(qtbot): # Verify the curves got assigned to the correct axes assert len(time_plot.curves) == 5 - assert time_plot.plotItem.curvesPerAxis["Axis 1"] == 2 - assert time_plot.plotItem.curvesPerAxis["Axis 2"] == 1 - assert time_plot.plotItem.curvesPerAxis["Axis 3"] == 1 - assert time_plot.plotItem.curvesPerAxis["Axis 4"] == 1 + assert len(time_plot.plotItem.axes["Axis 1"]["item"]._curves) == 2 + assert len(time_plot.plotItem.axes["Axis 2"]["item"]._curves) == 1 + assert len(time_plot.plotItem.axes["Axis 3"]["item"]._curves) == 1 + assert len(time_plot.plotItem.axes["Axis 4"]["item"]._curves) == 1 def test_multiaxis_plot_no_designer_flow(qtbot): @@ -249,8 +249,8 @@ def test_multiaxis_plot_no_designer_flow(qtbot): assert "Axis 2" in plot.plotItem.axes assert "right" in plot.plotItem.axes assert "top" in plot.plotItem.axes - assert plot.plotItem.curvesPerAxis["Axis 1"] == 2 - assert plot.plotItem.curvesPerAxis["Axis 2"] == 1 + assert len(plot.plotItem.axes["Axis 1"]["item"]._curves) == 2 + assert len(plot.plotItem.axes["Axis 2"]["item"]._curves) == 1 # Now check the case where no new y-axis name is specified for any of the new channels. plot = PyDMTimePlot() diff --git a/pydm/widgets/baseplot.py b/pydm/widgets/baseplot.py index 06f070f2e..962e5b5e6 100644 --- a/pydm/widgets/baseplot.py +++ b/pydm/widgets/baseplot.py @@ -475,7 +475,7 @@ def __init__( **kws, ) -> None: super(BasePlotAxisItem, self).__init__(orientation, **kws) - + self._curves: List[BasePlotCurveItem] = [] self._name = name self._orientation = orientation self._label = label @@ -640,6 +640,17 @@ def log_mode(self, log_mode: bool) -> None: self.setLogMode(x=False, y=log_mode) self.log_mode_updated.emit(self.name, log_mode) + def setHidden(self, shouldHide: bool): + """Set an axis to hide/show and do the same for all of its connected curves""" + if shouldHide: + for curve in self._curves: + curve.hide() + self.hide() + else: + for curve in self._curves: + curve.show() + self.show() + def to_dict(self) -> OrderedDict: """ Returns an OrderedDict representation with values for all properties @@ -896,7 +907,8 @@ def removeCurve(self, plot_item: BasePlotCurveItem) -> None: # Mark it as not existing so all curves that rely on this curve get destroyed as well plot_item.exists = False if plot_item.y_axis_name in self.plotItem.axes: - self.plotItem.unlinkDataFromAxis(plot_item.y_axis_name) + self.plotItem.unlinkDataFromAxis(plot_item) + self.removeItem(plot_item) self._curves.remove(plot_item) if len(self._curves) < 1: diff --git a/pydm/widgets/multi_axis_plot.py b/pydm/widgets/multi_axis_plot.py index 4f812634c..4ff5ec668 100644 --- a/pydm/widgets/multi_axis_plot.py +++ b/pydm/widgets/multi_axis_plot.py @@ -1,5 +1,4 @@ import weakref -from collections import Counter from pyqtgraph import AxisItem, PlotDataItem, PlotItem, ViewBox from typing import List, Optional from qtpy.QtCore import Qt @@ -30,7 +29,6 @@ def __init__(self, parent=None, axisItems=None, **kargs): viewBox.menu = MultiAxisViewBoxMenu(viewBox) super(MultiAxisPlot, self).__init__(viewBox=viewBox, axisItems=axisItems, **kargs) - self.curvesPerAxis = Counter() # A simple mapping of AxisName to a count of curves that using that axis self.axesOriginalRanges = {} # Dict from axis name to floats (x, y) representing original range of the axis # A set containing view boxes which are stacked underneath the top level view. These views will be needed @@ -113,7 +111,11 @@ def addAxis( def change_axis_name(self, old_name: str, new_name: str): """Change the name of the axis by changing the item's key in the axes dictionary.""" + axis = self.axes[old_name]["item"] self.axes[new_name] = self.axes[old_name] + if hasattr(axis, "_curves"): + for curve in axis._curves: + curve.y_axis_name = new_name del self.axes[old_name] def addStackedView(self, view): @@ -220,22 +222,27 @@ def linkDataToAxis(self, plotDataItem: PlotDataItem, axisName: str) -> None: # pyqtgraph expects data items on plots to be added to both the list of curves and items to function properly self.curves.append(plotDataItem) self.items.append(plotDataItem) - self.curvesPerAxis[axisName] += 1 + if hasattr(axisToLink, "_curves"): + axisToLink._curves.append(plotDataItem) + axisToLink.show() + for otherAxisName in self.axes.keys(): + self.autoVisible(otherAxisName) def removeAxis(self, axisName): if axisName not in self.axes: return - self.curvesPerAxis[axisName] = 0 - oldAxis = self.axes[axisName]["item"] self.layout.removeItem(oldAxis) if oldAxis.scene() is not None: oldAxis.scene().removeItem(oldAxis) + stackedView = oldAxis.linkedView() oldAxis.unlinkFromView() + if stackedView and stackedView is not self.vb: + self.stackedViews.remove(stackedView) del self.axes[axisName] - def unlinkDataFromAxis(self, axisName): + def unlinkDataFromAxis(self, curve: PlotDataItem): """ Lets the plot know that this axis is now associated with one less curve. If there are no longer any curves linked with this axis, then removes it from the scene and cleans it up. @@ -244,10 +251,39 @@ def unlinkDataFromAxis(self, axisName): axisName: str The name of the axis that a curve is being removed from """ + if ( + hasattr(curve, "y_axis_name") + and curve.y_axis_name in self.axes + and curve in self.axes[curve.y_axis_name]["item"]._curves + ): + self.axes[curve.y_axis_name]["item"]._curves.remove(curve) + self.autoVisible(curve.y_axis_name) + + def autoVisible(self, axisName): + """Handle automatically hiding or showing an axis based on whether it has + visible curves attached and/or if it's the last visible axis + (don't automatically hide the last axis, even if all of it's curves are hidden) - self.curvesPerAxis[axisName] -= 1 - if self.curvesPerAxis[axisName] == 0: - self.removeAxis(axisName) + Parameters + ------------- + axisName: str + The name of the axis we are going to try to hide if possible, or show if not""" + # Do we have any visible curves? + axis = self.axes[axisName]["item"] + if hasattr(axis, "_curves"): + for curve in axis._curves: + if curve.isVisible(): + axis.show() + return + + # We don't have any visible curves, but are we the only curve being shown? + for otherAxis in self.axes.keys(): + otherItem = self.axes[otherAxis]["item"] + if otherItem is not axis and otherAxis not in ["bottom", "top"] and otherItem.isVisible(): + axis.hide() + return + # No other axis is visible. + axis.show() def setXRange(self, minX, maxX, padding=0, update=True): """