Consider the following MRE:
# create data
df = pd.DataFrame()
df['x'] = [0, 1, 2] * 3
df['y'] = [0] * 3 + [1] * 3 + [2] * 3
# create selections
click_select = alt.selection_point(name='_click_select_', toggle='true', encodings=['x','y'], empty=False, clear=False)
box_select = alt.selection_interval(name='_box_select_', empty=False,
on="[mousedown[event.altKey], mouseup] > mousemove",
translate="[mousedown[event.altKey], mouseup] > mousemove!")
# initialize
base = alt.Chart(df).mark_point().encode(x='x', y='y')
base = base.encode(color=alt.when(click_select | box_select).then(alt.value('red')).otherwise(alt.value('blue')))
base = base.add_params(click_select, box_select)
This is a scatterplot with 9 points. I would expect that these points are BLUE to start, and then will be RED when selected by either clicking on them directly or enclosing them in the box select while holding alt.
However, the result is a plot where all points are RED to start. Only once BOTH the click_select has clicked a point and box_select has created a box does the plot appear as intended, with selected points in red and all others in blue.
My instinct tells me this has something to do with the "empty" parameter, as the behavior looks like all points "pass" the "click_select | box_select" logical combination even when nothing is selected. However, since I put empty=False for both selections, I thought both should evaluate as False and therefore the 'or' should be False as well, triggering the 'otherwise' condition. I've tested changing the "empty" parameter on both selections AND as an additional argument to when() but it seems to have no effect. And even then, why would it require that both selections be active to work, when it is an 'or' condition?
How should I achieve my desired behavior, and what am I missing about "empty"?
Your understanding is correct. There is a bug in altair where the empty
parameter is not preserve with parameter composition, which you can track in this issue https://github.com/vega/altair/issues/3598