Search code examples
pythonpandasdataframealtairvega-lite

Python Altair Generate a table on selection


I have a histogram with a bunch of binned data and I was wondering if it would be possible to say generate a table if I select a bar from the histogram and it would display the data as it is in the original dataframe.


Solution

  • You can create the appearance of a table using mark_text. Here is an example based on this page in the docs:

    import altair as alt
    from vega_datasets import data
    
    source = data.cars()
    
    # Brush for selection
    brush = alt.selection(type='interval')
    
    # Scatter Plot
    points = alt.Chart(source).mark_point().encode(
        x='Horsepower:Q',
        y='Miles_per_Gallon:Q',
        color=alt.condition(brush, alt.value('steelblue'), alt.value('grey'))
    ).add_selection(brush)
    
    # Base chart for data tables
    ranked_text = alt.Chart(source).mark_text(align='right').encode(
        y=alt.Y('row_number:O',axis=None)
    ).transform_filter(
        brush
    ).transform_window(
        row_number='row_number()'
    ).transform_filter(
        'datum.row_number < 15'
    )
    
    # Data Tables
    horsepower = ranked_text.encode(text='Horsepower:N').properties(title=alt.TitleParams(text='Horsepower', align='right'))
    mpg = ranked_text.encode(text='Miles_per_Gallon:N').properties(title=alt.TitleParams(text='MPG', align='right'))
    origin = ranked_text.encode(text='Origin:N').properties(title=alt.TitleParams(text='Origin', align='right'))
    text = alt.hconcat(horsepower, mpg, origin) # Combine data tables
    
    # Build chart
    alt.hconcat(
        points,
        text
    ).resolve_legend(
        color="independent"
    ).configure_view(strokeWidth=0)
    

    enter image description here

    For a histogram, things are slightly different due to current limitation in Vega-Lite and you need to create a second filtered layer to visually show the selection in the histogram.

    import altair as alt
    from vega_datasets import data
    
    
    source = data.cars()
    
    # Brush for selection
    brush = alt.selection(type='single', encodings=['x'])
    
    # Histogram base
    hist_base = alt.Chart(source).mark_bar(color='grey').encode(
        x=alt.X('Horsepower:Q', bin=True),
        y='count()',
    ).add_selection(brush)
    
    # Histogram selection
    hist_selection = alt.Chart(source).mark_bar().encode(
        x=alt.X('Horsepower:Q', bin=True),
        y='count()',
    ).transform_filter(brush)
    
    # Base chart for data tables
    ranked_text = alt.Chart(source).mark_text(align='right').encode(
        y=alt.Y('row_number:O',axis=None)
    ).transform_filter(
        brush
    ).transform_window(
        row_number='row_number()'
    ).transform_filter(
        'datum.row_number < 15'
    )
    
    # Data Tables
    horsepower = ranked_text.encode(text='Horsepower:N').properties(title=alt.TitleParams(text='Horsepower', align='right'))
    mpg = ranked_text.encode(text='Miles_per_Gallon:N').properties(title=alt.TitleParams(text='MPG', align='right'))
    origin = ranked_text.encode(text='Origin:N').properties(title=alt.TitleParams(text='Origin', align='right'))
    text = alt.hconcat(horsepower, mpg, origin) # Combine data tables
    
    # Build chart
    alt.hconcat(
        hist_base+hist_selection,
        text
    ).resolve_legend(
        color="independent"
    ).configure_view(strokeWidth=0)
    

    enter image description here