w00dy
w00dy

Reputation: 758

Plot two dataframes in different charts with shared selector/filter in Altair

I have two pandas dataframes data and data_queue with the same structure containing similar data. The former shall be plotted as a line while the latter as a scatter plot. I need a shared selector to filter on both charts. In the example below, the selector works only if I remove scatter.

How to achieve that in Altair?

Note: I need the last layer to add tooltip, rules, text, etc. to the line plot. For sake of readability, I omitted that part here.

input_dropdown = alt.binding_select(options=data.koplus_name.unique().tolist())
selection = alt.selection_single(fields=['koplus_name'], bind=input_dropdown, name='Koplus', init={'koplus_name': input_dropdown.options[0]})


line = alt.Chart(data).mark_line().encode(
    x=alt.X('yearmonthdatehoursminutes(timestamp)', title='timestamp', scale=alt.Scale(domain=(str(data.timestamp.min()), str(data.timestamp.min() + pd.Timedelta(value=1, unit='D'))))),
    y=alt.Y('value', axis=alt.Axis(title=''), scale=alt.Scale(domain=(0, data.value.max()))),
    color=alt.Color('variable', legend=alt.Legend(title=None)),
)

scatter = alt.Chart(data_queue).mark_point().encode(
    x='green time',
    y='value',
)

chart = line + scatter

layer = alt.layer(
    chart
).add_selection(
    selection
).transform_filter(
    selection
).properties(
    width=800, height=250
).interactive(bind_y=False)

messy plot

Upvotes: 1

Views: 1528

Answers (1)

jakevdp
jakevdp

Reputation: 86310

If you want data to respond to the same selection, it has to be part of the same data source. You can either join the datasets in pandas before creating the chart, or join the datasets with a Lookup Transform within the Altair grammar.

Here is an example of the second approach, with some small datasets:

import numpy as np
import pandas as pd
import altair as alt

df1 = pd.DataFrame({
    'x': np.arange(100),
    'y': np.random.randn(100).cumsum()
})

df2 = pd.DataFrame({
    'x': np.arange(100),
    'z': np.random.randn(100).cumsum()
})

selection = alt.selection_interval(encodings=['x'])

base = alt.Chart(df1).transform_lookup(
  lookup='x',
  from_=alt.LookupData(data=df2, key='x', fields=['z'])
).mark_point(color='steelblue').encode(
  x='x:Q',
  color=alt.condition(selection, alt.value('steelblue'), alt.value('lightgray'))
)

alt.layer(
  base.encode(y='y:Q'),
  base.encode(y='z:Q')
).add_selection(
  selection
)

enter image description here

Upvotes: 3

Related Questions