[python] 圆形嵌套图Circular Packing
圆形嵌套图Circular Packing
文章目录
圆形嵌套图Circular Packing能够将一组组圆形互相嵌套起来,以显示数据的层次关系。本文主要基于circlify实现圆形嵌套图的绘制。circlify包由Python实现。官方开源地址见:
circlify
您可以使用以下代码安装circlify:
pip install circlify
本文主要参考circlify和circular-packing
1 具有一级层次的圆形嵌套图绘制
circlify可以在没有层次结构的情况下工作,即只有一组数字变量,将每个变量都将显示为圆形。请注意,该包仅计算每个圆形的位置和大小。完成后,matplotlib用于制作图表本身。此外circlify库也提供了一个bubbles()函数完成所有绘图的功能。但它没有提供很多定制,所以matplotlib在这里是一个更好的绘图选择。
1.1 绘图数据与circlify计算
基于一级层次结构的基本圆形嵌套图只需要两列数据框。第一列提供每个项目的名称(用于标记)。第二列提供项目的数值。它控制圆形大小。
import pandas as pd
df = pd.DataFrame({
'Name': ['A', 'B', 'C', 'D', 'E', 'F'],
'Value': [10, 2, 23, 87, 12, 65]
})
df
Name | Value | |
---|---|---|
0 | A | 10 |
1 | B | 2 |
2 | C | 23 |
3 | D | 87 |
4 | E | 12 |
5 | F | 65 |
在具有一级层次结构的基本圆形嵌套图中,数据集的每个实体都由一个圆圈表示。圆圈大小与其代表的值成正比。工作中最难的部分是计算每个圆的位置和大小。幸运的是,该circlify库提供了一个circlify()进行计算的函数。它将作为绘图输入。
计算函数输入参数如下:
- data :(必需)从大到小排序的正值列表
- show_enclosure :(可选)一个布尔值,指示是否在所有圆之外添加一个最小包围圆(默认为 False)
- target_enclosure :(可选)最小包围圆的参数信息(默认为单位圆 (0, 0, 1))
# import the circlify library
# 导入库
import circlify
# compute circle positions:
# 计算圆的位置
# circle是一个列表
circles = circlify.circlify(
df['Value'].tolist(),
show_enclosure=False,
target_enclosure=circlify.Circle(x=0, y=0, r=1)
)
# 输出要绘制其中一个圆形信息,x,y为圆心坐标,level为绘制等级
circles[0]
Circle(x=-0.44578608966292743, y=0.537367020215489, r=0.08132507760370634, level=1, ex={'datum': 2})
1.2 图形绘制
1.2.1 基础图形绘制
通过circlify计算数据后,基础的圆形嵌套图绘制如下所示。
# import libraries
import circlify
import matplotlib.pyplot as plt
# Create just a figure and only one subplot
# 设置图像尺寸
fig, ax = plt.subplots(figsize=(7,7))
# Remove axes
# 设置matplotlib不显示坐标轴
ax.axis('off')
# Find axis boundaries
# 查找轴边界
lim = max(
max(
abs(circle.x) + circle.r,
abs(circle.y) + circle.r,
)
for circle in circles
)
plt.xlim(-lim, lim)
plt.ylim(-lim, lim)
# print circles
# 画圆
for circle in circles:
x, y, r = circle
# fill表示不填充圆
ax.add_patch(plt.Circle((x, y), r, alpha=0.2, linewidth=2, fill=False))
1.2.2 视觉调整
让我们从这里做一些更漂亮、更有洞察力的事情。我们将添加一个标题,给圆形着色并添加标签:
# import libraries
import circlify
import matplotlib.pyplot as plt
# Create just a figure and only one subplot
fig, ax = plt.subplots(figsize=(10,10))
# Title
# 添加标题
ax.set_title('Basic circular packing')
# Remove axes
ax.axis('off')
# Find axis boundaries
lim = max(
max(
abs(circle.x) + circle.r,
abs(circle.y) + circle.r,
)
for circle in circles
)
plt.xlim(-lim, lim)
plt.ylim(-lim, lim)
# list of labels
# 添加标签
labels = df['Name']
# print circles
for circle, label in zip(circles, labels):
x, y, r = circle
ax.add_patch(plt.Circle((x, y), r, alpha=0.2, linewidth=2))
# 添加标签
plt.annotate(
label,
(x,y ) ,
va='center',
ha='center'
)
1.2.3 圆形之间的空间设置
可以轻松地在圆形之间添加间距。只需要提供半径参数的百分比给add_patch()(此处为70%)。
# Create just a figure and only one subplot
fig, ax = plt.subplots(figsize=(10,10))
# Title
ax.set_title('Basic circular packing')
# Remove axes
ax.axis('off')
# Find axis boundaries
lim = max(
max(
abs(circle.x) + circle.r,
abs(circle.y) + circle.r,
)
for circle in circles
)
plt.xlim(-lim, lim)
plt.ylim(-lim, lim)
# list of labels
labels = df['Name']
# print circles
for circle, label in zip(circles, labels):
x, y, r = circle
# facecolor设置圆的填充颜色,edgecolor设置边框颜色
ax.add_patch(plt.Circle((x, y), r*0.7, alpha=0.9, linewidth=2, facecolor="#69b2a3", edgecolor="black"))
# boxstyle设置边框形状,pad设置边框填充
plt.annotate(label, (x,y ) ,va='center', ha='center', bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=.5))
2 具有多级层次的圆形嵌套图绘制
下面将解释如何构建具有多个层次结构的圆形嵌套图。它使用circlify库来计算圆形位置,并通过matplotlib用于渲染图形。
2.1 绘图数据与circlify计算
此示例考虑分层数据集。世界被大陆分割。大陆按国家划分。每个国家都有一个值(人口规模)。我们的目标是将每个国家表示为一个圆圈,其大小与其人口成正比。让我们创建这样一个数据集:
data = [{'id': 'World', 'datum': 6964195249, 'children' : [
{'id' : "North America", 'datum': 450448697,
'children' : [
{'id' : "United States", 'datum' : 308865000},
{'id' : "Mexico", 'datum' : 107550697},
{'id' : "Canada", 'datum' : 34033000}
]},
{'id' : "South America", 'datum' : 278095425,
'children' : [
{'id' : "Brazil", 'datum' : 192612000},
{'id' : "Colombia", 'datum' : 45349000},
{'id' : "Argentina", 'datum' : 40134425}
]},
{'id' : "Europe", 'datum' : 209246682,
'children' : [
{'id' : "Germany", 'datum' : 81757600},
{'id' : "France", 'datum' : 65447374},
{'id' : "United Kingdom", 'datum' : 62041708}
]},
{'id' : "Africa", 'datum' : 311929000,
'children' : [
{'id' : "Nigeria", 'datum' : 154729000},
{'id' : "Ethiopia", 'datum' : 79221000},
{'id' : "Egypt", 'datum' : 77979000}
]},
{'id' : "Asia", 'datum' : 2745929500,
'children' : [
{'id' : "China", 'datum' : 1336335000},
{'id' : "India", 'datum' : 1178225000},
{'id' : "Indonesia", 'datum' : 231369500}
]}
]}]
data
[{'id': 'World',
'datum': 6964195249,
'children': [{'id': 'North America',
'datum': 450448697,
'children': [{'id': 'United States', 'datum': 308865000},
{'id': 'Mexico', 'datum': 107550697},
{'id': 'Canada', 'datum': 34033000}]},
{'id': 'South America',
'datum': 278095425,
'children': [{'id': 'Brazil', 'datum': 192612000},
{'id': 'Colombia', 'datum': 45349000},
{'id': 'Argentina', 'datum': 40134425}]},
{'id': 'Europe',
'datum': 209246682,
'children': [{'id': 'Germany', 'datum': 81757600},
{'id': 'France', 'datum': 65447374},
{'id': 'United Kingdom', 'datum': 62041708}]},
{'id': 'Africa',
'datum': 311929000,
'children': [{'id': 'Nigeria', 'datum': 154729000},
{'id': 'Ethiopia', 'datum': 79221000},
{'id': 'Egypt', 'datum': 77979000}]},
{'id': 'Asia',
'datum': 2745929500,
'children': [{'id': 'China', 'datum': 1336335000},
{'id': 'India', 'datum': 1178225000},
{'id': 'Indonesia', 'datum': 231369500}]}]}]
然后我们需要用circlify()来计算表示每个国家和大陆圆形的位置,以及它们的半径。
# import the circlify library
import circlify
# Compute circle positions thanks to the circlify() function
# 计算
circles = circlify.circlify(
data,
show_enclosure=False,
target_enclosure=circlify.Circle(x=0, y=0, r=1)
)
circles
[Circle(x=0.0, y=0.0, r=1.0, level=1, ex={'id': 'World', 'datum': 6964195249, 'children': [{'id': 'North America', 'datum': 450448697, 'children': [{'id': 'United States', 'datum': 308865000}, {'id': 'Mexico', 'datum': 107550697}, {'id': 'Canada', 'datum': 34033000}]}, {'id': 'South America', 'datum': 278095425, 'children': [{'id': 'Brazil', 'datum': 192612000}, {'id': 'Colombia', 'datum': 45349000}, {'id': 'Argentina', 'datum': 40134425}]}, {'id': 'Europe', 'datum': 209246682, 'children': [{'id': 'Germany', 'datum': 81757600}, {'id': 'France', 'datum': 65447374}, {'id': 'United Kingdom', 'datum': 62041708}]}, {'id': 'Africa', 'datum': 311929000, 'children': [{'id': 'Nigeria', 'datum': 154729000}, {'id': 'Ethiopia', 'datum': 79221000}, {'id': 'Egypt', 'datum': 77979000}]}, {'id': 'Asia', 'datum': 2745929500, 'children': [{'id': 'China', 'datum': 1336335000}, {'id': 'India', 'datum': 1178225000}, {'id': 'Indonesia', 'datum': 231369500}]}]}),
Circle(x=-0.1891573044970616, y=0.7725949609994359, r=0.1964724487306323, level=2, ex={'id': 'Europe', 'datum': 209246682, 'children': [{'id': 'Germany', 'datum': 81757600}, {'id': 'France', 'datum': 65447374}, {'id': 'United Kingdom', 'datum': 62041708}]}),
Circle(x=-0.5193811141243917, y=-0.4774793174718824, r=0.22650056519090414, level=2, ex={'id': 'South America', 'datum': 278095425, 'children': [{'id': 'Brazil', 'datum': 192612000}, {'id': 'Colombia', 'datum': 45349000}, {'id': 'Argentina', 'datum': 40134425}]}),
Circle(x=-0.5250482991363239, y=0.4940564718994228, r=0.23988342689140008, level=2, ex={'id': 'Africa', 'datum': 311929000, 'children': [{'id': 'Nigeria', 'datum': 154729000}, {'id': 'Ethiopia', 'datum': 79221000}, {'id': 'Egypt', 'datum': 77979000}]}),
Circle(x=-0.7117329289789401, y=0.0, r=0.28826707102105975, level=2, ex={'id': 'North America', 'datum': 450448697, 'children': [{'id': 'United States', 'datum': 308865000}, {'id': 'Mexico', 'datum': 107550697}, {'id': 'Canada', 'datum': 34033000}]}),
Circle(x=0.28826707102105975, y=0.0, r=0.7117329289789401, level=2, ex={'id': 'Asia', 'datum': 2745929500, 'children': [{'id': 'China', 'datum': 1336335000}, {'id': 'India', 'datum': 1178225000}, {'id': 'Indonesia', 'datum': 231369500}]}),
Circle(x=-0.8015572298502232, y=0.13991165332617728, r=0.06017798041665636, level=3, ex={'id': 'Canada', 'datum': 34033000}),
Circle(x=-0.6218965087862706, y=-0.35827194898537407, r=0.06927524011838612, level=3, ex={'id': 'Argentina', 'datum': 40134425}),
Circle(x=-0.6715240632168605, y=-0.49229197511777817, r=0.07363823567480635, level=3, ex={'id': 'Colombia', 'datum': 45349000}),
Circle(x=-0.20484950837730978, y=0.8820383650518233, r=0.08590977893113161, level=3, ex={'id': 'United Kingdom', 'datum': 62041708}),
Circle(x=-0.2883116431566897, y=0.7291956444670085, r=0.08823620918716854, level=3, ex={'id': 'France', 'datum': 65447374}),
Circle(x=-0.5807524341097545, y=0.6266527390697123, r=0.09606159016055799, level=3, ex={'id': 'Egypt', 'datum': 77979000}),
Circle(x=-0.6616477217438194, y=0.4515509451194898, r=0.09682357206293761, level=3, ex={'id': 'Ethiopia', 'datum': 79221000}),
Circle(x=-0.10145547990466931, y=0.7291956444670085, r=0.09861995406485186, level=3, ex={'id': 'Germany', 'datum': 81757600}),
Circle(x=-0.8930220906231182, y=0.0, r=0.1069779093768817, level=3, ex={'id': 'Mexico', 'datum': 107550697}),
Circle(x=-0.42950888228212775, y=0.4515509451194898, r=0.13531526739875396, level=3, ex={'id': 'Nigeria', 'datum': 154729000}),
Circle(x=-0.44612447532083954, y=-0.49229197511777817, r=0.15176135222121462, level=3, ex={'id': 'Brazil', 'datum': 192612000}),
Circle(x=0.2610622289123354, y=0.3631857971321717, r=0.15273517341003195, level=3, ex={'id': 'Indonesia', 'datum': 231369500}),
Circle(x=-0.6047550196020585, y=0.0, r=0.18128916164417805, level=3, ex={'id': 'United States', 'datum': 308865000}),
Circle(x=-0.07879852383709784, y=0.0, r=0.34466733412078254, level=3, ex={'id': 'India', 'datum': 1178225000}),
Circle(x=0.6329344051418423, y=0.0, r=0.3670655948581576, level=3, ex={'id': 'China', 'datum': 1336335000})]
2.2 图形绘制
# import libraries
import circlify
import matplotlib.pyplot as plt
# Create just a figure and only one subplot
fig, ax = plt.subplots(figsize=(14,14))
# Title
ax.set_title('Repartition of the world population')
# Remove axes
ax.axis('off')
# Find axis boundaries
lim = max(
max(
abs(circle.x) + circle.r,
abs(circle.y) + circle.r,
)
for circle in circles
)
plt.xlim(-lim, lim)
plt.ylim(-lim, lim)
# Print circle the highest level (continents):
# 打印最高级别的圆形也就是数据中的大陆,这一部分circle的level为3
for circle in circles:
if circle.level != 2:
continue
x, y, r = circle
ax.add_patch( plt.Circle((x, y), r, alpha=0.5, linewidth=2, color="lightblue"))
# 打印次高级别的圆形也就是数据中的国家,这一部分circle的level为2
for circle in circles:
if circle.level != 3:
continue
x, y, r = circle
label = circle.ex["id"]
ax.add_patch( plt.Circle((x, y), r, alpha=0.5, linewidth=2, color="#69b3a2"))
# 画出国家的名字
plt.annotate(label, (x,y ), ha='center', color="white")
# Print labels for the continents
# 画出各大洲的标签
for circle in circles:
if circle.level != 2:
continue
x, y, r = circle
label = circle.ex["id"]
plt.annotate(label, (x,y ) ,va='center', ha='center', bbox=dict(facecolor='white', edgecolor='black', boxstyle='round', pad=.5))
3 circlify自带绘图函数
如果只是想看看数据如何,可以用circlify的自带绘图函数bubbles,但是不能定制图形。circlify的bubbles函数好处就是不需要用matplotlib一层一层的画圆。
一级层次绘图
from pprint import pprint as pp
import circlify
# 定义圆
# show_enclosure=True表示显示外圈大圆,也就是结果中的#0
circles = circlify.circlify([19, 17, 13, 11, 7, 5, 3, 2, 1], show_enclosure=True)
# 美化输出
pp(circles)
# 展示结果
circlify.bubbles(circles)
[Circle(x=0.0, y=0.0, r=1.0, level=0, ex=None),
Circle(x=-0.633232604611031, y=-0.47732413442115296, r=0.09460444572843042, level=1, ex={'datum': 1}),
Circle(x=-0.7720311587589236, y=0.19946176418549022, r=0.13379089020993573, level=1, ex={'datum': 2}),
Circle(x=-0.43168871955473165, y=-0.6391381648617572, r=0.16385970662353394, level=1, ex={'datum': 3}),
Circle(x=0.595447603036083, y=0.5168251295666467, r=0.21154197162246005, level=1, ex={'datum': 5}),
Circle(x=-0.5480911056188739, y=0.5115139053491098, r=0.2502998363185337, level=1, ex={'datum': 7}),
Circle(x=0.043747233552068686, y=-0.6848366902134195, r=0.31376744998074435, level=1, ex={'datum': 11}),
Circle(x=0.04298737651230445, y=0.5310431146935967, r=0.34110117996070605, level=1, ex={'datum': 13}),
Circle(x=-0.3375943908160698, y=-0.09326467617622711, r=0.39006412239133215, level=1, ex={'datum': 17}),
Circle(x=0.46484095011516874, y=-0.09326467617622711, r=0.4123712185399064, level=1, ex={'datum': 19})]
多级层次绘图
from pprint import pprint as pp
import circlify
data = [
0.05, {'id': 'a2', 'datum': 0.05},
{'id': 'a0', 'datum': 0.8, 'children': [0.3, 0.2, 0.2, 0.1], },
{'id': 'a1', 'datum': 0.1, 'children': [
{'id': 'a1_1', 'datum': 0.05}, {'datum': 0.04}, 0.01],
},
]
circles = circlify.circlify(data, show_enclosure=True)
pp(circles)
# 展示结果
circlify.bubbles(circles)
[Circle(x=0.0, y=0.0, r=1.0, level=0, ex=None),
Circle(x=-0.5658030759977484, y=0.4109778665114514, r=0.18469903125906464, level=1, ex={'datum': 0.05}),
Circle(x=-0.5658030759977484, y=-0.4109778665114514, r=0.18469903125906464, level=1, ex={'id': 'a2', 'datum': 0.05}),
Circle(x=-0.7387961250362587, y=0.0, r=0.2612038749637415, level=1, ex={'id': 'a1', 'datum': 0.1, 'children': [{'id': 'a1_1', 'datum': 0.05}, {'datum': 0.04}, 0.01]}),
Circle(x=0.2612038749637414, y=0.0, r=0.7387961250362586, level=1, ex={'id': 'a0', 'datum': 0.8, 'children': [0.3, 0.2, 0.2, 0.1]}),
Circle(x=-0.7567888163564135, y=0.1408782365133844, r=0.0616618704777984, level=2, ex={'datum': 0.01}),
Circle(x=-0.8766762590444033, y=0.0, r=0.1233237409555968, level=2, ex={'datum': 0.04}),
Circle(x=-0.6154723840806618, y=0.0, r=0.13788013400814464, level=2, ex={'id': 'a1_1', 'datum': 0.05}),
Circle(x=0.6664952237042414, y=0.33692908734605553, r=0.21174557028487648, level=2, ex={'datum': 0.1}),
Circle(x=-0.1128831469183017, y=-0.23039288135707192, r=0.29945345726929773, level=2, ex={'datum': 0.2}),
Circle(x=0.1563193680487183, y=0.304601976765483, r=0.29945345726929773, level=2, ex={'datum': 0.2}),
Circle(x=0.5533243963620487, y=-0.23039288135707192, r=0.3667540860110527, level=2, ex={'datum': 0.3})]
4 参考
[python] 圆形嵌套图Circular Packing的更多相关文章
- Python入门神图
国外某小哥制作的Python入门神图
- python数据结构之图的实现
python数据结构之图的实现,官方有一篇文章介绍,http://www.python.org/doc/essays/graphs.html 下面简要的介绍下: 比如有这么一张图: A -> B ...
- 【ZZ】Python入门神图
http://mp.weixin.qq.com/s?__biz=MzA3OTIxNTA0MA==&mid=401383338&idx=1&sn=73009cce06d58656 ...
- !!Python字典增删操作技巧简述+Python字典嵌套字典与排序
http://developer.51cto.com/art/201003/186006.htm Python编程语言是一款比较容易学习的计算机通用型语言.对于初学者来说,首先需要掌握的就是其中的一些 ...
- 孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归
孤荷凌寒自学python第十九天python函数嵌套与将函数作为返回对象及闭包与递归 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) Python函数非常的灵活,今天学习了python函数的以 ...
- Python成绩单雷达图
1numpy库 numpy 是 python 的科学计算库 部分功能: 1.使用numpy读取txt文件 # dtype = "str":指定数据格式 # delimiter = ...
- python数据结构之图的实现方法
python数据结构之图的实现方法 本文实例讲述了python数据结构之图的实现方法.分享给大家供大家参考.具体如下: 下面简要的介绍下: 比如有这么一张图: A -> B A ...
- python数据结构之图深度优先和广度优先实例详解
本文实例讲述了python数据结构之图深度优先和广度优先用法.分享给大家供大家参考.具体如下: 首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到 ...
- Python绘制面积图
一.Python绘制面积图对应代码如下图所示 import matplotlib.pyplot as plt from pylab import mpl mpl.rcParams['font.sans ...
随机推荐
- SpringBoot实战派读书笔记---响应式编程
1.什么是WebFlux? WebFlux不需要Servlet API,在完全异步且无阻塞,并通过Reactor项目实现了Reactor Streams规范. WebFlux可以在资源有限的情况下提高 ...
- 【算法训练营day1】LeetCode704. 二分查找 LeetCode27. 移除元素
[算法训练营day1]LeetCode704. 二分查找 LeetCode27. 移除元素 LeetCode704. 二分查找 题目链接:704. 二分查找 初次尝试 看到题目标题是二分查找,所以尝试 ...
- 猫狗识别-CNN与VGG实现
本次项目首先使用CNN卷积神经网络模型进行训练,最终训练效果不太理想,出现了过拟合的情况.准确率达到0.72,loss达到0.54.使用预训练的VGG模型后,在测试集上准确率达到0.91,取得了不错的 ...
- prometheus监控实战
第一节.环境和软件版本 1.1.操作系统环境 主机ip 操作系统 部署软件 备注 192.168.10.10 Centos7.9 Grafana.Pushgateway.Blackbox Export ...
- Java I/O(1):模型与流
在1990年以前,有一帮工程师们认为未来(1990年以后)会有很多小型设备需要得到电脑操控(不得不说,想法非常超前),鉴于当时市面上并没有任何一款编程语言能够跨平台,而且能够在诸如烤面包机这种小型设备 ...
- rabbitmq原理和应用
0.1.索引 https://blog.waterflow.link/articles/1663772504649 RabbitMQ 是一个轻量级且易于部署的消息队列.它支持开箱即用的多种消息传递协议 ...
- 知识图谱-生物信息学-医学顶刊论文(Bioinformatics-2022)-SGCL-DTI:用于DTI预测的监督图协同对比学习
14.(2022.5.21)Bioinformatics-SGCL-DTI:用于DTI预测的监督图协同对比学习 论文标题: Supervised graph co-contrastive learni ...
- jquery的toggle()函数,显示/隐藏交替
<!DOCTYPE html> <html lang="en"> <head> <script src="jquery.js&q ...
- CSP2022-J/S 游记
Day -2147483648 初赛 J组: 水. 单选没啥好说的,那道联通的傻掉挂了 \(2\). 读程 \(T1\) 手搓,\(T2\) 找规律(判断第一题蒙的,懒得算),\(T3\) 没注意 \ ...
- 【题解】P7860 [COCI2015-2016#2] ARTUR
题面传送门 好题. 主要思路和另一位巨佬差不多,详细讲一下判断的部分. 解决思路: 首先考虑本题与拓扑排序有和关系.可以想到,某些棍子的先后移动顺序是有限制的.比如: 这里红色的必须比蓝色的先移动,因 ...