Altair/Vega-Lite 条形图:从聚合字段中过滤前 K 条

Altair/Vega-Lite bar chart: filter top K bars from aggregated field

我正在可视化一个数据集,例如,它有一个分类字段。我想创建一个条形图,显示该字段的不同类别及其基数,按 'ascendind'/'descending' 顺序排序。这可以简单地通过 altair:

来实现
import pandas as pd
import altair as alt

data = {0:{'Name':'Mary', 'Sport':'Tennis'},
    1:{'Name':'Cal', 'Sport':'Tennis'},
    2:{'Name':'John', 'Sport':'Tennis'},
    3:{'Name':'Jane', 'Sport':'Tennis'},
    4:{'Name':'Bob', 'Sport':'Golf'},
    5:{'Name':'Jerry', 'Sport':'Golf'},
    6:{'Name':'Gustavo', 'Sport':'Golf'},
    7:{'Name':'Walter', 'Sport':'Swimming'},
    8:{'Name':'Jessy', 'Sport':'Swimming'},
    9:{'Name':'Patric', 'Sport':'Running'},
    10:{'Name':'John', 'Sport':'Shooting'}}

df = pd.DataFrame(data).T

bars = alt.Chart(df).mark_bar().encode(
    x=alt.X('count():Q', axis=alt.Axis(format='.0d', tickCount=4)),
    y=alt.Y('Sport:N', 
        sort=alt.SortField(op='count', field='Sport:N', order='descending'))
)
bars

现在假设我只对前三个最多的类别感兴趣。使用"transform_window"和“transform_filter”来过滤数据似乎是合理的,但我找不到这样做的方法。我也去 Vega-Lite Top K example 尝试修改它但没有成功(我的 "best" 尝试如下所示)。

bars.transform_window(window=[alt.WindowFieldDef(op='count', 
                                                 field='Sport:N',
                                                 **{'as':'cardinality'})],
                      frame=[None, None])

bars.transform_window(window=[alt.WindowFieldDef(op='rank',
                                                 field='cardinality',
                                                 **{'as':'rank'})],
                      frame=[None, None],
                      sort=[alt.WindowSortField(field='rank',
                                                order='descending')])

bars.transform_filter( ..... what??? .....)

我可能会首先使用聚合转换来计算每个组中的人数,然后按照您链接到的前 K 个示例进行操作。

alt.Chart(df).mark_bar().encode(
    x='count:Q',
    y=alt.Y('Sport:N',
        sort=alt.SortField(field='count', order='descending', op='sum')
    ),
).transform_aggregate(
    count='count()',
    groupby=['Sport']
).transform_window(
    window=[{'op': 'rank', 'as': 'rank'}],
    sort=[{'field': 'count', 'order': 'descending'}]
).transform_filter('datum.rank <= 3')

请注意,在 Altair 2.2 版(我撰写本文时尚未发布)中,alt.SortField 将重命名为 alt.EncodingSortField,因为底层 Vega-Lite 架构发生了变化。

(旁注:用于排序和 window 转换的 altair API 目前非常笨拙,但我们正在努力思考如何改进它)