华夫图(Waffle Chart)是一种数据可视化工具,用于呈现不同类别的占比关系。它的主要特点是将一个矩形图形(通常是正方形)分割成小块,每个小块代表一个特定的数据单元,如百分比、频率或数量。华夫图的颜色通常与数据类别相关联,使得观察者能够快速了解各个类别之间的比例关系。

华夫图的用途和优点包括:

  1. 显示占比关系: 华夫图适用于呈现不同类别之间的占比关系。通过将矩形分割成小块,每个小块的大小与类别的相对占比成比例,观察者可以一目了然地看到各个类别的相对大小。
  2. 易于理解: 华夫图的可视化形式非常直观,不需要复杂的解释即可传达数据信息。这使得它在简单地传达比例信息时非常有用。
  3. 可用于分类和分组: 华夫图可用于显示多个类别或分组的占比关系。它适用于呈现类别的分布情况,例如不同地区的销售份额、产品类别的销售比例等。
  4. 美观性: 华夫图的可视化效果通常很吸引人,能够吸引观众的注意力,从而更好地传达信息。
  5. 简化复杂数据: 华夫图可以用于将复杂的数据转化为简单的形式,以便更好地展示主要的占比关系,而不必深入细节。
  6. 与颜色编码相关性: 华夫图可以通过为每个小块选择不同的颜色来传达额外的信息。这可以用于显示不同类别之间的相关性、区分特定的子类别等。

PyWaffle是一个开源的、使用MIT许可的Python包,用于绘制华夫饼图。 提供了一个名为"Figure"的构造类"Waffle",可以传递给matplotlib.pyplot.figure,并生成一个matplotlib的"Figure"对象。


安装

!pip3 install pywaffle



一、快速入门

这是一个简单的示例,用于绘制一个 5行10列 的华夫图(Waffle Chart)。这三个数值直接绘制为块,块的数量与值中的数字相匹配,因为值的总和等于总块数(行数乘以列数)。

参数values接受多种格式的数字,包括列表、字典和pandas.DataFrame

1.1 列表数据

import matplotlib.pyplot as plt
from pywaffle import Waffle

fig = plt.figure(
    FigureClass = Waffle,
    rows = 5,
    columns = 10,
    values = [30, 16, 4]
)

fig.savefig('plot1.png', dpi=300)

注意:在这种情况下,参数中的 rows 和 columns 其中一个是多余的,因为图表的大小和值的总和都为50。因此,rows 和 columns 中的一个可以省略,并且仍然可以通过值的总和自动计算出它。详见“自动调整大小”以获取更多详细信息。


1.2 字典数据

当将一个字典传递给 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)}
)

fig.savefig('plot2.png', dpi=300)



1.3 DataFrame数据

与字典中的值可以自动生成标签和图例不同的是,当值是一个数据框(DataFrame)时,华夫图不会默认使用数据框的行索引作为标签。因此,如果您想要使用列索引作为标签,您必须手动将索引传递给参数 labels。

import pandas as pd

data = [30, 16, 4]
df = pd.DataFrame(data, 
                  columns=['Value'], 
                  index=['Cat1', 'Cat2', 'Cat3'])


fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=df['Value'],
    labels=list(df.index),  # 没有这行, Legend 不会显示
    legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1)}
)


fig = plt.figure()
ax = fig.add_subplot(111)

# 修改已存在的axis
ax.set_title("Axis Title")
# 确保绘制的图形在坐标轴两个方向上的比例保持一致
ax.set_aspect(aspect="equal")

Waffle.make_waffle(
    ax=ax,  # pass axis to make_waffle
    rows=5, 
    columns=10, 
    values=[30, 16, 4], 
    title={"label": "Waffle Title", "loc": "left"}
)




二、值缩放&尺寸调整

2.1 数值缩放

在实际情况中,图表的尺寸通常与数值的总和不相等。因此,必须对数值进行缩放,以适应图表的尺寸。

通过将参数 rounding_rule 设置为首选的舍入规则,可以实现这一目标。它接受三种值:floor、ceil 或 nearest

注意:当 rounding_rule 设置为 ceil 或 nearest 时,缩放后的值的总和可能会大于图表的尺寸。如果是这样,最后一个类别的块将不会完全显示在图表中。因此,尽管 nearest 是默认的舍入规则,但实际上,floor 是最一致的规则,因为它可以避免块的溢出。

在下面的示例中,通过使用 rounding_rule=floor,将值缩放为 24、23、1 作为块的数量。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[48, 46, 3],
    rounding_rule='floor'
)



2.2 自动调整尺寸

如果您想避免值的缩放,只需将一个整数传递给 rows 或 columns 参数中的一个。然后,绝对数量的值将直接用作块的数量,并且另一个参数会自动计算。

在以下示例中,我们将 rows 设置为 5,values 设置为 [48, 46, 3],并将 columns 留空。然后,块的数量将与值相同。由于值的总和为 97,列数必须为 20,以适应所有块。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[48, 46, 3]
)




三、标题、标签、图例

  • 参数 title 以字典形式接受 matplotlib.pyplot.title 的参数。
  • 参数 labels 以列表中的字符串标签形式接受。如果未指定,将使用 values 的键作为标签。
  • 参数 legend 以字典形式接受 matplotlib.pyplot.legend 的参数。

注意:标签也可以在参数 legend 下的 labels 键中指定。

这些信息描述了使用 pywaffle 库中某些参数的功能。这些参数用于在绘图中设置标题、标签和图例的属性。

data = {'Cat1': 30, 'Cat2': 16, 'Cat3': 4}

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=data,
    title={
        'label': 'Example plot',
        'loc': 'center',
        '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.4),
        'ncol': len(data),
        'framealpha': 0,
        'fontsize': 12
    }
)




四、块配色

参数colors接受一个颜色列表或元组。其长度必须与values相同,可接受的颜色格式包括不区分大小写的十六进制RGB或RGBA,RGB或RGBA元组,单字符表示法,不区分大小写的X11/CSS4颜色名称等,只要Matplotlib能够识别即可。请参阅Matplotlib颜色文档获取完整列表。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[30, 16, 4],
    colors=["#232066", "#983D3D", "#DCB732"]
)



改变块颜色的另一种方法是通过将颜色映射(Colormap)传递给参数 cmap_name,从而批量设置颜色。

注意:顺序型颜色映射在 PyWaffle 中不起作用。只支持质性颜色映射,包括 Pastel1、Pastel2、Paired、Accent、Dark2、Set1、Set2、Set3、tab10、tab20、tab20b、tab20c。请参阅Matplotlib中的颜色映射列表和示例以获取更多信息。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    columns=10,
    values=[30, 16, 4],
    cmap_name="tab10"
)




五、块形状

默认块的形状为正方形, 但是也可以用charactersicons确定为其他形状。

5.1 characters

可以通过将所需的字符传递给 characters 参数,而不是矩形块,来使用 Unicode 字符来表示块。

可以通过将包含每个类别对应字符的列表或元组传递给 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
)



5.2 图标

使用图标的华夫图也被称为象形图表(Pictogram Chart)。

PyWaffle 支持通过 Font Awesome 绘制带有图标的图表。有关 Font Awesome 如何集成到 PyWaffle 中的信息,请查看“Font Awesome 集成”页面。要在 Font Awesome 中搜索可用的图标名称,请访问 https://fontawesome.com/search

在使用图标时,设置块大小的参数将被忽略,包括 interval_ratio_x、interval_ratio_y 和 block_aspect_ratio。相反,使用 font_size 来设置图标的大小。有关允许的大小,请参见 FontProperties.set_size。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[30, 16, 4],
    colors=["#232066", "#983D3D", "#DCB732"],
    icons='star',
    font_size=24 #icon大小
)


每个类别可以有不同的图标,通过将图标名称的列表或元组传递给参数 icons 来实现。其长度必须与 values 的长度相同。

在 Font Awesome 图标库中,有不同风格的图标集,包括 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,图例中的符号将会是图标。否则,它将是一个颜色条。
    icon_legend=True,
    legend={
        'labels': ['Sun', 'Shower', 'Snow'], 
        'loc': 'upper left', 
        'bbox_to_anchor': (1, 1)
    }
)


Font Awesome根据图标名称和样式来定位图标。因此,不同图标的样式可能不同,您必须为所有图标单独指定图标样式。因此,icon_style 参数还可以接受一个包含样式字符串的列表或元组,以用于不同的图标。

在Font Awesome中,您需要根据图标的名称和样式来选择正确的图标。这些图标的样式可能包括不同的风格,因此您需要单独指定每个图标的样式。通过使用icon_style 参数,您可以为每个图标选择适当的样式,以确保它们在呈现时显示正确的外观。这在使用Font Awesome图标时很重要,因为它允许您根据需要选择不同的样式。

fig = plt.figure(
    FigureClass=Waffle,
    rows=5,
    values=[30, 16, 4],
    colors=["#FFA500", "#4384FF", "#C0C0C0"],
    icons=['sun', 'cloud-showers-heavy', 'font-awesome'],
    icon_size=20,
    icon_style=['regular', 'solid', 'brands'],
    icon_legend=True,
    legend={
        'labels': ['Sun', 'Shower', 'Flag'], 
        'loc': 'upper left', 
        'bbox_to_anchor': (1, 1)
    }
)



总结

尽管Waffle图在传达占比关系方面具有优势,但也需要注意它的局限性。例如,Waffle图不适合呈现大量数据或复杂数据关系,因为小块的数量可能会变得过多,难以解读。在选择数据可视化方式时,要根据数据的特点和需求来决定是否使用Waffle图以及何时使用。

点击下载本文代码



广而告之