dmeu
dmeu

Reputation: 4052

Superimpose two seaborn factorplots

I am having difficulties super-imposing (overlaying) two factorplots using the library seaborn.

The general problem is that I would like to plot in thin grey lines all the (background data) and then on top in colorful, thicker, lines the data we want to highlight. For one I don't succeed combining the two data-sets in a plot with FacetGrid and secondly I have a problem using zorder.

I did a dummy example with the exercise data set:

sns.set_style('whitegrid')
exercise = sns.load_dataset("exercise")
background = exercise.assign(idkind = lambda df: df['id'].astype(str)+df.kind.astype(str))
foreground = exercise.groupby(['kind','time']).mean().reset_index().rename(columns={'id':'idkind'})

Thus far I tried:

  1. factorplot + factorplot

Plotting two factorplots as if it were sns.pointplot twice analogue to this example. I need to the sns.factorplot due to the experimental setup of the data. This does not work, as simply two independant plots are produced. I basically would want the lower plot on top of the upper plot.

g=sns.factorplot(x="time", y="pulse", hue='idkind', col='kind', legend=False,color='lightgrey',data=background)
sns.factorplot(x="time", y="pulse", hue="kind", data=foreground)

enter image description here

  1. factorplot + gmap.(factorplot)

I thus tried to use sns.factorplot, which I think produces a FacetGrid and g.map a second sns.factorplot on top using a new dataset with the exact same design and categories. The result is, that instead of using the same subplots, it creates a number of rows with a repeated plot.

g=sns.factorplot(x="time", y="pulse", hue='idkind', col='kind', legend=False,color='lightgrey',data=background)
g.map(sns.factorplot, x="time", y="pulse",hue='idkind', col='kind', data=foreground)

enter image description here

  1. factorplot+ g.map(pointplot)

g.map a pointplot, which puts the entire data set in all the subplots, not respecting the design of the FacetGrid.

g=sns.factorplot(x="time", y="pulse", hue='idkind', col='kind', legend=False,color='lightgrey',data=background)
g.map(sns.pointplot,x="time", y="pulse", hue='idkind', col='kind', data=foreground,zorder='1000')

enter image description here

Upvotes: 1

Views: 1588

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339570

It should be mentionned that each call to factorplot creates its own figure. So in general if the aim is to have a single figure, you cannot call factorplot more than once. This explains why 1. and 2. simply can't work.

For 3., that would have been my first try as well (except that zorder should probably rather be a number, not a string).
However it seems that zorder is ignored or at least not correctly passed on to the underlying matplotlib functions.

An options is to set zorder manually. The following loops through all artists of the background plots and sets their zorder to 1. It also stores those artists in a list. After creating the foreground plot one can then loop through all artists again and set zorder to a higher values for those artists not in the previously stored list.

I'm leaving out foreground here completely because that seems to just calculate the mean, which would be done by pointplot automatically.

import seaborn as sns
import matplotlib.pyplot as plt

sns.set_style('whitegrid')
exercise = sns.load_dataset("exercise")
background = exercise.assign(idkind = lambda df: df['id'] \
                            .astype(str)+df.kind.astype(str))

g=sns.factorplot(x="time", y="pulse", hue='idkind', col='kind', 
                 legend=False,color='lightgrey',data=background)

backgroundartists = []
for ax in g.axes.flat:
    for l in ax.lines + ax.collections:
        l.set_zorder(1)
        backgroundartists.append(l)

g.map(sns.pointplot, "time", "pulse")

for ax in g.axes.flat:
    for l in ax.lines + ax.collections:
        if l not in backgroundartists:
            l.set_zorder(5)

plt.show()

enter image description here

Upvotes: 2

Related Questions