Repository: pyqtgraph/pyqtgraph

Issue:
PlotWidget (and other plotting widgets) unhides all Items after removing single item; Again
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

The issue is exact as previously reported by me in issue #985
which was fixed with #987.

I had bisected regression down to this PR: #1764;

The previously introduced fix was kind of reverted at commit fa1be1e5bf50c9da27cc9473b04f2399319dc324 ,
at method `updateDecimation`, where inserted unnecessary `curve.show()`, which ignores the fact that some curves intentionally could be hidden, makes everything show if anything is removed or added.



Discussion:

Resolving patch:
diff --git a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
--- a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
+++ b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
@@ -240,7 +240,7 @@ def __init__(self, parent=None, name=None, labels=None, title=None, viewBox=None
         self.ctrl.avgParamList.itemClicked.connect(self.avgParamListClicked)
         self.ctrl.averageGroup.toggled.connect(self.avgToggled)
         
-        self.ctrl.maxTracesCheck.toggled.connect(self.updateDecimation)
+        self.ctrl.maxTracesCheck.toggled.connect(self._handle_max_traces_toggle)
         self.ctrl.forgetTracesCheck.toggled.connect(self.updateDecimation)
         self.ctrl.maxTracesSpin.valueChanged.connect(self.updateDecimation)
         
@@ -1002,10 +1002,27 @@ def setClipToView(self, clip):
         
     def clipToViewMode(self):
         return self.ctrl.clipToViewCheck.isChecked()
-
+    
+    def _handle_max_traces_toggle(self, check_state):
+        if check_state:
+            self.updateDecimation()
+        else:
+            for curve in self.curves:
+                curve.show()
+    
     def updateDecimation(self):
+        """Reduce or increase number of visible curves depending from Max Traces spinner value
+        if Max Traces is checked in the context menu. Destroy not visible curves if forget traces
+        is checked. This function is called in most cases automaticaly when Max Traces GUI elements
+        are triggered. Also it is auto-called when state of PlotItem is updated, state restored
+        or new items being added/removed.
+        
+        This can cause unexpected/conflicting state of curve visibility (or destruction) if curve
+        visibilities are controlled externaly. In case of external control it is adviced to disable
+        the Max Traces checkbox (or context menu) to prevent user from the unexpected
+        curve state change."""
         if not self.ctrl.maxTracesCheck.isChecked():
-            numCurves = len(self.curves)
+            return
         else:
             numCurves = self.ctrl.maxTracesSpin.value()
 


Test patch:
diff --git a/tests/graphicsItems/PlotItem/test_PlotItem.py b/tests/graphicsItems/PlotItem/test_PlotItem.py
--- a/tests/graphicsItems/PlotItem/test_PlotItem.py
+++ b/tests/graphicsItems/PlotItem/test_PlotItem.py
@@ -54,6 +54,18 @@ def test_PlotItem_maxTraces():
     assert curve1 not in item.curves, "curve1 should not be in the item's curves"
 
 
+def test_PlotItem_preserve_external_visibility_control():
+    item = pg.PlotItem()
+    curve1 = pg.PlotDataItem(np.random.normal(size=10))
+    curve2 = pg.PlotDataItem(np.random.normal(size=10))
+    item.addItem(curve1)
+    curve1.hide()
+    item.addItem(curve2)
+    assert not curve1.isVisible()
+    item.removeItem(curve2)
+    assert not curve1.isVisible()
+
+
 def test_plotitem_menu_initialize():
     """Test the menu initialization of the plotitem"""
     item = pg.PlotItem()