Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

showGrid screws up tick labels at axis boundaries #1606

Open
paulmueller opened this issue Feb 23, 2021 · 9 comments · May be fixed by #2579
Open

showGrid screws up tick labels at axis boundaries #1606

paulmueller opened this issue Feb 23, 2021 · 9 comments · May be fixed by #2579

Comments

@paulmueller
Copy link
Contributor

paulmueller commented Feb 23, 2021

Short description

When I use showGrid (current master and 0.11.1), then the tick labels at the corner of the axes rectangle are not drawn correctly.

Code to reproduce

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np

win = pg.GraphicsLayoutWidget(show=True)
win.resize(800,350)
win.setWindowTitle('pyqtgraph example: Histogram')
plt1 = win.addPlot()
plt2 = win.addPlot()

## make interesting distribution of values
vals = np.hstack([np.random.normal(size=500), np.random.normal(size=260, loc=4)])

## compute standard histogram
y,x = np.histogram(vals, bins=np.linspace(-3, 8, 40))

## Using stepMode="center" causes the plot to draw two lines for each sample.
## notice that len(x) == len(y)+1
plt1.plot(x, y, stepMode="center", fillLevel=0, fillOutline=True, brush=(0,0,255,150))
plt2.plot(x, y, stepMode="center", fillLevel=0, fillOutline=True, brush=(0,0,255,150))

plt1.showGrid(x=False, y=False)
plt2.showGrid(x=True, y=True)

plt1.setRange(xRange=(5,10), yRange=(0,10), padding=0)
plt2.setRange(xRange=(5,10), yRange=(0,10), padding=0)


QtGui.QApplication.instance().exec_()

Actual and Expected behavior

This is the output of the above script:
image

Tested environment(s)

  • PyQtGraph version: master and 0.11.1
  • Qt Python binding: PyQt5 5.15.1 Qt 5.15.1
  • Python version: 3.8.5
  • NumPy version: 1.18.5
  • Operating system: Ubuntu 20.04
  • Installation method: pip
@hppi-johnsson
Copy link

hppi-johnsson commented Mar 11, 2021

I have this issue too. Thanks for pointing out the relationship with the grid. It helped me find the root cause.

In line 567 of graphicsItems/AxisItem.py following code is in place:

def boundingRect(self):
     linkedView = self.linkedView()
     if linkedView is None or self.grid is False:
         rect = self.mapRectFromParent(self.geometry())
         ## extend rect if ticks go in negative direction
         ## also extend to account for text that flows past the edges
         tl = self.style['tickLength']
         if self.orientation == 'left':
             rect = rect.adjusted(0, -15, -min(0,tl), 15)
         elif self.orientation == 'right':
             rect = rect.adjusted(min(0,tl), -15, 0, 15)
         elif self.orientation == 'top':
             rect = rect.adjusted(-15, 0, 15, -min(0,tl))
         elif self.orientation == 'bottom':
             rect = rect.adjusted(-15, min(0,tl), 15, 0)
         return rect
     else:
         return self.mapRectFromParent(self.geometry()) | linkedView.mapRectToItem(self, linkedView.boundingRect())

This function extends the rectange of the axis beyond the viewbox , but only if self.grid is False.
Adding "or True" in the first if statement solves the issue for me.

I am not sure what the purpose of this behavior is. Perhaps anyone of the developers can have a look.

Edit:

I just discovered that this change breaks the grid when zooming in the plot. The grid lines are sometimes not showing up, or just partly showing up.

@swvanbuuren
Copy link
Contributor

swvanbuuren commented Jul 31, 2021

I also am having this issue.

After some experimentation, I changed the method boundingRect in graphicsItems/AxisItem.py as follows:

def boundingRect(self):
    linkedView = self.linkedView()
    if linkedView is None or self.grid is False:
        rect = self.mapRectFromParent(self.geometry())
    else:
        rect = self.mapRectFromParent(self.geometry()) | linkedView.mapRectToItem(self, linkedView.boundingRect())
    ## extend rect if ticks go in negative direction
    ## also extend to account for text that flows past the edges
    tl = self.style['tickLength']
    if self.orientation == 'left':
        rect = rect.adjusted(0, -15, -min(0,tl), 15)
    elif self.orientation == 'right':
        rect = rect.adjusted(min(0,tl), -15, 0, 15)
    elif self.orientation == 'top':
        rect = rect.adjusted(-15, 0, 15, -min(0,tl))
    elif self.orientation == 'bottom':
        rect = rect.adjusted(-15, min(0,tl), 15, 0)
    return rect

That seems to correct the problem.

However, I am not sure, if this change causes problems elsewhere ...

@hppi-johnsson
Copy link

swvanbuuren's suggestion is a great improvement.
However, I found it to break the ability to pan the x axis by dragging on its axisItem. Dragging on the x axisItem causes the y axis to pan.

The issue is avoided by not extending the y-axis upwards

    if self.orientation == 'left':
        rect = rect.adjusted(0, -15, -min(0,tl), 0)

@swvanbuuren
Copy link
Contributor

By undoing the extension of the y-axis upwards, the original issue resurfaces when panning in vertical direction.

The problem is caused, due to the fact that grid lines are part of an AxisItem (i.e. vertical grid lines are part of a horizontal axis and vice versa).

If grid lines are not present, extending a particular axis does not interfere with the other axes, since the bounding box (defined in boundingRect) fits neatly around the axis labels and ticks and does not get in the way of other axes. However, when grid lines are present, the bounding box also includes the whole plot area (due to the grid lines) and extending this causes overlaps with other axes.

In the end, I think the best solution would be, to have a separate Item (that derives from GraphicsWidget, e.g. named GridItem) for the grid lines.

@ixjlyons
Copy link
Member

ixjlyons commented Sep 7, 2021

We do have a GridItem and I agree we should probably move toward that for providing a grid because the current situation with AxisItems causes a number of problems.

@paulmueller
Copy link
Contributor Author

FYI I Just noticed that GridItem does not work with a log-scaled axis.

@j9ac9k
Copy link
Member

j9ac9k commented Oct 20, 2021

FYI I Just noticed that GridItem does not work with a log-scaled axis.

another one for the list! log-scale

@swvanbuuren
Copy link
Contributor

We do have a GridItem and I agree we should probably move toward that for providing a grid because the current situation with AxisItems causes a number of problems.

I tested with GridItem instead of the built-in grid of AxisItem and this seems to overcome this current issue.

However, there's a problem with GridItem:
this seems to have its own method of calculating the tick and grid line positions and this differs from the one in AxisItem. Grid lines appear (for certain cases) at different positions, when comparing both approaches.

Wouldn't it be better if AxisItem and GridItem used the same method (in e.g. a TickItem or similar?) for calculating tick and grid line positions?

@swvanbuuren swvanbuuren linked a pull request Jan 8, 2023 that will close this issue
@Nelson-numerical-software

Any chance to have an official fix in a next release ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants