大家好,我是才哥。
华夫饼图(Waffle Chart),或称为直角饼图,可以直观的描绘百分比完成比例情况。与传统的饼图相比较,华夫饼图表达的百分比更清晰和准确,它的每一个格子代表 1%。华夫饼图的典型应用是比较同类型指标完成比例。例如,工作完成度,年度营收进度等。
1. Excel绘制华夫饼图
其实,用excel绘制华夫饼图的方式有多种,比较复杂的是通过插入柱状图图表后调整柱状图的规范实现;另外一种比较简单的操作则是采取单元格格式
的形式,也是我们今天要介绍的方案。
1.1. 效果预览
1.2. 实现步骤
先选中10*10
共100个单元格区间,然后将单元格的宽度和高度像素设置为相等的值,这里我们设置的值为25像素
接着我们在单元格中从左—>右、下—>上填入数字1-100
为了显示进度值,我们在最下方输入值(这里以66%为例),然后选中10*10的数字区域进行条件格式
设置—>图标集
—>形状
最后再次进入条件格式设置中选中管理规则进行详细规则设定,点击具体规则后可以单击编辑规则或者直接双击具体规则
具体规则如下:
- 类型选择 公式
- 单元格值超过指定值(这里是C13单元格66%*100)则会灰色
- 单元格值不超过指定值则为橙红色
- 同时记得勾选仅显示图标(否则会出现单元格数字显示覆盖图标的情况)
确定规则后,我们可以看到效果如下,继续进行简单的优化就完事了(比如去掉网格、添加其他元素)
2. Python绘制华夫饼图
这里介绍的是一个第三方库pywaffle
,看这库的名称就知道这货是专门用来绘制华夫饼图的。
老规矩,先安装再使用:
pip install pywaffle
接着就是简单的绘图过程:
import matplotlib.pyplot as plt
from pywaffle import Waffle
# 设置中文字体
plt.rcParams["font.family"] = "Microsoft YaHei"
# 进度值
value = 0.66
values = [value,1-value]
fig = plt.figure(
FigureClass=Waffle,
rows=10, # 10行
columns=10, # 10列
values=values, # 值
colors=["#FF4500", "#C0C0C0"], # 配色
vertical=True, # 设置绘图方向从下往上、从左往右
characters='●', # 用实心圆做图标
font_size=45, # 大小为45
title={
'label': '工作完成度', # 设置图表标题
'loc': 'center',
'y':1.05,
'fontdict': {
'fontsize': 20
}
},
)
fig.text( # 设置进度值显示
x=0.3,
y=-0.03,
s=f"{int(100*value)}%",
ha="center",
va="center",
fontsize=25,
color='orangered', # 橙红色
)
绘图输出如下:
3. pywaffle华夫饼图介绍
由于功能就是华夫饼图,所以内容不复杂,大家可以直接参考官方文档(功能和案例都有,且都比较简单)。
# 官网地址
https://pywaffle.readthedocs.io/
华夫饼图(Waffle Chart),也叫Square Pie Chart
,是饼图的一种变形,擅长展示部分在整体中的占比关系。一般来说,华夫饼图是由100个格子组成,一个格子代表1%
。用不同颜色的格子区分不同的分类数据,以展示各部分在整体中的占比。
3.1. 基础案例
引入matplotlib
和pywaffle
,绘图时指定FigureClass=Waffle
即可
import matplotlib.pyplot as plt
from pywaffle import Waffle
plt.figure(
FigureClass=Waffle,
rows=5, # 行数
columns=10, # 列数
values=[30, 16, 4] # 值(三类值,这里总和=50和格子总数相等,则行列可以只指定一个即可)
)
plt.show()
参数values
也接受字典中的数据,字典的键将用作标签并显示在图例中
fig = plt.figure(
FigureClass=Waffle,
rows=5,
columns=10,
values={'Cat1': 30, 'Cat2': 16, 'Cat3': 4},
legend={ # 图例
'loc': 'upper left', # 图例位置
'bbox_to_anchor': (1, 1) # 图例位置坐标
}
)
3.2. 数值缩放
当格子总数和values中数字总和不等时,设置参数rounding_rule
的值可以指定缩放规则。
当
rounding_rule
是ceil
或 时nearest
,缩放值的总和可能大于格子总数。如果是这样,最后一个类别的格子将不会完全显示出来。因此,虽然nearest
是默认的舍入规则,但floor
实际上是最一致的规则,因为它避免了格子溢出。
在以下示例中,值被缩放为 24、23、1 作为格子编号,并使用rounding_rule
= floor
plt.figure(
FigureClass=Waffle,
rows=5,
columns=10,
values=[48, 46, 3],
rounding_rule='floor'
)
当然,也可以通过只设置一个行列一个参数值的形式,自动调整格子数:
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[48, 46, 3],
)
3.3. 标题、标签与图例
标题参数title
,标签参数labels
,图例参数legend
。这些参数含义和matplotlib里一致,具体可以参考matplotlib对应介绍。
data = {'Cat1': 30, 'Cat2': 16, 'Cat3': 4}
fig = plt.figure(
FigureClass=Waffle,
rows=5,
columns=10,
values=data,
title={
'label': 'Example plot',
'loc': 'left',
'fontdict': {
'fontsize': 20
}
},
labels=[f"{k} ({int(v / sum(data.values()) * 100)}%)" for k, v in data.items()],
legend={
# 'labels': [f"{k} ({v}%)" for k, v in data.items()], # lebels could also be under legend instead
'loc': 'lower left',
'bbox_to_anchor': (0, -0.2),
'ncol': len(data),
'framealpha': 0,
'fontsize': 12
}
)
3.4. 格子颜色
参数colors
接受列表或元组中的颜色,它的长度必须与 相同values
。同时,我们也可以通过设置参数cmap_name
为指定Colormap
。
指定颜色colors
fig = plt.figure(
FigureClass=Waffle,
rows=5,
columns=10,
values=[30, 16, 4],
colors=["#232066", "#983D3D", "#DCB732"]
)
指定cmap_name
仅支持定性颜色图,包括Pastel1
、Pastel2
、Paired
、Accent
、Dark2
、Set1
、Set2
、Set3
、tab10
、tab20
、tab20b
、tab20c
。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
columns=10,
values=[30, 16, 4],
cmap_name="Accent"
)
3.5. 用字符或图标填充格子
字符
通过将字符列表或元组传递给参数,类别可以为每个类别具有不同的字符characters
,长度必须与values
。有时候发现默认字体不支持,则需要指定字体,请将 .ttf 或 .otf 文件的绝对路径传递给 参数 font_file
。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
colors=["#4C8CB5", "#B7CBD7", "#C0C0C0"],
characters='●',
font_size=24
)
图标
PyWaffle 支持使用Font Awesome 图标
进行绘图
https://fontawesome.com/
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
colors=["#232066", "#983D3D", "#DCB732"],
icons='star',
font_size=24
)
通过将图标名称列表或元组传递给参数,每个类别都可以有不同的图标icons
,长度必须与values
.
在 Font Awesome Icons 中,有不同风格的不同图标集,包括 Solid、Regular 和 Brands。可以通过参数指定icon_style
可以设置,默认情况下,它从solid
样式中搜索图标。
使用icon_legend
= True
,图例中的符号将是图标。否则,它将是一个颜色条。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
colors=["#FFA500", "#4384FF", "#C0C0C0"],
icons=['sun', 'cloud-showers-heavy', 'snowflake'],
font_size=20,
icon_style='solid',
icon_legend=True,
legend={
'labels': ['Sun', 'Shower', 'Snow'],
'loc': 'upper left',
'bbox_to_anchor': (1, 1)
}
)
Font Awesome Icons 按样式和图标名称定位图标。不同的样式包含不同的图标集。因此,所有图标的 icon_style 可能并不相同。在这种情况下,icon_style
可以是一个列表或一个样式元组。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
colors=["#FFA500", "#4384FF", "#C0C0C0"],
icons=['sun', 'cloud-showers-heavy', 'font-awesome-flag'],
icon_size=20,
icon_style=['regular', 'solid', 'brands'],
icon_legend=False,
legend={
'labels': ['Sun', 'Shower', 'Flag'],
'loc': 'upper left',
'bbox_to_anchor': (1, 1)
}
)
3.6. 格子其他属性
格子其他属性包含绘制的格子形状、间距、起始位置以及绘图方向等。
格子颜色
参数block_aspect_ratio
通过改变格子的宽度与高度的比率来控制格子的形状。默认情况下它是 1,所以格子是正方形。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
block_aspect_ratio=1.618
)
间距
参数interval_ratio_x
和interval_ratio_y
控制格子之间的水平和垂直距离。interval_ratio_x
是格子之间的水平距离与格子宽度interval_ratio_y
的比率,是格子之间的垂直距离与格子高度的比率。
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
interval_ratio_x=1,
interval_ratio_y=0.5
)
起始位置
使用参数starting_location
设置起始格子的位置。它接受字符串中的位置,如NW
, SW
,NE
并SE
代表四个角。默认情况下,它是SW
,这意味着 PyWaffle 从左下角开始绘制格子。
这是从右下角 ( SE
)开始绘图的示例:
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
starting_location='SE'
)
绘图方向
默认情况下,PyWaffle 逐列绘制格子,因此类别是水平绘制的。要使其垂直,请将参数设置vertical
为True
。
在下面的示例中,它从左下角到右下角逐行直到顶部绘制格子:
3.7. 其他
调整图形大小、背景颜色、DPI 等
像figsize
,dpi
,facecolor
,tight_layout
等都可以进行设置,如下设置背景色
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4],
colors=["#232066", "#983D3D", "#DCB732"],
facecolor='#DDDDDD' # facecolor is a parameter of matplotlib.pyplot.figure
)
添加其他元素
在下面的示例中,我们使用text()
方法为图形添加自定义水印
fig = plt.figure(
FigureClass=Waffle,
rows=5,
values=[30, 16, 4]
)
fig.text(
x=0.5,
y=0.5,
s="可以叫我才哥",
ha="center",
va="center",
rotation=30,
fontsize=40,
color='gray',
alpha=0.3,
bbox={
'boxstyle': 'square',
'lw': 3,
'ec': 'gray',
'fc': (0.9, 0.9, 0.9, 0.5),
'alpha': 0.3
}
)