微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

更新嵌入在 PyQt5 Matplotlib 中的 Networkx 图

如何解决更新嵌入在 PyQt5 Matplotlib 中的 Networkx 图

我创建了一个 GUI,用户可以在其中使用按钮打开选项卡。当他这样做时,它会添加以下选项卡:

class data_tab(QtWidgets.QWidget,data_tab_lib.Ui_data_tab):

#=========================================================================================
# Constructor
#=========================================================================================
def __init__(self,parent,title):

    QtWidgets.QWidget.__init__(self,parent)
    self.setupUi(self)

    # initialize save data button icon
    icon = _createIcon("dataname_save")
    self.dataname_save.setIcon(icon)

    self.canvas = Canvas(data_tab)
    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)

父母是

self.core_tab = QtWidgets.QTabWidget(self.main_widget)

在主窗口中。

“画布”定义如下:

from matplotlib.backends.backend_qt5agg import figureCanvasQTAgg as figureCanvas
import matplotlib.pyplot as plt

class Canvas(figureCanvas):
    def __init__(self,parent=None):
        self.figure = plt.figure()
        figureCanvas.__init__(self,self.figure)
        self.setParent(parent)

点击初始按钮时,会发生这种情况:

     new_data_tab = data_tab(self.core_tab,dataname)

     # associated data to the variable
     associated_data = self._getDataAssociatedToVariable(dataname)

     #1. draw Graph
     self._drawDataGraph(dataname,associated_data,new_data_tab)

dataname 是上面定义的字符串。 _drawDataGraph 定义如下:

def _drawDataGraph(self,dataname,associatedData,dataWidget):

    # 1. draw graph
    drawing_dictionary = self._getAllAssociatedVariablesTobedrawn(dataname,associatedData)
    producer = drawing_dictionary.get(dataname).get("producer")
    consumers = drawing_dictionary.get(dataname).get("consumers")

    color_map = []
    DG = nx.DiGraph()
    DG.add_node(producer)
    for cons in consumers:
        DG.add_node(cons)
    edges_bunch = [(producer,cons,1) for cons in consumers]
    DG.add_weighted_edges_from(edges_bunch)

    for node in drawing_dictionary.keys():
        if node != dataname:
            DG.add_node(drawing_dictionary.get(node).get("producer"))
            for node_cons in drawing_dictionary.get(node).get("consumers"):
                DG.add_node(node_cons)

            other_edges_bunch = [(drawing_dictionary.get(node).get("producer"),node_cons,1) for node_cons in
                                 drawing_dictionary.get(node).get("consumers")]
            DG.add_weighted_edges_from(other_edges_bunch)
    for i in range(len(DG.nodes())):
        if i < 1 + len(consumers):
            color_map.append("#DCE46F")
        else:
            color_map.append("#6FA2E4")
    #pos = nx.spring_layout(DG,k=0.4,iterations=20)
    nx.draw_circular(DG,node_color=color_map,with_labels=True,font_size=8,node_size=1000,node_shape='o')
    dataWidget.canvas.draw()

我不会通过函数 _getAllAssociatedVariablesTobedrawn 因为它只是返回带有提供列表的键的字典,这里不是问题。

因此,在创建时(在最初单击按钮时),一切正常,显示一个精美的 Networkx 图。

我的问题是我有一个按钮,我想刷新当前显示的所有图表:

def refreshFlowsDiagramFromDataTabs(self):

    # loop through all pages
    for tab_index in range(self.core_tab.count()):
        data_tab_widget = self.core_tab.widget(tab_index)
        data_tab_widget.axe.cla()

        # associated data to the variable
        data_name = self.core_tab.tabText(tab_index)

        associated_data = self._getDataAssociatedToVariable(data_name)

        # 1. draw graph
        self._drawDataGraph(data_name,data_tab_widget)

遗憾的是,当按钮被点击时,只有最后一个图(所以第 n 个选项卡中的一个)被刷新,之前的都是空白的(因为它们已经通过 data_tab_widget.axe.cla 清除了) ())

我试图评论 data_tab_widget.axe.cla() 以观察会发生什么:在这种情况下,显然第 1 到第 (n-1) 个图没有被清除,而是最后一个一个是用前面所有的图做的,即第n个图显示在最后一个

我绝不是 matplotlib 或 networkx 的专家,所以我不明白我做错了什么,这可能是一件非常简单的事情,但我很乐意在该主题上使用一些帮助。

希望我提供的代码足够了,应该是。

编辑

请在下面找到一个完全可复制的代码添加标签然后刷新它们以观察错误

import sys
from PyQt5 import QtCore,QtGui,QtWidgets
from matplotlib.backends.backend_qt5agg import figureCanvasQTAgg as figureCanvas
import matplotlib.pyplot as plt
import networkx as nx

class Canvas(figureCanvas):
    def __init__(self,self.figure)
        self.setParent(parent)

class data_tab(QtWidgets.QWidget):

    #=========================================================================================
    # Constructor
    #=========================================================================================
    def __init__(self,title):

        QtWidgets.QWidget.__init__(self,parent)

        self.data_tab_glayout = QtWidgets.qgridLayout(self)
        self.data_tab_glayout.setobjectName("data_tab_glayout")
        self.canvas = Canvas(self)
        self.canvas.setobjectName("canvas")
        self.canvas_vlayout = QtWidgets.QVBoxLayout(self.canvas)
        self.canvas_vlayout.setobjectName("canvas_vlayout")
        self.data_tab_glayout.addWidget(self.canvas,2,1)

        self.axe = self.canvas.figure.add_subplot(111)
        self.canvas.figure.subplots_adjust(left=0.025,right=0.975)
        # add the tab to the parent
        parent.addTab(self,"")

        # set text name
        parent.setTabText(parent.indexOf(self),title)


class spec_writer(QtWidgets.QMainWindow):


    #=========================================================================================
    # Constructor
    #=========================================================================================
    def __init__(self,parent=None):
        QtWidgets.QMainWindow.__init__(self,parent)

        self.showMaximized()

        self.centralwidget = QtWidgets.QWidget(self)
        self.centralwidget.setobjectName("centralwidget")
        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):

        # 1. draw graph
        producer = self.random_tabs[tabNb][0]
        consumers = self.random_tabs[tabNb][1]

        color_map = []
        DG = nx.DiGraph()
        DG.add_node(producer)
        for cons in consumers:
            DG.add_node(cons)
        edges_bunch = [(producer,1) for cons in consumers]
        DG.add_weighted_edges_from(edges_bunch)
        for i in range(len(DG.nodes())):
            if i < 1 + len(consumers):
                color_map.append("#DCE46F")
            else:
                color_map.append("#6FA2E4")
        #pos = nx.spring_layout(DG,iterations=20)
        nx.draw_circular(DG,node_shape='o')
        dataWidget.canvas.draw_idle()


    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)
            data_tab_widget.axe.cla()

            # draw graph
            self._drawDataGraph(tab_index % len(self.random_tabs),data_tab_widget)




sys.argv = ['']
app = QtWidgets.QApplication(sys.argv)
cbtc_spec_writer = spec_writer()
cbtc_spec_writer.show()
app.exec_()

解决方法

如果您打算使用后端,则不应使用 pyplot,因为 pyplot 默认仅在当前画布上工作,并且默认情况下它是最后一个。

例如,以下代码(已重新排序和清理)显示了如何实现它:

from PyQt5 import QtCore,QtWidgets

from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure

import networkx as nx


class DataTab(QtWidgets.QWidget):
    def __init__(self,parent=None):
        QtWidgets.QWidget.__init__(self,parent)

        self.canvas = FigureCanvas(Figure(figsize=(5,3)))
        self.axes = self.canvas.figure.add_subplot(111)
        self.canvas.figure.subplots_adjust(
            left=0.025,top=0.965,bottom=0.040,right=0.975
        )
        data_tab_glayout = QtWidgets.QGridLayout(self)
        data_tab_glayout.addWidget(self.canvas)


class Spec_Writer(QtWidgets.QMainWindow):
    def __init__(self,parent=None):
        QtWidgets.QMainWindow.__init__(self,parent)
        self.showMaximized()

        self.core_tab = QtWidgets.QTabWidget(
            tabShape=QtWidgets.QTabWidget.Rounded,elideMode=QtCore.Qt.ElideNone,documentMode=False,tabsClosable=True,movable=True,tabBarAutoHide=False,)
        self.add_tab_btn = QtWidgets.QPushButton("Add Tab")
        self.refresh_tab_btn = QtWidgets.QPushButton("Refresh Tabs")

        self.centralwidget = QtWidgets.QWidget()
        self.setCentralWidget(self.centralwidget)

        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.addWidget(self.core_tab)
        self.verticalLayout.addWidget(self.add_tab_btn)
        self.verticalLayout.addWidget(self.refresh_tab_btn)

        self.tab_counter = 0

        self.random_data = [
            ("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.open_random_tab)
        self.refresh_tab_btn.clicked.connect(self.refresh_all_tabs)

    def open_random_tab(self):
        tab = DataTab()
        index = self.core_tab.addTab(tab,"test {}".format(self.tab_counter))
        self.core_tab.setCurrentIndex(index)
        self.tab_counter += 1
        self._draw_graph(self.tab_counter % len(self.random_data),tab)

    def _draw_graph(self,index,tab):
        tab.axes.cla()
        producer,consumers = self.random_data[index]
        color_map = []
        DG = nx.DiGraph()
        DG.add_node(producer)
        for cons in consumers:
            DG.add_node(cons)
        edges_bunch = [(producer,cons,1) for cons in consumers]
        DG.add_weighted_edges_from(edges_bunch)
        for i in range(len(DG.nodes())):
            if i < 1 + len(consumers):
                color_map.append("#DCE46F")
            else:
                color_map.append("#6FA2E4")
        # pos = nx.spring_layout(DG,k=0.4,iterations=20)
        nx.draw_circular(
            DG,node_color=color_map,with_labels=True,font_size=8,node_size=1000,node_shape="o",ax=tab.axes,)
        tab.canvas.draw()

    def refresh_all_tabs(self):
        for tab_index in range(self.core_tab.count()):
            data_tab_widget = self.core_tab.widget(tab_index)
            self._draw_graph(tab_index % len(self.random_data),data_tab_widget)


def main():
    app = QtWidgets.QApplication([])
    cbtc_spec_writer = Spec_Writer()
    cbtc_spec_writer.show()
    app.exec_()


if __name__ == "__main__":
    main()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。