grozhd
grozhd

Reputation: 501

Altair: two independent sliders for a layered plot

I have a dataframe like this one (code to generate the data):

I want to compare two lines - l1 and l2, both depend on the parameter t. Each line has five values of t sampled that are numbered with t_i. I want to plot both lines, with one of the sampled points highlighted for each line. The points to highlight should be set with two sliders - one for each line.

I can get it working without the sliders:

base = alt.Chart(df).encode(x='x', y='y', color='line_name')
for line_name in df.line_name.unique():
  line = base.transform_filter(datum.line_name == line_name)
  plots += [line.mark_line(), line.mark_point().transform_filter(datum.t_i == int(line_name[1]))]
alt.layer(*plots)

Or with 1 slider:

for line_name in df.line_name.unique():
  line = base.transform_filter(datum.line_name == line_name)
  slider = alt.binding_range(min=0, max=4, step=1, name='t_i:')
  select_t_i = alt.selection_single(name="t_i", fields=['t_i'], bind=slider, init={'t_i': 0})
  plots += [line.mark_line(), 
            line.mark_point().add_selection(select_t_i).transform_filter(select_t_i)]
alt.layer(*plots[:-1])

I get the expected result:

But if I change the last line to actually add the second slider:

alt.layer(*plots[:-1]) -> alt.layer(*plots)

I get nothing - the plot does not show up and calling display does not help. How should I do that instead?

Also, I would like to see the value of t for the selected point, not the t_i. I actually added t_i because I couldn't define the slider with arbitrary values - all examples I saw, have min, max, step. How can I display the value of t, so it is updated with the slider?

Thanks!

EDIT (working code):

for line_name in df.line_name.unique():
  line = base.transform_filter(datum.line_name == line_name)
  slider = alt.binding_range(min=0, max=4, step=1, name='t_%s:' % line_name[1:])
  select_t_i = alt.selection_single(fields=['t_i'], bind=slider, init={'t_i': 0})
  plots += [line.mark_line(), 
            line.mark_point().add_selection(select_t_i).transform_filter(select_t_i)]
alt.layer(*plots[:-1])

Upvotes: 0

Views: 492

Answers (1)

jakevdp
jakevdp

Reputation: 86330

Two selections cannot have the same name. Remove name="t_i" from your selection definition (so that each one will have a unique automatically-generated name), and it will work.

Upvotes: 1

Related Questions