Mandias
Mandias

Reputation: 876

How to retain altair axis sort after adding joinaggregate transform?

I'm trying to add additional formatting to labels on an altair bar chart, but doing so resets the sorting I had applied back to default alphabetic.

In the below examples I am trying to order the vertical axis by descending average MPG per country of origin. This works until I try adding "MPG" to the bar labels, which breaks the sorting:

Example without the additional formatting:

import altair as alt
from vega_datasets import data
    
source = data.cars()
    
base = alt.Chart(source).encode(y=alt.Y('Origin', sort=alt.EncodingSortField(field='Miles_per_Gallon', op='average', order='descending')), x='mean(Miles_per_Gallon)')
bars = base.mark_bar(interpolate='step-after', line=True).encode(color='count(Origin)')
    
text = base.mark_text(align='left', dx=2).encode(text=alt.Text('mean(Miles_per_Gallon)', format=".1f"))

bars+text

visualization1

Example with added "MPG" to bar labels, requiring transforms:

import altair as alt
from vega_datasets import data
    
source = data.cars()
    
base = alt.Chart(source).encode(y=alt.Y('Origin', sort=alt.EncodingSortField(field='Miles_per_Gallon', op='average', order='descending')), x='mean(Miles_per_Gallon)')
bars = base.mark_bar(interpolate='step-after', line=True).encode(color='count(Origin)')
    
# Previous method without added formatting:
# text = base.mark_text(align='left', dx=2).encode(text=alt.Text('mean(Miles_per_Gallon)', format=".1f"))
    
# New method
text = base.mark_text(align='left', dx=2).encode(text='label:N'
    ).transform_joinaggregate(mpgMean='mean(Miles_per_Gallon)', groupby=['Origin']
    ).transform_calculate(label='format(datum.mpgMean,".1f")+" MPG"')
    
bars+text

viz2

As you can see when comparing the images, the bars are no longer in sorted order.

The workaround for similar issues mentioned in this altair issue does not work here, and the method I'm using is the official way to add extra text to labels per this issue.

Is there a way to retain the sorting after adding my additional formatting?

Upvotes: 1

Views: 31

Answers (1)

kgoodrick
kgoodrick

Reputation: 868

When you add the joinaggreagate and calculate transforms to the second layer the data sources are no longer the same and that's what causes the issue. If you look at the generated vega-lite spec in the editor you will see the warning:

[Warning] Dropping sort property {"field":"Miles_per_Gallon","op":"average","order":"descending"} as unioned domains only support boolean or op "count", "min", and "max".

If you do the aggregations in the base chart, you can achieve the chart you're looking for:

import altair as alt
from vega_datasets import data

source = data.cars()

base = (
    alt.Chart(source)
    .transform_aggregate(
        mpgMean="mean(Miles_per_Gallon)",
        originCount="count(Origin)",
        groupby=["Origin"],
    )
    .transform_calculate(label='format(datum.mpgMean,".1f")+" MPG"')
    .encode(
        y=alt.Y(
            "Origin",
            sort="-x",
        ),
        x="mpgMean:Q",
    )
)

bars = base.mark_bar(interpolate="step-after", line=True).encode(color="originCount:Q")

text = base.mark_text(align="left", dx=2).encode(text="label:N")

bars + text

enter image description here

Upvotes: 1

Related Questions