numentar
numentar

Reputation: 1079

How to draw on QGraphicsScene without scaling pen width?

I'm trying to plot on a QGraphicScene data which can, depending on situation, vary by orders of magnitude. Since the pen I'm using is cosmetic I'd expect the view to be independent of the magnitude of the data. But what I get instead is this:

Sine wave with noise multiplied by 50000:

scale 50000

Sine wave with noise multiplied by 50:

scale 50

However, if I zoom in to either of these plots (same amount of zooming in both), I eventually reach a level when both images look the same:

scale 50000 zoom enter image description here

What is going on here? Why is the width of the pen changing just because the data values are bigger. And why does the scaling disappear when zoomed in?

The code to reproduce this follows. Left clicking on the plot zooms in, right clicking zooms out.

import sys

from PyQt4 import QtGui as QG
from PyQt4 import QtCore as QC

import numpy as n

class ZoomView(QG.QGraphicsView):
    """Zoomable QGraphicsView"""
    def mouseReleaseEvent(self,event):
        if event.button() == QC.Qt.LeftButton:
            self.scale(1.5,1)
        elif event.button() == QC.Qt.RightButton:
            self.scale(1/1.5,1)

class MainUI(QG.QDialog):
    def __init__(self, parent=None):
        super(MainUI, self).__init__(parent)

        layout = QG.QVBoxLayout()
        self.setLayout(layout)
        button_layout = QG.QHBoxLayout()
        pb3 = QG.QPushButton('add plot')
        button_layout.addWidget(pb3)
        layout.addLayout(button_layout)
        pb3.clicked.connect(self.scene_maker_singleshot)
        scene = QG.QGraphicsScene()
        view = ZoomView(self)
        view.setTransformationAnchor(QG.QGraphicsView.AnchorUnderMouse)
        view.setRenderHint(QG.QPainter.Antialiasing)
        layout.addWidget(view)
        view.setScene(scene)

        self.view = view
        self.scene = scene

    def scene_maker_singleshot(self):
        """Draw scene and fit in view"""
        t1 = 50
        t2 = 100
        QC.QTimer.singleShot(t1, self.make_scene)
        QC.QTimer.singleShot(t2, lambda: self.view.fitInView(self.view.sceneRect()))


    def make_scene(self):
        scale = 50
        #scale = 50000
        noise_amp = 0.2*scale
        points = 1000

        xdata = n.arange(points)
        #generate sine data and random noise
        ydata = n.sin(xdata/(points/10.))*scale +\
                n.random.randint(noise_amp, size=points)
        pen = QG.QPen(QG.QColor("red"))

        for i in xrange(1, xdata.size):
            self.scene.addLine(xdata[i-1], ydata[i-1], xdata[i], ydata[i], pen)


if __name__=="__main__":
    app = QG.QApplication(sys.argv)
    gui = MainUI()
    gui.setFixedSize(500,500)
    gui.show()
    app.exec_()

Upvotes: 5

Views: 1813

Answers (1)

Marcel Petrick
Marcel Petrick

Reputation: 484

Just like Mad Physicist told you, set the pen to cosmetic or line-width of 0 (are equal in the behavior) and you have a non-scaling pen.

>> pen.setCosmetic(True);

Upvotes: 5

Related Questions