我在MongoDB中有一组文档,每个文档在列表中都有一个或多个类别。使用map reduce,我可以获得每个独特的类别组合有多少文档的详细信息:
['cat1'] = 523
['cat2'] = 231
['cat3'] = 102
['cat4'] = 72
['cat1','cat2'] = 710
['cat1','cat3'] = 891
['cat1','cat3','cat4'] = 621 ...
其中总数是针对精确组合类别的文档数量。
我正在寻找一种合理的方式来呈现这些数据,我认为具有比例区域的维恩图是个好主意。使用上面的例子,区域cat1将是523 + 710 + 891 + 621,cat1和cat3之间的重叠区域将是891 + 621,cat1,cat3,cat4之间的重叠区域将是621等。
有没有人对我如何实施这个有任何提示?我最好喜欢用Python(+ Numpy / MatPlotLib)或MatLab来做。
答案 0 :(得分:10)
我们需要表示多个互连的对象类别的计数,而维恩图表不能代表一些微不足道的类别及其重叠。
将每个类别及其组合视为图表中的节点。绘制图形,使节点的大小代表每个类别中的计数,边缘连接相关的类别。这种方法的优点是:可以轻松容纳多个类别,这成为一种连接的气泡图。
建议的解决方案使用NetworkX创建数据结构,使用matplotlib绘制数据结构。如果数据以正确的格式显示,则会扩展为具有多个连接的大量类别。
import networkx as nx
import matplotlib.pyplot as plt
def load_nodes():
text = ''' Node Size
1 523
2 231
3 102
4 72
1+2 710
1+3 891
1+3+4 621'''
# load nodes into list, discard header
# this may be replaced by some appropriate output
# from your program
data = text.split('\n')[1:]
data = [ d.split() for d in data ]
data = [ tuple([ d[0],
dict( size=int(d[1]) )
]) for d in data]
return data
def load_edges():
text = ''' From To
1+2 1
1+2 2
1+3 1
1+3 3
1+3+4 1
1+3+4 3
1+3+4 4'''
# load edges into list, discard header
# this may be replaced by some appropriate output
# from your program
data = text.split('\n')[1:]
data = [ tuple( d.split() ) for d in data ]
return data
if __name__ == '__main__':
scale_factor = 5
G = nx.Graph()
nodes = load_nodes()
node_sizes = [ n[1]['size']*scale_factor
for n in nodes ]
edges = load_edges()
G.add_edges_from( edges )
nx.draw_networkx(G,
pos=nx.spring_layout(G),
node_size = node_sizes)
plt.axis('off')
plt.show()
其他解决方案可能包括:bubble charts,Voronoi diagrams,chord diagrams和hive plots等。所有链接的示例都不使用Python;它们仅用于说明目的。
答案 1 :(得分:5)
我相信ninjagecko是正确的,这通常不能表示为交叉图,除非你不介意图是n维。但是,如果每个类别都有一个显示其所有交叉点的图表,它可以用2D表示 - 这本身可以是单个图表。因此,这可能是表示数据的更合适的方式。我制作了一个堆叠的条形图来说明:
代码:
cats = ['cat1','cat2','cat3','cat4']
data = {('cat1',): 523, ('cat2',): 231, ('cat3',): 102, ('cat4',): 72, ('cat1','cat2'): 710,('cat1','cat3'): 891,('cat1','cat3','cat4') : 621}
import matplotlib.pyplot as plt
import numpy as np
from random import random
colors = dict([(k,(random(),random(),random())) for k in data.keys()])
print colors
for i, cat in enumerate(sorted(cats)):
y = 0
for key, val in data.items():
if cat in key:
plt.bar(i, val, bottom=y, color=colors[key])
plt.text(i,y,' '.join(key))
y += val
plt.xticks(np.arange(len(cats))+0.4, cats )
plt.show()
答案 2 :(得分:4)
这通常不可能,除非粗略地说,交叉图是planar graph AND 你没有4路交叉点。边长也有限制(除非您愿意绘制无定形斑点来表示区域);因此,如果你坚持画圈,这甚至可以更多限制。
在非常简单的情况下,您可以制作一个例程来绘制三维维恩图,然后在三联体的“另一侧”“添加”另一个圆圈。在上述情况下,1,3,4
就是那个三元组,而2
是奇数一个。
如果 是可能的,因为您的数据满足上述条件(由于某种原因,您的图形是平面且极其复杂), AND 您使用无定形blob,您可以绘制平面图,慢慢地使每个边缘“膨胀”成椭圆体。你可以放松的方式做到这一点:如果他们的交叉点低于他们应该的交叉点,它们就会升起,如果它们的交叉点高于应该的交叉点,它们会收缩。 (它们实际上有2个尺寸来执行此操作:肥育和拉长;适当选择。伸长将推动图表的其余部分,因此您必须检查这不会使事情变得不可能,例如通过使用基于物理弹簧的物理布局。)最终你可能会收到一个答案,你必须检查它的准确性。
答案 3 :(得分:2)
Gauden的答案如何变化?每个类别都是一个节点,节点之间的加权边表示度重叠。重叠越多,边缘越厚。
答案 4 :(得分:1)
请参阅some examples of higher-order diagrams。
我不知道如何缩放比例区域。
也许如果您拍摄了相应订单的图表并对其进行了详细说明。那么你可以为每个三角形分配所需的区域并进行某种压力扩散,允许顶点移动并允许一些压力从每个三角形“泄漏”到属于同一组的邻居?
答案 5 :(得分:1)
您可能想尝试https://github.com/icetime/pyinfor/blob/master/venn.py,但我也在MatPlotLib上找到它https://github.com/icetime/matplotlib/blob/master/lib/matplotlib/venn.py,但我不认为它已被正式接受。