pyqtgraph
pyqtgraph copied to clipboard
movable InfiniteLine grabbing does not respect the bounding rect
Short description
I use a custom implementation found here that has the following differences compared to a plain InfinteLine:
- the line color does not change when the mouse cursor hovers over the line
- the mouse cursor changes to a
Qt::SplitHCursor(see https://doc.qt.io/qt-6/qt.html#CursorShape-enum) when the mouse hovers the line. This is used as a visual indicator that the line can be grabbed and moved.
I've noticed that coming from the left side of the line the mouse cursor changes to Qt::SplitHCursor 1 pixel before the line is actually movable (you can see this running the slightly modified example code bellow). Coming from the right side of the line there is no discrepancy.
Code to reproduce
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore
app = pg.mkQApp("InfiniteLine Example")
win = pg.GraphicsLayoutWidget(show=True, title="Plotting items examples")
win.resize(1000,600)
pg.setConfigOptions(antialias=True)
p1 = win.addPlot(title="Plot Items example", y=np.random.normal(size=100, scale=10), pen=0.5)
p1.setYRange(-40, 40)
inf1 = pg.InfiniteLine(movable=True, angle=90, label='x={value:0.2f}',
labelOpts={'position':0.1, 'color': (200,200,100), 'fill': (200,200,200,50), 'movable': True})
# this will change the cursor when hovering over the inifinte line
# ideally the cursor change and the line color change should happend at the same time
inf1.setCursor(QtCore.Qt.SplitHCursor)
inf2 = pg.InfiniteLine(movable=True, angle=0, pen=(0, 0, 200), bounds = [-20, 20], hoverPen=(0,200,0), label='y={value:0.2f}mm',
labelOpts={'color': (200,0,0), 'movable': True, 'fill': (0, 0, 200, 100)})
inf3 = pg.InfiniteLine(movable=True, angle=45, pen='g', label='diagonal',
labelOpts={'rotateAxis': [1, 0], 'fill': (0, 200, 0, 100), 'movable': True})
inf1.setPos([2,2])
p1.addItem(inf1)
p1.addItem(inf2)
p1.addItem(inf3)
targetItem1 = pg.TargetItem()
targetItem2 = pg.TargetItem(
pos=(30, 5),
size=20,
symbol="star",
pen="#F4511E",
label="vert={1:0.2f}",
labelOpts={
"offset": QtCore.QPoint(15, 15)
}
)
targetItem2.label().setAngle(45)
targetItem3 = pg.TargetItem(
pos=(10, 10),
size=10,
symbol="x",
pen="#00ACC1",
)
targetItem3.setLabel(
"Third Label",
{
"anchor": QtCore.QPointF(0.5, 0.5),
"offset": QtCore.QPointF(30, 0),
"color": "#558B2F",
"rotateAxis": (0, 1)
}
)
def callableFunction(x, y):
return f"Square Values: ({x**2:.4f}, {y**2:.4f})"
targetItem4 = pg.TargetItem(
pos=(10, -10),
label=callableFunction
)
p1.addItem(targetItem1)
p1.addItem(targetItem2)
p1.addItem(targetItem3)
p1.addItem(targetItem4)
lr = pg.LinearRegionItem(values=[70, 80])
p1.addItem(lr)
label = pg.InfLineLabel(lr.lines[1], "region 1", position=0.95, rotateAxis=(1,0), anchor=(1, 1))
if __name__ == '__main__':
pg.exec()
Expected behavior
The cursor change and the line color change happen at the same time. Once the cursor is changed dragging should be possible
Real behavior
On the left side of the infinite line the cursor change is activated 1 pixel before the color change. Trying to drag the line at this point will result in a viewbox change instead of the line movement.
An error occurred?
Post the full traceback inside these 'code fences'!
Tested environment(s)
- PyQtGraph version: 0.12.4
- Qt Python binding: PySide6.2.0 and PySide 6.3.2
- Python version: 3.10
- NumPy version: 1.23.3
- Operating system: Windows 10 x64
- Installation method: pip
Additional context
There is a known issue involving infinite lines at angles; see #2407 #1878 and #727
The cause of the issue has proven to be remarkably elusive, we believe the issue is a bug in GraphicsItem.pixelVectors
The above issues have some code-snippets to better highlight the issue. Help here would certainly be appreciated!
I would love to help but this is above my knowledge. For now I will just not use the mouse cursor and just change the line style when hovering as a visual indicator.
This issue has proven to be remarkably difficult to troubleshoot; I think at its core the issue is that Infinite Line is a 1D item, and we're trying to do calculations on it as of it was a 2D item.
Since https://github.com/pyqtgraph/pyqtgraph/commit/ab5ec85a4164fa350a6640810acc6716f73d631f the situation is reversed: the hover event is triggered before the mouse cursor is changed both from the left and right side.
For what it's worth, this issue is a bit distinct from some of the bounding rect issues we've seen before, though it may be related.
If you modify the example above to set the cursor on all 3 InfiniteLine objects, they all show similar behavior, so it's not a problem exclusive to angled lines.
And as @danielhrisca points out, #2383 causes lag between the cursor changing and the pen changing from both sides now.
If anyone has insight into how QGraphicsItem detects when to switch the cursor, that'd be helpful. I would've thought it'd be based on the item's bounding rect or the scene's itemsNearEvent, but that doesn't seem to be the case?
Disabling the InfiniteLine bounding rect cache and the GraphicsItem.pixelVectors cache didn't seem to help.
Does this mean that the bounding rect should be used for setting the cursor?