In PyQT, how can I plot small "Nodes" at given points and connect them with edges? All of the PyQT tutorials I find are "plot a button! plot a checkbox!"
Asked
Active
Viewed 1.0k times
2 Answers
4
It has been a pain to find a good explanation for this (as of by the end of 2014 already), and since this question asks exactely what I was looking for, I'll post a transcription (from C++ to Python) of what I found in this post.
The code is below, and here is the rationale:
QGrahpicsItem
,QPainterPath
andQPainterPath.Element
are the classes you are looking for. Specifically, QPainterPath implements the kind of vector functionality you expect in applications such as CorelDraw, Adobe Illustrator, or Inkscape.- The example below benefits from the pre-existing
QGraphicsEllipseItem
(for rendering nodes) andQGraphicsPathItem
(for rendering the path itself), which inherit fromQGraphicsItem
. - The
Path
constructor iterates over theQPainterPath
elements, creatingNode
items for each one; Each of them, in turn, send updates to the parent Path object, which updates itspath
property accordingly. - I found much, much easier to study the C++ Qt4 Docs than the rather less structured PyQt docs found elsewhere. Once you get used to mentally translate between C++ and Python, the docs themselves are a powerful way to learn how to use each class.
#!/usr/bin/env python
# coding: utf-8
from PyQt4.QtGui import *
from PyQt4.QtCore import *
rad = 5
class Node(QGraphicsEllipseItem):
def __init__(self, path, index):
super(Node, self).__init__(-rad, -rad, 2*rad, 2*rad)
self.rad = rad
self.path = path
self.index = index
self.setZValue(1)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
self.setBrush(Qt.green)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionChange:
self.path.updateElement(self.index, value.toPointF())
return QGraphicsEllipseItem.itemChange(self, change, value)
class Path(QGraphicsPathItem):
def __init__(self, path, scene):
super(Path, self).__init__(path)
for i in xrange(path.elementCount()):
node = Node(self, i)
node.setPos(QPointF(path.elementAt(i)))
scene.addItem(node)
self.setPen(QPen(Qt.red, 1.75))
def updateElement(self, index, pos):
path.setElementPositionAt(index, pos.x(), pos.y())
self.setPath(path)
if __name__ == "__main__":
app = QApplication([])
path = QPainterPath()
path.moveTo(0,0)
path.cubicTo(-30, 70, 35, 115, 100, 100);
path.lineTo(200, 100);
path.cubicTo(200, 30, 150, -35, 60, -30);
scene = QGraphicsScene()
scene.addItem(Path(path, scene))
view = QGraphicsView(scene)
view.setRenderHint(QPainter.Antialiasing)
view.resize(600, 400)
view.show()
app.exec_()

heltonbiker
- 26,657
- 28
- 137
- 252
-
This code has helped me so much lately! Thanks! Also I'm trying to plot an function in class Node - mousePressEvent / middle click to add a control point to path lineTo.() So that from point A > B I can add point C in the middle.. so I can do a "L" shape... meaning > A/B top left/right bottom and C being corner... But I'm not sure if its the right way as I don't detect red draw line only circles when I press... any hints how I can do it? Thanks! – Dariusz Sep 21 '16 at 21:15
-
1@Dariusz I'm sure there is some sort of built-in "mouseover" event or flag in Qt, but I don't remember it's name, neigher which class has it. I would start searching for that in `QGraphicsItem`. – heltonbiker Sep 23 '16 at 12:32
-
1@Dariusz, actually I found them, they're the `hoverEnterEvent` and `hoverLeaveEvent`, found [here](http://doc.qt.io/qt-4.8/qgraphicsitem.html). – heltonbiker Sep 23 '16 at 12:35
3
If you want to be able to interact with the objects displayed in the plot, you will be better off using a QGraphicsScene. It handles zooming and panning and can contain other QGraphicsItem objects that can handle their own interactions.
It's very easy to use, but there is a bit of overhead involved, especially if you plan to make thousands of objects.
You can find a PyQt tutorial here. This and the API docs should get you started.

drxzcl
- 2,952
- 1
- 26
- 28
-
Don't know about the tutorial that you have linked to. I'm getting segmentation fault whenever I close the PyQt application. – rbaleksandar Feb 23 '16 at 22:25
-
The tutorial is from 2008, so some things might have changed in the meantime. Segfault-on-close is usually a sign that something is wrong with the lifetime/configuration of your basic QT classes (QApplication, QMainWindow etc). If you can run tutorials for your PyQt version, you should be able to incorporate the necessary items to get QGraphicsScene to work. – drxzcl Feb 27 '16 at 19:13
-