Search code examples
altairvega-lite

Altair: merging legends in layer charts


I have a point chart encoding color, size, and shape. By itself all three encodings are collapsed as a single legend. However layering a line chart that shares the same color results in the duplicated legend below. There is no difference when marking size and shape as independent but color as shared. When I disable the legend in the line chart's color encoding, the [top] color legend and all color information disappears. What can I do?

layer chart with duplicate legends

rand = np.random.RandomState(0)
data = pd.DataFrame\
    ( rand.randint(100,500,(15,2))
    , index=[*["a"]*5,*["b"]*5,*["c"]*5]
    , columns=["x","y"]
    ).rename_axis("k").reset_index()

chart1 =\
    ( alt.Chart(data)
    . mark_point()
    . encode(x="x",y="y",color="k",shape="k",size="k")
    )

chart2 =\
    ( alt.Chart(data)
    . transform_regression
        ( on="x"
        , regression="y"
        , groupby=["k"]
        , method="poly"
        )
    . mark_line()
    . encode(x="x",y="y",color="k")
    )

chart =\
    ( (chart1 + chart2)
    . interactive()
    . properties(width="container")
    )

Solution

  • I don't think there's any good answer for this question. There's an open issue about it here.

    One workaround is to hide the line legend and set the others to independent:

    import numpy as np
    import pandas as pd
    import altair as alt
    
    rand = np.random.RandomState(0)
    data = pd.DataFrame\
        ( rand.randint(100,500,(15,2))
        , index=[*["a"]*5,*["b"]*5,*["c"]*5]
        , columns=["x","y"]
        ).rename_axis("k").reset_index()
    
    chart1 =\
        ( alt.Chart(data)
        . mark_point()
        . encode(x="x",y="y",color="k",shape="k",size="k")
        )
    
    chart2 =\
        ( alt.Chart(data)
        . transform_regression
            ( on="x"
            , regression="y"
            , groupby=["k"]
            , method="poly"
            )
        . mark_line()
        . encode(x="x",y="y",color=alt.Color("k", legend=None))
        )
    
    chart =\
        ( (chart1 + chart2)
        . interactive()
        ).resolve_scale(color='independent', shape='independent', size='independent')
    

    enter image description here