我有两个节点之间的连接列表,描述数据集中条目的相似性。
我正在考虑对条目及其连接进行可视化,以显示存在非常相似的条目的集群。
每个元组代表一对非常相似的节点。我为所有这些选择了权重为 1,因为这是必需的,但我希望所有边缘都一样厚。
我已经从
networkx
开始,问题是我现在不知道如何以有用的方式将相似的节点聚集在一起。
我有数据框中的连接列表:
smallSample =
[[0, 1492, 1],
[12, 937, 1],
[16, 989, 1],
[18, 371, 1],
[18, 1140, 1],
[26, 398, 1],
[26, 1061, 1],
[30, 1823, 1],
[33, 1637, 1],
[54, 1047, 1],
[63, 565, 1]]
我通过以下方式创建图表:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
for index, row in CC.iterrows():
G.add_edge(CC['source'].loc[index],CC['target'].loc[index], weight =1)
pos = nx.spring_layout(G, seed=7)
nx.draw_networkx_nodes(G, pos, node_size=5)
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), width=0.5)
pos = nx.spring_layout(G, k=1, iterations=200)
plt.figure(3, figsize=(2000,2000), dpi =2)
使用上面提供的小样本,结果如下所示:
我的真实 df 结果由数千个点组成:
如何将链接的节点分组在一起,以便更好地看到每个集群中有多少个节点?我不想让它们重叠得那么厉害,要掌握在大样本中到底有多少个真的不是那么容易。
如果您坚持使用networkx图来可视化您的数据,您可以定义相对于连接组件的[x,y]坐标,以更好地可视化图。一个例子可能是
Gcc=sorted(nx.connected_components(G), key=len, reverse=True)
cclens=[len(c) for c in Gcc]
pos_comp={ni:np.array([np.log(xi+1), yi])
for yi in range(len(cclens))
for (xi, ni) in enumerate(Gcc[yi]) }
nx.draw_networkx_nodes(G, pos_comp, node_size=10, alpha=0.45, linewidths=0.2)
nx.draw_networkx_edges(G, pos_comp, edgelist=G.edges(), width=0.5, alpha=0.1)
plt.title("Component length ordered")
plt.xlabel('Node ID')
plt.ylabel('Group ID')
从 InfoVis 的角度来看,您可以做一些事情
k
参数来设置 nx.spring_layout
,它越大,节点距离越远。默认为 1/sqrt(len(G))
稍微增加 [1.2-1.7]/sqrt(len(G))
可以让您更加清晰。最后但并非最不重要的一点是,我建议您使用抖动,稍微打乱节点的位置并减少重叠(有很多关于抖动的论文和一些比我在这里选择的统一更好的版本,但它是最简单的实现。 )
此代码创建了一个类似的数据集
import random
import numpy as np
import pandas as pd
from copy import deepcopy
import networkx as nx
import matplotlib.pyplot as plt
from math import sqrt
random.seed(7)
np.random.seed(7)
# Create a bigger dataset
smallSample = [
[0, 1492, 1],
[12, 937, 1],
[16, 989, 1],
[18, 371, 1],
[18, 1140, 1],
[26, 398, 1],
[26, 1061, 1],
[30, 1823, 1],
[33, 1637, 1],
[54, 1047, 1],
[63, 565, 1]]
sample = deepcopy(smallSample)
AMOUT = 4000
present_nodes = list(set(x for edge in sample for x in edge))
i = 2
while i < AMOUT:
source = target = None
while source == target:
if random.random() < 0.9:
# Create at least one new node
source = i
if random.random() < 0.7: # High value for many small clusters
# Create a second new node
target = i = i+1
present_nodes.append(target)
else:
target = random.choice(present_nodes)
present_nodes.append(source)
else: # Link existing ones
source = random.choice(present_nodes)
target = random.choice(present_nodes)
i += 1
sample.append([source, target, 1])
CC = pd.DataFrame(sample, columns=["source", "target", "weight"], dtype=int)
# Create the Graph
G = nx.Graph()
for index, row in CC.iterrows():
G.add_edge(CC['source'].loc[index],CC['target'].loc[index], weight =1)
计算仓位
# Defaul k = 1/sqrt(len(G))
pos = nx.spring_layout(G, k=1/sqrt(len(G)), seed=7, iterations=100)
# cast the pos dict to an np.array
apos = np.fromiter(pos.values(), dtype=np.dtype((float, 2)))
默认外观
nx.draw_networkx_nodes(G, pos, node_size=10, alpha=0.45, linewidths=0.2)
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), width=0.5, alpha=0.2)
plt.title("Transparency")
plt.figure(3, figsize=(2000,2000), dpi =2)
这增加了节点之间的距离并减少了结块
pos15 = nx.spring_layout(G, k=1.5/sqrt(len(G)), seed=7, iterations=100) # Larger k to make it less clumpy
# cast the pos dict to an np.array
apos15 = np.fromiter(pos15.values(), dtype=np.dtype((float, 2)))
nx.draw_networkx_nodes(G, pos15, node_size=10, alpha=0.55, linewidths=0.2)
nx.draw_networkx_edges(G, pos15, edgelist=G.edges(), width=0.5, alpha=0.2)
plt.title("Larger k")
plt.figure(3, figsize=(2000,2000), dpi =2)
JITTER = 0.025
jitter = np.random.uniform(low=-JITTER, high=JITTER, size=apos.shape)
jpos = {k:p for k,p in zip(pos.keys(), apos + jitter)}
jpos15 = {k:p for k,p in zip(pos15.keys(), apos15 + jitter)}
nx.draw_networkx_nodes(G, jpos, node_size=10, alpha=0.45, linewidths=0.2)
nx.draw_networkx_edges(G, jpos, edgelist=G.edges(), width=0.5, alpha=0.2)
plt.title("default + jitter")
plt.figure(3, figsize=(2000,2000), dpi =2)
plt.show()
nx.draw_networkx_nodes(G, jpos15, node_size=10, alpha=0.55, linewidths=0.2) # As nodes overlapp less I would increase the alpha level a bit
nx.draw_networkx_edges(G, jpos15, edgelist=G.edges(), width=0.5, alpha=0.2)
plt.title("larger k + jitter")
plt.figure(3, figsize=(2000,2000), dpi =2)
最后,需要调整一下参数来选择你喜欢的东西。
我曾经使用 networkx + 导出
gml
文件来制作这些图表,以解决您使用名为 Cytoscape 的免费软件所询问的问题。它有一堆不同的可视化设置,可以很好地组织节点/边。
使用
nx.write_gml(G, "your_filename.gml")
输出到文件。然后,您可以将该文件导入 Cytoscape 并使用自动布局使节点很好地组织起来。我真的很喜欢Prefuse Force Directed Layout
。然后将最终结果导出到图像以便在您需要的地方使用。
它有点笨重,不是一个编程解决方案,所以如果您需要重复创建这些图表,则无法工作,但我发现这样做可以产生最好看的最终结果。