news 2026/11/5 16:20:46

集合关系图怎么做到“面积即数量“:从韦恩图到 UpSet 的取舍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
集合关系图怎么做到“面积即数量“:从韦恩图到 UpSet 的取舍

想画一个韦恩图时,真正卡住人的通常不是画圆,而是三个技术问题:手工画的圆面积能不能反映真实数量?集合超过 3 个怎么办?导出到论文或印刷品时字体和矢量怎么处理?

这篇不聊工具怎么挑,只解决这三个问题,顺带给出可以直接跑的代码。

一、先分清两种图,选错方向后面全白做

同样叫"韦恩图",实际是两类东西:

逻辑示意图数据驱动图
圆的面积无关紧要,只是版面代表子集大小
绘制方式手工摆放、调透明度由代码根据数值计算圆心与半径
适用场景会议讨论、方案说明、PPT论文、数据报告、严谨表达
典型工具画布/白板类工具、演示软件matplotlib-venn、eulerr

关键判断:如果读者可能从圆的面积读出数量信息,就必须用第二类。手工画的圆面积是随手的,读者却会当真——这是集合图最常见的误导来源。

反过来说,如果这张图只是讲"职责边界""需求重叠区"这类结构关系,用第一类就够了,硬套数据驱动是自找麻烦。

二、数据驱动的两种实现路径

路径 A:Python +matplotlib-venn

这个库的定位是"area-weighted two- and three-circle venn diagrams",即按面积加权绘制两圆和三圆韦恩图。

两集合,subsets传三元组(Ab, aB, AB),分别对应:只在 A、只在 B、A 与 B 的交集。

frommatplotlib_vennimportvenn2# 只在 A = 10,只在 B = 5,交集 = 3venn2(subsets=(10,5,3),set_labels=('A','B'))

三集合,subsets传七元组(Abc, aBc, ABc, abC, AbC, aBC, ABC),命名规则是"属于该区域的集合用大写,不属于的用小写":

frommatplotlib_vennimportvenn3# 顺序:只在A、只在B、AB交、只在C、AC交、BC交、ABC交venn3(subsets=(1,1,2,1,2,2,3),set_labels=('销售','产品','研发'))

自 0.7 版起,也可以直接把集合对象交给它去算,不必自己统计:

venn2([{'a','b','c','d'},{'d','e','f'}])

必须知道的一条硬限制(官方文档原话):“for a three-circle venn diagram it is not in general possible to achieve exact correspondence between the required set sizes and region areas”——三圆韦恩图在一般情况下无法让七个区域的面积与集合大小精确对应,只能尽量接近。

这不是库的实现问题,是几何约束:三个圆的位置和半径只有有限的自由度,而你要同时满足七个区域面积。数据稍微极端一点(比如某个区域为 0、或某个集合远大于其他),画出来就会明显失真。

如果只想要结构、不在乎面积,用配套的非加权版本venn2_unweighted/venn3_unweighted,它会画出标准等大的圆,至少版面稳定,不会再让读者误读面积。

一个容易踩的坑:某个区域的数量为 0 时,该区域的标注不会显示。这不是 bug,而是那个区域在几何上塌缩成了点或不存在,没有位置放标签。遇到这种情况要么在正文里说明"某区域为空",要么改用 UpSet。

路径 B:R +eulerr

如果对面积准确度要求高,或者集合数是 3~4 个,eulerr是更合适的选择。它的包描述是"Area-Proportional Euler and Venn Diagrams",思路和前面的库不同:用残差平方和(stress)去拟合各区域面积,并且不限于圆,可以用椭圆。

椭圆比圆多出的自由度,正好用来逼近那七个区域的面积约束,所以能明显缓解三集合失真的问题。它还会报告拟合的质量指标,你可以据此判断这张图能不能用来支撑结论——如果 stress 很大,就该老实换图,而不是硬发。

三、超过 3 个集合:换图,不要硬凑

4 个以上的集合,韦恩图的可读性会迅速崩塌(圆与圆的交叠区域太多,且几何上更不可能精确)。相关社区的经验是超过 4 个集合就优先考虑 UpSet 图。

UpSet 图把"集合"和"交集"拆成两个维度:下方矩阵表示这次统计的是哪几个集合的交集,上方柱状图表示该交集的大小。集合再多也不会乱。

Python 侧用upsetplot,它接受两种输入方式:

fromupsetplotimportfrom_memberships,plotfrommatplotlibimportpyplotasplt# 按"每个数据点属于哪些集合"描述,data 给出各组合的数量example=from_memberships([[],['cat2'],['cat1'],['cat1','cat2'],['cat0'],['cat0','cat2'],['cat0','cat1'],['cat0','cat1','cat2']],data=[56,283,1279,5882,24,90,429,1957],)plot(example)plt.show()

如果数据本来就是pandas的布尔列(每列一个集合),可以直接按类别分组后交给它,不必手工整理成员关系。

R 侧的对应实现是ComplexUpset,基于ggplot2,主题和配色能跟着现有图表体系统一。

取舍原则:

  • 集合 ≤ 2 个,且需要精确比例 → 韦恩图(圆能精确表达)
  • 集合 = 3 个,需要精确比例 →eulerr(椭圆拟合)或改 UpSet
  • 集合 = 3 个,只要结构 → 非加权韦恩图
  • 集合 ≥ 4 个 → UpSet,不要犹豫

四、导出与排版:两个高频问题

1. SVG 里的字变成路径,没法再编辑

matplotlib默认把文字转成路径写进 SVG,用 Illustrator 或 Inkscape 打开后无法再改字。如果交付方需要二次编辑,改这个全局设置:

frommatplotlibimportpyplotasplt,rcParams rcParams['svg.fonttype']='none'# 文字以 <text> 形式写入,保留可编辑性

代价是文件在其他机器上打开时依赖字体,缺字体就会替换。稳妥做法是随文件一起交付字体,或同时导出一份 PDF 备案。

2. 中文字体不生效

matplotlib默认字体没有中文字形,会显示为方框。指定字体并关掉负号渲染问题:

rcParams['font.sans-serif']=['Noto Sans CJK SC','Source Han Sans SC','SimHei']rcParams['axes.unicode_minus']=False

用ax参数可以精细控制版式,而不是依赖当前坐标系:

fig,ax=plt.subplots(figsize=(6,5),dpi=200)venn2(subsets=(10,5,3),set_labels=('A','B'),ax=ax)fig.savefig('venn.svg',bbox_inches='tight')

dpi只影响位图导出,SVG/PDF 是矢量、不受影响;如果最终要插入 Word 或公众号,再单独导一份 2x/3x 的透明背景 PNG。

3. 格式怎么选

用途格式理由
论文、印刷、LaTeXPDF / SVG矢量,放大不糊
需要交付方二次编辑SVG(配svg.fonttype='none')文字保留为文本节点
网页、公众号、PPTPNG(2x/3x,透明底)兼容性稳妥
需要现场演示改数据代码与数据一起交付改数字即重出图,避免手工返工

五、避坑清单

  • 不要让面积说谎。手工画的圆面积不代表数量,除非你用代码生成。这比图不好看严重得多。
  • 三集合别迷信精确。几何上做不到就是做不到;eulerr会告诉你拟合质量,matplotlib-venn官方也直接说明了这一点。
  • 每个区域都要有信息。空白区域会让读者怀疑你没想清楚,宁可标注"无重叠"。
  • 颜色优先考虑可读性。用透明度区分交叠,避免红绿并置(色觉障碍不友好),可用边框、纹理或灰度增强区分。
  • 集合多就换图。4 个以上优先 UpSet 或拆成多张局部图。
  • 交付格式与场景匹配。印刷要矢量,屏幕传播要高分辨率位图,两者不能互相替代。

六、小结

集合关系图的核心判断只有一条:这张图的面积要不要承载数量信息。

  • 不承载 → 用画布或演示软件手工排版即可,几十秒的事,重点是版面清楚。
  • 承载 → 交给代码,两集合用圆可以精确表达,三集合要接受"尽量接近",集合再多就换 UpSet。

工具在这里的位置其实很靠后:讨论阶段用画布类工具(例如诺智白板 NuromBoard 这类把白板、流程图、思维导图放在同一张画布上的实现,适合边讨论边改),正式出图无论用 Python 还是 R,最终都要落到代码上才能保证面积可信。


参考资料

  1. matplotlib-venn官方文档与 README(含"三圆精确对应不可行"的说明、venn2/venn3参数定义)
  2. upsetplot官方文档:from_memberships与plot用法
  3. CRANeulerr包:Area-Proportional Euler and Venn Diagrams
  4. CRANComplexUpset包:基于ggplot2的 UpSet 实现
  5. Lex et al.,UpSet: Visualization of Intersecting Sets, IEEE TVCG 2014

说明:以上均为开源项目官方文档与论文,核对时间 2026 年 10 月。本文为个人实践记录,未接受任何形式的赞助;库的 API 与默认行为随版本变化,请以实际安装版本的文档为准。

附:文中涉及的项目与工具

名称性质文中出现位置
matplotlib-venn开源(Python)§二、§四
eulerr开源(R,CRAN)§二
upsetplot开源(Python,BSD-3)§三
ComplexUpset开源(R,CRAN)§三
诺智白板(NuromBoard)商业 SaaS§六
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 8:37:39

CSDN 多平台同步助手:一键分发,排版无损,安全高效

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 11:25:54

基于Python的电影受众群体特征分析与可视化实战

提到“基于Python的电影受众群体特征研究”这个毕设题目&#xff0c;很多准备开题的同学第一个反应是&#xff1a;这方向是不是太普通了&#xff1f;我自己的看法是&#xff0c;普通题目更容易做出完整度和深度。它把Python数据处理、统计分析、可视化、机器学习串成了一条完整…

作者头像 李华
网站建设 2026/10/29 3:03:44

我们在联想 ThinkStation PGX 上搭了一个“AI 编辑部“

在输入框里只敲了五个字&#xff1a;“本周的选题”&#xff0c;随后&#xff0c;屏幕上的工具调用记录一行行滚过&#xff1a;分析账号定位、生成检索条件、搜索近期内容、排出候选题。我们选定一个&#xff0c;它又去补资料、搭大纲、写初稿……这不是一次简单的模型问答&…

作者头像 李华
网站建设 2026/10/30 12:52:38

【计算机毕业设计单片机案例】基于STM32的婴儿监护环境调节与摇篮哄睡系统设计 基于物联网的智能婴儿床环境调节与生理状态监测装置设计(032707)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/10/24 4:42:59

Unity帧同步技术原理与商业实战:从确定性到落地避坑

Unity程序员想进阶&#xff0c;迟早会碰到一个绕不开的硬核话题&#xff1a;帧同步。尤其是做过MOBA、RTS、格斗类联网游戏&#xff0c;或者想尝试多人同屏竞技玩法的人&#xff0c;最终都会意识到&#xff0c;自己缺的不是战斗系统的设计能力&#xff0c;而是对帧同步技术原理…

作者头像 李华