[英]Sorting a stacked bar chart as a whole along Y-axis, based on the value of a particular category field using Altair
使用文檔中的一個示例,我可以使用 order 對堆疊的條形本身進行order
,但我希望看到沿 Y 軸的整個條形通過site
-> Crookston的產量總和進行排序,即藍色條,升序/降序命令。
根據這篇文章,我嘗試使用transform_calculate
和transform_join_aggregate
,但它沒有按預期工作。
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'
)
)
預計 Output
沿 Y 軸的條按藍色(站點=Crookston)條的大小排序。
圖表中的每個彩色條代表數據集中所有年份該地點和品種內所有產量的總和。 當您使用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'
)
)
如 jakevdp 的回答所示,您可以首先使用計算轉換來定義一個新字段,該字段在站點為“Crookston”時復制產量,否則為 0。 從那里,沒有必要執行 Join Aggregate 轉換; 默認情況下, SortField
將直接在 y 軸排序命令中自動對 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"
).encode(
x=alt.X("sum(yield)"),
y=alt.Y(
"variety",
sort=alt.SortField("filtered", order="ascending"),
),
color="site",
order=alt.Order(
# Sort the segments of the bars by this field
"site",
sort="ascending",
),
)
實際上,使用transform_joinaggregate
的上一個答案的方法通常不能按預期工作,並且僅在此示例中有效,因為源數據集對於每個品種具有完全相同的記錄數。 例如,如果您將產量為 0 的“滿洲”品種的記錄添加到 Crookston 站點,那么該方法現在會將滿洲排序在 y 軸上更遠的兩個位置,低於 Velvet 和 No. 475,高於 No . 462.
source = data.barley()
source = source.append(
{"yield": 0, "variety": "Manchuria", "site": "Crookston"},
ignore_index=True,
)
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"),
)
從視覺上可以明顯看出,圖表不再按需要排序。 添加零產量不應該影響排序順序; 滿洲里品種在克魯克斯頓的產量仍然低於天鵝絨和 475 號品種。
要查看出了什么問題,您可以在 Vega Editor 中打開第二個代碼塊生成的圖表。 在那里,您將找到一個名為“data_0”的表,其中包含以下條目(不按此順序):
屈服 | 種類 | 年 | 地點 | 過濾 | 排序值 |
---|---|---|---|---|---|
39.93333 | 《滿洲里》 | 1931年 | “克魯克斯頓” | 39.93333 | 72.9 |
32.96667 | 《滿洲里》 | 1932年 | “克魯克斯頓” | 32.96667 | 72.9 |
0 | 《滿洲里》 | null | “克魯克斯頓” | 0 | 72.9 |
22.56667 | 《滿洲里》 | 1932年 | “德盧斯” | 0 | 72.9 |
41.33333 | “天鵝絨” | 1931年 | “克魯克斯頓” | 41.33333 | 73.39999 |
32.06666 | “天鵝絨” | 1932年 | “克魯克斯頓” | 32.06666 | 73.39999 |
22.46667 | “天鵝絨” | 1932年 | “德盧斯” | 0 | 73.39999 |
48.56666 | “462號” | 1931年 | “克魯克斯頓” | 48.56666 | 79.09999 |
Manchuria 的sort_val
為 72.9,比 Velvet 的要少,這是應該的。 但是,Vega 仍然需要確定如何聚合給定品種的每一行中出現的sort_val
的重復值。 堆疊圖的默認行為是將其嘗試排序的組中排序字段中的所有條目相加(請參閱: https://vega.github.io/vega-lite/docs/sort.html#sort- by-a-different-field ),這是在第一個代碼塊中派上用場的事實。
源數據集開始時每個品種有 12 個條目。 添加記錄后,滿洲里品種現在有13個條目,所以滿洲里得到的排序值為72.9 · 13=947.7,大於天鵝絨的排序值73.39999 · 12≈880.8,但仍小於462號品種排序值為 79.09999 · 12 ≈ 949.2。 這反映了第二張圖表中的情況。
要解決此問題,您可以指定只使用一個sort_val
作為每個品種的排序值,方法是使用EncodingSortField
而不是SortField
,並將"min"
、 "max"
或"average"
作為聚合操作傳遞給op
參數,例如sort=alt.EncodingSortField("sort_val", op="min", order="ascending")
。 或者您可以使用上面的第一種方法並跳過 Join Aggregate 轉換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.