PyQt 应用程序中带有选项卡的可点击网络图
clickable netgraph in PyQt application with tabs
我有一个 PyQt 应用程序,它有一个选项卡小部件,可以打开任意数量的选项卡。每个选项卡都嵌入了一个 matplotlib canvas 显示图表。
最近,我尝试从 netgraph
库实现 InteractiveGraph
,尽管有 的帮助,但收效甚微。可能是因为标签的额外存在,我不知道。
我观察到我无法点击图形节点。虽然图表显示正确。
下面是我的代码的一个简单示例(选项卡具有用于测试的静态图形值,每个添加的选项卡都会添加一个嵌入式图形),以及我如何尝试实现类似主题的建议解决方案。我不确定使用 mpl_connect
的必要性,所以我尝试使用和不使用它,但没有任何改变。
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def on_key_press(self, event):
print("you press", event.key)
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout(DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes(DG, 'label')
graph_instance = InteractiveGraph(DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=dataWidget.axe
)
dataWidget.canvas.draw()
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()
如果你什么点击图,我觉得你需要在图上连接mpl_connect
,而不是在canvas
上
self.figure = Figure(facecolor='white')
self.canvas = FigureCanvas(self.figure)
然后与'button_press_event'
建立联系
self.figure.canvas.mpl_connect('button_press_event', self.onclick)
如果想获取被点击的节点,可以在data_tab
class
中放入DG
和graph_instance
dataWidget.DG = DG
dataWidget.graph_instance =graph_instance
然后在回调函数中使用它们
def onclick(self,event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
x = event.xdata
y = event.ydata
for n in self.graph_instance.node_artists :
node = self.graph_instance.node_artists [n]
dist = ((x-node.xy[0])**2 + (y-node.xy[1])**2)**0.5
if dist < node.radius:
print(node)
函数可能类似于
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.parent = parent
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.figure = Figure(facecolor='white')
self.canvas = FigureCanvas(self.figure)
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
# self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.figure.canvas.mpl_connect('button_press_event', self.onclick)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def onclick(self,event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
x = event.xdata
y = event.ydata
for n in self.graph_instance.node_artists :
node = self.graph_instance.node_artists [n]
dist = ((x-node.xy[0])**2 + (y-node.xy[1])**2)**0.5
if dist < node.radius:
print(node)
def on_key_press(self, event):
print("you press", event.key)
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout( DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes( DG, 'label')
graph_instance = InteractiveGraph( DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=dataWidget.axe,pickable=True
)
dataWidget.DG = DG
dataWidget.graph_instance =graph_instance
# dataWidget.canvas.show(pickable=True )
dataWidget.canvas.draw()
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()
好的,根据 ymmx 的回答,我发现 InteractiveGraph 的实例化不需要是本地的。
所以这是在我的案例中似乎符合要求的解决方案:
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.figure = Figure(figsize=(5, 3))
self.canvas = FigureCanvas(self.figure)
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
#self.figure.canvas.mpl_connect('button_press_event', self.onclick)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def createInteractiveGraph(self, DG, pos, node_color, labels):
self.graph_instance = InteractiveGraph(DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=self.axe
)
self.canvas.draw()
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout(DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes(DG, 'label')
dataWidget.createInteractiveGraph(DG, pos, node_color, labels)
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()
我有一个 PyQt 应用程序,它有一个选项卡小部件,可以打开任意数量的选项卡。每个选项卡都嵌入了一个 matplotlib canvas 显示图表。
最近,我尝试从 netgraph
库实现 InteractiveGraph
,尽管有
我观察到我无法点击图形节点。虽然图表显示正确。
下面是我的代码的一个简单示例(选项卡具有用于测试的静态图形值,每个添加的选项卡都会添加一个嵌入式图形),以及我如何尝试实现类似主题的建议解决方案。我不确定使用 mpl_connect
的必要性,所以我尝试使用和不使用它,但没有任何改变。
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def on_key_press(self, event):
print("you press", event.key)
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout(DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes(DG, 'label')
graph_instance = InteractiveGraph(DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=dataWidget.axe
)
dataWidget.canvas.draw()
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()
如果你什么点击图,我觉得你需要在图上连接mpl_connect
,而不是在canvas
self.figure = Figure(facecolor='white')
self.canvas = FigureCanvas(self.figure)
然后与'button_press_event'
self.figure.canvas.mpl_connect('button_press_event', self.onclick)
如果想获取被点击的节点,可以在data_tab
class
DG
和graph_instance
dataWidget.DG = DG
dataWidget.graph_instance =graph_instance
然后在回调函数中使用它们
def onclick(self,event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
x = event.xdata
y = event.ydata
for n in self.graph_instance.node_artists :
node = self.graph_instance.node_artists [n]
dist = ((x-node.xy[0])**2 + (y-node.xy[1])**2)**0.5
if dist < node.radius:
print(node)
函数可能类似于
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.parent = parent
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.figure = Figure(facecolor='white')
self.canvas = FigureCanvas(self.figure)
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
# self.canvas.mpl_connect('key_press_event', self.on_key_press)
self.figure.canvas.mpl_connect('button_press_event', self.onclick)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def onclick(self,event):
print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' %
('double' if event.dblclick else 'single', event.button,
event.x, event.y, event.xdata, event.ydata))
x = event.xdata
y = event.ydata
for n in self.graph_instance.node_artists :
node = self.graph_instance.node_artists [n]
dist = ((x-node.xy[0])**2 + (y-node.xy[1])**2)**0.5
if dist < node.radius:
print(node)
def on_key_press(self, event):
print("you press", event.key)
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout( DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes( DG, 'label')
graph_instance = InteractiveGraph( DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=dataWidget.axe,pickable=True
)
dataWidget.DG = DG
dataWidget.graph_instance =graph_instance
# dataWidget.canvas.show(pickable=True )
dataWidget.canvas.draw()
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()
好的,根据 ymmx 的回答,我发现 InteractiveGraph 的实例化不需要是本地的。
所以这是在我的案例中似乎符合要求的解决方案:
import sys
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
import networkx as nx
import numpy as np
from netgraph import InteractiveGraph
class data_tab(QtWidgets.QWidget):
def __init__(self, parent, title):
QtWidgets.QWidget.__init__(self, parent)
self.data_tab_glayout = QtWidgets.QGridLayout(self)
self.figure = Figure(figsize=(5, 3))
self.canvas = FigureCanvas(self.figure)
self.canvas.setParent(parent)
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()
self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
self.data_tab_glayout.addWidget(self.canvas, 0, 0, 2, 1)
#self.figure.canvas.mpl_connect('button_press_event', self.onclick)
self.axe = self.canvas.figure.add_subplot(111)
self.canvas.figure.subplots_adjust(left=0.025, top=0.965, bottom=0.040, right=0.975)
# add the tab to the parent
parent.addTab(self, "")
# set text name
parent.setTabText(parent.indexOf(self), title)
def createInteractiveGraph(self, DG, pos, node_color, labels):
self.graph_instance = InteractiveGraph(DG, node_layout=pos, edge_layout='curved', origin=(-1, -1), scale=(2, 2),
node_color=node_color, node_size=8.,
node_labels=True, node_label_fontdict=dict(size=10),
edge_labels=labels, edge_label_fontdict=dict(size=10), ax=self.axe
)
self.canvas.draw()
class MyApp(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.core_tab = QtWidgets.QTabWidget(self.centralwidget)
self.verticalLayout.addWidget(self.core_tab)
self.add_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.add_tab_btn)
self.refresh_tab_btn = QtWidgets.QPushButton(self.centralwidget)
self.verticalLayout.addWidget(self.refresh_tab_btn)
self.setCentralWidget(self.centralwidget)
self.add_tab_btn.setText("Add Tab")
self.refresh_tab_btn.setText("Refresh Tabs")
self.core_tab.setEnabled(True)
self.core_tab.setTabShape(QtWidgets.QTabWidget.Rounded)
self.core_tab.setElideMode(QtCore.Qt.ElideNone)
self.core_tab.setDocumentMode(False)
self.core_tab.setTabsClosable(True)
self.core_tab.setMovable(True)
self.core_tab.setTabBarAutoHide(False)
self.tab_counter = 0
self.random_tabs = [("a", ["b", "c"]),
("d", ["e", "f", "g"]),
("h", ["i", "j", "k", "l"]),
("m", ["n"]),
("o", ["p", "q"]),
("r", ["s", "t", "u", "v", "w", "x", "y", "z"])]
self.add_tab_btn.clicked.connect(self.openRandomTab)
self.refresh_tab_btn.clicked.connect(self.refreshAllTabs)
def openRandomTab(self):
tab = data_tab(self.core_tab, "test " + str(self.tab_counter))
self._drawDataGraph(self.tab_counter % len(self.random_tabs), tab)
self.tab_counter += 1
self.core_tab.setCurrentIndex(self.core_tab.indexOf(tab))
def _drawDataGraph(self, tabNb, dataWidget):
dataWidget.axe.cla()
# 1. draw graph
producer = self.random_tabs[tabNb][0]
consumers = self.random_tabs[tabNb][1]
color_map = []
DG = nx.DiGraph()
for i, cons in enumerate(consumers):
DG.add_edge(producer, cons, label=f"edge-{i}")
node_color = dict()
for node in DG:
if node in producer:
node_color[node] = "#DCE46F"
else:
node_color[node] = "#6FA2E4"
pos = nx.shell_layout(DG)
pos[producer] = pos[producer] + np.array([0.2, 0])
labels = nx.get_edge_attributes(DG, 'label')
dataWidget.createInteractiveGraph(DG, pos, node_color, labels)
def refreshAllTabs(self):
# loop through all pages and associated to get
for tab_index in range(self.core_tab.count()):
data_tab_widget = self.core_tab.widget(tab_index)
# draw graph
self._drawDataGraph(tab_index % len(self.random_tabs), data_tab_widget)
sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
main_app = MyApp()
main_app.show()
app.exec_()