You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于Altair的通道选择动态更新风味筛选器的可选选项?

问题描述

我正在使用Altair构建可视化图表,当前实现的flavor选择器可选选项为固定列表,不会随channel的选择动态更新。例如通道a仅包含spicy风味,但选择a时flavor选择器仍显示mild选项。需要实现flavor选择器根据用户选择的channel自动更新可选选项,同时想知道使用JupyterChart是否能实现该交互并生成具备相同交互性的HTML图表。

示例代码

import sys
import polars as pl
import altair as alt
import numpy as np


# ============================================
# Creating the dummy data dataframe

channels = pl.DataFrame(pl.Series("channel", ["a", "b"]))
flavors = pl.DataFrame(pl.Series("flavor", ["spicy", "mild"]))
dates = pl.DataFrame(pl.Series("date", [0, 1]))

flavors_dates = flavors.join(dates, how="cross")
channels_flavors_dates = channels.join(flavors_dates, how="cross").filter(
    ~(pl.col.channel.eq("a") & pl.col.flavor.ne("spicy"))
)

rng = np.random.default_rng(seed=0)

df = channels_flavors_dates.with_columns(
    pl.Series(
        "stock",
        rng.integers(0, 11, size=len(channels_flavors_dates)),
    )
)

sys.displayhook(df)

# ============================================

channel_selection = alt.selection_point(
    "channel_selection",
    fields=["channel"],
    bind=alt.binding_select(
        options=list(df["channel"].unique()), name="channel_selector"
    ),
)

# the problem is that this is initialized with too many flavor options, as it is
# insensitive to the channel selection
flavor_selection = alt.selection_point(
    "flavor_selection",
    fields=["flavor"],
    # options is a required property...
    bind=alt.binding_select(
        options=list(df["flavor"].unique()), name="flavor_selector"
    ),
)

alt.Chart(df).mark_bar().encode(alt.X("date:O"), alt.Y("stock:Q")).add_params(
    channel_selection, flavor_selection
).transform_filter(channel_selection).transform_filter(flavor_selection)

虚拟数据集

shape: (6, 4)
┌─────────┬────────┬──────┬───────┐
│ channel ┆ flavor ┆ date ┆ stock │
│ ---     ┆ ---    ┆ ---  ┆ ---   │
│ str     ┆ str    ┆ i64  ┆ i64   │
╞═════════╪════════╪══════╪═══════╡
│ a       ┆ spicy  ┆ 0    ┆ 9     │
│ a       ┆ spicy  ┆ 1    ┆ 7     │
│ b       ┆ spicy  ┆ 0    ┆ 5     │
│ b       ┆ spicy  ┆ 1    ┆ 2     │
│ b       ┆ mild   ┆ 0    ┆ 3     │
│ b       ┆ mild   ┆ 1    ┆ 0     │
└─────────┴────────┴──────┴───────┘

解决方案

一、实现Flavor选择器动态更新

要实现选择器联动,不能使用固定的options参数,需利用Altair的条件绑定功能,根据channel_selection的当前值动态生成flavor选项。修改后的完整代码如下:

import sys
import polars as pl
import altair as alt
import numpy as np

# 生成虚拟数据(原代码保留)
channels = pl.DataFrame(pl.Series("channel", ["a", "b"]))
flavors = pl.DataFrame(pl.Series("flavor", ["spicy", "mild"]))
dates = pl.DataFrame(pl.Series("date", [0, 1]))

flavors_dates = flavors.join(dates, how="cross")
channels_flavors_dates = channels.join(flavors_dates, how="cross").filter(
    ~(pl.col.channel.eq("a") & pl.col.flavor.ne("spicy"))
)

rng = np.random.default_rng(seed=0)
df = channels_flavors_dates.with_columns(
    pl.Series("stock", rng.integers(0, 11, size=len(channels_flavors_dates)))
)

# 通道选择器:添加初始选中值,确保页面加载时联动生效
channel_selection = alt.selection_point(
    "channel_selection",
    fields=["channel"],
    bind=alt.binding_select(options=list(df["channel"].unique()), name="Channel: "),
    init={"channel": "a"}
)

# 动态风味选择器:根据通道选择过滤选项
flavor_selection = alt.selection_point(
    "flavor_selection",
    fields=["flavor"],
    bind=alt.binding_select(
        options=alt.condition(
            channel_selection,
            # 选中通道后,筛选对应通道的有效风味
            alt.expr.filter(
                list(df["flavor"].unique()),
                lambda f: alt.expr.any(df.filter(pl.col.channel == channel_selection.channel)["flavor"] == f)
            ),
            # 初始化时显示所有选项
            list(df["flavor"].unique())
        ),
        name="Flavor: "
    )
)

# 构建图表(原逻辑保留)
chart = alt.Chart(df).mark_bar().encode(
    alt.X("date:O", title="Date"),
    alt.Y("stock:Q", title="Stock")
).add_params(
    channel_selection, flavor_selection
).transform_filter(channel_selection).transform_filter(flavor_selection)

chart

核心逻辑说明

  • 使用alt.condition将flavor选择器的options与channel_selection绑定,实现动态过滤。
  • 通过alt.expr.filter和lambda表达式,从所有风味中筛选出当前选中通道对应的有效选项。
  • 给channel_selection设置init初始值,确保页面加载时flavor选择器直接显示对应通道的选项。

二、JupyterChart与HTML导出

1. JupyterChart支持该交互

Altair v5+引入的JupyterChart完全支持这种联动交互,只需将最后一行的chart替换为:

alt.JupyterChart(chart)

在Jupyter Notebook/Lab中即可正常使用动态选择器。

2. 导出带交互的HTML

无论使用普通alt.Chart还是JupyterChart,都可以通过以下代码导出保留完整交互的HTML文件:

chart.save("dynamic_flavor_selector.html")

打开导出的HTML文件后,channel和flavor选择器的联动功能会完全保留,与Jupyter环境中的交互效果一致。


内容的提问来源于stack exchange,提问作者bzm3r

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:02:02