在 Altair 中设置自定义配色方案并合并图例

Set custom color scheme and merge legends in Altair

我想要一个总结散点图形状和颜色的图例。

我想自己选择点的颜色。

我知道如何独立完成这些事情。 但是当我尝试同时执行这两项操作时,我最终得到了两个图例而不是一个。

我的代码如下:

x_axis = 'Publication date'
y_axis = 'Training compute (FLOPs)'

import altair as alt
alt.themes.enable('fivethirtyeight')
selection = alt.selection_multi(fields=['Domain'], bind='legend')

domain_to_color =  {
    'Vision' : '#6d904f', 
    'Language' : '#b96db8',   
    'Games' : '#30a2da', 
    'Drawing' : 'black', 
    'Speech' : 'black',   
    'Other' : '#e5ae38', 
    'Large Scale' : '#fc4f30',     
    'All' : '#30a2da'
    }

present_domains = [domain for domain in domain_to_color.keys() if domain in df['Domain'].unique()]
domain_scale = alt.Scale(
        domain=present_domains,
        range=[domain_to_color[domain] for domain in present_domains],
        )

## Chart with historical data
chart = alt.Chart(df, width=1100, height=600,)\
.mark_point(size=120, filled=False)\
.encode(
  x=alt.X(f'{x_axis}:{"T" if x_axis == "Publication date" else "Q"}',
          scale=alt.Scale(type='linear', 
                          domain=(df[x_axis].min(), df[x_axis].max())), 
          axis = alt.Axis(grid=True)
          ),
  y=alt.Y(f'{y_axis}:Q',
          scale=alt.Scale(type='log', 
                          domain=(df[y_axis].min(), df[y_axis].max())), 
          axis=alt.Axis(format=".1e", grid = True)
          ),
  color= alt.Color('Domain', scale=domain_scale),
  shape = 'Domain',
  opacity=alt.condition(selection, alt.value(1), alt.value(0.2)),
)

chart = chart.add_selection(selection)

chart

这会生成如下图表:

有两个传说!如果我将行 color = alt.Color('Domain', scale=domain_scale), 更改为 color = 'Domain',那么我将得到一个图例。但是颜色不是我想要的。

我怎样才能同时做这两件事?

通常您会通过 .resolve_scalementioned here, but I don't think it is possibly when using a custom domain (maybe for similar reasons as mentioned here) 控制图例项目的合并。您可以改为设置自定义范围并获得所需的结果:

import altair as alt
import pandas as pd


df = pd.DataFrame(
    data=[[0, 10, "a"], [1, 20, "a"], [0, 15, "b"], [1, 25, "b"]],
    columns=["x", "y", "c"]
)
alt.Chart(df).mark_point().encode(
    x="x",
    y="y",
    color=alt.Color('c', scale=alt.Scale(range=['coral', 'steelblue'])),
    shape="c"
)

我认为问题是您的比例域不匹配,因此无法合并它们。您应该尝试使域明确匹配:

  color=alt.Color('Domain', scale=domain_scale),
  shape=alt.Shape('Domain', scale=alt.Scale(domain=domain_scale.domain),