Search code examples
pythonpyqt5pyqtgraph

ScaleBar in pyqtgraph doesn't update when scale is changed


When I change the scale of the axis of my image, my ScaleBar shows the incorrect scale. How do I update the scale bar when I change the axes?

from PyQt5 import QtWidgets
import pyqtgraph as pg
import numpy as np

if __name__ == '__main__':
    import sys

    app = QtWidgets.QApplication(sys.argv)

    imvOCTTopLeft = pg.ImageView(view=pg.PlotItem())
    imvOCTTopLeft.setImage(np.random.normal(size=(100,100)))

    imvOCTTopLeft.view.getAxis('left').setScale(0.6)
    imvOCTTopLeft.view.getAxis('bottom').setScale(0.4)

    scale = pg.ScaleBar(size=10,suffix = "px")
    viewbox = imvOCTTopLeft.view
    if not isinstance(viewbox, pg.ViewBox): viewbox = viewbox.getViewBox()
    scale.setParentItem(viewbox)
    scale.anchor((1, 1), (1, 1), offset=(-20, -20))
    imvOCTTopLeft.show()

    sys.exit(app.exec_())

This image shows that the scale bar is showing approximately 4 pixels but states that it is showing 10 pixels.

I think this is because I changed the axis scale.


Solution

  • This seems to be a bug: link. The viewbox rescales after sigRangeChanged is emitted.

    "Hacky" solution is to delay the ScaleBar update: (You might need to play around with the time, 100 and 10 worked for me. If it doesnt work, increase it.)

    from PyQt5 import QtWidgets, QtCore
    import pyqtgraph as pg
    import numpy as np
    
    
    def updateDelay(scale, time):
        QtCore.QTimer.singleShot(time, scale.updateBar)
    
    
    if __name__ == '__main__':
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        plotItem = pg.PlotItem()
        imvOCTTopLeft = pg.ImageView(view=plotItem)
        imvOCTTopLeft.setImage(np.random.normal(size=(100, 100)))
    
        imvOCTTopLeft.view.getAxis('left').setScale(0.6)
        scale = 0.4 #edit
        imvOCTTopLeft.view.getAxis('bottom').setScale(scale) #edit
    
        scale = pg.ScaleBar(size=10*(1/scale), suffix="px") #edit
        scale.text.setText('10 px') #edit
        plotItem.sigRangeChanged.connect(lambda: updateDelay(scale, 10))  # here: time=10ms
        viewbox = imvOCTTopLeft.view
        if not isinstance(viewbox, pg.ViewBox): viewbox = viewbox.getViewBox()
        scale.setParentItem(viewbox)
        scale.anchor((1, 1), (1, 1), offset=(-20, -20))
        imvOCTTopLeft.show()
        updateDelay(scale, 100)  # here time=100ms
    
        sys.exit(app.exec_())
    

    Result: result