Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Labelling Layered Charts in Altair (Python)

Tags:

python

altair

I am attempting to create two layered histograms in Altair (and a vertical mean ruler for each). I would like a legend to label each of these four.

I am using the first 'Birth weight I' data that can be found here

My code (real long, apologies) looks something like this:

from altair import datum

# This histogram for baby weights of mothers who dont smoke
dont = alt.Chart(babyData).mark_bar().encode(
    alt.X("bwt-oz:Q", axis=alt.Axis(title='Birth Weight (Ounces)'), bin=True),
    alt.Y('count()', axis=alt.Axis(title='Count'), scale=alt.Scale(domain=[0, 350]))
).properties(
    width=400,
    height=400
).transform_filter(
    datum.smoke == 0,
)

mean = alt.Chart(babyData).mark_rule(color='red').encode(
    x='mean(bwt-oz):Q',
    size=alt.value(4)
).transform_filter(
    datum.smoke == 0
)

dontSmokeChart = dont + mean

# This histogram for baby weights of mothers who smoke
do = alt.Chart(babyData).mark_bar().encode(
    alt.X("bwt-oz:Q", axis=alt.Axis(title='Birth Weight (Ounces)'), bin=True),
    alt.Y('count()', axis=alt.Axis(title='Count'), scale=alt.Scale(domain=[0, 350]))
).transform_filter(
    datum.smoke == 1
).properties(
    width=400,
    height=400
)

mean2 = alt.Chart(babyData).mark_rule(color='red').encode(
    x='mean(bwt-oz):Q',
    size=alt.value(4)
).transform_filter(
    datum.smoke == 1
)

doSmokeChart = do + mean2

# This layers, and puts them all together

layer = alt.layer(
    dont,
    mean,
    do,
    mean2
).properties(
    title="Layered Histogram of Baby Weights of Mothers Who smoke Vs. Who Don't",
).configure_mark(
    opacity=0.5,
    color='blue',
)
layer

The final layered chart looks something like this: https://i.sstatic.net/OR9f4.png

I would simply like a legend specifying which histogram/mean belongs to what.

If I could color them too, and perhaps add a legend that way, that would be nice as well, but I am unsure how to do so.

Thanks for any insight!

like image 715
Marco Sousa Avatar asked Sep 07 '26 07:09

Marco Sousa


2 Answers

Rather than manually creating layers with filtered data, you should use a color encoding on your full dataset: then a legend will be generated automatically.

For example:

import altair as alt
import pandas as pd

babyData = pd.read_csv('https://www.stat.berkeley.edu/users/statlabs/data/babiesI.data', delim_whitespace=True)

base = alt.Chart(babyData).transform_filter(
    'datum.smoke != 9'
)

hist = base.mark_bar(opacity=0.5).encode(
    alt.X("bwt:Q",title='Birth Weight (Ounces)', bin=True),
    alt.Y('count()', title='Count'),
    color='smoke:N'
).properties(
    width=400,
    height=400
)

mean = base.mark_rule().encode(
    x='mean(bwt):Q',
    size=alt.value(4),
    color='smoke:N'
)

hist + mean

enter image description here

From there you could use standard approaches to Customize the color schemes used for each mark.

like image 77
jakevdp Avatar answered Sep 09 '26 21:09

jakevdp


@jakevdp just beat me to it! I was going to say the same thing. Here is a full example for you to work with.

import pandas as pd
import altair as alt

# Link to data source
URL =  'https://www.stat.berkeley.edu/users/statlabs/data/babiesI.data'
# Read data into a pandas dataframe
df = pd.read_table(URL, sep='\s+')

hist = alt.Chart(df).mark_area(
    opacity=0.7,
    interpolate='step'
).encode(
    alt.X("bwt:Q", axis=alt.Axis(title='Birth Weight (Ounces)'), bin=True),
    alt.Y('count()', axis=alt.Axis(title='Count'), stack=None), 
    alt.Color('smoke:N')
).properties(
    width=400,
    height=400
).transform_filter(alt.datum.smoke != 9)

rule = alt.Chart(df).mark_rule(color='red').encode(
    alt.Detail('smoke:N'),
    alt.Color('smoke:N'),
    alt.X('mean(bwt):Q'),
    size=alt.value(4), 
).transform_filter(alt.datum.smoke != 9)

hist + rule

like image 39
eitanlees Avatar answered Sep 09 '26 23:09

eitanlees



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!