Search code examples
pythonvega-litealtair

How to sort Y-axis labels different for each row in my plot?


I want each subplot to sort the labels based on the value defining the size of the bar.

See example image:

enter image description here

data = {'label': ['A','A','B','B'], 'variable': ['x', 'y', 'x', 'y'], 'value':[2,4,3,1]}
    df = pd.DataFrame.from_dict(data)
    selector = alt.selection_single(empty='all', fields=['label'])
    bar = alt.Chart(df,title='My Plot').mark_bar().encode(
        alt.Y('label', sort=alt.EncodingSortField(field="value", op="mean", order='ascending'), axis=alt.Axis(title='Label')),
        alt.X('value:Q', axis=alt.Axis(format='%', title='Value')),
        alt.Row('variable', title='Variable'),
        color=alt.condition(selector, alt.value('orange'), alt.value('lightgray')),
        tooltip=[alt.Tooltip('label', title='Label'),
                 alt.Tooltip('value:Q', format='.2%', title='Value'),]
    ).add_selection(selector)
    chart = (bar).properties(width=700, height=300)
    display(chart)

In the example, the labels (A, B) are now sorted based on the mean of all values for those labels. I want the order to be B-A for label X and A-B for label Y (so descending based on the value of the label showed in the row of the Altair plot).


Solution

  • By design facet charts share their axes, so it means that when you sort the column you are sorting both axes by the entire dataset.

    If you would like each chart to have its axis sorted individually, I believe the only way to do that is to manually filter the dataset and concatenate the charts. Here is one way you might do this:

    import altair as alt
    import pandas as pd
    
    df = pd.DataFrame({'label': ['A','A','B','B'],
                       'variable': ['x', 'y', 'x', 'y'],
                       'value':[2,4,3,1]})
    
    base = alt.Chart(df).mark_bar().encode(
      alt.Y('label', axis=alt.Axis(title='Label'), 
            sort=alt.EncodingSortField(field="value", op="sum", order='descending')),
      alt.X('value:Q', axis=alt.Axis(format='d', title='Value')),
      tooltip=[alt.Tooltip('label', title='Label'),
               alt.Tooltip('value:Q', format='d', title='Value'),],
    )
    
    alt.vconcat(
      base.transform_filter("datum.variable == 'x'").properties(title='x'),
      base.transform_filter("datum.variable == 'y'").properties(title='y'),
      title='My Chart'
    )
    

    enter image description here