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!"
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
and QPainterPath.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.QGraphicsEllipseItem
(for rendering nodes) and QGraphicsPathItem
(for rendering the path itself), which inherit from QGraphicsItem
.Path
constructor iterates over the QPainterPath
elements, creating Node
items for each one; Each of them, in turn, send updates to the parent Path object, which updates its path
property accordingly.#!/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_()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With