Search code examples
altair

Is there a way to offset concatenations manually and/or add connecting lines to concatenated charts in Altair?


I have the following concatenated chart: enter image description here

The code used to generate it is as follows:

def quarterly_avg_bar_graph(city):
    data = climate_with_seasons[climate_with_seasons['city'] == city]
    grouped = data.groupby('season')[['sunshine']].mean().reset_index()
    
    chart = alt.Chart(grouped).mark_bar().encode(
        alt.X('season:N', sort=['spring', 'summer', 'autumn', 'winter']),
        alt.Y('sunshine:Q'),
        alt.Color('season:N', scale=alt.Scale(scheme='pastel1'), sort=['spring', 'summer', 'autumn', 'winter'], legend=None)
    ).properties(
        height=75,
        width=75
    )
    
    return chart

seattle = quarterly_avg_bar_graph('Seattle')
chicago = quarterly_avg_bar_graph('Chicago')
sf = quarterly_avg_bar_graph('San Francisco')
houston = quarterly_avg_bar_graph('Houston')
miami = quarterly_avg_bar_graph('Miami')
ny = quarterly_avg_bar_graph('New York')

background = alt.Chart(states).mark_geoshape(
        fill='white',
        stroke='lightgray'
    ).properties(
        width=300,
        height=300
    ).project('albersUsa')

# Generate the points themselves
climate_points = alt.Chart(climate).mark_square(color='red').encode(
    alt.Longitude('lon:Q'),
    alt.Latitude('lat:Q'),
    alt.OpacityValue(0.05),
)

text = climate_points.mark_text(
        dx=15,
        dy=10
    ).encode(
        text='city:N'
    )

map_chart = background + climate_points + text
left = seattle & sf
right = ny & miami
middle = alt.vconcat(alt.vconcat(chicago, map_chart, center=True), houston, center=True)
final_chart = alt.hconcat(left, middle, right, center=True)
final_chart.configure_square(size=150)

I would like to make the connections between geographic location and bar graph a little more clear (move the top bar graph a little to the right, the right bottom one down a little, etc.), as well as add a line connecting each city square mark to its respective bar graph. Can this be done natively in Altair?


Solution

  • You can control the spacing between concatenated objects with the spacing parameter:

    import altair as alt
    from vega_datasets import data
    
    source = data.cars()
    
    points = alt.Chart(source).mark_point().encode(
        x='Horsepower:Q',
        y='Miles_per_Gallon:Q',
        color='Origin:N'
    )
    
    bars = alt.Chart(source).mark_bar().encode(
        y='Origin:N',
        color='Origin:N',
        x='count(Origin):Q'
    )
    
    alt.vconcat(points, bars, spacing=200)
    

    enter image description here

    I don't think that you can add an annotation that spans the space between the graphs unfortunately. You can add a line that goes outside the grid by using clip and limiting the domain as in the documentation, but it would not span the spacing between the charts (you could possibly use this line to push the charts apart instead of the spacing, but it will require a lot of fiddling I am afraid).