跳至主要内容

Python Plotly Express 教程:解锁高颜值可视化

学习如何使用 Python Plotly Express 创建高度交互、视觉吸引力强的图表。
· 10分钟 阅读

使用 AI 探索

Plotly 不仅用于创建漂亮的可视化,更在于释放数据的全部潜力,揭示那些原本可能被埋没的洞见。它是数字与叙事之间的桥梁,帮助个人与组织做出明智决策并推动有意义的改变。

这正是 ChatGPT 描述 Plotly 的语言。显然,Plotly 是最优秀的数据可视化库之一。

Plotly Express

它可以创建高度交互且视觉效果出众的图表,如下所示:

今天,您将学习用 Plotly 创建精彩可视化的基础知识。

Plotly Express 基础

与其他教程一样,我们先通过 pip(或您偏好的 conda)安装库。

$ pip install --upgrade plotly
$ conda install -c conda-forge plotly

Plotly 会定期更新,因此如果您已经安装了该库,请确保包含 --upgrade 参数。

本教程聚焦于 2019 年引入的 Plotly Express API,相比旧方式与核心 Plotly 库交互,它有诸多优势:

  • 语法简单(几乎像英语一样可读)
  • 可视化类型丰富(或提供工具让您自定义)
  • 坐标轴与颜色自动缩放
  • 与 pandas 集成(可将 Plotly 作为 Pandas .plot 函数的绘图后端)

下面是一个 Plotly Express 基本图表的结构:

import plotly.express as px

fig = px.plotting_function(
    dataframe,
    x='column-for-xaxis',
    y='column-for-yaxis',
    title='Title For the Plot',
    width=width_in_pixels,
    height=height_in_pixels
)

fig.show()

不同的图表以各自的名称存在,例如 histogram 或 scatter 均位于 express 模块下,并以 px 导入。任何绘图函数的第一个参数是数据框,以及用于 X 与 Y 轴的列名。

最佳实践要求为图表提供信息量充足的 title,以便读者了解图表所表达的内容。

绘图函数执行后会返回一个 Figure 对象,随后调用其 show 方法即可在笔记本中显示图表。

开始绘图前,我们需要一个数据集。本教程使用的是钻石(Diamonds)数据集。它包含数值型与分类型特征的良好组合——非常契合本文目的。

import pandas as pd

diamonds = pd.read_csv("data/diamonds.csv")

diamonds.head()

Data Set

该数据集包含超过 5.3 万颗钻石及其 10 项物理特征。您可以在下方查看数据的基本统计信息。

diamonds.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 53940 entries, 0 to 53939
Data columns (total 10 columns):
#   Column   Non-Null Count  Dtype 
---  ------   --------------  ----- 
0   carat    53940 non-null  float64
1   cut      53940 non-null  object
2   color    53940 non-null  object
3   clarity  53940 non-null  object
4   depth    53940 non-null  float64
5   table    53940 non-null  float64
6   price    53940 non-null  int64 
7   x        53940 non-null  float64
8   y        53940 non-null  float64
9   z        53940 non-null  float64
dtypes: float64(6), int64(1), object(3)
memory usage: 4.1+ MB
diamonds.describe()

进行探索性数据分析(EDA)时,首先要做的之一就是探索单个分布。

针对这一任务,Plotly 提供了许多图表:直方图、箱线图、小提琴图、条形图等。我们来看几个示例。

Plotly Express 中的直方图

直方图大概是人们最先学习的可视化之一。

它将分布的数值进行排序并划分到区间(bins)中,然后用柱状表示每个区间中数值的数量:

import plotly.express as px
​
fig = px.histogram(
  diamonds,
  x="price",
  title="Histogram of diamond prices",
  width=600,
  height=400,
)
​
fig.show()

Histogram Plotly Express

将鼠标悬停在任意柱子上,您可以看到其对应区间的范围。Plotly 会自动确定区间数量,但如果您想自行设置,可以使用 nbins 参数。

然而,为每个分布单独找到“完美”的区间数并不容易。因此,常见做法是将区间数设置为分布长度的平方根:

# Find the correct number of bins
nbins = int(len(diamonds) ** (1 / 2))
​
fig = px.histogram(
  diamonds,
  x="price",
  title="Histogram of diamond prices",
  nbins=nbins,
  width=600,
  height=400,
)
​
fig.show()

Plotly Express 条形图

直方图用于分析定量特征。要分析分类型数据,我们转向条形图。例如,将分类型的 cut 列传给 histogram 函数,我们会得到一种称为 countplot 的条形图。没错,它会统计每个类别中的观测数量。

fig = px.histogram(diamonds, x="cut")
​
fig.show()

Bar Chart Plotly Express

等等,我们还没有在图上添加任何标签!我们可以使用 update_layout 函数来修正,它可以在图形创建后修改很多方面。

fig.update_layout(
  title="The number of diamonds in each diamond cut category",
  xaxis_title="",
  yaxis_title="Count",
)

Bar Chart Labels Plotly Express

您已经知道 title 的作用了。xaxis_title 与 yaxis_title 会替换 Plotly 生成的轴标签(默认即列名)。

现在,我们来查看每个切工类别的平均价格。首先使用 pandas 的 groupby:

mean_prices = (
    diamonds.groupby("cut")["price"].mean().reset_index()
)

mean_prices

Groupby

在 groupby 操作末尾串接 reset_index 会将输出转为 DataFrame,而 Plotly 更青睐 DataFrame。接下来将其传给 bar 函数:

fig = px.bar(mean_prices, x="cut", y="price")
​
fig.update_layout(
  title="Average diamond prices for each cut category",
  xaxis_title="",
  yaxis_title="Mean price ($)",
)
​
fig.show()

Mean Price

bar 接受一个分类型与一个数值型特征,为传入 DataFrame 的每一行创建一个柱子。这样即可直观比较各类钻石的价格。

Plotly Express 中的箱线图

另一个常见的分布分析图表是箱线图,在 Plotly Express 中使用 box 创建:

fig = px.box(diamonds, x="clarity", y="carat")
​
fig.update_layout(
  title="Distribution of diamond carats for each clarity category",
  xaxis_title="Clarity",
  yaxis_title="Carat",
)
​
fig.show()

Box Plot Plotly Express

与仅显示平均克拉数的柱状图不同,箱线图会显示多种统计量:

Box Plot Statistics

您可以看到:

  • 最小值/最大值
  • 中位数
  • 第 25 百分位
  • 第 75 百分位
  • 以及离群值

对应于每个钻石净度(clarity)类别。

Plotly Express 中的小提琴图

探索分布的另一种有趣图表是小提琴图。小提琴图本质上是带有一些额外修饰的箱线图:

fig = px.violin(diamonds, x="cut", y="price")
​
fig.show()

Violin Plot Plotly Express

它不显示箱体,而是显示一条平滑曲线,表示特征的密度。若要叠加箱线图,只需将 box 参数设为 True:

fig = px.violin(diamonds, x="cut", y="price", box=True)
​
fig.show()

Violin Box Plot Plotly Express

不同于只显示汇总统计的箱线图,小提琴图还能呈现分布形状。

在 Plotly Express 中可视化特征间关系

当您绘制彼此密切相关的特征时,会开始发现新的模式与洞见。举例而言,若我们假设钻石的克拉(重量)是决定其价格的主要因素,那么就来探索这一关系。

Plotly Express 中的散点图

我们可以使用散点图(px.scatter),将数据集中所有钻石绘制为点。点的位置由其对应的价格与克拉值决定:

fig = px.scatter(diamonds, x="price", y="carat")
​
fig.update_layout(
  title="Price vs. Carat",
  xaxis_title="Price ($)",
  yaxis_title="Carat",
)
​
fig.show()

Scatter Plot Plotly Express

我们遇到了严重的过度绘制问题。当单个图表需要展示的数据量过多时,就会发生过度绘制。它会掩盖数据中的真实模式与趋势。

我们可以仅绘制约 10% 的数据集,这足以揭示潜在模式:

fig = px.scatter(
  diamonds.sample(5000), x="price", y="carat"
)
​
fig.update_layout(
  title="Price vs. Carat",
  xaxis_title="Price ($)",
  yaxis_title="Carat",
)
​
fig.show()

Scatter Plot 10 Percent

在调用 scatter 时,我们仅传入了 5000 行(.sample(5000)),这显示了价格与克拉关系的轻微上升趋势。

Plotly Express 热力图

热力图非常适合可视化复杂数据集,例如很大的矩阵——当单元格中充斥着数字时,单靠肉眼很难发现模式。

热力图会根据矩阵中每个单元格的大小(数值)赋予颜色。一个典型的应用场景是查看数据集的相关性矩阵。

相关性用于度量数值特征之间的线性关系。因此,相关性矩阵的每个单元格代表一对特征之间的相关性。

您可以使用 pandas 的 corr 方法计算任意数据集的相关性矩阵,它会返回一个 DataFrame。将其传给 Express 的 imshow 函数即可得到热力图:

import plotly.express as px
​
# Create heatmap using Plotly Express
fig = px.imshow(
  diamonds.corr(),
  color_continuous_scale="Inferno_r",
)
​
# Show plot
fig.show()

Heatmap Plotly Express

相关系数范围是 -1 到 1。接近区间两端的值表示特征间存在强正相关或强负相关的线性关系。

我们将 color_continuous_scale 参数设置为反转的 Inferno 色带。您也可以从 Plotly 文档颜色刻度页面选择其他色带。

在 Plotly Express 中自定义图表

Plotly Express API 的一大亮点是能轻松自定义图表。

update_layout 函数包含许多参数,几乎可以修改图表的任何方面。

根据图表的展示位置,您有责任让它们在任何受众、场景或媒介中都足够美观可读。

首先要选择的事项之一是图表主题。Plotly 的主题是默认的图表配置,几乎控制所有组件。

您可以在任意绘图函数中通过 template 参数进行更改:

sample = diamonds.sample(3000)
​
fig = px.scatter(
  sample, x="price", y="carat", template="ggplot2"
)
​
fig.show()

Plot Theme Plotly Express

一些常用主题包括 ggplot2、seaborn、plotly_dark 和 presentation。您可以调用 plotly.io.templates 查看完整列表。

颜色

到目前为止,我们的散点图是二维的。但我们可以通过颜色添加额外信息。

例如,可根据钻石所属类别为图中每个点着色。为此,只需将 cut 传给 color 参数:

sample = diamonds.sample(3000)
​
fig = px.scatter(sample, x="price", y="carat", color="cut")
​
fig.show()

Colors Plotly Express

cut 参数也会在图上强制显示图例,以展示各类别的颜色。

标记大小

我们还可以通过点的大小来呈现一个数值特征。

将 size 参数设置为 carat,即可根据钻石克拉显示不同大小的点:

fig = px.scatter(sample, x="price", y="x", size="carat")
​
fig.show()

Marker Size Plotly Express

同时使用颜色与大小如何?当然可以! 

fig = px.scatter(
  sample, x="price", y="x", size="carat", color="cut"
)
​
fig.show()

Size and Color

但该图包含的信息过多,不太利于肉眼解读,因此信息量并不高。一个良好实践是不要在单个图中塞入超过三种特征。

总结

恭喜您读到这里!通过本教程,您已经学到足够的知识,可以借助我们的其他资源自行深入学习 Plotly:

您还可以了解 Plotly 的 Graph Objects API,以获得更多自定义选项、对交互与动画的完整控制,以及对高级可视化类型的支持。

主题