Repository: pyqtgraph/pyqtgraph

Issue:
Bug introduced in setState in version 0.11.x, 0.12.3 (but it's working on 0.12.0!)
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

### Short description
Prior to version of pyqtgraph 0.11.x, I heavily used the **setState** property in order to be able to keep the pan and zoom settings the user defined. For example, some of my application have the imageView on top and a slider at the bottom. The user click on the slider to display a different image. But if he pan or zoom into the image, switching to another image keeps the pan and zoom settings. Other applications I wrote modified the image and refresh it, still keeping the pan and zoom settings as shown in this animation. 

![without_issue](https://user-images.githubusercontent.com/1138324/137905140-dbbeeb5a-13a1-430e-8be6-bddbe81fe263.gif)

But if I'm using pyqtgraph 0.11.x or later, the view auto-reset. and a single action on the mouse (little pan, little zooming) correctly reset the image view to the range previously defined. 

![withIssue](https://user-images.githubusercontent.com/1138324/137906205-84130e9e-8f99-4d24-89ea-c48df6f3eb15.gif)

I tested the issue with various pyqtgraph version and came up with the following conclusion:
0.10.x -> it's working
0.11.0 -> not working
0.12.0 -> it's working
0.12.3 -> not working

### Code to reproduce
<!-- Please provide a minimal working example that reproduces the issue in the code block below.
     Ideally, this should be a full example someone else could run without additional setup. -->

Here is some of the code that I use to record the image settings before plotting a new image, and then resetting the 
view according to the parameters saved

```python

[...]

 _view = self.parent.ui.image_view.getView()
 _view_box = _view.getViewBox()
 _state = _view_box.getState()

  self.parent.ui.image_view.setImage(_image)
  _view_box.setState(_state)

[...]

```

### Expected behavior
The new plot should have the same view state as the previous plot

### Real behavior
The new plot state is reset. 

```
An error occurred?
Post the full traceback inside these 'code fences'!
```

### Tested environment(s)

 * PyQtGraph version: tested with 0.10.x, 0.11.0, 0.12.0, 0.12.3
 * Qt Python binding: PyQt5 5.15.4 Qt 5.15.2
 * Python version:  3.7
 * NumPy version: 1.21.0
 * Operating system:  Mac OS, Linux
 * Installation method: Using conda environment for most librairies. Used pip for pyqtgraph.

### Additional context



Discussion:
Hi @JeanBilheux 

Thanks for reporting, the gifs are 👍🏻 

It would be helpful to have a reproducible example (often one of the built-in examples can be useful here, to make a slight modification).  Once we have that, we can run `git bisect` and identify the commit that the breakage got re-introduced.  Alternatively, if you have pyqtgraph installed from the cloned repository in editable mode, you can run `git bisect` yourself, and test for which commit was good/bad against your own application.

It's also possible someone else may recognize the failure mode here more clearly and know what's wrong right away.
More testing. it's working on 0.12.1 as well.

working version: 0.10.x, 0.12.1
not working version: 0.11.0, 0.12.0, 0.12.2


@JeanBilheux can you clone the repository to your local machine; and use that version (not the one from pypi) within your application?

Assuming your application is part of a custom venv

```bash
source .venv/bin/activate # activate the virtual environment your application runs in
pip uninstall pyqtgraph
cd ~/
git clone https://github.com/pyqtgraph/pyqtgraph.git
cd pyqtgraph
pip install -e .
```

that will install pyqtgraph from the current commit on the `master` branch into the virtual environment your application runs.  From there make sure you're exhibiting the same behavior....

Since it's working in 0.12.1 but not working on 0.12.2, that's probably the easiest span of commits to browse between


```bash
git bisect start pyqtgraph-0.12.2 pyqtgraph-0.12.1
```

On each iteration, rerun your application and see if the issue appears or not, if it's working as intended then run `git bisect good` if not, then run `git bisect bad`.  Eventually you will zero in on the first commit that was "bad".
@j9ac9k Ok I will try that. 
I used the wrong account, but yes, Bidochon is still me. I will then try that. 
let me know if you run into issues 
I narrowed down the issue to the following commit:

```
0cc35806872c1b658a239046de34f9b18c8189dd is the first bad commit
commit 0cc35806872c1b658a239046de34f9b18c8189dd
Author: Nils Nemitz <nils.nemitz@gmx.de>
Date:   Thu Oct 7 14:40:38 2021 +0900

    Traditional log10 mode for PlotDataItem (by adding "mapped data" stage) (#1992)

    * make PlotDataItem aware of mapped data

    * inf suppression, metadata storage and refactor of data structures

    * cleanup, test, and documentation pass

    * re-added prepareForPaint, added PlotDataset to sphinx index

    * strip more print statements

    * indicate (internal) PlotDataset documentation as orphaned to avoid sphinx error

    * Do not export PlotDataset

    * replacement example

    * example comments

:040000 040000 66d1a6aeb3ca9b49888dd000f1de587c39463a6c e5554fa71bb0adda72e567abe42133e2f08653de M	examples
:040000 040000 0fb45789db1a105ef0b3e167dba5a7813f5f9230 8ffbd7f54a31b984c2d032f447f47bff8aedcf17 M	pyqtgraph
:040000 040000 ff4e6675c061455a439f5d911c9813666a5997ed 441d9fb6cc89fb051e56b8665a3324db910247e4 M	tests
```
Hi @JeanBilheux, nice work on the `git-bisect`

Here you can see the diff from that commit itself: https://github.com/pyqtgraph/pyqtgraph/commit/0cc35806872c1b658a239046de34f9b18c8189dd

If you're editing the code, can you comment out the entire [`update`](https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/graphicsItems/ViewBox/ViewBox.py#L1471-L1473) method in `ViewBox.py`, and rerun and see if that resolves your issue? 
Working with version 0.11.0, I commented out the update method. Zooming/pan using the mouse did not update the plot (as expected I guess) but switching from one image to another using my slider did not reset the plot, that means it does work. 

First GIF is before commenting out the code
![update_code_not_comment_out](https://user-images.githubusercontent.com/1138324/138941108-a22fec9f-e9c1-4b82-9299-83c3508ade96.gif)

and with code commented out
![with_code_commented_out](https://user-images.githubusercontent.com/1138324/138941557-fcf85745-ef4f-4c80-8b08-55ca464d027f.gif)


> Working with version 0.11.0, I commented out the update method. 

It's not particularly helpful to modify a version of pyqtgraph from that long ago; there have been a _ton_ of changes to the library since then.  The `update` method was removed, and very recently re-added.  Would you you mind trying the current `master` branch of pyqtgraph with the `update` method in `ViewBox.py` commented out and see if that resolves things?


I tried version 0.12.1 and it works!
works -> 0.12.2
not working -> 0.12.3
not working -> latest master 
I should retry bisect from there! I will.

I think you zero'd in on the right commit in bisect to `0cc35806872c1b658a239046de34f9b18c8189dd`

That commit is between 0.12.2 and 0.12.3.  One of the changes that commit had is (re-)adding the update method in ViewBox.py (it used to be there, then it was removed, then it was readded).  I would recomment hoping on the lastest commit of master and commenting out the update method of ViewBox.py. 
ok. I did that as you recommended. Commenting out the method fixes the issue but the image does not update when once zoom in/out using the mouse. 
Thanks for testing;  the update method was re-added because on macOS it helped with rendering _some_ non-finite values, but the extent of the benefit was only macOS, so we can remove it again, why the image is not updating, i'm not sure...


Unfortunately the commit that git bisect pointed to does not appear to have made any other changes that would impact rendering of images, the rest of the changes were for PlotDataItem.py, it's example and some test code for it.

Suppose the next question would be can you git bisect your way from 0.12.2 to 0.12.3 and comment out that `update` method in ViewBox.py in each step along the way?  That should point to which commit introduces the issue with the image not updating.
An example where zoom/pan gets reset when image is updated. (BAD)
After commenting out ```self.prepareForPaint()``` in ```ViewBox.update()```, the zoom/pan doesn't get reset. (GOOD)
I am not able to reproduce "the issue with the image not updating"
```python
import pyqtgraph as pg 
from pyqtgraph.Qt import QtWidgets
import scipy.misc

pg.mkQApp()
main = QtWidgets.QWidget()

face = scipy.misc.face()
imgitem = pg.ImageItem(face, axisOrder='row-major')
imgview = pg.ImageView(imageItem=imgitem)

def onActivated(v):
    radios = group.findChildren(QtWidgets.QRadioButton)
    sel = [r.text() for r in radios if r.isChecked()]
    idx = "RGB".find(sel[0])
    vb = imgview.getView()
    state = vb.getState()
    imgview.setImage(face[..., idx], autoLevels=False)
    vb.setState(state)

group = QtWidgets.QGroupBox()
hlayout = QtWidgets.QHBoxLayout()
for x in "RGB":
    radio = QtWidgets.QRadioButton(x)
    radio.clicked.connect(onActivated)
    hlayout.addWidget(radio)
hlayout.addStretch(1)
group.setLayout(hlayout)

vlayout = QtWidgets.QVBoxLayout()
vlayout.addWidget(imgview)
vlayout.addWidget(group)
main.setLayout(vlayout)
main.setMinimumSize(640, 480)
main.show()
pg.exec()
```


Resolving patch:
diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
--- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
+++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py
@@ -1468,10 +1468,17 @@ def childrenBoundingRect(self, *args, **kwds):
 
         bounds = QtCore.QRectF(range[0][0], range[1][0], range[0][1]-range[0][0], range[1][1]-range[1][0])
         return bounds
-        
-    def update(self, *args, **kwargs):
-        self.prepareForPaint()
-        GraphicsWidget.update(self, *args, **kwargs)
+
+    # Including a prepareForPaint call is part of the Qt strategy to
+    # defer expensive redraw opertions until requested by a 'sigPrepareForPaint' signal
+    # 
+    # However, as currently implemented, a call to prepareForPaint as part of the regular 
+    # 'update' call results in an undesired reset of pan/zoom:
+    # https://github.com/pyqtgraph/pyqtgraph/issues/2029
+    #
+    # def update(self, *args, **kwargs):
+    #     self.prepareForPaint()
+    #     GraphicsWidget.update(self, *args, **kwargs)
 
     def updateViewRange(self, forceX=False, forceY=False):
         ## Update viewRange to match targetRange as closely as possible, given


Test patch: