Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

seaborn produces separate figures in subplots

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()
like image 212
lgd Avatar asked Nov 25 '15 20:11

lgd


1 Answers

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

like image 152
tmdavison Avatar answered Oct 03 '22 00:10

tmdavison