'Drawing median and quartile lines on an Altair violin plot
Suppose I had the following plot (taken from the tutorial in the Altair documentation):
import altair as alt
from vega_datasets import data
alt.Chart(data.cars()).transform_density(
'Miles_per_Gallon',
as_=['Miles_per_Gallon', 'density'],
extent=[5, 50],
groupby=['Origin']
).mark_area(orient='horizontal').encode(
y='Miles_per_Gallon:Q',
color='Origin:N',
x=alt.X(
'density:Q',
stack='center',
impute=None,
title=None,
axis=alt.Axis(labels=False, values=[0],grid=False, ticks=True),
),
column=alt.Column(
'Origin:N',
header=alt.Header(
titleOrient='bottom',
labelOrient='bottom',
labelPadding=0,
),
)
).properties(
width=100
).configure_facet(
spacing=0
).configure_view(
stroke=None
)
How would I got about drawing quartile and median lines on each of those violin plots? Would I have to define another plot and layer it on top of the violin plots? It would also be nice if the lines are the same width as the violin plot at the specific location on the distribution.
Solution 1:[1]
Yes, you would layer them before faceting. It get a little tricky with what needs to be added to the layered and the faceted chart respectively, but something like this would work:
import altair as alt
from vega_datasets import data
violins = alt.Chart().transform_density(
'Miles_per_Gallon',
as_=['Miles_per_Gallon', 'density'],
extent=[5, 50],
groupby=['Origin']
).mark_area(orient='horizontal').encode(
y='Miles_per_Gallon:Q',
color='Origin:N',
x=alt.X(
'density:Q',
stack='center',
impute=None,
title=None,
axis=alt.Axis(labels=False, values=[0],grid=False, ticks=True),
),
)
alt.layer(
violins,
alt.Chart().mark_rule().encode(
y='median(Miles_per_Gallon)',
x=alt.X(),
color=alt.value('black')),
).properties(
width=100
).facet(
data=data.cars(),
column=alt.Column(
'Origin:N',
header=alt.Header(
titleOrient='bottom',
labelOrient='bottom',
labelPadding=0,
),
)
).configure_facet(
spacing=0
).configure_view(
stroke=None
)
Then you can do the same for the quartiles. I am not sure how you would limit the lines to the width of the area other than manually putting in the values, and I think that would be a bit tricky as well. I would suggest putting a boxplot inside the violin instead:
alt.layer(
violins,
alt.Chart().mark_boxplot(size=5, extent=0, outliers=False).encode(
y='Miles_per_Gallon',
x=alt.value(46),
color=alt.value('black')
)
).properties(
width=100
).facet(
data=data.cars(),
column=alt.Column(
'Origin:N',
header=alt.Header(
titleOrient='bottom',
labelOrient='bottom',
labelPadding=0,
),
)
).configure_facet(
spacing=0
).configure_view(
stroke=None
)
This is similar to how seaborn handles violinplots by default and it is also how they were described in the original paper by Hintze and Nelson in 1997.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | joelostblom |