Labelling Layered Charts in Altair (Python)

烂漫一生 提交于 2020-07-10 01:19:41

问题


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:

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!


回答1:


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

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




回答2:


@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



来源:https://stackoverflow.com/questions/59921991/labelling-layered-charts-in-altair-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!