绑定与微件#

了解参数类型和条件后,您现在可以将参数绑定到图表元素(例如图例)和微件(例如下拉列表和滑块)。这是通过在 paramselection 中使用 bind 选项来完成的。根据Vega-lite 绑定文档的说明,有三种可用的绑定类型

  1. 点和区间选择可用于数据驱动的交互式元素,例如基于数据中的值进行高亮和筛选。

  2. 滑块和复选框可用于逻辑驱动的交互式元素,例如基于这些微件中的绝对值进行高亮和筛选。

  3. 区间选择可以绑定到比例尺,例如放大地图。

下表总结了 Vega-Lite 中支持的输入元素

输入元素

描述

示例

binding_checkbox

渲染为复选框,允许选择多个项目。

多重交互

binding_radio

单选按钮,强制只能选择一个

多重交互

binding_select

下拉框,用于从列表中选择单个项目

多重交互

binding_range

显示为滑块,允许沿比例尺选择。

按年龄和性别划分的美国人口

binding

支持许多 HTML 输入元素的通用方法

微件绑定#

微件是 HTML 输入元素,例如下拉列表、滑块、单选按钮和搜索框。变量和选择参数与微件结合使用有三种策略:数据驱动查找、数据驱动比较和逻辑驱动比较。

数据驱动查找#

数据驱动查找使用微件的活动值以及 selection 参数,在图表的数据集中查找具有匹配值的点。例如,我们可以建立输入微件和点选择之间的绑定,以过滤数据,如下面的示例所示,其中使用下拉列表高亮显示特定 Origin 的汽车

import altair as alt
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)
color = (
    alt.when(selection)
    .then(alt.Color("Origin:N").legend(None))
    .otherwise(alt.value("lightgray"))
)

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

请注意,尽管看起来下拉列表中从一开始就选中了一个值,但我们需要设置 value= 才能真正在图表中以初始选择开始。我们之前使用变量参数完成了此操作,选择参数遵循相同的模式,您将在下面的编码通道绑定部分中看到。

正如您上面看到的,我们仍然使用条件使图表对选择做出响应,就像我们在没有微件的情况下所做的那样。绑定和输入元素还可以用于筛选数据,允许用户只看到选定的点,如下面的示例所示。在此示例中,我们还添加了一个空选择,以说明如何在单选按钮或下拉列表(无法取消选择)中进行选择后恢复显示所有点。

# Make radio button less cramped by adding a space after each label
# The spacing will only show up in your IDE, not on this doc page
options = ['Europe', 'Japan', 'USA']
labels = [option + ' ' for option in options]

input_dropdown = alt.binding_radio(
    # Add the empty selection which shows all when clicked
    options=options + [None],
    labels=labels + ['All'],
    name='Region: '
)
selection = alt.selection_point(
    fields=['Origin'],
    bind=input_dropdown,
)

alt.Chart(cars).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    # We need to set a constant domain to preserve the colors
    # when only one region is shown at a time
    color=alt.Color('Origin:N').scale(domain=options),
).add_params(
    selection
).transform_filter(
    selection
)

除了上表中列出的微件之外,Altair 还可以通过更通用的 binding 函数访问任何 html 微件。在下面的示例中,我们使用搜索输入来筛选与搜索字符串完全匹配的点。您可以将鼠标悬停在点上以查看汽车名称,然后尝试在搜索框中输入一个名称,例如 vw pickup 以查看高亮显示的点(您需要输入完整的名称)。

search_input = alt.selection_point(
    fields=['Name'],
    empty=False,  # Start with no points selected
    bind=alt.binding(
        input='search',
        placeholder="Car model",
        name='Search ',
    )
)
alt.Chart(data.cars.url).mark_point(size=60).encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    tooltip='Name:N',
    opacity=alt.when(search_input).then(alt.value(1)).otherwise(alt.value(0.05)),
).add_params(
    search_input
)

要求精确匹配搜索语法并不总是很有用,当我们学习表达式时,我们将看到如何通过正则表达式匹配部分字符串。

数据驱动比较#

到目前为止,我们已经看到了使用选择来查找数据中精确匹配值的点。这通常很有用,但有时我们可能想要进行比精确匹配更复杂的比较。例如,我们可能想要创建一个条件,选择数据中高于或低于通过滑块指定阈值的点。对于此工作流程,建议通过 param 使用变量参数,如下所示,我们使用特殊语法 datum.xval 引用要比较的列。在列名前加上 datum 会告诉 Altair 我们想要与数据框中的列进行比较,而不是与名为 xval 的 Python 变量进行比较,如果只写 xval < selector 就会是后者的情况。

import numpy as np
import pandas as pd


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

slider = alt.binding_range(min=0, max=100, step=1, name='Cutoff ')
selector = alt.param(name='SelectorName', value=50, bind=slider)
predicate = alt.datum.xval < selector

alt.Chart(df).mark_point().encode(
   x='xval',
   y='yval',
   color=alt.when(predicate).then(alt.value("red")).otherwise(alt.value("blue")),
).add_params(
   selector
)

在这种特定情况下,我们实际上可以使用选择参数,因为可以选择值并直接在影响图表的表达式中使用。例如,这里我们创建一个滑块来选择截止值,并根据点是小于还是大于该值来着色

slider = alt.binding_range(min=0, max=100, step=1, name='Cutoff ')
selector = alt.selection_point(
    name="SelectorName",
    fields=['cutoff'],
    bind=slider,
    value=[{'cutoff': 50}]
)
predicate = alt.datum.xval < selector.cutoff

alt.Chart(df).mark_point().encode(
    x='xval',
    y='yval',
    color=alt.when(predicate).then(alt.value("red")).otherwise(alt.value("blue")),
).add_params(
    selector
)

虽然了解如何在表达式字符串中访问选择值可能很有用,但 Altair 5 中引入的参数语法通常为这种简单的交互提供了更方便的语法,因为它们也可以像我们上面看到的那样在表达式字符串中访问。同样,通常可以使用相等语句,例如 alt.datum.xval == selector 来查找精确值,但切换到选择参数并指定字段/编码通常更方便。

逻辑驱动比较#

逻辑比较是一种基于逻辑规则和条件的比较,而不是基于实际数据值本身。例如,对于复选框微件,我们希望检查复选框的状态是 True 还是 False,并根据是否选中它执行某些操作。当我们像这样使用复选框作为切换时,我们需要使用 param 而不是 selection_point,因为我们不想检查数据中是否有 True/False 值,而只是检查复选框的值是 True(选中)还是 False(未选中)

bind_checkbox = alt.binding_checkbox(name='Scale point size by "Acceleration": ')
param_checkbox = alt.param(bind=bind_checkbox)

alt.Chart(cars).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    size=alt.when(param_checkbox).then("Acceleration:Q").otherwise(alt.value(25)),
).add_params(
    param_checkbox
)

创建独立于数据的微件绑定的另一个示例涉及更通用的 binding 函数的有趣用例。在下一个示例中,此函数引入了一个颜色选择器,用户可以交互式地选择图表的颜色

color_usa = alt.param(value="#317bb4", bind=alt.binding(input='color', name='USA '))
color_europe = alt.param(value="#ffb54d", bind=alt.binding(input='color', name='Europe '))
color_japan = alt.param(value="#adadad", bind=alt.binding(input='color', name='Japan '))

alt.Chart(data.cars.url).mark_circle().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color=alt.Color(
        'Origin:N',
        scale=alt.Scale(
            domain=['USA', 'Europe', 'Japan'],
            range=[color_usa, color_europe, color_japan]
        )
    )
).add_params(
    color_usa, color_europe, color_japan
)

图例绑定#

交互式图例通常有助于聚焦于数据组。Altair 提供了 bind='legend' 选项,以方便创建可点击的图例,而无需手动构建单独的图表作为图例

selection = alt.selection_point(fields=['Origin'], bind='legend')

alt.Chart(cars).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N',
    opacity=alt.when(selection).then(alt.value(0.8)).otherwise(alt.value(0.2)),
).add_params(
    selection
)

比例尺绑定#

对于区间选择,bind 属性可以设置为 "scales" 的值。在这种情况下,绑定将自动响应图表的平移和缩放

selection = alt.selection_interval(bind='scales')

alt.Chart(cars).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N',
).add_params(
    selection
)

因为这是一种常见的模式,Altair 提供了 interactive() 方法,可以更简洁地创建比例尺绑定的选择

alt.Chart(cars).mark_point().encode(
    x='Horsepower:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N',
).interactive()

编码通道绑定#

要根据微件中的选择更新图表中显示的列,我们需要将微件绑定到编码通道。与图例和比例尺绑定不同,无法在选择初始化时设置与编码通道的绑定(例如,输入 bind='x')。相反,可以使用参数将选择的值传递给编码通道。这提供了更大的灵活性,但在解决 vega/vega-lite#7365 之前需要使用单独的计算转换(如下面的示例所示)。

在此示例中,我们通过按名称引用参数来访问参数值。通过使用参数值索引数据(通过 datum[]),我们可以提取与参数选定值匹配的数据列,并使用此数据列的值填充 x 通道。

dropdown = alt.binding_select(
    options=['Horsepower', 'Displacement', 'Weight_in_lbs', 'Acceleration'],
    name='X-axis column '
)
xcol_param = alt.param(
    value='Horsepower',
    bind=dropdown
)

alt.Chart(data.cars.url).mark_circle().encode(
    x=alt.X('x:Q').title(''),
    y='Miles_per_Gallon:Q',
    color='Origin:N'
).transform_calculate(
    x=f'datum[{xcol_param.name}]'
).add_params(
    xcol_param
)

在计算转换中使用参数允许我们定义动态计算(例如,减去不同对的列),正如您在交互式列选择图库示例中看到的那样。在该示例中,图表标题也使用表达式中的参数动态更新,这在标题中的内联表达式中有更详细的描述。请注意,目前无法根据选定的参数值动态更改轴标题,但可以使用文本标记代替(如此 SO 答案中所述),直到解决 vega/vega-lite#7264