pythonchartsaltair

How to create an Altair faceted and layered chart with dual axis?


I'm trying to create an Altair faceted bar chart with lines that are represents other measure and would better use of a second y-axis on the right side. I don't know if it is possible using Atair. The code is as follows:

import altair as alt
import pandas as pd

data = {
    'Date': ['2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02'],
    'Value': [50, 200, 300, 150, 250, 350, 200, 200, 10, 20, 15, 20, 20, 30, 20, 30],
    'DESCR': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D'],
    'Company': ['X', 'X', 'Y', 'Y', 'X', 'X', 'Y', 'Y', 'X', 'X', 'Y', 'Y', 'X', 'X', 'Y', 'Y'],
}

source = pd.DataFrame(data)

bars = alt.Chart(source).mark_bar().transform_filter(f"(datum.DESCR=='A') | (datum.DESCR=='B')").encode(
    x='Date:N',
    y='Value:Q',
    color=alt.Color('DESCR:N', legend=alt.Legend(title=None))
)

lines = alt.Chart(source).mark_line().transform_filter(f"(datum.DESCR=='C') | (datum.DESCR=='D')").encode(
    x='Date:N',
    y='Value',
    stroke=alt.Stroke('DESCR', legend=alt.Legend(title=None), scale=alt.Scale(scheme='redblue'))
)

chart = (bars+lines).facet(column='Company')
chart

I have tried .resolve_scale(y='independent') after .facet, but it doesn't show the second axis on the right side.

Any help would be appreciated.


Solution

  • As per https://github.com/vega/vega-lite/issues/4373#issuecomment-617153232, you need some additional resolves:

    chart = (
        (bars+lines)
        .resolve_scale(y='independent')  # Create dual axis
        .facet(column='Company')
        .resolve_axis(y='independent')  # Make sure dual axis works with facet (redraws the axis for each subplot)
        .resolve_scale(y='shared')  # Set the y-max across facets to be the same (the default when not having dual axes)
    )
    

    enter image description here