简体   繁体   中英

How to add layers to a faceted chart in Altair?

Altair is a lovely visualization lib, with nice intuitive visual grammar API. I am however struggling adding a layer with rule marks to a faceted chart.

Imagine you have a simple dataset:

print(df[['Year', 'Profile', 'Saison', 'Pos']].to_csv())
,Year,Profile,Saison,Pos
0,2017,6.0,Sommer,VL
1,2017,6.0,Winter,VL
13,2017,6.0,Winter,HL
12,2017,6.0,Sommer,HL
18,2017,6.0,Sommer,HR
6,2017,6.0,Sommer,VR
7,2017,6.0,Winter,VR
19,2017,6.0,Winter,HR
14,2018,5.5,Winter,HL
8,2018,5.5,Winter,VR
15,2018,5.5,Sommer,HL
20,2018,4.3,Winter,HR
21,2018,5.0,Sommer,HR
3,2018,5.5,Sommer,VL
2,2018,6.2,Winter,VL
9,2018,4.5,Sommer,VR
17,2019,4.5,Sommer,HL
11,2019,4.2,Sommer,VR
22,2019,3.5,Winter,HR
10,2019,5.28,Winter,VR
5,2019,4.6,Sommer,VL
4,2019,4.9,Winter,VL
16,2019,4.0,Winter,HL
23,2019,4.5,Sommer,HR

Than you can simply display it with:

base = alt.Chart(df[df.Saison=='Winter']).mark_bar().encode(x='Year:O', y='Profile:Q', column='Pos:N')
base

在此处输入图像描述

Than, let's say I want to add horizontal marks to visualize some limits:

在此处输入图像描述

For that I define the DataSet:

print(Limits.to_csv())
,Profil
0,3.0
1,1.5

And add it to the collection of charts:

limits = alt.Chart(Limits).mark_rule(color='red').encode(y='Profil')
base + limits

This does not work and generates and error:

ValueError: Faceted charts cannot be layered.

How can I overcome this limitation? Underlying vega-light grammar apparently supports such complex composition of layers, but I cannot figure out the way how to express it in Altair.

You cannot layer a facteted chart, because in general there is no guarantee that the contents of each layer contains compatible faceting.

However, you can facet a layered chart. It might look something like this:

import altair as alt
import pandas as pd
import io

df = pd.read_csv(io.StringIO("""
,Year,Profile,Saison,Pos
0,2017,6.0,Sommer,VL
1,2017,6.0,Winter,VL
13,2017,6.0,Winter,HL
12,2017,6.0,Sommer,HL
18,2017,6.0,Sommer,HR
6,2017,6.0,Sommer,VR
7,2017,6.0,Winter,VR
19,2017,6.0,Winter,HR
14,2018,5.5,Winter,HL
8,2018,5.5,Winter,VR
15,2018,5.5,Sommer,HL
20,2018,4.3,Winter,HR
21,2018,5.0,Sommer,HR
3,2018,5.5,Sommer,VL
2,2018,6.2,Winter,VL
9,2018,4.5,Sommer,VR
17,2019,4.5,Sommer,HL
11,2019,4.2,Sommer,VR
22,2019,3.5,Winter,HR
10,2019,5.28,Winter,VR
5,2019,4.6,Sommer,VL
4,2019,4.9,Winter,VL
16,2019,4.0,Winter,HL
23,2019,4.5,Sommer,HR
"""))

bars = alt.Chart().mark_bar().encode(
    x='Year:O',
    y='Profile:Q',
)

limits = alt.Chart(
  pd.DataFrame({'Profil': [3, 1.5]})
).mark_rule(
  color='red'
).encode(y='Profil')

alt.layer(
    bars,
    limits,
    data=df[df.Saison=='Winter']
).facet(
    'Pos:N',
)

在此处输入图像描述

Specifying the data here is a little tricky: the facet() method keys-off the top-level data in the chart it's called on, so when you're faceting layers built from different datasets, you need to specify the relevant data at the top level.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM