演示:探索汽车数据集¶
我们将从一个演示开始本教程,以激发您进一步学习的兴趣。本节会快速浏览许多概念(例如,数据、标记、编码、聚合、数据类型、选择等)。我们将在本教程后面更深入地探讨这些概念,因此如果感觉进度有点快,请不要担心!
在教程本身中,这将从空白笔记本开始从头完成。然而,为了方便那些想回顾我们现场演示内容的人,我会尽力在此处重现示例和讨论。
1. 导入与数据¶
我们将从导入 Altair 包开始
import altair as alt
现在我们将使用 vega_datasets 包来加载一个示例数据集
from vega_datasets import data
cars = data.cars()
cars.head()
名称 | 每加仑英里数 | 气缸数 | 排量 | 马力 | 重量(磅) | 加速度 | 年份 | 产地 | |
---|---|---|---|---|---|---|---|---|---|
0 | chevrolet chevelle malibu | 18.0 | 8 | 307.0 | 130.0 | 3504 | 12.0 | 1970-01-01 | USA |
1 | buick skylark 320 | 15.0 | 8 | 350.0 | 165.0 | 3693 | 11.5 | 1970-01-01 | USA |
2 | plymouth satellite | 18.0 | 8 | 318.0 | 150.0 | 3436 | 11.0 | 1970-01-01 | USA |
3 | amc rebel sst | 16.0 | 8 | 304.0 | 150.0 | 3433 | 12.0 | 1970-01-01 | USA |
4 | ford torino | 17.0 | 8 | 302.0 | 140.0 | 3449 | 10.5 | 1970-01-01 | USA |
请注意,此数据采用列式格式:也就是说,每列包含一个数据点的属性,每行包含数据的单个实例(此处指汽车的单个品牌&型号)。
2. 零维、一维和二维图表¶
使用 Altair,我们可以开始探索此数据。
最基本的图表包含数据集,以及一个代表每一行的标记
alt.Chart(cars).mark_point()
这是一个相当愚蠢的图表,因为它包含 406 个点,全部叠加在一起。
为了使其更有趣,我们需要将数据的列编码到图表的视觉特征中(例如,x 位置、y 位置、大小、颜色等)。
让我们使用 encode()
方法在 x 轴上编码每加仑英里数
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon'
)
这稍微好一些,但 point
标记可能不是适合这种一维图表的最佳选择。
让我们改用 tick
标记
alt.Chart(cars).mark_tick().encode(
x='Miles_per_Gallon'
)
或者我们可以通过同时编码 y 值将其扩展为二维图表。我们将回到使用 point
标记,并将 Horsepower
放在 y 轴上
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower'
)
3. 简单交互¶
Altair 最棒的功能之一是它提供的交互语法。最简单的交互类型是沿图表平移和缩放的能力;Altair 提供了一个快捷方式,可以通过 interactive()
方法启用此功能
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower'
).interactive()
这允许您通过点击和拖动,以及使用计算机的滚动/缩放行为来放大和缩小图表。
我们稍后将看到其他交互。
4. 第三个维度:颜色¶
二维图表允许我们编码数据的两个维度。让我们看看如何使用颜色编码第三个维度
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Origin'
)
请注意,当我们对颜色使用分类值时,它会为分类数据选择适当的颜色映射。
让我们看看使用连续颜色值会发生什么
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Acceleration'
)
连续颜色会生成适合连续数据的颜色比例。
介于两者之间的情况呢:有序分类,比如气缸数?
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Cylinders'
)
Altair 仍然选择一个连续值,因为气缸数是数值型的。
我们可以通过指定数据应被视为离散有序值来改进这一点;我们可以在编码后添加 ":O"
(“O”代表“序数”或“有序分类”)来实现
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Cylinders:O'
)
现在我们获得了一个带有有序颜色映射的离散图例。
5. 分箱与聚合¶
让我们快速回到我们的每加仑英里数的一维图表
alt.Chart(cars).mark_tick().encode(
x='Miles_per_Gallon',
)
表示此数据的另一种方式是创建直方图:对 x 数据进行分箱并在 y 轴上显示计数。在许多绘图库中,这是通过 hist()
等特殊方法完成的。在 Altair 中,这种分箱和聚合是声明性 API 的一部分。
为了超越简单的字段名称,我们使用 alt.X()
进行 x 编码,并使用 'count()'
进行 y 编码
alt.Chart(cars).mark_bar().encode(
x=alt.X('Miles_per_Gallon', bin=True),
y='count()'
)
如果我们想对分箱有更多控制,我们可以使用 alt.Bin
来调整分箱参数
alt.Chart(cars).mark_bar().encode(
x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=30)),
y='count()'
)
如果我们应用另一个编码(例如 color
),数据将在每个分箱内自动分组
alt.Chart(cars).mark_bar().encode(
x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=30)),
y='count()',
color='Origin'
)
如果您更喜欢为每个类别单独绘制图表,column
编码可以提供帮助
alt.Chart(cars).mark_bar().encode(
x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=30)),
y='count()',
color='Origin',
column='Origin'
)
分箱和聚合在二维中也有效;我们可以使用 rect
标记并使用颜色可视化计数
alt.Chart(cars).mark_rect().encode(
x=alt.X('Miles_per_Gallon', bin=True),
y=alt.Y('Horsepower', bin=True),
color='count()'
)
聚合不仅仅是简单的计数;我们还可以在每个分箱内聚合并计算第三个数量的平均值
alt.Chart(cars).mark_rect().encode(
x=alt.X('Miles_per_Gallon', bin=True),
y=alt.Y('Horsepower', bin=True),
color='mean(Weight_in_lbs)'
)
6. 时间序列&分层¶
到目前为止,我们一直在忽略 date
列,但查看时间趋势(例如,每加仑英里数)很有趣
alt.Chart(cars).mark_point().encode(
x='Year',
y='Miles_per_Gallon'
)
每年都有一定数量的汽车,并且数据存在很多重叠。我们可以通过在每个 x 值处绘制平均值来稍微整理一下
alt.Chart(cars).mark_line().encode(
x='Year',
y='mean(Miles_per_Gallon)',
)
或者,我们可以将标记更改为 area
,并使用 ci0
和 ci1
标记来绘制平均值估计的置信区间
alt.Chart(cars).mark_area().encode(
x='Year',
y='ci0(Miles_per_Gallon)',
y2='ci1(Miles_per_Gallon)'
)
让我们稍微调整一下这个图表:增加一些不透明度,按产地国家着色,加宽一点宽度,并添加一个更清晰的轴标题
alt.Chart(cars).mark_area(opacity=0.3).encode(
x=alt.X('Year', timeUnit='year'),
y=alt.Y('ci0(Miles_per_Gallon)', axis=alt.Axis(title='Miles per Gallon')),
y2='ci1(Miles_per_Gallon)',
color='Origin'
).properties(
width=800
)
最后,我们可以使用 Altair 的分层 API 将代表平均值的折线图叠加在代表置信区间的面积图之上
spread = alt.Chart(cars).mark_area(opacity=0.3).encode(
x=alt.X('Year', timeUnit='year'),
y=alt.Y('ci0(Miles_per_Gallon)', axis=alt.Axis(title='Miles per Gallon')),
y2='ci1(Miles_per_Gallon)',
color='Origin'
).properties(
width=800
)
lines = alt.Chart(cars).mark_line().encode(
x=alt.X('Year', timeUnit='year'),
y='mean(Miles_per_Gallon)',
color='Origin'
).properties(
width=800
)
spread + lines
7. 交互性:选择¶
让我们回到散点图,看看 Altair 提供的其他类型的交互性
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Origin'
)
回想一下,您可以在图表末尾添加 interactive()
来启用最基本的交互式比例
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Origin'
).interactive()
Altair 提供了一个通用的 selection
API 用于创建交互式图表;例如,此处我们创建一个区间选择
interval = alt.selection_interval()
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color='Origin'
).add_selection(
interval
)
当前此选择实际上什么也不做,但我们可以通过根据此选择条件化颜色来改变这一点
interval = alt.selection_interval()
alt.Chart(cars).mark_point().encode(
x='Miles_per_Gallon',
y='Horsepower',
color=alt.condition(interval, 'Origin', alt.value('lightgray'))
).add_selection(
interval
)
此选择 API 的优点在于它可以自动应用于任何复合图表;例如,此处我们可以水平连接两个图表,由于它们都具有相同的选择,它们都会做出适当的响应
interval = alt.selection_interval()
base = alt.Chart(cars).mark_point().encode(
y='Horsepower',
color=alt.condition(interval, 'Origin', alt.value('lightgray')),
tooltip='Name'
).add_selection(
interval
)
base.encode(x='Miles_per_Gallon') | base.encode(x='Acceleration')
我们还可以使用选择做更复杂的事情。例如,让我们创建一个按产地划分的汽车数量直方图,并将其堆叠在我们的散点图上
interval = alt.selection_interval()
base = alt.Chart(cars).mark_point().encode(
y='Horsepower',
color=alt.condition(interval, 'Origin', alt.value('lightgray')),
tooltip='Name'
).add_selection(
interval
)
hist = alt.Chart(cars).mark_bar().encode(
x='count()',
y='Origin',
color='Origin'
).properties(
width=800,
height=80
).transform_filter(
interval
)
scatter = base.encode(x='Miles_per_Gallon') | base.encode(x='Acceleration')
scatter & hist
本演示涵盖了 Altair 的许多可用组件。在接下来的部分中,我们将更系统地深入研究每个组件。