Search code examples
sliderconcatenationbar-chartaltair

How to concat two bar charts in Altair with space between series?


I have the following code to generate two bar charts. The first one is a "Central" scenario that needs to be always visible. The second represents multiple stress scenarios with values depending on two sliders.

My problem is to concat the two charts, letting spaces between the two series and making them visible in any cases (like a grouped bar chart).

Here is my code :

import altair as alt
from vega_datasets import data

pvfp=Res.loc[(Res.Item=="PVFP")&(Res.annee>0)]


base = alt.Chart(pvfp, width=500, height=300).mark_bar(color="Green").encode(
    x=alt.X('annee:Q'),
    y='valeur:Q',
    tooltip="valeur:Q"
)
central = alt.Chart(pvfp.loc[(Res.TS=='Central')&(Res.TRA=='Central')], width=500, height=300).mark_bar().encode(
    x=alt.X('annee:Q'),
    y='valeur:Q',
    tooltip="valeur:Q"
)


# A slider filter
TRA_slider = alt.binding_range(min=-40, max=20, step=10,name="Sensi TRA :")
TS_slider = alt.binding_range(min=-20, max=20, step=5,name="Sensi TS : ")

slider1 = alt.selection_single(bind=TRA_slider, fields=['TRA2'],init={'TRA2': 0})
slider2 = alt.selection_single(bind=TS_slider, fields=['TS2'],init={'TS2': 0})

filter_TRA = base.add_selection(
    slider1,slider2
).transform_filter(
    slider1&slider2
).properties(title="Sensi_TRA")

central + filter_TRA

And a view of the chart I obtain for now :

enter image description here

If you have any idea of a way to do that, I would be very grateful.

UPDATE : Here is a reproductible example of the same problem.

import altair as alt
import pandas as pd
from vega_datasets import data

dataset = data.population.url
source=pd.read_json(dataset)
source2=df.loc[df.year==1900]


pink_blue = alt.Scale(domain=('Male', 'Female'),
                      range=["steelblue", "salmon"])

slider = alt.binding_range(min=1900, max=2000, step=10)
select_year = alt.selection_single(name="year", fields=['year'],
                                   bind=slider, init={'year': 2000})

chart1 = alt.Chart(source).mark_bar().encode(
    x=alt.X('age:O', title=None),
    y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
).properties(
    width=300
).add_selection(
    select_year
).transform_filter(
    select_year
)
chart2 = alt.Chart(source2).mark_bar(color="green").encode(
    x=alt.X('age:O', title=None),
    y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
)
chart1+chart2

As described, what I would like is to find a way to separate the two series and obtain an output like in the example mentioned by @joelostblom

Hope it's more clear


Solution

  • You can do this with a combination of bandPaddingInner and xOffset. For example:

    import altair as alt
    import pandas as pd
    from vega_datasets import data
    
    dataset = data.population.url
    source=pd.read_json(dataset)
    source2=source.loc[source.year==1900]
    
    
    pink_blue = alt.Scale(domain=('Male', 'Female'),
                          range=["steelblue", "salmon"])
    
    slider = alt.binding_range(min=1900, max=2000, step=10)
    select_year = alt.selection_single(name="year", fields=['year'],
                                       bind=slider, init={'year': 2000})
    
    chart1 = alt.Chart(source).mark_bar(
        xOffset=-3
    ).encode(
        x=alt.X('age:O', title=None),
        y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
    ).properties(
        width=300
    ).add_selection(
        select_year
    ).transform_filter(
        select_year
    )
    chart2 = alt.Chart(source2).mark_bar(
        xOffset=5,
        color="green",
    ).encode(
        x=alt.X('age:O', title=None),
        y=alt.Y('people:Q', scale=alt.Scale(domain=(0, 12000000))),
    )
    (chart1+chart2).configure_scale(bandPaddingInner=0.6)
    

    enter image description here