Search code examples
pythondata-visualizationaltair

Show selection box over multiple rows in Altair


I want to create a plot using altair that spans multiple rows and is interactive. Highlighting a subregion of the plot correctly highlights that region in all rows by changing the color outside that region to grey. Here's my MWE with a screenshot of the interactive plot that's generated:

import altair as alt
from vega_datasets import data

source = data.stocks()

brush = alt.selection_interval(encodings=["x"], mark=alt.BrushConfig(fill="green"))

histogram = (
    alt.Chart(source)
    .mark_bar()
    .encode(
        x="date:T",
        y="price:Q",
        color=alt.condition(brush, "symbol:N", alt.value("gray"), legend=None),
    )
)
   
overlay = (
    alt.Chart(source)
    .mark_rect(opacity=0.8)
    .encode(
        x="date:T",
        y="proce:Q",
        color=alt.condition(brush, alt.value("green"), alt.value("gray"), legend=None),
    )
)
(histogram + overlay).properties(height=50, width=400).facet(
    row=alt.Row("symbol:N",)
).transform_filter(alt.datum.symbol != "GOOG").add_selection(brush)

enter image description here

I selected a range in the first row and only that row has the green background that I tried to add to every row (via the overlay). Clearly I failed. Is there a way to have the green selection box on all rows, regardless of which row I select the range from?


Solution

  • It is not possible to show a selection on multiple charts https://github.com/vega/vega-lite/issues/3686, https://github.com/vega/vega-lite/issues/7030, vega-lite: synchron selection in multiple chart.

    Building on your approach, you could do something like this (can't figure out how to remove the spacing/padding between the bars in the overlay, might be an issue with temporal scales or strokes):

    import altair as alt
    from vega_datasets import data
    
    source = data.stocks()
    
    brush = alt.selection_interval(encodings=["x"], mark=alt.BrushConfig(fill='w'), empty='none')
    
    histogram = (
        alt.Chart(source)
        .mark_bar()
        .encode(
            x="date:T",
            y="price:Q",
            color=alt.condition(brush, "symbol:N", alt.value("gray"), legend=None),
        )
    )
       
    overlay = (
        alt.Chart(source)
        .mark_bar(color='green')
        .encode(
            x=alt.X('date:T', scale=alt.Scale(paddingInner=0)),
            y=alt.datum(250),
            opacity=alt.condition(brush, alt.value(0.1), alt.value(0), legend=None),
        )
    )
    (histogram + overlay).properties(height=50, width=400).facet(
        row=alt.Row("symbol:N",)
    ).transform_filter(alt.datum.symbol != "GOOG").add_selection(brush)
    

    enter image description here