I am trying to create a series of histograms (from a pd.DataFrame
). I would like different quantities (fare
in the example below) in different rows and different classes (class
in the example below) in different columns, as follows:
import seaborn as sns
from matplotlib import pyplot as plt
titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
sns.displot(
data=df,
x="value",
row="variable",
col="class",
hue="sex",
facet_kws={"sharex": "row", "sharey": "row"},
)
plt.show()
Unfortunately, because of the common_bins=True
parameter it seems that the axis are shared both across the rows and across the columns, which I don't want because different rows have different quantities that can be in very different ranges. Using common_bins=False
I get the following:
import seaborn as sns
from matplotlib import pyplot as plt
titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
sns.displot(
data=df,
x="value",
row="variable",
col="class",
hue="sex",
facet_kws={"sharex": "row", "sharey": "row"},
common_bins=False,
)
plt.show()
In this case the axis are shared only across the same row as I want (which is better suited to represent quantities with different ranges), but the bins are not shared anymore. I'd like the bins to be shared across columns, or at least in the same histogram (but much preferably across columns).
I also tried to use sns.FacetGrid
directly, but in such case it does not seem possible to get a legend
Is there a simple way to share bins and axis on the same row and get a legend based on hue
? Essentially the last figure but with the legend of the first two figures (and possibly bins shared across the same row).
CodePudding user response:
FacetGrid
is designed to show the same x/y relationship in every facet. If that's not what you're trying to do, you may have more success using a more procedural approach. Here's one idea where we use FacetGrid
to set up the figure but loop over the axes individually.
titanic = sns.load_dataset("titanic")
df = pd.melt(titanic, id_vars=["sex", "class"], value_vars=["fare", "age"])
binwidths = {"fare": 20, "age": 5}
g = sns.FacetGrid(df, col="class", row="variable", sharex="row", sharey="row", height=2.5)
for (var, cls), ax in g.axes_dict.items():
sns.histplot(
data=titanic[titanic["class"] == cls],
x=var, hue="sex",
binwidth=binwidths[var],
ax=ax, legend=ax is g.axes.flat[-1])
g.set_titles(template="{col_name} {col_var}")
plt.setp(g.axes[1], title="")
sns.move_legend(ax, loc="lower left", bbox_to_anchor=(1, 1))