在 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_scale
和 mentioned 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),
我想要一个总结散点图形状和颜色的图例。
我想自己选择点的颜色。
我知道如何独立完成这些事情。 但是当我尝试同时执行这两项操作时,我最终得到了两个图例而不是一个。
我的代码如下:
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_scale
和 mentioned 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),