pyqtgraph get text of node and change color on MouseClick

我怕爱的太早我们不能终老 提交于 2019-12-12 04:39:53

问题


I found this example from the pyqtgraph github repo.

I would like to create an interactive (network) graph with pyqtgraph with the following functionality:

  • When the user clicks on a node, he/she will get the 'text'-info of that node.
  • When a node was clicked the color of that node, as well as of all its neighbors (edges and nodes) will change (e.g. to yellow)
  • Allow for multiple selection

Code:

# -*- coding: utf-8 -*-
"""
Simple example of subclassing GraphItem.
"""

import initExample ## Add path to library (just for examples; you do not need this)

import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np

# Enable antialiasing for prettier plots
pg.setConfigOptions(antialias=True)

w = pg.GraphicsWindow()
w.setWindowTitle('pyqtgraph example: CustomGraphItem')
v = w.addViewBox()
v.setAspectLocked()

class Graph(pg.GraphItem):
    def __init__(self):
        self.dragPoint = None
        self.dragOffset = None
        self.textItems = []
        pg.GraphItem.__init__(self)
        self.scatter.sigClicked.connect(self.clicked)

    def setData(self, **kwds):
        self.text = kwds.pop('text', [])
        self.data = kwds
        if 'pos' in self.data:
            npts = self.data['pos'].shape[0]
            self.data['data'] = np.empty(npts, dtype=[('index', int)])
            self.data['data']['index'] = np.arange(npts)
        self.setTexts(self.text)
        self.updateGraph()

    def setTexts(self, text):
        for i in self.textItems:
            i.scene().removeItem(i)
        self.textItems = []
        for t in text:
            item = pg.TextItem(t)
            self.textItems.append(item)
            item.setParentItem(self)

    def updateGraph(self):
        pg.GraphItem.setData(self, **self.data)
        for i,item in enumerate(self.textItems):
            item.setPos(*self.data['pos'][i])


    def mouseDragEvent(self, ev):
        if ev.button() != QtCore.Qt.LeftButton:
            ev.ignore()
            return

        if ev.isStart():
            # We are already one step into the drag.
            # Find the point(s) at the mouse cursor when the button was first 
            # pressed:
            pos = ev.buttonDownPos()
            pts = self.scatter.pointsAt(pos)
            if len(pts) == 0:
                ev.ignore()
                return
            self.dragPoint = pts[0]
            ind = pts[0].data()[0]
            self.dragOffset = self.data['pos'][ind] - pos
        elif ev.isFinish():
            self.dragPoint = None
            return
        else:
            if self.dragPoint is None:
                ev.ignore()
                return

        ind = self.dragPoint.data()[0]
        self.data['pos'][ind] = ev.pos() + self.dragOffset
        self.updateGraph()
        ev.accept()

    def clicked(self, pts):
        print("clicked: %s" % pts)


g = Graph()
v.addItem(g)

## Define positions of nodes
pos = np.array([
    [0,0],
    [10,0],
    [0,10],
    [10,10],
    [5,5],
    [15,5]
    ], dtype=float)

## Define the set of connections in the graph
adj = np.array([
    [0,1],
    [1,3],
    [3,2],
    [2,0],
    [1,5],
    [3,5],
    ])

## Define the symbol to use for each node (this is optional)
symbols = ['o','o','o','o','t','+']

## Define the line style for each connection (this is optional)
lines = np.array([
    (255,0,0,255,1),
    (255,0,255,255,2),
    (255,0,255,255,3),
    (255,255,0,255,2),
    (255,0,0,255,1),
    (255,255,255,255,4),
    ], dtype=[('red',np.ubyte),('green',np.ubyte),('blue',np.ubyte),('alpha',np.ubyte),('width',float)])

## Define text to show next to each symbol
texts = ["Point %d" % i for i in range(6)]

## Update the graph
g.setData(pos=pos, adj=adj, pen=lines, size=1, symbol=symbols, pxMode=False, text=texts)




## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

The above code returns the following info, when a node is clicked:

<pyqtgraph.graphicsItems.ScatterPlotItem.ScatterPlotItem object at 0x7f1e51657558>

Which is actually the whole graph item (because the clicking signal is called on the whole graph).

Now: how can I call the MouseClicking functionality on every node, get the text of that node and change its (and its neighbors) color on the clicking event?

Another example shows changing the color of a clicked curve in another plot. Here, the clicking signal gets called on every curve. I tried to use this as a starting point to implement something similar on the first mentioned code example below, but honestly, I don't even know how to get to the single nodes in a pyqtgraph graph object (as [I might be wrong here], the nodes are only defined through their positions).

As always, any help here would be very much appreciated.

Edit: Thanks to kesumu's answer, I was able to get the text content of a clicked node like this:

def clicked(self, scatter, pts):
    data_list = scatter.data.tolist()
    mypoint = [tup for tup in data_list if pts[0] in tup][0]
    mypoint_index = data_list.index(mypoint)
    mypoint_text = self.text[mypoint_index]

Edit II:

A more elaborate example of the same problem can be found here.


回答1:


The problem is that your clicked function is wrong.

It should be like this:

def clicked(self, scatter, pts):
    print(scatter)
    print(pts[0])
    print("clicked: %s" % pts)

Because the sigClicked has TWO parameters: self, points. This is its definition:

sigClicked = QtCore.Signal(object, object)  ## self, points

After fixed, you can get the clicked points like this:

Hope this is helpful to you.



来源:https://stackoverflow.com/questions/46791395/pyqtgraph-get-text-of-node-and-change-color-on-mouseclick

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!