首页 > 解决方案 > Sorting a stacked bar chart as a whole along Y-axis, based on the value of a particular category field using Altair

问题描述

Using an example from the docs, I can sort the stacked bars themselves using order, but I want to see the whole bar along Y-axis sorted via the sum of yield of site -> Crookston, i.e the blue bar, in ascending/descending order.

Based on this post I tried using transform_calculate and transform_join_aggregate, but it doesn't work as expected.

import altair as alt
from vega_datasets import data

source = data.barley()

alt.Chart(source).mark_bar().transform_calculate(
    key="datum.site == 'Crookston'"
).transform_joinaggregate(
    sort_key="argmax(key)", groupby=['variety']
).transform_calculate(
    sort_val='datum.sort_key.value'  
).encode(
    x=alt.X('sum(yield)', stack='normalize'),
    y=alt.Y('variety', sort=alt.SortField('sort_val', order='ascending')),
    color='site',
    order=alt.Order(
      # Sort the segments of the bars by this field
      'site',
      sort='ascending'
    )
)

enter image description here

Expected Output
The bars along Y-axis are sorted by the size of blue (site=Crookston) bar.

标签: python-3.xaltairvega-lite

解决方案


图表中的每个彩色条代表数据集中所有年份该地点和品种内所有产量的总和。当您使用 时argmax,您是按一年的 Crookston 产量排序,而不是所有年份的 Crookston 总产量。您可以使用稍微不同的转换策略来获得后者:

import altair as alt
from vega_datasets import data

source = data.barley()

alt.Chart(source).mark_bar().transform_calculate(
    filtered="datum.site == 'Crookston' ? datum.yield : 0"
).transform_joinaggregate(
    sort_val="sum(filtered)", groupby=["variety"]
).encode(
    x=alt.X('sum(yield)', stack='normalize'),
    y=alt.Y('variety', sort=alt.SortField('sort_val', order='ascending')),
    color='site',
    order=alt.Order(
      # Sort the segments of the bars by this field
      'site',
      sort='ascending'
    )
)

在此处输入图像描述

结果按 Crookston 的总产量正确排序,您可以通过删除x编码中的标准化来确认:

alt.Chart(source).mark_bar().transform_calculate(
    filtered="datum.site == 'Crookston' ? datum.yield : 0"
).transform_joinaggregate(
    sort_val="sum(filtered)", groupby=["variety"]
).encode(
    x=alt.X('sum(yield)'),
    y=alt.Y('variety', sort=alt.SortField('sort_val', order='ascending')),
    color='site',
    order=alt.Order(
      'site',
      sort='ascending'
    )
)

在此处输入图像描述


推荐阅读