Skip to content

Fix InfiniteLine bounding rect calculation#2407

Merged
j9ac9k merged 2 commits intopyqtgraph:masterfrom
ixjlyons:infiniteline-boundingrect
Oct 2, 2022
Merged

Fix InfiniteLine bounding rect calculation#2407
j9ac9k merged 2 commits intopyqtgraph:masterfrom
ixjlyons:infiniteline-boundingrect

Conversation

@ixjlyons
Copy link
Copy Markdown
Member

@ixjlyons ixjlyons commented Sep 4, 2022

Fixes #1878

Sometimes the smallest changes need the most explanation...

InfiniteLine previously used GraphicsItem.pixelLength(Point(0, 1), ortho=True) to compute the size of 1 pixel in the direction orthogonal to the line, in the item's coordinate system. I'm not sure why the current version requests pixel length orthogonal to the direction along the line rather than via the orthogonal direction directly - I'm still suspicious that I'm missing something.

I haven't figured out yet if pixelVectors does what it should or not. It'd be worth taking a closer look at it as I vaguely recall some bounding rect type issues with ROIs which also use it.

Demonstration

Without the proposed change, zooming on say the y axis causes the blue bounding rect to change "width", when it should hug the line with a small ~constant buffer.

Notice also the red and green lines stay parallel and orthogonal to the infinite line. If you change it to pixelVectors(pg.Point(0, 1)), this is no longer the case.

It's also strange that if you directly plot Point(0, 1) and Point(1, 0), Point(0, 1) doesn't really do what you'd expect. I'm not sure what to make of that.

import pyqtgraph as pg


class InfLine(pg.InfiniteLine):

    def paint(self, p, *args):
        tr = p.transform()

        # bounding rect in blue
        p.setPen(pg.mkPen("b", width=1))
        p.drawRect(self.boundingRect())

        super().paint(p, args)

        # draw pixelVectors
        p.setTransform(tr)
        normV, orthoV = self.pixelVectors(pg.Point(1, 0))  # try pg.Point(0, 1)
        print(normV, orthoV)
        p.setPen(pg.mkPen("r"))
        # p.drawLine(pg.Point(0, 0), pg.Point(1, 0))
        p.drawLine(pg.Point(0, 0), 10*normV)
        p.setPen(pg.mkPen("g"))
        # p.drawLine(pg.Point(0, 0), pg.Point(0, 1))
        p.drawLine(pg.Point(0, 0), 10*orthoV)


app = pg.mkQApp()

plt = pg.plot()
plt.setXRange(-10, 10)
plt.setYRange(-10, 10)
plt.resize(600, 600)
plt.showGrid(x=True, y=True)

oline = InfLine(angle=30)
plt.addItem(oline)

app.exec()

@ixjlyons
Copy link
Copy Markdown
Member Author

ixjlyons commented Sep 4, 2022

Just (re-)remembered #727. That also appears to be a valid fix if we get rid of the extra padding that was removed with #2383.

It's interesting that #727 effectively does the same thing, but in a different way (i.e. using Point(1, 0) and ortho=True)

@ixjlyons
Copy link
Copy Markdown
Member Author

ixjlyons commented Sep 4, 2022

Well, #727 appears to be more correct - re-enabling the 4-pixel padding on this branch and comparing to #727, #727 gives a more consistently thick bounding box. I'm still not sure why exactly but I'm guessing it's related to the bounding rect being initialized from self.viewRect() vs. the default QRectF.

In any case, I think #727 cleans up the _computeBoundingRect implementation a bit and works better anyway. I'll close this and maybe start a new branch to address testing.

@ixjlyons ixjlyons marked this pull request as ready for review October 2, 2022 23:05
@ixjlyons
Copy link
Copy Markdown
Member Author

ixjlyons commented Oct 2, 2022

Discussed with Luke and he figured out the issue. For the purposes of computing how much to extend the bounding rect orthogonal to the line, we want the y component instead of the length.

Better demonstration of the issue than in the original comment:

import numpy as np

import pyqtgraph as pg


class InfLine(pg.InfiniteLine):
    def paint(self, p, *args):
        p.setPen(pg.mkPen("b", width=1))
        p.drawRect(self.boundingRect())
        super().paint(p, args)


app = pg.mkQApp()

plt = pg.plot()
plt.showGrid(x=True, y=True)

angle = 1
mag = 50
sample = plt.plot(np.arange(10) * mag, np.arange(10))

oline = InfLine(angle=angle, movable=True)
oline.addMarker("o")
plt.addItem(oline)

app.exec()

@j9ac9k j9ac9k merged commit 3f3639c into pyqtgraph:master Oct 2, 2022
@ixjlyons ixjlyons deleted the infiniteline-boundingrect branch October 2, 2022 23:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InfiniteLine mouse behavior failures at very small angles

2 participants