Repository: pyqtgraph/pyqtgraph

Issue:
Regression: modified zoom behavior with showGrid
<!-- In the following, please describe your issue in detail! -->
<!-- If some of the sections do not apply, just remove them. -->

### Short description

Enabling the grid on a `PlotItem`causes zoom on the `ViewBox` to affect only the y axis when it should affect both. Zooming by scolling on the x axis still works. A more severe side-effect can be seen with `setAspectLocked`.

Bisect points to #1726 - I haven't looked further into it yet, but this should probably hold up 0.12.2 in my view.

### 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. -->
```python
import pyqtgraph as pg

app = pg.mkQApp()

p = pg.plot([1, 2, 3], [4, 5, 6])
p.showGrid(x=True, y=True)
#p.setAspectLocked(True)

app.exec()
```

### Tested environment(s)

 * PyQtGraph version: 30bc138
 * Qt Python binding: PyQt5 5.15.4 Qt 5.15.2
 * Python version: 3.9.5
 * Operating system: Linux


Discussion:
Narrowed it down to:

https://github.com/pyqtgraph/pyqtgraph/blob/ba517aba0e3dbddb925fcb47f9a0359432fd4a10/pyqtgraph/graphicsItems/PlotItem/PlotItem.py#L336-L337

Setting it < 0 fixes the zoom issue but is obviously going to break what's intended by the change (previously was -1000)
that's an amazing MWE.
Actually the magic number at least in the example above is -100. Zoom works for any negative value but pan doesn't. That is the z value of the `ViewBox`:

https://github.com/pyqtgraph/pyqtgraph/blob/07a99cb443062940cad20bd20de22d038cf3e982/pyqtgraph/graphicsItems/ViewBox/ViewBox.py#L215

So that answers one question posed in #1728:

> The default Z position of AxisItem has been changed to be 0.1, in order to always draw the axes on top of the image... With the current default of -1000, the ImageItem obscures them completely. I am not aware of the reason for the previous default setting, though.

What we probably want in `PlotItem` is something like `axis.setZValue(self.vb.zValue() - 1)`. Maybe the `- 1` isn't necessary. 

@NilsNemitz could you maybe elaborate on the behavior you're talking about with the `ImageItem` obscuring the axes?

I do see this if I revert the z value change, but I think that may be a bounding rect issue because it only occurs on the left and bottom axes:

![Screenshot_2021-06-18_17-00-08](https://user-images.githubusercontent.com/943602/122624814-cd983000-d056-11eb-9a25-c5ee2ec6ff98.png)

![Screenshot_2021-06-18_17-05-12](https://user-images.githubusercontent.com/943602/122624940-629b2900-d057-11eb-84af-98d88e44ebd6.png)

Dear @ixjlyons ,
That is pretty much what I was trying to avoid.
Ideally, the tick marks should also draw on top of the image, but I guess that could be considered secondary.
I am not sure if there is a reliable solution (across scaling and DPI settings) that clips the graph on the inside of the axis. That would be the ideal hot-fix, though.

I cannot yet comment on the complete z-ordering arrangements, but the change in behavior at z=-100 looks like there is another "fix" somewhere else that moves the viewbox level down so that it doesn't steal mouse events.

So I am expecting that the requirements are (graphs) > viewbox;  viewbox > axes;  axes > (graphs)
That might be hard, so maybe it's best to bump AxisItem back to z-level -1000 and figure out a better solution.

The fundamental issue is that maybe AxisItem shouldn't be drawing the grid?


Resolving patch:
diff --git a/pyqtgraph/graphicsItems/AxisItem.py b/pyqtgraph/graphicsItems/AxisItem.py
--- a/pyqtgraph/graphicsItems/AxisItem.py
+++ b/pyqtgraph/graphicsItems/AxisItem.py
@@ -1151,7 +1151,7 @@ def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):
         pen, p1, p2 = axisSpec
         p.setPen(pen)
         p.drawLine(p1, p2)
-        p.translate(0.5,0)  ## resolves some damn pixel ambiguity
+        # p.translate(0.5,0)  ## resolves some damn pixel ambiguity
 
         ## draw ticks
         for pen, p1, p2 in tickSpecs:
@@ -1184,20 +1184,31 @@ def hide(self):
         else:
             self._updateHeight()
 
-    def wheelEvent(self, ev):
+    def wheelEvent(self, event):
         lv = self.linkedView()
         if lv is None:
             return
-        if self.orientation in ['left', 'right']:
-            lv.wheelEvent(ev, axis=1)
+        # Did the event occur inside the linked ViewBox (and not over the axis iteself)?
+        if lv.sceneBoundingRect().contains(event.scenePos()):
+            # pass event to linked ViewBox without marking it as single axis zoom
+            lv.wheelEvent(event)
         else:
-            lv.wheelEvent(ev, axis=0)
-        ev.accept()
+            # pass event to linked viewbox with appropriate single axis zoom parameter
+            if self.orientation in ['left', 'right']:
+                lv.wheelEvent(event, axis=1)
+            else:
+                lv.wheelEvent(event, axis=0)
+        event.accept()
 
     def mouseDragEvent(self, event):
         lv = self.linkedView()
         if lv is None:
             return
+        # Did the mouse down event occur inside the linked ViewBox (and not the axis)?
+        if lv.sceneBoundingRect().contains(event.buttonDownScenePos()):
+            # pass event to linked ViewBox without marking it as single axis pan
+            return lv.mouseDragEvent(event)
+        # otherwise pass event to linked viewbox with appropriate single axis parameter
         if self.orientation in ['left', 'right']:
             return lv.mouseDragEvent(event, axis=1)
         else:


Test patch: