Is there any way to change the legends in seaborn? - seaborn

I would like to change the format of pIC50 in the legend box. I would like it to be "circle according to the size with no filled color". Any suggestions are welcome!
plt.figure(figsize=(7, 7))
sns.scatterplot(x='MW', y='LogP', data=df_2class, hue='class', size='pIC50', edgecolor='black', alpha=0.2)
sns.set_style("whitegrid", {"ytick.major.size": 100,"xtick.major.size": 2, 'grid.linestyle': 'solid'})
plt.xlabel('MW', fontsize=14, fontweight='bold')
plt.ylabel('LogP', fontsize=14, fontweight='bold')
plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0)

In this case, you can loop through the last legend handles and change the color of the dots. Here is an example using the iris dataset:
import matplotlib.pyplot as plt
import seaborn as sns
iris = sns.load_dataset('iris')
ax = sns.scatterplot(data=iris, x='sepal_length', y='petal_length', hue='species', size='sepal_width')
handles, labels = ax.get_legend_handles_labels()
for h in handles[-5:]: # changes the 5 last handles, this number might be different in your case
h.set_facecolor('none')
ax.legend(handles=handles, labels=labels, bbox_to_anchor=[1.02, 1.02], loc='upper left')
plt.tight_layout()
plt.show()

Related

Rotating both subplots x ticks [duplicate]

I am trying to rotate the x axis labels for every subplot. Here is my code:
fig.set_figheight(10)
fig.set_figwidth(20)
ax.set_xticklabels(dr_2012['State/UT'], rotation = 90)
ax[0, 0].bar(dr_2012['State/UT'], dr_2012['Primary Total'])
ax[0, 0].set_title('Dropout Ratios 2012-2013 (Primary)')
ax[0, 1].bar(dr_2012['State/UT'], dr_2012['Upper Primary Total'])
ax[0, 1].set_title('Dropout Ratios 2012-2013 (Upper Primary)')
ax[1, 0].bar(dr_2012['State/UT'], dr_2012['Secondary Total'])
ax[1, 0].set_title('Dropout Ratios 2012-2013 (Secondary)')
ax[1, 1].bar(dr_2012['State/UT'], dr_2012['HS Total'])
ax[1, 1].set_title('Dropout Ratios 2012-2013 (HS)')
subplot
None of the usual things seem to work for me. I have tried ax.set_xticklabels and ax.tick_params. I have also tried looping through the ticks using ax.get_xticklabels and even that didn't work. It always gave me this error -
AttributeError: 'numpy.ndarray' object has no attribute 'set_xticklabels'/'get_xticklabels'/'tick_params'
I am at a loss. Why wouldn't it be working?
Use tick_params on the AxesSubplot, but ax in your case is an np array of AxesSubplot objects.
Fix
ax[1][0].tick_params(axis='x', rotation=90)
Sample usage
import matplotlib.pyplot as plt
fig,ax = plt.subplots(2,2)
import numpy as np
x = np.arange(1,5)
ax[0][0].plot(x,x*x)
ax[0][0].set_title('square')
ax[0][0].tick_params(axis='x', rotation=90)
ax[0][1].plot(x,np.sqrt(x))
ax[0][1].set_title('square root')
ax[0][1].tick_params(axis='x', rotation=90)
ax[1][0].plot(x,np.exp(x))
ax[1][0].set_title('exp')
ax[1][0].tick_params(axis='x', rotation=90)
ax[1][1].plot(x,np.log10(x))
ax[1][1].set_title('log')
ax[1][1].tick_params(axis='x', rotation=90)
plt.show()
Output:

Seaborn Scatter plot custom legend showing Single Label

I used the below code to plot a scatter plot using seaborn. I need to change the labels text in legend. But when I add custom text for the legends, it's only showing one label. I need to have legend text as ['set', 'versi', 'vir']. The code is as below -
import seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset("iris")
scatter = sns.scatterplot(x='sepal_length', y ='sepal_width', hue='species', data=iris, legend=False)
scatter.legend(labels = ['set', 'versi', 'vir'], loc='upper right')
plt.show(scatter)
Seaborn's sophisticated way of working can't always follow the rules needed for a standard legend (see e.g. issue 2280). Often, the legend is custom created. Currently, matplotlib doesn't provide simple functions to move (or alter) such a legend.
In seaborn 0.11.2, a function sns.move_legend(ax, ...) (info on github) is added, which can move the legend and change some other properties (but not the labels).
So, you can first let sns.scatterplot create a legend, and then move it.
The labels in the legend come from the element names in the hue-column. To obtain different names, the most straightforward way is to temporarily rename them.
Here is some example code (note that plt.show() doesn't have an ax as parameter, but does have an optional block= parameter):
import seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset("iris")
ax = sns.scatterplot(x='sepal_length', y='sepal_width', hue='species',
data=iris.replace({'species': {'setosa': 'set', 'versicolor': 'versi', 'virginica': 'vir'}}))
sns.move_legend(ax, loc='upper right')
plt.show()

How to customize seaborn.scatterplot legends?

I plotted a scatterplot with seaborn library and I want to change the legend text but dont know how to do that.
example:
The following is iris dataset with species columns encoded in 0/1/2 as per species.
plt.figure(figsize=(8,8))
pl = sns.scatterplot(x='petal_length', y ='petal_width', hue='Species', data=data, s=40,
palette='Set1', legend='full')
I want to change the legends text from [0, 1, 2] to ['setosa', 'versicolor', 'virginica'].
can anybody help.
First, Seaborn (and Matplotlib) usually picks up the labels to put into the legend for hue from the unique values of the array you provide as hue. So as a first step, check that the column Species in your dataframe actually contains the values "setosa", "versicolor", "virginica". If not, one solution is to temporarily map them to other values, for the purpose of plotting:
legend_map = {0: 'setosa',
1: 'versicolor',
2: 'virginica'}
plt.figure(figsize=(8,8))
ax = sns.scatterplot(x=data['petal_length'], y =data['petal_width'], hue=data['species'].map(legend_map),
s=40, palette='Set1', legend='full')
plt.show()
Alternatively, if you want to directly manipulate the plot information and not the underlying data, you can do by accessing the legend names directly:
plt.figure(figsize=(8,8))
ax = sns.scatterplot(x='petal_length', y ='petal_width', hue='species', data=data, s=40,
palette='Set1', legend='full')
l = ax.legend()
l.get_texts()[0].set_text('Species') # You can also change the legend title
l.get_texts()[1].set_text('Setosa')
l.get_texts()[2].set_text('Versicolor')
l.get_texts()[3].set_text('Virginica')
plt.show()
This methodology allows you to also change the legend title, if need be.

How do I get rid of space between x-ticks and axis in Seaborn heatmap?

In a Seaborn heatmap (within Jupyter Notebook), I am getting extra space between the axis and the x-ticks, which I've moved to the top. If I leave the ticks at the bottom, they are flush as expected, but I need them at the top. I can't figure how to get rid of that space between the upper edge of the plot and the x-ticks. I tried the padding setting in set_tick_params, but that only adjusts space between the tick and the label.
Here's a subset of the data to play with
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
axis_labels = ['Q1','Q2','Q3','Q4','Q5']
data = pd.DataFrame([[np.nan,0.14,0.01,0.00,-0.05],
[0.30,np.nan,0.01,0.03,-0.04],
[0.16,0.10,np.nan,0.01,-0.02],
[0.14,0.05,0.02,np.nan,-0.04],
[0.16,0.09,0.01,0.02,np.nan]])
fig, ax = plt.subplots(figsize=(15,15))
sb.heatmap(data, ax=ax, center=0, annot=True, mask=data.isnull(),
square=True, cmap=sb.diverging_palette(275, 150, s=80, l=55, as_cmap=True), cbar_kws={"shrink": 0.75})
ax.set_ylim(5,-0.5)
ax.set_xticklabels(axis_labels, rotation=90, ha='center', fontsize=12)
ax.set_yticklabels(axis_labels, rotation=0, fontsize=12)
ax.xaxis.tick_top();
Probably something super simple that I'm missing. Any ideas?

How to rotate ylabel of pairplot in searborn? [duplicate]

I have a simple factorplot
import seaborn as sns
g = sns.factorplot("name", "miss_ratio", "policy", dodge=.2,
linestyles=["none", "none", "none", "none"], data=df[df["level"] == 2])
The problem is that the x labels all run together, making them unreadable. How do you rotate the text so that the labels are readable?
I had a problem with the answer by #mwaskorn, namely that
g.set_xticklabels(rotation=30)
fails, because this also requires the labels. A bit easier than the answer by #Aman is to just add
plt.xticks(rotation=45)
You can rotate tick labels with the tick_params method on matplotlib Axes objects. To provide a specific example:
ax.tick_params(axis='x', rotation=90)
This is still a matplotlib object. Try this:
# <your code here>
locs, labels = plt.xticks()
plt.setp(labels, rotation=45)
Any seaborn plots suported by facetgrid won't work with (e.g. catplot)
g.set_xticklabels(rotation=30)
however barplot, countplot, etc. will work as they are not supported by facetgrid. Below will work for them.
g.set_xticklabels(g.get_xticklabels(), rotation=30)
Also, in case you have 2 graphs overlayed on top of each other, try set_xticklabels on graph which supports it.
If anyone wonders how to this for clustermap CorrGrids (part of a given seaborn example):
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(context="paper", font="monospace")
# Load the datset of correlations between cortical brain networks
df = sns.load_dataset("brain_networks", header=[0, 1, 2], index_col=0)
corrmat = df.corr()
# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(12, 9))
# Draw the heatmap using seaborn
g=sns.clustermap(corrmat, vmax=.8, square=True)
rotation = 90
for i, ax in enumerate(g.fig.axes): ## getting all axes of the fig object
ax.set_xticklabels(ax.get_xticklabels(), rotation = rotation)
g.fig.show()
You can also use plt.setp as follows:
import matplotlib.pyplot as plt
import seaborn as sns
plot=sns.barplot(data=df, x=" ", y=" ")
plt.setp(plot.get_xticklabels(), rotation=90)
to rotate the labels 90 degrees.
For a seaborn.heatmap, you can rotate these using (based on #Aman's answer)
pandas_frame = pd.DataFrame(data, index=names, columns=names)
heatmap = seaborn.heatmap(pandas_frame)
loc, labels = plt.xticks()
heatmap.set_xticklabels(labels, rotation=45)
heatmap.set_yticklabels(labels[::-1], rotation=45) # reversed order for y
One can do this with matplotlib.pyplot.xticks
import matplotlib.pyplot as plt
plt.xticks(rotation = 'vertical')
# Or use degrees explicitly
degrees = 70 # Adjust according to one's preferences/needs
plt.xticks(rotation=degrees)
Here one can see an example of how it works.
Use ax.tick_params(labelrotation=45). You can apply this to the axes figure from the plot without having to provide labels. This is an alternative to using the FacetGrid if that's not the path you want to take.
If the labels have long names it may be hard to get it right. A solution that worked well for me using catplot was:
import matplotlib.pyplot as plt
fig = plt.gcf()
fig.autofmt_xdate()

Resources