我想使用Networkx和Matplotlib输出三维图形

ecbunoof  于 2022-11-15  发布在  其他
关注(0)|答案(1)|浏览(315)

摘要

作为一个原型,我们能够输出一个二维图形。源代码如下所示。我想尝试输出这个三维图形,所以我开始在现有的代码上乱翻,但经过大量的研究后,我感到不知所措。所以我决定冒着被指出缺乏研究的风险,在stackoverflow上发表一个问题。

我想要实现的目标

目前,这是我们要实现的三个主要目标。

  • 我们不希望尽可能多地更改Tkenter的UI,因为我们希望覆盖链接并在以后进行比较。
  • 使节点的大小与链接的密度成比例地变大。
  • 我想从文本文件中读取拓扑信息并输出图形。

有问题的源代码

  • 由于是冗余的,所以源代码做了一定程度的删减,所以可能会有一些不自然的地方,请大家理解。
  • 输出二维图形的源代码
import networkx as nx
from networkx.algorithms.centrality.betweenness_subset import edge_betweenness_centrality_subset
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import messagebox
import tkinter.filedialog as fd

# Input Window Settings
tki = tk.Tk()  # Tk class generation
tki.geometry('350x300')  # screen size
tki.title('link')  # screen title

# List check button labels
chk_txt = ['Normal network visualization']
chk_bln = {}  #Check box ON/OFF status

# Dynamically create and place check buttons
for i in range(len(chk_txt)):
    chk_bln[i] = tk.BooleanVar()
    chk = tk.Checkbutton(tki,
                         variable=chk_bln[i],
                         text=chk_txt[i]) 
    chk.place(x=50,
              y=30 + (i * 24))

path = fd.askopenfilename()

# Command to exit
def close_window():
    tki.destroy()

# button generation
btn3 = tk.Button(tki,
                 text = '  decision  ')
btn3.place(x = 100 , y = 200)

btn4 = tk.Button(tki,
                 text = 'exit',
                 command = close_window)
btn4.place(x = 150 , y = 250)

# Graph Window Settings

# Load a list of edges
G = nx.read_edgelist(path,
                     nodetype=int)
edge_size = nx.number_of_edges(G) # number of edges
node_size = nx.number_of_nodes(G) # number of nodes

# Figure Layout Determination 
pos = nx.spring_layout(G, k=0.8)
degs = dict(G.degree)

# Figure Creation
plt.figure(figsize=(15, 15))
plt.title("graph",
          fontsize = 30,
          fontweight = 'bold')

# nodes
# Determine nodes size
average_deg = sum(d for n,d in G.degree()) / G.number_of_nodes()  #Calculate the average number of hours for the entire network
sizes = [300 * deg * 2 / average_deg for node,deg in G.degree()]  #Sized to be proportional to node order

# Drawing Nodes and Labels
nx.draw_networkx_nodes(G,
                       pos,
                       node_color = 'w',
                       edgecolors = "k",
                       alpha = 0.75,
                       node_size = sizes,
                       linewidths = 2)
nx.draw_networkx_labels(G,
                        pos,
                        font_size = 10)

# Reading topology information (.txt)
with open(path, "r") as tf:
    line = tf.read().split()
ran = int(len(line) / 2)

# Graph Output
# Button click event (set to checked or unchecked)
def btn_click(bln):
    for i in range(len(chk_bln)):
        chk_bln[i].set(bln)

# How to draw for each event
def while_1(event):
    if(chk_bln[0].get() == True):
        #Normal link drawing
        nx.draw_networkx_edges(G,
                               pos,
                               edge_color = 'c')
    plt.show()
    
#Bind function to button
btn3.bind('<Button-1>',while_1)
  • 源代码捏合输出一个3D图形
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import networkx as nx
import numpy as np
import tkinter as tk
from tkinter import messagebox
import tkinter.filedialog as fd

# Input Window Settings
#omission

# Generate edge data
with open(path, "r") as tf:
    line = tf.read().split()
ran = int(len(line) / 2)

# Create graphs from generated edge data
G = nx.read_edgelist(path,
                     nodetype=int)
edge_size = nx.number_of_edges(G) # number of edges
node_size = nx.number_of_nodes(G) # number of nodes

# spring_layout algorithm to generate 3D coordinates
pos = nx.spring_layout(G, k = 0.8, dim = 3)
degs = dict(G.degree)

# Conversion from dictionary type to array type
pos_ary = np.array([pos[n] for n in G])

# visualization
fig = plt.figure()
ax = fig.add_subplot(121, projection="3d")

#Set graph title
ax.set_title("3D graph",size=20)

# Dot the position of each node
ax.scatter(
    pos_ary[:, 0],
    pos_ary[:, 1],
    pos_ary[:, 2],
    s=50,
)

# Display labels on nodes
for n in G.nodes:
    ax.text(*pos[n], n)

# Edge display
for e in G.edges:
    node0_pos = pos[e[0]]
    node1_pos = pos[e[1]]
    xx = [node0_pos[0], node1_pos[0]]
    yy = [node0_pos[1], node1_pos[1]]
    zz = [node0_pos[2], node1_pos[2]]
    ax.plot(xx, yy, zz, c="#aaaaaa")

# Graph Output
# Button click event (set to checked or unchecked)
def btn_click(bln):
    for i in range(len(chk_bln)):
        chk_bln[i].set(bln)

# How to draw for each event
def while_1(event):
    if(chk_bln[0].get() == True):
        #Normal link drawing
        nx.draw_networkx_edges(G,
                               pos#_ary[:,2],
                               #edge_color = 'c'
                               )
    #View the resulting diagram
    plt.show()

#Bind function to button
btn3.bind('<Button-1>',while_1)

遇到问题/错误消息

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:/Program Files/Python36/3D_test2.py", line 106, in while_1
    ,edge_color = 'c'
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\networkx\drawing\nx_pylab.py", line 684, in draw_networkx_edges
    alpha=alpha,
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\matplotlib\collections.py", line 1393, in __init__
    self.set_segments(segments)
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\matplotlib\collections.py", line 1408, in set_segments
    self._paths = [mpath.Path(_seg) for _seg in _segments]
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\matplotlib\collections.py", line 1408, in <listcomp>
    self._paths = [mpath.Path(_seg) for _seg in _segments]
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\matplotlib\path.py", line 132, in __init__
    cbook._check_shape((None, 2), vertices=vertices)
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\matplotlib\cbook\__init__.py", line 2304, in _check_shape
    f"{k!r} must be {len(target_shape)}D "
ValueError: 'vertices' must be 2D with shape (M, 2). Your input has shape (2, 3).
  • 拓扑信息(.txt)

补充信息

Python 3.6.8
网络x 2.5.1
绘制库3.3.4

我们尝试的

enter image description here第106行的“edge_color = 'c'”被注解掉了,因为发生了与上面相同的错误。当使用“pos_ary[n]”时,输出了以下错误语句。

>>> Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Program Files\Python36\3D_test2.py", line 105, in while_1
    pos_ary[n]
IndexError: index 21 is out of bounds for axis 0 with size 21

在第105行中,当使用“pos[n]”时,生成另一个错误消息。这与“pos_ary[n-1]"相同。

>>> Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\Python36\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Program Files\Python36\3D_test2.py", 
line 105, in while_1
    pos[n]#_ary[:,2],
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\networkx\drawing\nx_pylab.py", line 656, in draw_networkx_edges
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
  File "C:\Users\████\AppData\Roaming\Python\Python36\site-packages\networkx\drawing\nx_pylab.py", line 656, in <listcomp>
    edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist])
IndexError: index 10 is out of bounds for axis 0 with size 3
icomxhvb

icomxhvb1#

如果我没理解错你的问题,复选框“正常网络可视化”控制是否绘制边。是这样吗?如果这是你想要做的,你可以在选中复选框时使用你的代码中的边绘制过程:

def while_1(event):
    if(chk_bln[0].get() == True):
        for e in G.edges:
            node0_pos = pos[e[0]]
            node1_pos = pos[e[1]]
            xx = [node0_pos[0], node1_pos[0]]
            yy = [node0_pos[1], node1_pos[1]]
            zz = [node0_pos[2], node1_pos[2]]
            ax.plot(xx, yy, zz, c="#aaaaaa")

若要根据节点的度更改节点的大小,请使用ax.scatter并根据节点的度更改标记的大小:[ax.scatter(pos_ary[i, 0],pos_ary[i, 1],pos_ary[i, 2],s=sizes[i],color='b',alpha=0.5) for i in range(len(pos_ary))]
下面是完整的代码。UI保持不变,仍然可以从GUI中选择文件:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import networkx as nx
import numpy as np
import tkinter as tk
from tkinter import messagebox
import tkinter.filedialog as fd

# Input Window Settings
tki = tk.Tk()  # Tk class generation
tki.geometry('350x300')  # screen size
tki.title('link')  # screen title
# List check button labels
chk_txt = ['Normal network visualization']
chk_bln = {}  #Check box ON/OFF status

# Dynamically create and place check buttons
for i in range(len(chk_txt)):
    chk_bln[i] = tk.BooleanVar()
    chk = tk.Checkbutton(tki,variable=chk_bln[i],text=chk_txt[i]) 
    chk.place(x=50,y=30 + (i * 24))
    
path = fd.askopenfilename()
# Command to exit
def close_window():
    tki.destroy()

# button generation
btn3 = tk.Button(tki,text = '  decision  ')
btn3.place(x = 100 , y = 200)
btn4 = tk.Button(tki,text = 'exit',command = close_window)
btn4.place(x = 150 , y = 250)

# Graph Window Settings
# Generate edge data
with open(path, "r") as tf:
    line = tf.read().split()
ran = int(len(line) / 2)

# Create graphs from generated edge data
G = nx.read_edgelist(path,nodetype=int)
edge_size = nx.number_of_edges(G) # number of edges
node_size = nx.number_of_nodes(G) # number of nodes

# spring_layout algorithm to generate 3D coordinates
pos = nx.spring_layout(G, k = 0.8, dim = 3)
degs = dict(G.degree)
average_deg = sum(d for n,d in G.degree()) / G.number_of_nodes()  #Calculate the average number of hours for the entire network
sizes = [100 * deg * 2 / average_deg for node,deg in G.degree()]  #Sized to be proportional to node order
# Conversion from dictionary type to array type
pos_ary = np.array([pos[n] for n in G])

# visualization
fig = plt.figure()
ax = fig.add_subplot(121, projection="3d")

#Set graph title
ax.set_title("3D graph",size=20)

# Dot the position of each node
[ax.scatter(pos_ary[i, 0],pos_ary[i, 1],pos_ary[i, 2],s=sizes[i],color='b',alpha=0.5) for i in range(len(pos_ary))]

# Display labels on nodes
for n in G.nodes:
    ax.text(*pos[n], n)

# Graph Output
# Button click event (set to checked or unchecked)
def btn_click(bln):
    for i in range(len(chk_bln)):
        chk_bln[i].set(bln)

# How to draw for each event
def while_1(event):
    if(chk_bln[0].get() == True):
        for e in G.edges:
            node0_pos = pos[e[0]]
            node1_pos = pos[e[1]]
            xx = [node0_pos[0], node1_pos[0]]
            yy = [node0_pos[1], node1_pos[1]]
            zz = [node0_pos[2], node1_pos[2]]
            ax.plot(xx, yy, zz, c="k",lw=2)
    #View the resulting diagram
    plt.show()

#Bind function to button
btn3.bind('<Button-1>',while_1)
tk.mainloop()

以下是未选中“正常网络可视化”复选标记时的结果:

如果“正常网络可视化”复选标记打开:

相关问题