Python 3套以上的比例维恩图
我在MongoDB中有一个文档集合,每个文档在列表中都有一个或多个类别。使用map reduce,我可以获得每个类别的唯一组合包含多少文档的详细信息:Python 3套以上的比例维恩图,python,matlab,plot,matplotlib,Python,Matlab,Plot,Matplotlib,我在MongoDB中有一个文档集合,每个文档在列表中都有一个或多个类别。使用map reduce,我可以获得每个类别的唯一组合包含多少文档的详细信息: ['cat1'] = 523 ['cat2'] = 231 ['cat3'] = 102 ['cat4'] = 72 ['cat1','cat2'] = 710 ['cat1','cat3'] = 891 [
['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来做这件事。一般来说,这是不可能的,除非大致上,交点图是a,并且没有四向交点。边缘长度也有限制(除非您愿意绘制无定形斑点来表示区域);因此,如果你坚持画圆圈,这甚至会受到限制 在非常简单的情况下,您可以制作一个例程来绘制一个三向维恩图,然后在三元组的“另一侧”上“添加”另一个圆。在上述情况下,
1,3,4
是该三元组,2
是奇数
如果可能是因为数据满足上述条件(由于某些原因,图形是平面的,非常复杂),并且您使用的是无定形斑点,那么您可以绘制平面图形,并缓慢地将每条边“气球状”增长为椭球体。你可以用一种放松的方式来做这件事:如果它们的交点低于它们应该的值,它们就会膨胀;如果它们的交点高于它们应该的值,它们就会收缩。(他们实际上有两个维度来做这件事:育肥和拉长;根据需要选择。拉长将推动图表的其余部分,因此您必须检查这不会使事情变得不可能,例如使用基于弹簧的物理布局。)最终您可能会找到一个答案,您必须检查其准确性。请参阅
不过,我不知道你会如何按比例缩放面积
也许如果你拿一张顺序合适的图表,把它镶嵌起来。然后你可以为每个三角形指定所需的区域,并进行某种压力扩散,允许顶点移动,可能允许一些压力“泄漏”从每个三角形到属于同一集合的相邻三角形?您可能想尝试一下,但我也在MatPlotLib上找到了它,但我认为它没有被正式接受。我认为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()
问题
我们需要表示多个相互关联的对象类别的计数,而维恩图只能表示少量的类别及其重叠
解决办法
将每个类别及其组合视为图中的一个节点。绘制图形,使节点的大小表示每个类别中的计数,边连接相关类别。这种方法的优点是:可以轻松容纳多个类别,这将成为一种连接气泡图
结果
代码
建议的解决方案使用创建数据结构并绘制它。如果数据以正确的格式显示,这将扩展到具有多个连接的大量类别
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()
其他解决方案
其他解决方案可能包括:、等。所有链接的示例都没有使用Python;它们只是为了说明的目的而给出的。对Gauden的答案进行修改怎么样?每个类别都是一个节点,节点之间的加权边表示重叠程度。重叠越多,边缘越厚。鉴于维恩图无法做到这一点(见下面ninjagecko的评论),而且由于有人提出了替代方案(见fraxel创意),我想我自己也会尝试一种替代方案,一种网络图。感谢大家提出的所有伟大创意和替代方案。我认为gauden的这个网络图想法最适合我的需要。