Reputation: 4052
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:
factorplot
+ factorplot
Plotting two factorplot
s 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)
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)
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')
Upvotes: 1
Views: 1588
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()
Upvotes: 2