Search code examples
pythonplotpyqt5screen-resolutionpyqtgraph

How to stop display resolution from affecting axes in pyqtgraph plots


I am using pyqtgraph to plot some data and noticed that when I move the plot from my laptop screen to a second monitor, the scaling on the plot is affected:

laptop monitor: original laptop

external monitor: original ext. monitor

notice that the axes got "compressed", and the plot is no longer scaled properly on the second monitor.

I found others reporting similar issues on the web, but could not find any real solution. One solution suggested was to make the monitors' resolutions the same. I don't like this solution because I'd have to sacrifice laptop resolution to accommodate my lower resolution external monitor.

The other solution I found was to add the line app.setAttribute(QtCore.Qt.AA_Use96Dpi) to the main loop, prior to instantiating the Qapplication as shown below, to allegedly have Qt ignore the OS's DPI settings:

def main():
 import sys
 app = QtWidgets.QApplication(sys.argv)
 app.setAttribute(QtCore.Qt.AA_Use96Dpi)
 MainWindow =GraphWindow()
 MainWindow.show()
 sys.exit(app.exec_())

This seems at first to work, because the plotted data is scaled properly on the axes. However, it doesn't seem to really work -- the addition of this line affected the scaling of the axes on the laptop as shown below (same data is now plotted on axes that span 0 to 7000 on the x-axis, and -2 to -26dB on the Yaxis):

laptop_96DPI setting ,

but did "fix" the issue when moving the plot onto the second monitor to look like the first "original" laptop plot shown above.

This is particularly worrisome, because in the case of the laptop output after the app.setAttribute(QtCore.Qt.AA_Use96Dpi) instruction "looks" right, but misrepresents the actual data. I could have easily missed this had included this instruction when I first plotted the data.

What is the right way to have the plot accurately display regardless of the OS's DPI setting and monitor resolutions? It is very strange that the plotted data seems disassociated with the axis values.

Here is a mininimal reproducible sample:

from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys  # We need sys so that we can pass argv to QApplication
import os
from  numpy.random import seed
from  numpy.random import randint

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.graphWidget = pg.PlotWidget()
        self.setCentralWidget(self.graphWidget)

        x = [1,2,3,4,5,6,7,8,9,10]
        seed(1)
        y = randint(5,35,10)

        # plot data: x, y values
        self.graphWidget.plot(x, y)


def main():
    app = QtWidgets.QApplication(sys.argv)
    app.setAttribute(QtCore.Qt.AA_Use96Dpi)
    main = MainWindow()
    main.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Solution

  • Answers can be found here: https://github.com/pyqtgraph/pyqtgraph/issues/756

    Quick Summary of this issue: There are essentially two ways to solve this problem.

    1. Make your app DPI-aware (by Androwei)
    import ctypes
    import platform
    
    def make_dpi_aware():
        if int(platform.release()) >= 8:
            ctypes.windll.shcore.SetProcessDpiAwareness(True)
    
    # add this code before "app = QtWidgets.QApplication(sys.argv)"
    make_dpi_aware()
    
    1. set Qt.HighDpiScaleFactorRoundingPolicy to PassThrough (by andybarry)
    # add this code before "app = QtWidgets.QApplication(sys.argv)"
    QtWidgets.QApplication.setAttribute(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
    

    I have tried both, and they both work perfectly! Thanks to these contributors. Hope you can find this useful as well.