表达式#

Altair 通过利用 Vega 的表达式语言编写基本公式来实现自定义交互。Vega 表达式字符串是一组定义良好的 JavaScript 风格的操作。为了简化在 Python 中构建这些表达式,Altair 提供了 expr 模块,该模块提供了常量和函数,用于使用 Python 语法构建表达式。Altair 中同时支持 JavaScript 语法和 Python 语法来定义表达式,每种语法都有一个入门示例,可以在 Calculate 转换文档中找到,因此我们建议在继续之前查阅该页面。

参数中的表达式#

在以下示例中,我们定义了一个与名为 param_width 的参数关联的范围。然后,我们通过 param 使用 JavaScript 和 Python 语法分别赋值两个表达式。如前所述,我们通过引用参数名称来访问参数值;在 JavaScript 中通过 f"{param_width.name}" 完成,而在 Python 中只需键入变量名即可。使用这两个在参数中定义的表达式,我们可以将它们连接到编码通道选项,例如轴的标题颜色。如果宽度小于 200,颜色为 red;否则,颜色为 blue

import altair as alt
import numpy as np
import pandas as pd

rand = np.random.RandomState(42)
df = pd.DataFrame({
    'xval': range(100),
    'yval': rand.randn(100).cumsum()
})

bind_range = alt.binding_range(min=100, max=300, name='Slider value:  ')
param_width = alt.param(bind=bind_range)

# Examples of how to write both js and python expressions
param_color_js_expr = alt.param(expr=f"{param_width.name} < 200 ? 'red' : 'black'")
param_color_py_expr = alt.param(expr=alt.expr.if_(param_width < 200, 'red', 'black'))

chart = alt.Chart(df).mark_point().encode(
    alt.X('xval').axis(titleColor=param_color_js_expr),
    alt.Y('yval').axis(titleColor=param_color_py_expr)
).add_params(
    param_width,
    param_color_js_expr,
    param_color_py_expr
)
chart

在上面的示例中,我们使用了 JavaScript 风格的三元运算符 f"{param_width.name} < 200 ? 'red' : 'blue'",它等价于 Python 函数 expr.if_(param_width < 200, 'red', 'blue')。定义为参数的表达式也需要在图表中通过 .add_params() 添加。

内联表达式#

除了如上所示在参数定义中赋值表达式外,expr() 工具函数允许我们定义内联表达式。内联表达式不是参数,因此可以直接添加到图表规范中,而不是通过 add_params 添加,这是一种方便的简写方式,避免编写完整的参数代码。

在此示例中,我们修改上面的图表,根据内联表达式改变点的大小。我们没有创建条件语句,而是直接使用表达式的值作为大小,因此只需指定参数的名称。

chart.mark_point(size=alt.expr(param_width.name))

除了修改 mark_* 参数外,内联表达式还可以作为值定义传递给编码通道。在这里,我们通过这种替代方法对图表进行了与上一个示例完全相同的修改

chart.encode(size=alt.value(alt.expr(param_width.name)))

某些参数名称在 Vega-Lite 中具有特殊含义,例如,将参数命名为 width 会自动将其链接到图表的宽度。

bind_range = alt.binding_range(min=100, max=300, name='Chart width: ')
param_width = alt.param('width', bind=bind_range)

alt.Chart(df).mark_point().encode(
    alt.X('xval'),
    alt.Y('yval')
).add_params(
    param_width
)

标题中的内联表达式#

内联表达式可用于更新图表标题,以显示参数的当前值。在这里,我们通过在内联表达式内部使用 f-string 来扩展前一个示例的代码。参数值需要额外的引号和加号才能正确解释。

bind_range = alt.binding_range(min=100, max=300, name='Chart width: ')
param_width = alt.param('width', bind=bind_range)

# In Javascript, a number is converted to a string when added to an existing string,
# which is why we use this nested quotation.
title=alt.Title(alt.expr(f'"This chart is " + {param_width.name} + " px wide"'))
alt.Chart(df, title=title).mark_point().encode(
    alt.X('xval'),
    alt.Y('yval')
).add_params(
    param_width
)

在上面的示例中,我们访问了一个可变参数的值并将其插入到图表标题中。如果我们要让图表标题反映来自选择参数的值,仅引用参数名称是不够的。我们还需要引用选择参数指定的字段(即下例中的 Origin

from vega_datasets import data

cars = data.cars.url
input_dropdown = alt.binding_select(options=['Europe', 'Japan', 'USA'], name='Region ')
selection = alt.selection_point(fields=['Origin'], bind=input_dropdown, value='Europe')

title = alt.Title(alt.expr(f'"Cars from " + {selection.name}.Origin'))

alt.Chart(cars, title=title).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
).add_params(
    selection
).transform_filter(
    selection
)

正则表达式搜索控件#

现在我们了解了表达式的基础知识,让我们看看如何改进搜索输入示例,使其通过正则表达式模式进行匹配。为此,我们需要使用 expr.regex 定义正则表达式字符串,并使用 expr.test 将其与另一个字符串(在本例中是 Name 列中的字符串)进行测试。i 选项使正则表达式不区分大小写,您可以看到我们已经切换到使用 param 而不是 selection_point,因为我们正在进行比在数据中精确匹配查找值更复杂的操作。要尝试此功能,您可以在下面的搜索输入框中键入 mazda|ford

search_input = alt.param(
    value='',
    bind=alt.binding(
        input='search',
        placeholder="Car model",
        name='Search ',
    )
)
search_matches = alt.expr.test(alt.expr.regexp(search_input, "i"), alt.datum.Name)

alt.Chart(cars).mark_point(size=60).encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    tooltip='Name:N',
    opacity=alt.when(search_matches).then(alt.value(1)).otherwise(alt.value(0.05)),
).add_params(search_input)

请记住,所有这些交互性都在客户端进行。您可以将此图表保存为 HTML 文件,或将其放在 GitHub/GitLab Pages 等静态网站生成器上,任何人都可以与之交互,无需安装 Python。相当强大!

表达式总结#

  • Altair 可以利用 Vega 的表达式语言编写基本公式,从而实现自定义交互。

  • Altair 中支持 JavaScript 风格和 Python 风格的语法来定义表达式。

  • Altair 提供了 expr 模块,允许使用 Python 语法构建表达式。

  • 可以在图表规范中使用两种方法包含表达式:通过 param(expr=...) 参数定义或使用 expr(...) 工具函数内联。

  • 表达式可用于文档中提及接受 ExprRef 的任何位置。这主要在图表规范内的三个位置:标记属性、编码通道选项以及编码通道的值定义内。它们也支持在图表标题中使用,但尚不支持副标题或引导标题(即坐标轴和图例,详见 vega/vega-lite#7408)。