HOWTO · Seaborn
如何创建 Seaborn 饼图
使用 Matplotlib 的 plt.pie 和 Seaborn 颜色调色板创建饼图,然后添加标签、百分比、间距和样式。
本页内容
在 Python 中创建饼图的方法是:用 Matplotlib 的 plt.pie 绘制,并用 Seaborn 的 sns.color_palette 选择切片颜色。Seaborn 不提供自己的饼图函数;在这个流程中,这两个库各自承担不同的角色,因为 Seaborn 提供颜色,而 Matplotlib 绘制图表。您需要同时安装这两个库(pip install matplotlib seaborn)。下面的示例为几个类别使用数值,为每个切片添加标签并显示其占总体的份额;第二个示例将图表改造成带图例的环形图;最后一个示例展示当标签与数值不匹配时 Matplotlib 引发的错误。
在 Seaborn 中创建饼图
import matplotlib.pyplot as plt
import seaborn as sns
values = [35, 21, 29, 39, 11]
labels = ["A", "B", "C", "D", "E"]
colors = sns.color_palette("pastel", n_colors=len(values))
explode = [0.08, 0, 0, 0, 0]
plt.pie(
values,
labels=labels,
colors=colors,
autopct="%1.1f%%",
explode=explode,
startangle=90,
counterclock=False,
textprops={"fontsize": 10},
wedgeprops={"linewidth": 1, "edgecolor": "white"},
)
plt.show()
这段代码生成上图所示的图表。五个值的总和为 135,因此切片上打印的百分比分别为:A 为 25.9%,B 为 15.6%,C 为 21.5%,D 为 28.9%,E 为 8.1%。由于 explode 偏移,切片 A 与其余切片略微分开。
让值和标签按位置对齐:第一个标签命名第一个值,第二个标签命名第二个值,依此类推。使用描述一个整体各部分的数值列表,例如按类别统计的数量。百分比由这些数量计算得出,因此它们描述的是每个类别的份额,而不是单独提供的百分比。
作为 values 传入的列表决定了每个切片的相对大小。plt.pie 绘制图表,而 sns.color_palette 返回切片的颜色。调色板名称是一个字符串;将 "pastel" 改为其他 Seaborn 调色板,例如 "deep"、"muted"、"colorblind"、"bright" 或 "dark"。根据数据长度设置 n_colors,即可为每个值请求一种颜色。
labels 列表按与值相同的顺序提供类别名称。autopct 格式显示每个值占所有值总和的百分比;例如,"%1.1f%%" 将百分比格式化为小数点后一位。使用不同的格式字符串可更改显示精度。标签标识类别,而百分比使它们的比例易于比较。
若要在视觉上分离切片,请向 explode 传递一个与每个值对应一项的序列。每一项控制相应切片的偏移,因此第一个 0.08 将类别 A 向外移动,其余的零则让它们的切片保持原位。调整这些项以强调不同的类别,或全部使用零以获得无偏移的图表。
自定义饼图
您可以使用更多的 plt.pie 参数调整图表的方向和外观。startangle 旋转起始位置,counterclock=False 设置切片绘制的方向。使用 shadow=True 添加阴影,使用 textprops 设置标签和百分比文本的属性,使用 wedgeprops 设置切片边界的样式。一个有用的 wedgeprops 设置是 width:它将每个楔形向边缘收缩,把饼图变成环形图,如下一个示例所示。其他参数包括:添加坐标轴边框的 frame=True、放置饼图中心的 center=(x, y),以及让标签沿其切片旋转的 rotatelabels=True;这些布尔选项采用不带引号的 Python 值 True 或 False。
import matplotlib.pyplot as plt
import seaborn as sns
values = [58, 33, 6, 3]
labels = ["Desktop", "Mobile", "Tablet", "Other"]
colors = sns.color_palette("colorblind", n_colors=len(values))
wedges, texts = plt.pie(
values,
colors=colors,
startangle=90,
counterclock=False,
wedgeprops={"width": 0.45, "linewidth": 1, "edgecolor": "white"},
)
plt.legend(wedges, labels, title="Device", loc="center left", bbox_to_anchor=(1, 0.5))
plt.title("Sessions by Device")
plt.show()
在这里,wedgeprops={"width": 0.45, ...} 只保留每个楔形外侧的 45%,从而使中心留空。由于这次切片没有标签,plt.pie 返回楔形对象,将它们与标签列表一起传递给 plt.legend,即可在图表旁边构建图例。plt.title 添加标题。当类别名称很长或有几个切片很细时,图例比切片上的标签更易读;示例数据的总和为 100,因此各段的大小可以直接读作百分比(58%、33%、6% 和 3%)。
避免长度和数值错误
每个按切片传递的参数都必须与数据匹配:labels、explode 和颜色列表都必须为每个值恰好提供一项,并且每个值都必须为非负数,因为切片不可能占整体的负份额。如果长度不一致,plt.pie 会引发 ValueError 并停止,而不是绘制图表:
import matplotlib.pyplot as plt
values = [35, 21, 29]
labels = ["A", "B"]
plt.pie(values, labels=labels)
plt.show()
输出:
ValueError: 'labels' must be of length 'x', not 2
修复方法是为 labels 提供与三个值一一对应的项。同样的规则适用于 explode:为三个值提供只有两项的 explode 列表会引发 ValueError: 'explode' must be of length 'x', not 2。values 中的负数项同样会失败,并引发 ValueError: Wedge sizes 'x' must be non negative values。最后,请让类别数量保持较少:切片过多过细时,标签会相互碰撞,份额也难以比较,因此请将次要类别归入一个 “Other” 切片,或改用条形图。