networkx - 根据列表或字典值改变节点大小

12 投票
2 回答
27345 浏览
提问于 2025-04-18 12:30

我正在尝试用networkx制作一个图形,但在给节点设置不同大小时遇到了麻烦。

这是我一直在尝试的代码:

import sys
from collections import defaultdict
import networkx as nx
import matplotlib.pyplot as plt

inp = sys.argv[1]
cluster = sys.argv[1] + ".cluster"
counts = sys.argv[1] + ".counts"

with open(cluster, "r") as f1:
        edges = [line.strip().split('\t') for line in f1]

with open(counts, "r") as f2:
        countsdic = defaultdict(list)
        for line in f2:
                k,v = line.strip().split()
                countsdic[k].append(v)

tmp = []

for el in sum(edges, []):
        tmp.append(el)

nodes = []

for t in tmp:
        if t not in nodes:
                nodes.append(t)

node_sizes = {}
for n in nodes:
        node_sizes[n] = ' '.join(countsdic[n])
print node_sizes

nodes2 = []
sizes = []
for k in node_sizes.keys():
        nodes2.append(k)
for v in node_sizes.values():
        sizes.append(v)
print nodes2
print len(nodes2)
print sizes
print len(sizes)
g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)

nx.draw_random(g, node_list = nodes2, node_size = sizes)

# I've also tried assigning node_list and node_size with node_sizes.keys() and node_sizes.values()

plt.savefig(inp + "." + gtype + ".png")
plt.show()

如果我不去改变节点的大小,图形看起来还不错。我的字典值在1到10之间,还有一些比较大的值,比如156,我希望这个值能是最大的。所以我需要做一些调整,比如:node_sizes = [n*100 for n in sizes],这样小的值至少能在图上显示出来,而大的值也能显得重要,但这样做也没有成功。

我遇到的错误是:

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1489, in __call__
    return self.func(*args)
  File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 276, in resize
    self.show()
  File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 348, in draw
    FigureCanvasAgg.draw(self)
  File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_agg.py", line 451, in draw
    self.figure.draw(self.renderer)
  File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/figure.py", line 1034, in draw
    func(*args)
  File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/axes.py", line 2086, in draw
    a.draw(renderer)
  File "/usr/lib/pymodules/python2.7/matplotlib/artist.py", line 55, in draw_wrapper
    draw(artist, renderer, *args, **kwargs)
  File "/usr/lib/pymodules/python2.7/matplotlib/collections.py", line 717, in draw
    for x in self._sizes]
TypeError: Not implemented for this type

经过几个小时的谷歌搜索,我还是没能解决这个问题。下面是没有改变节点大小生成的图:

一个示例图,所有节点大小相同。(需要所有节点根据值的大小来调整)

欢迎大家提供意见和帮助。

2 个回答

4

根据mdml的回答,我终于解决了这个问题。原来我给networkx传递了一个列表来设置节点的大小,但它不喜欢这个列表。我把字符串加到了列表里,而不是整数。把v改成int()就解决了这个问题,然后我把它乘以100,因为有些值太小了,这样节点的大小才更合适:

with open(cluster, "r") as f1:
     edges = [line.strip().split('\t') for line in f1]

with open(counts, "r") as f2:
     countsdic = defaultdict(list)
     for line in f2:
         k,v = line.strip().split()
         countsdic[k].append(v)

tmp = []

for el in sum(edges, []):
    tmp.append(el)

nodes = []

for t in tmp:
    if t not in nodes:
        nodes.append(t)

node_sizes = {}
for n in nodes:
    node_sizes[n] = ' '.join(countsdic[n])

sizes = []
for v in node_sizes.values():
    x = int(v) * 100
    sizes.append(x)

g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)

nx.draw_random(g, node_size = sizes)

plt.savefig(inp + "." + gtype + ".png")
plt.show()

这是我想要的图形输出:

enter image description here

19

2014年7月8日 12:29PM: 根据@user3358205的评论进行了更新

问题在于,NetworkX中的绘图函数需要你输入的node_sizes是一个包含整数的list,而你传入的是一个字符串的list。你可以在这里查看绘图函数的参数

因为我没有你程序的输入文件,所以无法复现你的输出。不过,这里有一个例子,展示了如何通过传递一个node_sizeslist来改变节点的大小。注意在输出中,我用节点的大小给每个节点打了标签。

import sys, networkx as nx, matplotlib.pyplot as plt

# Create a list of 10 nodes numbered [0, 9]
nodes = range(10)
node_sizes = []
labels = {}
for n in nodes:
        node_sizes.append( 100 * n )
        labels[n] = 100 * n

# Node sizes: [0, 100, 200, 300, 400, 500, 600, 700, 800, 900]

# Connect each node to its successor
edges = [ (i, i+1) for i in range(len(nodes)-1) ]

# Create the graph and draw it with the node labels
g = nx.Graph()
g.add_nodes_from(nodes)
g.add_edges_from(edges)

nx.draw_random(g, node_size = node_sizes, labels=labels, with_labels=True)    
plt.show()

示例图

撰写回答