Altair 内部结构#
本节将提供一些关于Altair API如何与Vega-Lite可视化规范相关的信息,以及您如何利用这些知识更有效地使用该包。
首先,重要的是要意识到,当本质被剥离到核心时,Altair 本身无法渲染可视化。Altair 是一个 API,它仅执行一个非常明确定义的操作:
Altair 提供了一种用于生成经过验证的 Vega-Lite 规范的 Python API
就这样。为了将这些规格转换为实际的可视化,需要一个正确设置的前端,但严格来说,这种渲染通常不由Altair包控制。
Altair 图表到 Vega-Lite 规范#
由于 Altair 是关于构建图表规范的基本概念,因此任何图表对象的核心功能是 to_dict() 和 to_json() 方法,它们分别将图表规范输出为 Python 字典或 JSON 字符串。例如,这里是一个简单的散点图,我们可以从中输出 JSON 表示:
import altair as alt
from vega_datasets import data
chart = alt.Chart(data.cars.url).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin:N',
).configure_view(
continuousHeight=300,
continuousWidth=300,
)
print(chart.to_json(indent=2))
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.20.1.json",
"config": {
"view": {
"continuousHeight": 300,
"continuousWidth": 300
}
},
"data": {
"url": "https://cdn.jsdelivr.net/npm/vega-datasets@v1.29.0/data/cars.json"
},
"encoding": {
"color": {
"field": "Origin",
"type": "nominal"
},
"x": {
"field": "Horsepower",
"type": "quantitative"
},
"y": {
"field": "Miles_per_Gallon",
"type": "quantitative"
}
},
"mark": {
"type": "point"
}
}
在返回字典或JSON输出之前,Altair会使用jsonschema包对其进行验证,确保其符合Vega-Lite schema。Vega-Lite schema定义了可以出现在Vega-Lite图表规范中的有效属性和值。
手握JSON schema后,可以将其传递给一个库,比如 Vega-Embed,这个库知道如何读取 规范并渲染它所描述的图表,结果是以下可视化:
Click to show code
chart
每当您在 JupyterLab、Jupyter notebook 或其他前端中使用 Altair 时, 是前端扩展从 Altair 图表对象中提取 JSON 输出并将该规范传递给适当的渲染代码。
Altair的低级对象结构#
在Altair中使用的标准API方法(例如 mark_point(),
encode(), configure_*(), transform_*() 等)
是包装低级API的高级便利函数。
该低级API本质上是一个Python对象层次结构,反映了
JSON架构定义的层次结构。
例如,我们可以选择避免使用便利方法,而是直接使用这些低级对象类型构建上述图表:
alt.Chart(
data=alt.UrlData(
url='https://vega.github.io/vega-datasets/data/cars.json'
),
mark='point',
encoding=alt.FacetedEncoding(
x=alt.PositionFieldDef(
field='Horsepower',
type='quantitative'
),
y=alt.PositionFieldDef(
field='Miles_per_Gallon',
type='quantitative'
),
color=alt.StringFieldDefWithCondition(
field='Origin',
type='nominal'
)
),
config=alt.Config(
view=alt.ViewConfig(
continuousHeight=300,
continuousWidth=300
)
)
)
这种低级方法比创建Altair图表的典型习惯用法要冗长得多,但它更清楚地显示了Altair的python对象结构与Vega-Lite的架构定义结构之间的映射。
Altair的一大优点是,这个低级对象层次结构并不是手动构建的,而是通过程序生成的,基于Vega-Lite架构,使用你可以在Altair’s repository中找到的generate_schema_wrapper.py脚本。代码的自动生成将描述从vega-lite架构传播到Python类文档字符串,从而在Altair的文档中自动生成API Reference。这意味着,随着Vega-Lite架构的发展,Altair可以非常快速地更新,只有更高级的图表方法需要手动更新。
将Vega-Lite转换为Altair#
牢记这些知识,并进行一些练习,从Vega-Lite规范构建Altair图表是相当简单的。比如,考虑Vega-Lite文档中的简单柱状图示例,它具有以下JSON规范:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple bar chart with embedded data.",
"data": {
"values": [
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
]
},
"mark": {"type": "bar"},
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"}
}
}
在最低级别,我们可以使用 from_json() 类方法从这一串 Vega-Lite JSON 构建 Altair 图表对象:
import altair as alt
alt.Chart.from_json("""
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple bar chart with embedded data.",
"data": {
"values": [
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
]
},
"mark": {"type": "bar"},
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"}
}
}
""")
同样,如果您有JSON字符串的Python字典等效项,您可以使用from_dict()方法来构建图表对象:
import altair as alt
alt.Chart.from_dict({
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"description": "A simple bar chart with embedded data.",
"data": {
"values": [
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
]
},
"mark": {"type": "bar"},
"encoding": {
"x": {"field": "a", "type": "ordinal"},
"y": {"field": "b", "type": "quantitative"}
}
})
通过更多的努力和一些明智的复制与粘贴,我们可以手动将其转换为相同图表的更具习惯性的 Altair 代码,包括从数据值构建 pandas 数据框:
import altair as alt
import pandas as pd
data = pd.DataFrame.from_records([
{"a": "A","b": 28}, {"a": "B","b": 55}, {"a": "C","b": 43},
{"a": "D","b": 91}, {"a": "E","b": 81}, {"a": "F","b": 53},
{"a": "G","b": 19}, {"a": "H","b": 87}, {"a": "I","b": 52}
])
alt.Chart(data).mark_bar().encode(
x='a:O',
y='b:Q'
)
关键是要意识到 "encoding" 属性通常通过 encode() 方法设置,编码类型通常从简写类型代码计算得出,"transform" 和 "config" 属性来自 transform_*() 和 configure_*() 方法,等等。
这种方法是Altair贡献者构建许多初始示例的过程,灵感来自于Vega-Lite示例库。在此级别上熟悉Altair与Vega-Lite之间的映射有助于在Altair的文档薄弱或不完整的地方利用Vega-Lite文档。