Expressions#
Altair allows custom interactions by utilizing the expression language of Vega for writing basic formulas. A Vega expression string is a well-defined set of JavaScript-style operations.
To simplify building these expressions in Python, Altair provides the expr
module, which offers constants and functions to construct expressions using Python syntax. Both JavaScript-syntax and Python-syntax are supported within Altair to define an expression
and an introductory example of each is available in the Calculate transform documentation so we recommend checking out that page before continuing.
Expressions inside Parameters#
In the following example, we define a range connected to a parameter named param_width
. We then assign two expressions via param
using both JavaScript and Python-syntax.
As previously,
we access the parameter values by referencing the parameters by name;
in JavaScript that is done via f"{param_width.name}"
whereas in Python it is sufficient to just type the variable name.
Using these two expressions defined inside parameters, we can connect them to an encoding channel option, such as the title color of the axis. If the width is below 200
, then the color is red
; otherwise, the color is 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
In the example above, we used a JavaScript-style ternary operator f"{param_width.name} < 200 ? 'red' : 'blue'"
which is equivalent to the Python function expr.if_(param_width < 200, 'red', 'blue')
.
The expressions defined as parameters also needed to be added to the chart within .add_params()
.
Inline Expressions#
In addition to assigning an expression within a parameter definition as shown above,
the expr()
utility function allows us to define inline expressions.
Inline expressions are not parameters,
so they can be added directly in the chart spec instead of via add_params
,
which is a convenient shorthand for writing out the full parameter code.
In this example, we modify the chart above to change the size of the points based on an inline expression. Instead of creating a conditional statement, we use the value of the expression as the size directly and therefore only need to specify the name of the parameter.
chart.mark_point(size=alt.expr(param_width.name))
In addition to modifying the mark_*
parameters,
inline expressions can be passed to encoding channels as a value definition.
Here, we make the exact same modification to the chart as in the previous example
via this alternate approach:
chart.encode(size=alt.value(alt.expr(param_width.name)))
Some parameter names have special meaning in Vega-Lite, for example, naming a parameter width
will automatically link it to the width of the chart.
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
)
Inline Expressions in Titles#
An inline expression can be used to update the chart title to show the current value of the parameter. Here, we extend the code from the previous example by using an f-string inside an inline expression. The additional quotations and plus signs are needed for the parameter value to be interpreted correctly.
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
)
In the example above,
we accessed the value of a variable parameter
and inserted it into the chart title.
If we instead want our chart title to reflect the value from a selection parameter,
it is not enough to reference only the name of the parameter.
We also need to reference the field specified by the selection parameter
(i.e. Origin
in the example below):
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
)
A Regex Search Widget#
Now that we know the basics of expressions,
let’s see how we can improve on our search input example
to make the search string match via a regex pattern.
To do this we need to use expr.regex
to define the regex string,
and expr.test
to test it against another string
(in this case the string in the Name
column).
The i
option makes the regex case insensitive,
and you can see that we have switched to using param
instead of selection_point
since we are doing something more complex
than looking up values with an exact match in the data.
To try this out, you can type mazda|ford
in the search input box below.
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)
And remember, all this interactivity is client side. You can save this chart as an HTML file or put it on a static site generator such as GitHub/GitLab pages and anyone can interact with it without having to install Python. Quite powerful!
Summary of Expressions#
Altair can utilize the expression language of Vega for writing basic formulas to enable custom interactions.
Both JavaScript-style syntax and Python-style syntax are supported in Altair to define expressions.
Altair provides the
expr
module which allows expressions to be constructed with Python syntax.Expressions can be included within a chart specification using two approaches: through a
param(expr=...)
parameter definition or inline using theexpr(...)
utility function.Expressions can be used anywhere the documentation mentions that an ExprRef is an accepted value. This is mainly in three locations within a chart specification: mark properties, encoding channel options, and within a value definition for an encoding channel. They are also supported in the chart title, but not yet for subtitles or guide titles (i.e. axis and legends, see vega/vega-lite#7408 for details).