Reputation: 876
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
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
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
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
Upvotes: 1