Python, Seaborn FacetGrid change titles - python

I am trying to create a FacetGrid in Seaborn
My code is currently:
g = sns.FacetGrid(df_reduced, col="ActualExternal", margin_titles=True)
bins = np.linspace(0, 100, 20)
g.map(plt.hist, "ActualDepth", color="steelblue", bins=bins, width=4.5)
This gives my the Figure
Now, instead of "ActualExternal =0.0" and "ActualExternal =1.0" I would like the titles "Internal" and "External"
And, instead of "ActualDepth" I would like the xlabel to say "Percentage Depth"
Finally, I would like to add a ylabel of "Number of Defects".
I've tried Googling and have tried a few things but so far no success. Please can you help me?
Thanks

Although you can iterate through the axes and set the titles individually using matplotlib commands, it is cleaner to use seaborn's built-in tools to control the title. For example:
# Add a column of appropriate labels
df_reduced['measure'] = df_reduced['ActualExternal'].replace({0: 'Internal',
1: 'External'}
g = sns.FacetGrid(df_reduced, col="measure", margin_titles=True)
g.map(plt.hist, "ActualDepth", color="steelblue", bins=bins, width=4.5)
# Adjust title and axis labels directly
g.set_titles("{col_name}") # use this argument literally
g.set_axis_labels(x_var="Percentage Depth", y_var="Number of Defects")
This has the benefit of not needing modification regardless of whether you have 1D or 2D facets.

You can access the axes of a FacetGrid (g = sns.FacetGrid(...)) via g.axes. With that you are free to use any matplotlib method you like to tweak the plot.
Change titles:
axes = g.axes.flatten()
axes[0].set_title("Internal")
axes[1].set_title("External")
Change labels:
axes = g.axes.flatten()
axes[0].set_ylabel("Number of Defects")
for ax in axes:
ax.set_xlabel("Percentage Depth")
Note that I prefer those above the FacetGrid's internal g.set_axis_labels and set_titles methods, because it makes it more obvious which axes is to be labelled.

The easiest way to set multiple titles would be:
titles = ['Internal','External']
for ax,title in zip(g.axes.flatten(),titles):
ax.set_title(title )

Related

Seaborn catplot + barplot : extra axis

I use Seaborn/Matplotlib to display different outputs (time and distance for example) for different parameters. I would like to associate the two outputs on the same plot, thus I use seaborn's satplot and barplot.
My problem is I don't get the expected display. The graph is here but some noisy extra axis appear.
I'm running the following code
ax = plt.subplot(311)
ax2 = ax.twinx()
data = sns.load_dataset("tips")
sns.barplot(ax=ax, x="day",y="total_bill", hue="size" , data=data, ci=None)
ax.set_yscale("log")
sns.catplot(data=data, x="day", y="tip", ax=ax2, hue="size", kind="swarm", palette="bright")
And I have the following result :
Could you help me to remove this extra axis ? It is especially inconvenient when having multiple subplots.
The extra axis you see is the one returned by the catplot. To get rid of it, you can add the following line after the sns.catplot(...) where the index 2 refers to the count of the figure.
plt.close(2)
To test that, if you use plt.close(1), it will remove the main figure containing bar chart
The extra axes you see is the catplot you create. catplot is a figure-level function (i.e. it creates its own figure); and hence does not really have an ax argument. One could see it as bug that it still allows for it. What you would probably like to do is to create a sns.swarmplot instead, which does have the ax argument.

seaborn/matplotlib change number of columns in legend object

I've seen Creating multi column legend in python seaborn plot but I think my question is a bit different. In short, I've got a dataframe that I'm plotting in seaborn's lmplot and getting a FacetGrid. Trouble is, there are tons of values for hue so I get a super long, single column legend. Code example below:
ers = sns.lmplot(
data=emorb,
x="Pb",
y="Nd",
row="Ridge Sys",
hue="Seg Name",
scatter=True,
fit_reg=False,
scatter_kws={"alpha":0.7, "edgecolor": "w"},
palette=sns.color_palette("bright", 20),
legend=True
)
ers.set(ylim=(0.5122,0.5134))
I can access the legend object that is created by calling ers._legend and this returns an object with type Legend (basically, a matplotlib object). However, I can't then call to this legend object to change the number of columns, e.g., with:
l = ers._legend
l(ncols=9)
Any suggestions, or am I missing something perhaps more obvious, such as a way to redraw the legend and specify any parameters?
Thanks.
Whoops, figured it out:
The FacetGrid object has an attribute fig, i.e.
g = sns.lmplot()
parent_mpl_figure = g.fig
And so if I set legend=False in sns.lmplot(), I can then specify parent_mpl_figure.legend(labels=[], ncol=9, bbox_to_anchor=(1,1)).
Written cleanly:
g = sns.lmplot(legend = False)
parent_mpl_figure = g.fig
parent_mpl_figure.legend(labels = [], ncol = 9, bbox_to_anchor = (1,1))
Hope this is instructive for someone else / now to figure out how to have each Facet span the full color palette so that different hue groups within each Facet group are easier to distinguish...

Changing subplot titles in seaborn's FacetGrid [duplicate]

I am trying to create a FacetGrid in Seaborn
My code is currently:
g = sns.FacetGrid(df_reduced, col="ActualExternal", margin_titles=True)
bins = np.linspace(0, 100, 20)
g.map(plt.hist, "ActualDepth", color="steelblue", bins=bins, width=4.5)
This gives my the Figure
Now, instead of "ActualExternal =0.0" and "ActualExternal =1.0" I would like the titles "Internal" and "External"
And, instead of "ActualDepth" I would like the xlabel to say "Percentage Depth"
Finally, I would like to add a ylabel of "Number of Defects".
I've tried Googling and have tried a few things but so far no success. Please can you help me?
Thanks
Although you can iterate through the axes and set the titles individually using matplotlib commands, it is cleaner to use seaborn's built-in tools to control the title. For example:
# Add a column of appropriate labels
df_reduced['measure'] = df_reduced['ActualExternal'].replace({0: 'Internal',
1: 'External'}
g = sns.FacetGrid(df_reduced, col="measure", margin_titles=True)
g.map(plt.hist, "ActualDepth", color="steelblue", bins=bins, width=4.5)
# Adjust title and axis labels directly
g.set_titles("{col_name}") # use this argument literally
g.set_axis_labels(x_var="Percentage Depth", y_var="Number of Defects")
This has the benefit of not needing modification regardless of whether you have 1D or 2D facets.
You can access the axes of a FacetGrid (g = sns.FacetGrid(...)) via g.axes. With that you are free to use any matplotlib method you like to tweak the plot.
Change titles:
axes = g.axes.flatten()
axes[0].set_title("Internal")
axes[1].set_title("External")
Change labels:
axes = g.axes.flatten()
axes[0].set_ylabel("Number of Defects")
for ax in axes:
ax.set_xlabel("Percentage Depth")
Note that I prefer those above the FacetGrid's internal g.set_axis_labels and set_titles methods, because it makes it more obvious which axes is to be labelled.
The easiest way to set multiple titles would be:
titles = ['Internal','External']
for ax,title in zip(g.axes.flatten(),titles):
ax.set_title(title )

Seaborn Boxplot: get the xtick labels

I am using Seaborn to make a boxplot using data from a pandas dataframe.
colorpalette = sns.hls_palette(8,h=.9)
g = sns.boxplot(x="estimator", y="mean_score", data=dFrame, palette=colorpalette)
g.set(ylabel='Mean Accuracy', xlabel='')
plt.show()
This results me in the previous figure. As you can see the ticklabels are too long to be in one line. So, I plan to use textwrap on the xticklabels to span them over multiple rows. In order to get the labels, I tried using
g.xaxis.get_ticklabels()
Returns me the following
<a list of 9 Text major ticklabel objects>
If I try it in a loop like this
for item in g.xaxis.get_ticklabels():
print(item)
I get the following output
Text(0,0,'ExtraTreesClassifier')
Text(1,0,'RandomForestClassifier')
Text(2,0,'GradientBoostingClassifier')
Text(3,0,'LogisticRegression')
Text(4,0,'DecisionTreeClassifier')
Text(5,0,'kNearestNeighbors')
Text(6,0,'LinearSVC')
Text(7,0,'Perceptron')
Is there a way to do it more efficiently using default functions/methods in seaborn.
Having a matplotlib axes instance ax (as it is e.g. returned by seaborn plots),
ax = sns.boxplot(...)
allows to obtain the ticklabels as
ax.get_xticklabels()
The easiest way to get the texts out of the list would be
texts = [t.get_text() for t in ax.get_xticklabels()]
Wrapping the text could be done as well on the fly
texts = [textwrap.fill(t.get_text(), 10) for t in ax.get_xticklabels()]
and even setting the text back as ticklabels can be done in the same line
ax.set_xticklabels([textwrap.fill(t.get_text(), 10) for t in ax.get_xticklabels()])
The accepted answer didn't work for me (there was message like: 'FacetGrid' object has no attribute 'get_xticklabels'.
but this worked:
g.fig.autofmt_xdate()

set axis limits on individual facets of seaborn facetgrid

I'm trying to set the x-axis limits to different values for each facet a Seaborn facetgrid distplot. I understand that I can get access to all the axes within the subplots through g.axes, so I've tried to iterate over them and set the xlim with:
g = sns.FacetGrid(
mapping,
col=options.facetCol,
row=options.facetRow,
col_order=sorted(cols),
hue=options.group,
)
g = g.map(sns.distplot, options.axis)
for i, ax in enumerate(g.axes.flat): # set every-other axis for testing purposes
if i % 2 == 0[enter link description here][1]:
ax.set_xlim(-400, 500)
else:
ax.set_xlim(-200, 200)
However, when I do this, all axes get set to (-200, 200) not just every other facet.
What am I doing wrong?
mwaskom had the solution; posting here for completeness - just had to change the following line to:
g = sns.FacetGrid(
mapping,
col=options.facetCol,
row=options.facetRow,
col_order=sorted(cols),
hue=options.group,
sharex=False, # <- This option solved the problem!
)
As suggested by mwaskom you can simply use FacetGrid's sharex (respectively sharey) to allow plots to have independent axis scales:
share{x,y} : bool, ‘col’, or ‘row’ optional
If true, the facets will share y axes across columns and/or x axes across rows.
For example, with:
sharex=False each plot has its own axis
sharex='col' each column has its own axis
sharex='row' each row has its own axis (even if this one doesn't make too much sense to me)
sns.FacetGrid(data, ..., sharex='col')
If you use FacetGrid indirectly, for example via displot or relplot, you will have to use the facet_kws keyword argument:
sns.displot(data, ..., facet_kws={'sharex': 'col'})

Categories

Resources