- 数据可视化
【免费下载链接】altair
Declarative visualization library for Python
本文围绕 Altair 中的 Lookup 变换(Chart.transform_lookup/LookupTransform)展开,系统讲解如何在不依赖 pandas 预处理的情况下,于图表规范内部把主数据源与另一数据源按字段进行"单边连接",并给出人群-分组关联、美国县级失业率地理可视化等可直接运行的实战示例,同时从 api.py 与 core.py 源码层面剖析其参数语义、底层结构(LookupData/LookupSelection)与类型兼容性陷阱。
Lookup 变换是什么:图表内的"单边连接"
Lookup 变换(Lookup Transform)的作用是用一个数据源中的值去扩充(enrich)主数据源,它本质上等价于数据库中的一次单侧连接(one-sided join)。与需要先把数据下载到本地、用 pandas 预先合并再交给图表的做法不同,Lookup 变换直接把关联逻辑写进图表的 Vega-Lite 规范里,由渲染引擎在浏览器端完成合并。这在数据源是 URL 或实时流式数据、无法或不适合在 Python 侧做预处理时尤其有价值。
在 Altair 中,Lookup 变换通过顶层图表的Chart.transform_lookup方法添加。例如,当手头有两份数据——一份是人员的姓名、身高、体重,另一份是每个人所属的分组信息——虽然两份数据可以各自独立可视化,但要绘制"每个分组的平均年龄"这类需要同时引用两份数据的特征图,就必须先把它们合并起来。
参考原始文档:doc/user_guide/transform/lookup.rst
两种合并思路:pandas 预处理 vs 图表内 Lookup
方式一:使用 pandas.merge 在 Python 侧合并
传统做法是先下载数据,用 pandas 完成合并后再绘图。pandas 提供了非常丰富的合并、连接工具(如merge、join、concat等)。对于上面的"人员 + 分组"数据,可以用左连接把两组数据合二为一:
import altair as alt import pandas as pd # 示例数据来自 altair.datasets from altair.datasets import data people = data.lookup_people() groups = data.lookup_groups() merged = pd.merge(groups, people, how='left', left_on='person', right_on='name') alt.Chart(merged).mark_bar().encode( x='mean(age):Q', y='group:O' )这里指定的是左连接(how='left'):对于groups中"person"列的每一个条目,去people的"name"列中寻找对应值,并把匹配到的行追加进数据。合并之后,就能轻松画出"每个分组的平均年龄"柱状图。
方式二:使用 Lookup 变换在图表规范内合并
对于通过 URL 提供或处于流式传输中的数据,如果先下载到本地再用 pandas 做预处理并不理想,这时就该用 Altair 的transform_lookup。下面这段代码完全在图表规范内部完成同样的合并,无需任何 pandas 预处理:
import altair as alt from altair.datasets import data people = data.lookup_people() groups = data.lookup_groups() alt.Chart(groups).mark_bar().encode( x='mean(age):Q', y='group:O' ).transform_lookup( lookup='person', from_=alt.LookupData(data=people, key='name', fields=['age', 'height']) )其中:
lookup='person':指定在主数据源(这里是groups)中用于匹配的字段名;from_=alt.LookupData(data=people, key='name', fields=['age', 'height']):指定辅助数据源,即一个LookupData结构,其中data是要去查找的第二份数据,key是辅助数据源中用于匹配的键字段,fields是从辅助数据源中提取出来的字段列表。
注意 Altair 中的from_之所以带下划线后缀,是因为from是 Python 保留字;API 层会把from_正确映射为 Vega-Lite 规范中的from属性(见 api.py 中kwargs["from"] = from_的处理)。
transform_lookup 的完整参数语义
根据 api.py 中Chart.transform_lookup的方法签名,以及底层 LookupTransform schema 包装类,该方法支持以下参数:
| 参数 | 类型 | 说明 |
|---|---|---|
lookup | str | 主数据源中用于匹配的键字段(Key in primary data source)。必填。 |
from_ | LookupData或LookupSelection | 辅助数据引用:可以是另一个数据源(LookupData),也可以是某个选择参数(LookupSelection)。 |
as_ | str或list[str] | 存放查询结果的输出字段名。对数据查找(data lookup)而言:若已指定from_.fields则可省略(将直接使用那些字段名);若未指定from_.fields,则as_必须是一个字符串。对选择查找(selection lookup)而言该参数可选:省略时结果存放在以选择名称命名的属性下;指定时则必须与from_.fields对应。API 层会将as_映射为规范中的as(见 api.py)。 |
default | 任意值 | 查找失败(未匹配到)时使用的默认值。默认值为null。 |
**kwargs | — | 透传给底层core.LookupTransform的额外参数。 |
方法内部把参数组装后通过self._add_transform(core.LookupTransform(**kwargs))挂载到图表的transform数组中(api.py),因此一个图表中可以链式叠加多个 transform。此外,若同时传入as_与as(或from_与from),API 会抛出ValueError以提示参数重复(api.py)。
底层结构:LookupData 与 LookupSelection
LookupTransform的from属性可以是两种结构之一(参见 vega-lite-schema.json 中的anyOf定义):
LookupData:从辅助数据源查找
在 core.py 中,LookupData接受三个参数:
| 参数 | 类型 | 说明 |
|---|---|---|
data | Data及其子类(UrlData、InlineData、NamedData、Generator等) | 要去查找的辅助数据源。必填。 |
key | str/FieldName | 辅助数据中用于匹配的键字段。必填(JSON schema 中data与key均为required)。 |
fields | Sequence[str / FieldName] | 需要从辅助数据中提取的字段列表;若不指定,则查询整个对象。可选。 |
值得注意的一点是:LookupData在 Altair API 层有一个专门包装类(api.py),它重写了to_dict,在序列化前会对data调用_prepare_data(api.py)——这意味着data参数可以直接传 pandas DataFrame 或其它被 data transformers 识别的对象,Altair 会在导出规范时自动完成内联数据与命名数据集的整理。数据既可以像人群示例那样直接传 DataFrame,也可以通过alt.UrlData(url)包装一个远程 URL(例如 tests/vegalite/v6/test_api.py 中alt.LookupData(alt.UrlData("foo.csv"), "id", ["rate"])的写法)。
LookupSelection:从选择参数查找
在 core.py 中,LookupSelection用于从图表中已有的**选择参数(selection parameter)**中查找值:
| 参数 | 类型 | 说明 |
|---|---|---|
key | str/FieldName | 数据中用于匹配的键字段。必填。 |
param | str/ParameterName | 用于查找的选择参数名称。必填。 |
fields | Sequence[str / FieldName] | 需要提取的字段;不指定则查询整个对象。可选。 |
例如,tests/vegalite/v6/test_api.py 展示了alt.LookupSelection(key="key", param="sel")与transform_lookup("a", from_=lookup_selection, as_="a", default="b")的组合用法,其序列化结果与LookupTransform的数据查找形态完全一致。这一特性使得 Lookup 变换可以在交互式图表中把用户选择状态(如点击、刷选)映射为数据行,用于驱动跨视图联动。
关键注意事项:键值与数据类型的兼容性
Lookup 匹配基于字段值的精确相等比较,因此必须确保主数据源中的lookup字段与辅助数据源中的key字段使用兼容的值与数据类型。一个典型的坑是零填充空间 ID(zero-padded spatial ID):字符串形式的"06001"永远不会匹配上数值形式的6001。如果你的 DataFrame 中空间 ID 是零填充字符串、而地理数据使用的是数值 ID,请在创建图表之前把列转换成兼容类型,例如在 pandas 中执行:
df["id"] = df["spatial_id"].astype(int)这一规则同样适用于其它类型的编码差异(字符串 vs 数值、大小写不一致、前后空格等),在正式使用前值得对两个键列的数据类型做一次一致性检查。
实战示例:用 Lookup 变换绘制美国县级失业率地图
Lookup 变换在地理可视化中尤为常用——把普通表格数据与描述地理边界的 TopoJSON 数据组合在一起,正是它的典型场景。下面的示例展示全美各县级失业率的可视化:
import altair as alt from altair.datasets import data counties = alt.topo_feature(data.us_10m.url, 'counties') unemp_data = data.unemployment.url alt.Chart(counties).mark_geoshape().encode( color='rate:Q' ).transform_lookup( lookup='id', from_=alt.LookupData(unemp_data, 'id', ['rate']) ).properties( projection={'type': 'albersUsa'}, width=500, height=300 )工作原理拆解:
alt.topo_feature(data.us_10m.url, 'counties')加载美国州郡边界 TopoJSON,作为主数据源,其中每个县以id标识;data.unemployment.url提供失业率表格数据(URL 数据源),作为辅助数据源;transform_lookup(lookup='id', from_=alt.LookupData(unemp_data, 'id', ['rate']))以id为键把失业率rate字段"贴"到对应的县边界几何对象上;encode(color='rate:Q')用查到的rate数值驱动颜色映射,projection={'type': 'albersUsa'}采用适用于美国的 Albers 投影。
从源码结构看,这个模式在仓库的示例与测试中反复出现:例如 tests/examples_arguments_syntax/choropleth.py 与 tests/examples_methods_syntax/maps_faceted_species.py 均使用transform_lookup把表格数据关联到地理边界,choropleth_repeat.py甚至通过variable_list一次关联多个变量,验证了 Lookup 变换在多变量专题地图中的可扩展性。
延伸:更多组合用法与典型场景
- 仅指定 key、不指定 fields:当
fields省略时,辅助数据源中整条记录都会被查询并附加到主数据行上。例如 tests/examples_arguments_syntax/maps_faceted_species.py 中alt.LookupData(data=counties, key='id')不带fields的写法。 - 多字段提取:在
fields中列出多个字段(如人群示例的['age', 'height']),查找后这些字段会作为独立列并入主数据,可直接参与x='mean(age):Q'之类的聚合编码。 - 默认值兜底:通过
default参数为未匹配上的记录提供兜底值(默认null),避免缺失值影响后续计算。 - 与其它变换链式组合:
transform_lookup返回图表对象本身以支持链式调用,可与transform_filter、transform_aggregate、transform_window等任意变换叠加使用。
小结
Lookup 变换把数据关联能力从 Python 侧迁移到了图表规范内部,让基于 URL、流式数据的可视化无需本地预处理即可完成多数据源整合。掌握transform_lookup的lookup/from_/as_/default四个核心参数,理解LookupData(数据查找)与LookupSelection(选择查找)两种底层结构,并时刻留意键字段的类型兼容性,你就能在人群统计、地理专题图、交互联动等场景中熟练运用这一能力。更完整的参数细节可继续查阅 api.py、core.py 以及 vega-lite-schema.json 中的对应定义。
- 数据可视化
【免费下载链接】altair
Declarative visualization library for Python
相关推荐
Altair数据可视化:图表自定义完全指南
Altair数据可视化:图表自定义完全指南 还在为Altair图表的美观度和专业性发愁?想要打造符合品牌风格的个性化可视化效果?本文将为您全面解析Altair图
数据可视化Altair 数据可视化库:图表保存全指南
Altair 数据可视化库:图表保存全指南 还在为如何保存和分享你的数据可视化作品而烦恼吗?Altair 作为 Python 生态中最优雅的声明式可视化库,提供
数据可视化Polars 数据可视化完整指南:从内置 Altair 绘图到六种主流可视化库实战
Polars 数据可视化完整指南:从内置 Altair 绘图到六种主流可视化库实战 Polars 本身是专注于数据查询与变换的高性能 DataFrame 引擎,
数据分析大数据
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考