1

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

dmeu
  • 3,842
  • 5
  • 27
  • 43

1 Answers1

2

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

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Hi. Thank you so much for your answers and clarifications. I think your solution still has the problem that all three plots contain the foreground data of all three *kind's*. This is my other problem, that it won't respect the `FacetGrid`. In the end I think I just have to make seperate plots for each *kind*. In any case your answer has been helpful to highlight how I can distinguish between elements of the 'background and foreground' – dmeu Apr 28 '18 at 06:12
  • Oh sorry I did not realize this to be the problem. So just don't supply `foreground` to the mapping. It's rather the original dataset which should be mapped. I updated the answer. – ImportanceOfBeingErnest Apr 28 '18 at 09:35
  • What does `zorder` do? – rahul-ahuja Sep 01 '21 at 11:29