如何在networkx中定义图形的大小并绘制具有特定颜色的弧形边缘?

How can I define the size of the graph and draw arced edges with a certain color in networkx?

在 networkx 中绘制图形以及显示节点之间的循环时,我无法弄清楚如何定义输出文件的大小 =34=].

问题定义

我有一个节点列表,这些节点**可能**或**可能不**在它们之间有循环。正如您在下面我提供的代码中看到的那样,我使用两种颜色来区分两种不同类型的边缘(边缘的颜色决定了这种差异)。

现状

到目前为止我还不能在边缘显示不同的颜色(根据添加边缘时可以定义documentation颜色),也没有我能够避免边重叠(当两个节点组成一个循环时,一条边与另一条边重叠,因此只有一条边可见)。

我也无法在绘图时设置图形的大小(或保存绘图 mith matplotlib)。我已经看到一些询问输出大小的问题,但 none 到目前为止对我有用(代码中注释了一些示例,但我尝试了其他一些)。

    def plot(self):
    """
    plot graph
    """

    nx.draw(self.G, with_labels = True)
    #nx.draw_kamada_kawai(self.G, with_labels = True)
    #plt.figure(1, figsize=(200, 80), dpi=60, font_weight='normal')
    #plt.figure(figsize=(280,80))
    plt.savefig("filename.png")

当前输出

[![当前输出][2]][2]

期望的输出

我需要相同的输出,但带有 **弧形边缘**,使用 **提供的颜色** 绘制,因此它们不会 **彼此重叠**。我还需要最终输出大小来适应图形的大小。正如您在图像中看到的,**节点的名称被截断并且图形被清楚地裁剪**。如果您尝试更改 number_of_nodes 的值,您会看到一切都被切断了... 请记住,这些图可能有 25 到 100 个节点,它们之间有多个边(包括循环)

到目前为止我的代码

from tkinter.ttk import Notebook
import networkx as nx
import matplotlib.pyplot as plt

class Graph:
    """
    create and visualize a graph using networkx
    """
    def __init__(self):
        """
        basic constructor
        """
        
        self.G = nx.MultiDiGraph()


    def addNodes(self,nodes, options = {'color' : 'blue'}):
        """
        add nodes to the graph
        """
        #asserts
        assert(self.G is None, 'graph not created')
        assert(options is None, 'options  parameter is none type')
        assert(not isinstance(nodes, list), 'nodes parameter must be a list')

        #add nodes with options
        for n in nodes:
            opt = options
            opt['label'] = n
            self.G.add_nodes_from(
                [(n, opt)]
            )


    def addEdges(self, edges, options = {'color' : 'green'}):
        """
        add edges to the graph
        """
        #asserts
        assert(self.G is None, 'graph not created')
        assert(options is None, 'options  parameter is none type')
        assert(not isinstance(edges, list), 'edges parameter must be a list')
        
        #add edges with options
        
        for n in edges:
            opt = options
            opt['label'] = n

            self.G.add_edges_from(
                [n + (options,)]
            )
        print([n + (options,)])
        #self.G.add_edges_from(edges, options)
    
    def removeNodes(self, nodes):
        """
        remove nodes from graph
        """
        assert(self.G is None, 'graph not created')
        assert(not isinstance(nodes, list), 'nodes parameter must be a list')

        self.G.remove_nodes_from(nodes)

    def removeEdges(self,edges):
        """
        remove edges from graph
        """

        assert(self.G is None, 'graph not created')
        assert(not isinstance(edges, list), 'edges parameter must be a list')

        self.G.remove_edges_from(edges)
    
    def plot(self):
        """
        plot graph
        """

        nx.draw(self.G, with_labels = True)
        #nx.draw_kamada_kawai(self.G, with_labels = True)
        #plt.figure(1, figsize=(200, 80), dpi=60, font_weight='normal')
        #plt.figure(figsize=(280,80))
        plt.savefig("filename.png")

    def save_graph(self, filename):
        """
        save graph to file
        """
        pass

class CubeGraph(Graph):
    """
    this class handles graphs for cubes
    """

    def __init__(self, nodes, green_edges, red_edges):
        """
        constructor for cube graph
        """
        #asserts
        assert(not isinstance(nodes, list), 'nodes parameter must be a list')
        assert(not isinstance(green_edges, list), 'green_edges parameter must be a list')
        assert(not isinstance(red_edges, list), 'red_edges parameter must be a list')

        #assign variables
        self._nodes = nodes
        self._greenEdges = green_edges
        self._redEdges = red_edges
        
        #init parent object
        super().__init__()

    def createAll(self):
        """
        create the graph with all the nodes and edges
        """
        self.addNodes(self._nodes)
        self.addEdges(self._greenEdges, {'color' : 'green'})
        self.addEdges(self._redEdges, {'color' : 'red'})

    def create(self, node):
        """
        create a graph only with related node
        """

        assert(node in self._nodes, 'node parameter is not nodes list provided at initialization')
        #clean the graph
        self.removeEdges(self._redEdges)
        self.removeEdges(self._greenEdges)
        self.removeNodes(self._nodes)

        #make sure node is lower case
        node = node.lower()

        #filter only those edges matching the node
        green_filtered = list(filter(lambda x : x[0] == node, self._greenEdges))
        red_filtered = list(filter(lambda x : x[1] == node, self._redEdges))

        #add nodes and edges to graph
        self.addNodes(node)
        self.addEdges(green_filtered, {'color' : 'green'})
        self.addEdges(red_filtered, {'color' : 'red'})

number_of_nodes = 6
nodes = ['0000 very long and unique string number {}'.format(i) for i in range(0,number_of_nodes)]
green = []
red = []
green.append(('0000 very long and unique string number 0', '0000 very long and unique string number 1'))
red.append(('0000 very long and unique string number 1', '0000 very long and unique string number 0'))

green.append(('0000 very long and unique string number 2', '0000 very long and unique string number 3'))
red.append(('0000 very long and unique string number 3', '0000 very long and unique string number 2'))

green.append(('0000 very long and unique string number 4', '0000 very long and unique string number 5'))
red.append(('0000 very long and unique string number 5', '0000 very long and unique string number 4'))

net = CubeGraph(nodes, green, red)
net.createAll()
net.plot()
print('')

在边缘的格式化上苦苦挣扎之后,我得到了我需要的东西。 nx 的 draw 函数毕竟不是我需要的 draw 选项,因为为了实现我想要的,我需要创建一个布局以便计算节点的位置。之后,函数 draw_networkx_nodes 和 draw_networkx_edges 提供了我正在寻找的实用程序。该函数如下所示:

def plot(self):
    """
    plot graph
    """
    fig = plt.figure(1, figsize=(self.IMAGE_WIDTH, self.IMAGE_HEIGHT), dpi=60)
    
    # Compute position of nodes
    pos = nx.kamada_kawai_layout(self.G)
    # Draw nodes and edges
    nx.draw_networkx_nodes(self.G, pos, labels = list(self.G.nodes))
    nx.draw_networkx_labels(self.G, pos, {n: n for n in list(self.G.nodes)}, font_size=10)
    
    nx.draw_networkx_edges(
        self.G, pos,
        connectionstyle="arc3,rad=0.1"
        ,edge_color = self.edgesColor
        ,arrowsize=20
    )
    #nx.draw_networkx_edge_labels(self.G, pos, {n: n for n in list(self.G.edges)}, font_size=6)

    plt.show()