对比excel,用python绘制华夫饼图

2021-08-05 15:24:55 浏览数 (1)

我们的第87篇原创

作者:才哥


大家好,我是才哥。

最近在工作中用到了华夫饼图,不过我这边主要是excel去制作,这里我们试着看看excel和python绘制华夫饼图的一些小技巧吧!

华夫饼图(Waffle Chart),或称为直角饼图,可以直观的描绘百分比完成比例情况。与传统的饼图相比较,华夫饼图表达的百分比更清晰和准确,它的每一个格子代表 1%。华夫饼图的典型应用是比较同类型指标完成比例。例如,工作完成度,年度营收进度等。

1. Excel绘制华夫饼图

其实,用excel绘制华夫饼图的方式有多种,比较复杂的是通过插入柱状图图表后调整柱状图的规范实现;另外一种比较简单的操作则是采取单元格格式的形式,也是我们今天要介绍的方案。

1.1. 效果预览

excel绘制效果

1.2. 实现步骤

先选中10*10共100个单元格区间,然后将单元格的宽度和高度像素设置为相等的值,这里我们设置的值为25像素

设置单元格高&宽

接着我们在单元格中从左—>右下—>上填入数字1-100

填入数字1-100

为了显示进度值,我们在最下方输入值(这里以66%为例),然后选中10*10的数字区域进行条件格式设置—>图标集—>形状

条件格式设置

最后再次进入条件格式设置中选中管理规则进行详细规则设定,点击具体规则后可以单击编辑规则或者直接双击具体规则

编辑规则

具体规则如下:

  • 类型选择 公式
  • 单元格值超过指定值(这里是C13单元格66%*100)则会灰色
  • 单元格值不超过指定值则为橙红色
  • 同时记得勾选仅显示图标(否则会出现单元格数字显示覆盖图标的情况)

具体规则

确定规则后,我们可以看到效果如下,继续进行简单的优化就完事了(比如去掉网格、添加其他元素)

初步结果预览

2. Python绘制华夫饼图

这里介绍的是一个第三方库pywaffle,看这库的名称就知道这货是专门用来绘制华夫饼图的。

老规矩,先安装再使用:

代码语言:javascript复制
pip install pywaffle

接着就是简单的绘图过程:

代码语言:javascript复制
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', # 橙红色
)

绘图输出如下:

python绘制华夫饼图

3. pywaffle华夫饼图介绍

由于功能就是华夫饼图,所以内容不复杂,大家可以直接参考官方文档(功能和案例都有,且都比较简单)。

代码语言:javascript复制
# 官网地址
https://pywaffle.readthedocs.io/

华夫饼图(Waffle Chart),也叫Square Pie Chart,是饼图的一种变形,擅长展示部分在整体中的占比关系。一般来说,华夫饼图是由100个格子组成,一个格子代表1%。用不同颜色的格子区分不同的分类数据,以展示各部分在整体中的占比。

3.1. 基础案例

引入matplotlibpywaffle,绘图时指定FigureClass=Waffle即可

代码语言:javascript复制
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也接受字典中的数据,字典的键将用作标签并显示在图例中

代码语言:javascript复制
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_ruleceil或 时nearest,缩放值的总和可能大于格子总数。如果是这样,最后一个类别的格子将不会完全显示出来。因此,虽然nearest是默认的舍入规则,但floor实际上是最一致的规则,因为它避免了格子溢出。

在以下示例中,值被缩放为 24、23、1 作为格子编号,并使用rounding_rule= floor

代码语言:javascript复制
plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[48, 46, 3],
    rounding_rule='floor'
)

当然,也可以通过只设置一个行列一个参数值的形式,自动调整格子数:

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[48, 46, 3],
)

3.3. 标题、标签与图例

标题参数title,标签参数labels,图例参数legend。这些参数含义和matplotlib里一致,具体可以参考matplotlib对应介绍。

代码语言:javascript复制
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

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[30, 16, 4],
    colors=["#232066", "#983D3D", "#DCB732"]
)

指定cmap_name

仅支持定性颜色图,包括Pastel1Pastel2PairedAccentDark2Set1Set2Set3tab10tab20tab20btab20c

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[30, 16, 4],
    cmap_name="Accent"
)

3.5. 用字符或图标填充格子

字符

通过将字符列表或元组传递给参数,类别可以为每个类别具有不同的字符characters,长度必须与values。有时候发现默认字体不支持,则需要指定字体,请将 .ttf 或 .otf 文件的绝对路径传递给 参数 font_file

代码语言:javascript复制
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/

代码语言:javascript复制
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,图例中的符号将是图标。否则,它将是一个颜色条。

代码语言:javascript复制
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可以是一个列表或一个样式元组。

代码语言:javascript复制
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,所以格子是正方形。

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[30, 16, 4],
    block_aspect_ratio=1.618
)

间距

参数interval_ratio_xinterval_ratio_y控制格子之间的水平和垂直距离。interval_ratio_x是格子之间的水平距离与格子宽度interval_ratio_y的比率,是格子之间的垂直距离与格子高度的比率。

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[30, 16, 4],
    interval_ratio_x=1,
    interval_ratio_y=0.5
)

起始位置

使用参数starting_location设置起始格子的位置。它接受字符串中的位置,如NW, SW,NESE代表四个角。默认情况下,它是SW,这意味着 PyWaffle 从左下角开始绘制格子。

这是从右下角 ( SE)开始绘图的示例:

代码语言:javascript复制
fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[30, 16, 4],
    starting_location='SE'
)

绘图方向

默认情况下,PyWaffle 逐列绘制格子,因此类别是水平绘制的。要使其垂直,请将参数设置verticalTrue

在下面的示例中,它从左下角到右下角逐行直到顶部绘制格子:

3.7. 其他

调整图形大小、背景颜色、DPI 等

figsizedpifacecolortight_layout等都可以进行设置,如下设置背景色

代码语言:javascript复制
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()方法为图形添加自定义水印

代码语言:javascript复制
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
    }
)

0 人点赞