I am new to seaborn, and I was going through documentation and examples. I have attached the plot below. How can we interpret the color intensity in this plot?
We will not be able to really understand what those bluish colours mean unless there is a scale or a guide which represents the mapping of colors to some attributes of the data.
Thus, the best way to do this would be to add a cbar=True argument in sns.displot, along with the title of the colorbar to make sure the visualisation conveys the context properly.
import matplotlib.pyplot as plt
import seaborn as sns
penguins = sns.load_dataset("penguins")
sns.displot(data=penguins, x="bill_length_mm", y="bill_depth_mm", cbar=True,
cbar_kws={'label': 'Counts in the bin'})
plt.show()
This gives:
Related
I'm experimenting with seaborn and have a question about specifying axes properties. In my code below, I've taken two approaches to creating a heatmap of a matrix and placing the results on two sets of axes in a figure.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
A=np.random.randn(4,4)
labels=['a','b','c','d']
fig, ax = plt.subplots(2)
sns.heatmap(ax =ax[0], data = A)
ax[0].set_xticks(range(len(labels)))
ax[0].set_xticklabels(labels,fontsize=10,rotation=45)
ax[0].set_yticks(range(len(labels)))
ax[0].set_yticklabels(labels,fontsize=10,rotation=45)
ax[1].set_xticks(range(len(labels)))
ax[1].set_xticklabels(labels,fontsize=10,rotation=45)
ax[1].set_yticks(range(len(labels)))
ax[1].set_yticklabels(labels,fontsize=10,rotation=45)
sns.heatmap(ax =ax[1], data = A,xticklabels=labels, yticklabels=labels)
plt.show()
The resulting figure looks like this:
Normally, I would always take the first approach of creating the heatmap and then specifying axis properties. However, when creating an animation (to be embedded on a tkinter canvas), which is what I'm ultimately interested in doing, I found such an ordering in my update function leads to "flickering" of axis labels. The second approach will eliminate this effect, and it also centers the tickmarks within squares along the axes.
However, the second approach does not rotate the y-axis tickmark labels as desired. Is there a simple fix to this?
I'm not sure this is what you're looking for. It looks like you create your figure after you change the yticklabels. so the figure is overwriting your yticklabels.
Below would fix your issue.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
A=np.random.randn(4,4)
labels=['a','b','c','d']
fig, ax = plt.subplots(2)
sns.heatmap(ax =ax[0], data = A)
ax[0].set_xticks(range(len(labels)))
ax[0].set_xticklabels(labels,fontsize=10,rotation=45)
ax[0].set_yticks(range(len(labels)))
ax[0].set_yticklabels(labels,fontsize=10,rotation=45)
ax[1].set_xticks(range(len(labels)))
ax[1].set_xticklabels(labels,fontsize=10,rotation=45)
ax[1].set_yticks(range(len(labels)))
sns.heatmap(ax =ax[1], data = A,xticklabels=labels, yticklabels=labels)
ax[1].set_yticklabels(labels,fontsize=10,rotation=45)
plt.show()
'''
Hi there,
I created a clustermap using seaborn. Because the legend overlaps with the figure, I'd like to move it. However, plt.legend(bbox_to_anchor=(1,1)) gave the following error 'No handles with labels found to put in legend.'
That makes me wonder: what is the color scale -20 to 20 on the top left that I want to re-position? isn't that a legend?
Thank you in advance for shedding light on that for me.
'''
import matplotlib.pyplot as plt
import seaborn as sns
g = sns.clustermap(data=df_highestPivot,cmap='coolwarm')
plt.legend(bbox_to_anchor=(1,1)) #This line generate the error
plt.savefig('plot.png',dpi=300,bbox_to_inches='tight')
plt.show()
plt.close()
The colorbar is not a legend per se (not an object of type Legend at least). It is actually it's own subplots Axes, that you can access using g.ax_cbar.
If you want to move it, you can pass an argument cbar_pos= to clustermap(). However, it's complicated to find an empty space in the figure to place it. I would recommend you make some room using subplots_adjust() then move the ax_cbar Axes at the desired location
iris = sns.load_dataset('iris')
species = iris.pop("species")
g = sns.clustermap(iris)
g.fig.subplots_adjust(right=0.7)
g.ax_cbar.set_position((0.8, .2, .03, .4))
The color map in matplotlib allows to mark "bad" values, i.e. NaNs, with a specific color. When we plot the color bar afterwards, this color is not included. Is there a preferred approach to have both the contiuous color bar and a discrete legend for the specific color for bad values?
Edit:
Certainly, it's possible to make use of the "extend" functionality. However, this solution is not satisfactory. The function of the legend/colorbar is to clarify the meaning of colors to the user. In my opinion, this solution does not communicate that the value is a NaN.
Code example:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
data = np.random.rand(10, 10)
data[0:3, 0:3] = np.nan # some bad values for set_bad
colMap = cm.RdBu
colMap.set_bad(color='black')
plt.figure(figsize=(10, 9))
confusion_matrix = plt.imshow(data, cmap=colMap, vmin=0, vmax=1)
plt.colorbar(confusion_matrix)
plt.show()
Which produces:
A legend element could be created and used as follows:
from matplotlib.patches import Patch
legend_elements = [Patch(facecolor=colMap(np.nan), label='Bad values')]
plt.legend(handles=legend_elements)
You can do this using one of the approaches used for out-of-range plotting shown at https://matplotlib.org/3.1.1/tutorials/colors/colorbar_only.html#discrete-intervals-colorbar
Set the color of the bad value e.g. to -999 and use the keyword extend.
Another approach is to used masked plotting as shown here.
Another way could be to use cmap.set_bad(). An example can be found here.
So I need to create a number of heatmaps in seaborn with varying datascales. Some range from 0-100 and some +100 to -100. What I need to do is to keep the colour grading the same throughout all graphs. So for example I want anything below 0 to be steadily getting from dark blue to light blue and anything above 0 to be getting darker red such as the terrible example graph below.
What I need that is not shown below very well is a fluid colour transition as currently I am not fully sure how seaborn is working it out as I have just listed a number of colours - Code below
sns.heatmap(df.T, cmap=ListedColormap(['#000066','#000099','#0000cc','#1a1aff','#6666ff','#b3b3ff','#ffff00','#ffcccc','#ff9999','#ff6666','#ff3333','#ff0000']), annot=False)
Thanks for any advise.
To specify the color normalization, you can use a Normalize instance, plt.Normalize(vmin, vmax) and supply it to the heatmap using the norm keyword (which is routed to the underlying pcolormesh).
To obtain a colormap with gradually changing colors, you may use the static LinearSegmentedColormap.from_list method and supply it with a list of colors.
import numpy as np; np.random.seed(0)
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
x1 = np.random.randint(0,100,size=(12,8))
x2 = np.random.randint(-100,100,size=(12,8))
fig, axes = plt.subplots(ncols=2)
cmap = mcolors.LinearSegmentedColormap.from_list("n",['#000066','#000099','#0000cc','#1a1aff','#6666ff','#b3b3ff',
'#ffff00','#ffcccc','#ff9999','#ff6666','#ff3333','#ff0000'])
norm = plt.Normalize(-100,100)
sns.heatmap(x1, ax=axes[0], cmap=cmap, norm=norm)
sns.heatmap(x2, ax=axes[1], cmap=cmap, norm=norm)
plt.show()
I tried to get the legend right for the dashed line so I played with the rcParams a little bit, but it for some reasons wouldn't work on my computer.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['legend.numpoints'] = 5
matplotlib.rcParams['legend.scatterpoints'] = 5
fig, axs = plt.subplots()
axs.plot(range(10), '--k', label="line")
axs.plot(range(10), range(10)[::-1], ':k', label="scatter")
axs.legend(loc=9)
plt.show()
And the resultant figure is:
And as can be seen, the numpoints for the dashed line is not enough. Would anyone please help?
Thanks!
If you make a plot with markers, matplotlib.rcParams['legend.numpoints'] adjust the number of points drawn on the legend lines.
If you substitute your plot by these:
axs.plot(range(10), '--k', label="line", marker='d')
axs.plot(range(10), range(10)[::-1], ':k', label="scatter", marker='o')
you get this image:
I don't know what does matplotlib.rcParams['legend.scatterpoints'] do, but I guess regulates the number of points in the legend of scatter plots.
If you want to change the length of the lines in the legend give a try with matplotlib.rcParams['legend.handlelength'] and/or matplotlib.rcParams['legend.handleheight']. More info about rc file can be found here
As suggested by #tcaswell, you don't have to set rc parameters. All the legend.* parameters are available as keywords for the legend function. See matplotlib.pyplot.legend documentation