Тиковая диаграмма Altair / Vega-Lite: отфильтровать верхние K полос из агрегированного поля

Я визуализирую набор данных, который имеет, например, категориальное поле и временное поле. Я хочу создать ленточную диаграмму, которая показывает временное распределение различных категорий, отсортированных в «возрастающем» / «убывающем» порядке в зависимости от их количества элементов. Этого можно просто достичь с помощью altair:

import pandas as pd
import altair as alt

data = {0:{'Name':'Mary', 'Sport':'Tennis', 'competition':'2018/06/01'},
    1:{'Name':'Cal', 'Sport':'Tennis','competition':'2018/06/05'},
    2:{'Name':'John', 'Sport':'Tennis','competition':'2018/05/28'},
    3:{'Name':'Jane', 'Sport':'Tennis','competition':'2018/05/20'},
    4:{'Name':'Bob', 'Sport':'Golf','competition':'2018/03/01'},
    5:{'Name':'Jerry', 'Sport':'Golf','competition':'2018/03/03'},
    6:{'Name':'Gustavo', 'Sport':'Golf','competition':'2018/02/28'},
    7:{'Name':'Walter', 'Sport':'Swimming','competition':'2018/01/01'},
    8:{'Name':'Jessy', 'Sport':'Swimming','competition':'2018/01/03'},
    9:{'Name':'Patric', 'Sport':'Running','competition':'2018/02/01'},
    10:{'Name':'John', 'Sport':'Shooting','competition':'2018/04/01'}}

df = pd.DataFrame(data).T

alt.Chart(df).mark_tick().encode(
    x='yearmonthdate(competition):T',
    y=alt.Y('Sport:N',
        sort=alt.SortField(field='count(Sport:N)', order='ascending', op='sum')
    ),
)

Полосовой участок

Теперь предположим, что меня интересуют только первые три самые многочисленные категории. Следуя принятому решению для "Altair / Гистограмма Vega-Lite: отфильтруйте верхние K столбцов из агрегированного поля ", на этот раз график не отображается:

alt.Chart(df).mark_tick().encode(
    x='yearmonthdate(competition):T',
    y=alt.Y('Sport:N',
        sort=alt.SortField(field='count', order='ascending', 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')

График с отфильтрованной полосой

Обратите внимание, что даже порядок y-меток не соответствует ожидаемому.


person Eraldo P.    schedule 18.06.2018    source источник


Ответы (1)


Читая (и понимая) документацию более подробно, я думаю, что могу заявить, что то, что я спросил, в настоящее время (июнь 2018 года) невозможно с _1 _ / _ 2_. Вот мое объяснение ...

Выполнение агрегированного преобразования данных эквивалентно добавлению предложения GROUP BY в запрос SQL, поэтому мы больше не можем связать с закодированным каналом любое «исходное» поле данных в его «неагрегированной» форме: когда я пытаюсь сослаться на competition в канале x это значит undefined.

Я мог бы попытаться «самосоединиться» с помощью преобразования поиска, но даже в этом случае конечный результат - это не то, что я искал, потому что он эквивалентен left join, поэтому я получаю только одно значение для каждого агрегированного класса.

alt.Chart(df).mark_tick().encode(
    x=alt.X(field='competition',type='temporal', timeUnit='yearmonthdate'),
    y=alt.Y('Sport:N',
        sort=alt.SortField(field='count', order='ascending', op='sum')
    ),
).transform_aggregate(
    countX='count()',
    groupby=['Sport']
).transform_window(
    window=[{'op': 'rank', 'as': 'rank'}],
    sort=[{'field': 'countX', 'order': 'descending'}]
).transform_filter('datum.rank <= 3').transform_lookup(
    lookup='Sport',
    from_=alt.LookupData(data=df, key='Sport',
                         fields=['competition'])
)

Участок после присоединения

Я обнаружил, что все, что необходимо для достижения желаемого результата, в настоящее время поддерживается в Vega, но не в Vega-Lite и Altair: это JoinAggregate преобразование, которое« расширяет »исходные данные результатом одного или нескольких агрегатов.

Для следующих входных данных:

[
  {"foo": 1, "bar": 1},
  {"foo": 1, "bar": 2},
  {"foo": null, "bar": 3}
]

Агрегатное преобразование соединения:

{
  "type": "joinaggregate",
  "fields": ["foo", "bar", "bar"],
  "ops": ["valid", "sum", "median"],
  "as": ["v", "s", "m"]
}

производит вывод:

[
  {"foo": 1, "bar": 1, "v": 2, "s": 6, "m": 2},
  {"foo": 1, "bar": 2, "v": 2, "s": 6, "m": 2},
  {"foo": null, "bar": 3, "v": 2, "s": 6, "m": 2}
]
person Eraldo P.    schedule 20.06.2018
comment
Если меня никто не поправит, я приму свой ответ - person Eraldo P.; 20.06.2018
comment
агрегат объединения теперь доступен в vega-lite - person Malik Koné; 10.02.2020