Skip to content

an issue on ViewBox.mapToView #1136

@hf429

Description

@hf429

Hi, I do love pyqtgraph, it really save my life, but there is a little problem in it.

At first start of pg.GraphicsWindow, it seems that ViewBox return (0, 0) size by ViewBox.rect() method, which lead to ViewBox.updateMatrix get 0 size of bound and so that functions.invertQTransform fail.

one of the ways to work around it is mannually resize the Window by setFixedSize() or adjustSize().

For example, I post the cross hair example of pyqtgraph below for illustration.

Short description

GraphicsWindow.addPlot doesn't initialize correct ViewBox size, which lead to exception when use ViewBox.mapToView.
My tricky is just resize GraphicsWindow by adjustSize() method, and it does work.

Code to reproduce

"""
Demonstrates some customized mouse interaction by drawing a crosshair that follows
the mouse.
"""

#import initExample ## Add path to library (just for examples; you do not need this)
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.Point import Point



#generate layout
app = QtGui.QApplication([])
#app = QtGui.QApplication()
#win = pg.GraphicsLayoutWidget(show=True)
#win = pg.GraphicsLayoutWidget(show=True, parent=None)

win = pg.GraphicsWindow()    # Using GraphicsWindow so can I run the file on PyCharm
win.setWindowTitle('pyqtgraph example: crosshair')

label = pg.LabelItem(justify='right')
win.addItem(label)

p1 = win.addPlot(row=1, col=0)
p2 = win.addPlot(row=2, col=0)

region = pg.LinearRegionItem()
region.setZValue(10)
#Add the LinearRegionItem to the ViewBox, but tell the ViewBox to exclude this
#item when doing auto-range calculations.

p2.addItem(region, ignoreBounds=True)

#pg.dbg()
'''
Set whether automatic range uses only visible data when determining the range to show.
'''
#p1.setAutoVisible(x=False, y=False)


#create numpy arrays
#make the numbers large to show that the xrange shows data from 10000 to all the way 0
data1 = 10000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)
data2 = 15000 + 15000 * pg.gaussianFilter(np.random.random(size=10000), 10) + 3000 * np.random.random(size=10000)

p1.plot(data1, pen="r")
p1.plot(data2, pen="g")

p2.plot(data1, pen="w")

'''*********The Issue*********'''
#win.adjustSize()    # my trick, please decomment the line and the program would work out

print(p1.getViewBox().size())               # ->PyQt5.QtCore.QSizeF()
print(p1.getViewBox().viewPixelSize())      # exception raised due to empty viewBox size
'''*********The Issue*********'''

def update():
    region.setZValue(10)
    minX, maxX = region.getRegion()
    p1.setXRange(minX, maxX, padding=0)


region.sigRegionChanged.connect(update)

def updateRegion(window, viewRange):
    rgn = viewRange[0]
    region.setRegion(rgn)


p1.sigRangeChanged.connect(updateRegion)



region.setRegion([1000, 2000])

#cross hair
vLine = pg.InfiniteLine(angle=90, movable=False)
hLine = pg.InfiniteLine(angle=0, movable=False)
p1.addItem(vLine, ignoreBounds=True)
p1.addItem(hLine, ignoreBounds=True)


vb = p1.vb




def mouseMoved(evt):
    #print(evt)

    pos = evt[0]  #using signal proxy turns original arguments into a tuple
    print(pos)

    if p1.sceneBoundingRect().contains(pos):
        mousePoint = vb.mapSceneToView(pos)
        print(mousePoint)
        index = int(mousePoint.x())
        if index > 0 and index < len(data1):
            label.setText("<span style='font-size: 12pt'>x=%0.1f,   <span style='color: red'>y1=%0.1f</span>,   <span style='color: green'>y2=%0.1f</span>" % (mousePoint.x(), data1[index], data2[index]))
        vLine.setPos(mousePoint.x())
        hLine.setPos(mousePoint.y())



proxy = pg.SignalProxy(p1.scene().sigMouseMoved, rateLimit=60, slot=mouseMoved)
#p1.scene().sigMouseMoved.connect(mouseMoved)

##Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

Expected behavior

p1.getViewBox().viewPixelSize() should work

Real behavior

but it raises an exception

Traceback (most recent call last):
  File "C:/Users/Lee King Batchelor/Desktop/PythonExcel4Securities/pyqtgraph/CrossHair.py", line 86, in <module>
    print(p1.getViewBox().viewPixelSize())      # exception raised due to empty viewBox size
  File "C:\Anaconda3\envs\pyqtgraph\lib\site-packages\pyqtgraph\graphicsItems\ViewBox\ViewBox.py", line 1176, in viewPixelSize
    o = self.mapToView(Point(0,0))
  File "C:\Anaconda3\envs\pyqtgraph\lib\site-packages\pyqtgraph\graphicsItems\ViewBox\ViewBox.py", line 1142, in mapToView
    m = fn.invertQTransform(self.childTransform())
  File "C:\Anaconda3\envs\pyqtgraph\lib\site-packages\pyqtgraph\functions.py", line 2199, in invertQTransform
    inv = numpy.linalg.inv(arr)
  File "<__array_function__ internals>", line 6, in inv
  File "C:\Anaconda3\envs\pyqtgraph\lib\site-packages\numpy\linalg\linalg.py", line 547, in inv
    ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)
  File "C:\Anaconda3\envs\pyqtgraph\lib\site-packages\numpy\linalg\linalg.py", line 97, in _raise_linalgerror_singular
    raise LinAlgError("Singular matrix")
numpy.linalg.LinAlgError: Singular matrix

Tested environment(s)

  • PyQtGraph version: 0.1 and 0.11 dev0
  • Qt Python binding:PyQt5.9.2 and PySide2 5.13.1
  • Python version: 3.7
  • NumPy version: 1.8.1
  • Operating system: Win 10
  • Installation method: pip and system package

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions