12

i'm trying to make a 2x1 subplot figure in seaborn using:

data = pandas.DataFrame({"x": [1, 2, 4],
                        "y": [10,20,40],
                        "s": [0.01,0.1,1.0]})

plt.figure()
plt.subplot(2, 1, 1)
sns.pointplot(x="x", y="y", data=data)
plt.errorbar(np.arange(len(data["x"])), data["y"], yerr=data["s"])
plt.subplot(2, 1, 2)
sns.factorplot(x="x", y="y", data=data)
plt.show()

it produces two separate figures instead of a single figure with two subplots. why does it do this and how can seaborn be called multiple times for separate subplots?

i tried looking at the post referenced below but i cannot see how the subplots can be added even if factorplot is called first. can someone show an example of this? it would be helpful. my attempt:

data = pandas.DataFrame({"x": [1, 2, 4],
                        "y": [10,20,40],
                        "s": [0.01,0.1,1.0]})

fig = plt.figure()
sns.pointplot(x="x", y="y", data=data)
ax = sns.factorplot(x="x", y="y", data=data)
fig.add_subplot(212, axes=ax)
plt.errorbar(np.arange(len(data["x"])), data["y"], yerr=data["s"])
plt.show()
lgd
  • 1,472
  • 5
  • 17
  • 35
  • Possible duplicate of [Plotting with seaborn using the matplotlib object-oriented interface](http://stackoverflow.com/questions/23969619/plotting-with-seaborn-using-the-matplotlib-object-oriented-interface) – mwaskom Nov 26 '15 at 01:05
  • @mwaskom: i saw that but don't see how it answers the question since ``factorplot`` doesn't take an ``ax=`` argument. it sounds like it's impossible to do? i want to get the prettyness of seaborn ``factorplot`` but simply inside a subplot – lgd Nov 26 '15 at 01:07

1 Answers1

19

The issue is that factorplot creates a new FacetGrid instance (which in turn creates its own figure), on which it will apply a plotting function (pointplot by default). So if all you want is the pointplot, it would make sense to just use pointplot, and not factorplot.

The following is a bit of a hack, if you really want to, for whatever reason, tell factorplot which Axes to perform its plotting on. As @mwaskom points out in comments, this is not a supported behaviour, so while it might work now, it may not in the future.

You can tell factorplot to plot on a given Axes using the ax kwarg, which gets passed on down to matplotlib, so the linked answer does sort of answer your query. However, it will still create the second figure because of the factorplot call, but that figure will just be empty. A workaround here it to close that extra figure before calling plt.show()

For example:

import matplotlib.pyplot as plt
import pandas
import seaborn as sns
import numpy as np

data = pandas.DataFrame({"x": [1, 2, 4],
                        "y": [10,20,40],
                        "s": [10,10,10]}) # I increased your errors so I could see them

# Create a figure instance, and the two subplots
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)

# Tell pointplot to plot on ax1 with the ax argument
sns.pointplot(x="x", y="y", data=data, ax=ax1)

# Plot the errorbar directly on ax1
ax1.errorbar(np.arange(len(data["x"])), data["y"], yerr=data["s"])

# Tell the factorplot to plot on ax2 with the ax argument
# Also store the FacetGrid in 'g'
g=sns.factorplot(x="x", y="y", data=data, ax=ax2)

# Close the FacetGrid figure which we don't need (g.fig)
plt.close(g.fig)

plt.show()

enter image description here

tmdavison
  • 64,360
  • 12
  • 187
  • 165
  • 2
    This "works" because `factorplot` passes its kwargs through, so the `ax` parameter gets to the right place, but this particularly behavior isn't supported and I wouldn't rely on it. – mwaskom Nov 26 '15 at 13:55
  • @mwaskom, agreed, but do you know a better way to do it? Just thought this might be useful for now – tmdavison Nov 26 '15 at 14:34
  • 3
    There is a fundamental confusion. `factorplot` just applies a plotting function (`pointplot` by default) onto a grid of subplots managed by a `FacetGrid`. It does not make sense to try to draw a `factorplot` onto an existing subplot. Just use `pointplot`. – mwaskom Nov 26 '15 at 14:50
  • @mwaskom: but factorplot does something very useful that pointplot doesn't: it makes a pointplot that reads the labels from your df. with pointplot, i would need to do this by hand. having a function that behaves like pointplot's takes kwargs like ``hue`` that read values from the dataframe would be very useful, because that can be used without giving control over the whole figure to factorplot. it is useful inside individual subplots. – lgd Nov 27 '15 at 21:33
  • 2
    I really am not sure what you mean. Within a single subplot, there is nothing `factorplot` does that `pointplot` doesn't do, because `factorplot` is literally just calling `pointplot` on each of the axes. – mwaskom Nov 27 '15 at 21:37