JupyterChart#
在 Vega-Altair 5.1 中引入的 JupyterChart
类使得在图表显示后可以更新图表,并从 Python 访问 交互式图表 的状态。
支持的环境#
JupyterChart
是一个基于 AnyWidget 库构建的 Jupyter 小部件。因此,它与支持第三方 Jupyter 小部件的开发环境和仪表板工具包兼容。经过测试的环境包括
经典 Jupyter Notebook
JupyterLab
Visual Studio Code
Google Colab
Voila
注意
如果您在另一个支持 Jupyter 小部件的环境中尝试 JupyterChart
,请告诉我们进展如何,以便我们更新此列表。
基本用法#
要创建 JupyterChart
,请将常规的 Chart
实例传递给 alt.JupyterChart
构造函数。如果笔记本单元格中的最后一个表达式评估为 JupyterChart
实例,图表将自动显示。例如
import altair as alt
import pandas as pd
source = pd.DataFrame({
'a': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'],
'b': [28, 55, 43, 91, 81, 53, 19, 87, 52]
})
chart = alt.Chart(source).mark_bar().encode(
x='a',
y='b'
)
jchart = alt.JupyterChart(chart)
jchart
更新图表#
JupyterChart
的 chart
属性可以被赋给一个新的图表实例,新图表将立即替换旧图表显示。
jchart.chart = chart.mark_bar(color="crimson", cornerRadius=10)
参数:变量与选择#
如 交互式图表 中所述,Vega-Altair 丰富的交互语法构建在参数概念之上。特别是,变量参数(存储简单值)和选择参数(将用户交互映射到数据查询)。
JupyterChart
类使变量参数和选择参数都可在 Python 中使用。
变量参数#
JupyterChart 可以访问、观察、设置和链接变量参数。
访问变量参数#
图表的变量参数存储在 JupyterChart
实例的 params
属性中。可以使用常规的属性访问来访问单个命名变量参数的值。这里有一个示例,使用 绑定与小部件 将名为 cutoff
的变量参数绑定到滑块。变量 cutoff
的当前值可以通过 jchart.params.cutoff
访问。
import altair as alt
import pandas as pd
import numpy as np
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)
cutoff = alt.param(name="cutoff", bind=slider, value=50)
predicate = alt.datum.xval < cutoff
chart = alt.Chart(df).mark_point().encode(
x='xval',
y='yval',
color=alt.when(predicate).then(alt.value("red")).otherwise(alt.value("blue")),
).add_params(
cutoff
)
jchart = alt.JupyterChart(chart)
jchart
观察变量参数#
params
属性上的 observe 方法可用于注册回调函数,该函数将在参数更改时被调用。在此示例中,注册了一个简单的回调函数来打印参数 cutoff
的值。
def on_cutoff_change(change):
print(change.new)
jchart.params.observe(on_cutoff_change, ["cutoff"])
设置变量参数#
可以通过对相应的 params
属性赋值来从 Python 更新变量参数的值。这是一个通过对 jchart.params.cutoff
赋值来更新变量参数 cutoff
的示例。
链接变量参数#
因为 params
是一个 traitlet 对象,所以可以使用 ipywidgets 的 link function 将参数绑定到其他 ipywidgets。这是一个将变量参数 cutoff
链接到 ipywidgets IntSlider
值 的示例。
from ipywidgets import IntSlider, link
slider = IntSlider(23, min=0, max=100)
link((slider, "value"), (jchart.params, "cutoff"))
slider
如果 ipywidget 已链接到 Vega-Altair 变量参数,则无需再将该参数绑定到 Vega-Altair 小部件。在这里,上面的示例被更新为仅通过 IntSlider
ipywidget 来控制变量 cutoff
的值。
import pandas as pd
import numpy as np
rand = np.random.RandomState(42)
df = pd.DataFrame({
'xval': range(100),
'yval': rand.randn(100).cumsum()
})
cutoff = alt.param(name="cutoff", value=50)
predicate = alt.datum.xval < cutoff
chart = alt.Chart(df).mark_point().encode(
x='xval',
y='yval',
color=alt.when(predicate).then(alt.value("red")).otherwise(alt.value("blue"))
).add_params(
cutoff
)
jchart = alt.JupyterChart(chart)
jchart
选择参数#
JupyterChart 可以访问和观察选择参数。为了从 Python 访问选择,选择参数分为三种类型:点选择、索引选择和区间选择。这些选择类型分别由名为 PointSelection
、IndexSelection
和 IntervalSelection
的 Python 类表示。
这些选择类的实例可作为 JupyterChart 的 selections
属性的属性使用。
点选择#
PointSelection
类用于存储 Vega-Altair 点选择(由 alt.selection_point()
创建)的当前状态,前提是提供了 fields
或 encodings
规范。一个常见的例子是带有 encodings=["color"]
并绑定到图例的点选择。
import altair as alt
from vega_datasets import data
source = data.cars()
brush = alt.selection_point(name="point", encodings=["color"], bind="legend")
chart = alt.Chart(source).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.when(brush).then("Origin:N").otherwise(alt.value("grey")),
).add_params(brush)
jchart = alt.JupyterChart(chart)
jchart
PointSelection
实例可以通过 jchart.selections.point
访问(其中“point”是 alt.selection_point
的 name
参数的值)。
jchart.selections.point.value
属性包含一个字典列表,其中每个元素代表选择中的一个点。此字典列表可转换为 pandas query 字符串,如下所示
filter = " or ".join([
" and ".join([
f"`{col}` == {repr(val)}" for col, val in sel.items()
])
for sel in jchart.selections.point.value
])
source.query(filter)
例如,当选中 Japan 和 Europe 图例条目时,上面的 filter
字符串将评估为 "`Origin` == 'Japan' or `Origin` == 'Europe'"
,并且 source.query(filter)
表达式将评估为包含 source
中属于选择的行的 pandas DataFrame
。
索引选择#
IndexSelection
类用于存储 Vega-Altair 点选择(由 alt.selection_point()
创建)的当前状态,前提是未提供 fields
或 encodings
规范。在这种情况下,选择的 value
属性是选定行的索引列表。这些索引可用于 pandas DataFrame 的 iloc
属性,以提取输入 DataFrame 中选定的行。
import altair as alt
from vega_datasets import data
source = data.cars()
brush = alt.selection_point(name="point")
chart = alt.Chart(source).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.when(brush).then("Origin:N").otherwise(alt.value("grey")),
).add_params(brush)
jchart = alt.JupyterChart(chart)
jchart
警告
返回的索引仅对应于不包含聚合的图表的输入 DataFrame。如果图表包含聚合,则 alt.selection_point
规范应包含 fields
或 encodings
参数之一,这将导致 JupyterChart
包含 PointSelection
而非 IndexSelection
。
区间选择#
IntervalSelection
类用于存储 Vega-Altair 区间选择(由 alt.selection_interval()
创建)的当前状态。在这种情况下,选择的 value
属性是一个从列名到选择区间的字典
import altair as alt
from vega_datasets import data
source = data.cars()
brush = alt.selection_interval(name="interval")
chart = alt.Chart(source).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.when(brush).then("Cylinders:O").otherwise(alt.value("grey")),
).add_params(brush)
jchart = alt.JupyterChart(chart)
jchart
选择字典可以转换为 pandas query 字符串,如下所示
filter = " and ".join([
f"{v[0]} <= `{k}` <= {v[1]}"
for k, v in jchart.selections.interval.value.items()
])
source.query(filter)
例如,当 x 选择范围是 120 到 160 且 y 选择范围是 25 到 35 时,jchart.selections.interval.value
将是 {'Horsepower': [120, 160], 'Miles_per_Gallon': [25, 30]}
,filter
字符串将是 "120 <= `Horsepower` <= 160 and 25 <= `Miles_per_Gallon` <= 35"
,并且 source.query(filter)
表达式将评估为包含 source
中属于选择的行的 pandas DataFrame
。
观察选择#
与变量参数一样,可以通过在 selections
属性上使用 observe
方法来注册回调函数,该函数将在选择更改时被调用。这是一个示例,监听区间选择的变化,然后使用选择值过滤输入 DataFrame 并显示其 HTML 表示形式。使用 ipywidgets VBox
将图表和 HTML 表格组合在列布局中。
import ipywidgets
from IPython.display import display
from ipywidgets import HTML, VBox
import altair as alt
from vega_datasets import data
source = data.cars()
brush = alt.selection_interval(name="brush")
chart_widget = alt.JupyterChart(alt.Chart(source).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.when(brush).then("Cylinders:O").otherwise(alt.value("grey")),
).add_params(brush))
table_widget = HTML(value=source.iloc[:0].to_html())
def on_select(change):
sel = change.new.value
if sel is None or 'Horsepower' not in sel:
filtered = source.iloc[:0]
else:
filter_query = (
f"{sel['Horsepower'][0]} <= `Horsepower` <= {sel['Horsepower'][1]} and "
f"{sel['Miles_per_Gallon'][0]} <= `Miles_per_Gallon` <= {sel['Miles_per_Gallon'][1]}"
)
filtered = source.query(filter_query)
table_widget.value = filtered.to_html()
chart_widget.selections.observe(on_select, ["brush"])
VBox([chart_widget, table_widget])
离线使用#
默认情况下,JupyterChart
小部件从 CDN 位置动态加载其 JavaScript 依赖项,这需要活动的互联网连接。从 Altair 5.3 开始,JupyterChart 支持从 vl-convert-python
包加载其 JavaScript 依赖项,从而实现离线使用。
离线模式通过 JupyterChart.enable_offline
类方法启用。
import altair as alt
alt.JupyterChart.enable_offline()
只需调用一次此方法,之后所有显示的 JupyterCharts 都将在离线模式下运行。
可以通过向同一方法传递 offline=False
来禁用离线模式。
import altair as alt
alt.JupyterChart.enable_offline(offline=False)
限制#
设置选择#
目前尚无法从 Python 设置选择状态。