Altair/Vega-Lite 分时图表:从聚合字段中过滤前 K 个条带
Altair/Vega-Lite tick chart: filter top K strips from aggregated field
我正在可视化一个数据集,例如,它有一个分类字段和一个时间字段。我想创建一个带状图,显示不同类别的时间分布,这些类别根据它们的基数按 'ascending'/'descending' 顺序排序。这可以通过 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')
),
)
现在假设我只对前三个最多的类别感兴趣。按照“”的公认解决方案,这次情节没有出现:
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 标签顺序也不符合预期。
更深入地阅读(和理解)文档,我想我可以说我所问的目前(2018 年 6 月)在 altair
/Vega-Lite
下是不可行的。这是我的解释...
对数据执行聚合转换,相当于在 SQL 查询中添加 GROUP BY
子句,因此我们无法再将任何“原始”数据字段关联到编码通道以其“未聚合”形式:当我尝试在 x
频道中引用 competition
时,因此这是 undefined
。
我可以尝试 "selfjoin" 使用查找转换,但即使在这种情况下,最终结果也不是我想要的,因为这等同于 left join
所以我得到每个聚合只有一个值 class。
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}
]
我正在可视化一个数据集,例如,它有一个分类字段和一个时间字段。我想创建一个带状图,显示不同类别的时间分布,这些类别根据它们的基数按 'ascending'/'descending' 顺序排序。这可以通过 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')
),
)
现在假设我只对前三个最多的类别感兴趣。按照“
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 标签顺序也不符合预期。
更深入地阅读(和理解)文档,我想我可以说我所问的目前(2018 年 6 月)在 altair
/Vega-Lite
下是不可行的。这是我的解释...
对数据执行聚合转换,相当于在 SQL 查询中添加 GROUP BY
子句,因此我们无法再将任何“原始”数据字段关联到编码通道以其“未聚合”形式:当我尝试在 x
频道中引用 competition
时,因此这是 undefined
。
我可以尝试 "selfjoin" 使用查找转换,但即使在这种情况下,最终结果也不是我想要的,因为这等同于 left join
所以我得到每个聚合只有一个值 class。
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}
]