如何对绘图中每一行的 Y 轴标签进行排序?

Posted

技术标签:

【中文标题】如何对绘图中每一行的 Y 轴标签进行排序?【英文标题】:How to sort Y-axis labels different for each row in my plot? 【发布时间】:2019-07-20 22:39:03 【问题描述】:

我希望每个子图根据定义条形大小的值对标签进行排序。

查看示例图片:

data = 'label': ['A','A','B','B'], 'variable': ['x', 'y', 'x', 'y'], 'value':[2,4,3,1]
    df = pd.DataFrame.from_dict(data)
    selector = alt.selection_single(empty='all', fields=['label'])
    bar = alt.Chart(df,title='My Plot').mark_bar().encode(
        alt.Y('label', sort=alt.EncodingSortField(field="value", op="mean", order='ascending'), axis=alt.Axis(title='Label')),
        alt.X('value:Q', axis=alt.Axis(format='%', title='Value')),
        alt.Row('variable', title='Variable'),
        color=alt.condition(selector, alt.value('orange'), alt.value('lightgray')),
        tooltip=[alt.Tooltip('label', title='Label'),
                 alt.Tooltip('value:Q', format='.2%', title='Value'),]
    ).add_selection(selector)
    chart = (bar).properties(width=700, height=300)
    display(chart)

在示例中,标签 (A, B) 现在根据这些标签的所有值的平均值进行排序。我希望标签 X 的顺序为 B-A,标签 Y 的顺序为 A-B(因此根据 Altair 图行中显示的标签值递减)。

【问题讨论】:

【参考方案1】:

根据设计,分面图共享它们的轴,因此这意味着当您对列进行排序时,您将按 整个 数据集对 两个 轴进行排序。

如果您希望每个图表的轴单独排序,我认为唯一的方法是手动过滤数据集并连接图表。这是您可以执行此操作的一种方法:

import altair as alt
import pandas as pd

df = pd.DataFrame('label': ['A','A','B','B'],
                   'variable': ['x', 'y', 'x', 'y'],
                   'value':[2,4,3,1])

base = alt.Chart(df).mark_bar().encode(
  alt.Y('label', axis=alt.Axis(title='Label'), 
        sort=alt.EncodingSortField(field="value", op="sum", order='descending')),
  alt.X('value:Q', axis=alt.Axis(format='d', title='Value')),
  tooltip=[alt.Tooltip('label', title='Label'),
           alt.Tooltip('value:Q', format='d', title='Value'),],
)

alt.vconcat(
  base.transform_filter("datum.variable == 'x'").properties(title='x'),
  base.transform_filter("datum.variable == 'y'").properties(title='y'),
  title='My Chart'
)

【讨论】:

嗨,Jake,我们实际上可以使用resolve 使 facet 使用独立的比例。 (见我的回答。):)【参考方案2】:

我尝试使用 facet,但这并没有解决问题。我在这里提供代码是因为它可能会激发一个解决方案:

import altair as alt
import pandas as pd

df = pd.DataFrame('label': ['A','A','B','B'],
               'variable': ['x', 'y', 'x', 'y'],
               'value':[2,4,3,1])
bar = alt.Chart(df,title='My Plot').mark_bar().encode(
    alt.Y('label', axis=alt.Axis(title='Label'), 
          sort=alt.EncodingSortField(field="value", op="values", order='descending')),
    alt.X('value:Q', axis=alt.Axis(format='d', title='Value')),
    tooltip=[alt.Tooltip('label', title='Label'),
             alt.Tooltip('value:Q', format='d', title='Value'),]
).facet(
    row='variable:O'
)
bar

对于变量 x 和 y,行顺序仍然是 ['B', 'A']。我希望变量 y 条形图有 ['A', 'B]。

进一步阐述 jakevdp 提供的解决方案,我得到这个:

selector = alt.selection_single(empty='all', fields=['label'])
base = alt.Chart(df, title='My Plot').mark_bar().encode(
    alt.Y('label', axis=alt.Axis(title='Label'), sort=alt.EncodingSortField(field="value", op="sum", order='descending')),
    alt.X('value:Q', axis=alt.Axis(format='d', title='Value')),
    color=alt.condition(selector, alt.value('orange'), alt.value('lightgray')),
    tooltip=[alt.Tooltip('label', title='Label'),
             alt.Tooltip('value:Q', format='d', title='Value'),]
).add_selection(selector)

bar = alt.vconcat(title='My Chart')
for v in df['variable'].unique():
    bar &= base.transform_filter(f"datum.variable == 'v'").properties(title=f"'v'")

bar

【讨论】:

【参考方案3】:

Facet 默认共享比例,但您可以使用 resolve 属性覆盖比例分辨率:

import altair as alt
import pandas as pd

df = pd.DataFrame('label': ['A','A','B','B'],
                   'variable': ['x', 'y', 'x', 'y'],
                   'value':[2,4,3,1])

alt.Chart(df,title='My Plot').mark_bar().encode(
    alt.Y('label', sort=alt.EncodingSortField(field="value", op="mean", order='descending'), axis=alt.Axis(title='Label')),
    alt.X('value:Q', axis=alt.Axis(format='%', title='Value'))
).facet(
    alt.Row('variable', title='Variable'),
    resolve="scale": "y": "independent"
)

请注意,您不能再在 Altair 2 中使用行编码速记,因为 Altair 2(和 Vega-Lite 2)中带有行/列的单位规范没有 resolve 属性。我们现在将resolve 添加到 Vega-Lite 3,因此我认为一旦 Altair 3 推出,您应该能够执行以下操作:


df = pd.DataFrame('label': ['A','A','B','B'],
                   'variable': ['x', 'y', 'x', 'y'],
                   'value':[2,4,3,1])

alt.Chart(df,title='My Plot', resolve="scale": "y": "independent").mark_bar().encode(
    alt.Y('label', sort=alt.EncodingSortField(field="value", op="mean", order='descending'), axis=alt.Axis(title='Label')),
    alt.X('value:Q', axis=alt.Axis(format='%', title='Value')),
    alt.Row('variable', title='Variable')
)

【讨论】:

以上是关于如何对绘图中每一行的 Y 轴标签进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不改变绘图宽度的情况下使用 ggplot2 在 R 中添加可变大小的 y 轴标签?

如何使用R中的绘图功能更改散点图中x轴和y轴标签的字体大小和颜色?

将轴刻度标签格式化为绘图中的百分比

ggplot2:x 和 y 轴带有黑色标签的经典绘图

Matplotlib 库 : 绘图和可视化

两个单独的y轴标题,用于绘图的两个面,同时使用ggplot2保持刻面顶部条带标签