matplotlib: colorbars and its text labels - python

I'd like to create a colorbar legend for a heatmap, such that the labels are in the center of each discrete color. Example borrowed from here:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
#discrete color scheme
cMap = ListedColormap(['white', 'green', 'blue','red'])
#data
np.random.seed(42)
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=cMap)
#legend
cbar = plt.colorbar(heatmap)
cbar.ax.set_yticklabels(['0','1','2','>3'])
cbar.set_label('# of contacts', rotation=270)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
ax.invert_yaxis()
#labels
column_labels = list('ABCD')
row_labels = list('WXYZ')
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
This generates the following plot:
Ideally I'd like to generate a legend bar which has the four colors and for each color, a label in its center: 0,1,2,>3. How can this be achieved?

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
#discrete color scheme
cMap = ListedColormap(['white', 'green', 'blue','red'])
#data
np.random.seed(42)
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=cMap)
#legend
cbar = plt.colorbar(heatmap)
cbar.ax.get_yaxis().set_ticks([])
for j, lab in enumerate(['$0$','$1$','$2$','$>3$']):
cbar.ax.text(.5, (2 * j + 1) / 8.0, lab, ha='center', va='center')
cbar.ax.get_yaxis().labelpad = 15
cbar.ax.set_ylabel('# of contacts', rotation=270)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
ax.invert_yaxis()
#labels
column_labels = list('ABCD')
row_labels = list('WXYZ')
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
You were very close. Once you have a reference to the color bar axis, you can do what ever you want to it, including putting text labels in the middle. You might want to play with the formatting to make it more visible.

To add to tacaswell's answer, the colorbar() function has an optional cax input you can use to pass an axis on which the colorbar should be drawn. If you are using that input, you can directly set a label using that axis.
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, ax = plt.subplots()
heatmap = ax.imshow(data)
divider = make_axes_locatable(ax)
cax = divider.append_axes('bottom', size='10%', pad=0.6)
cb = fig.colorbar(heatmap, cax=cax, orientation='horizontal')
cax.set_xlabel('data label') # cax == cb.ax

This will make you add label and change colorbar's tick and label size:
clb=plt.colorbar()
clb.ax.tick_params(labelsize=8)
clb.ax.set_title('Your Label',fontsize=8)
This can be also used if you have sublots:
plt.tight_layout()
plt.subplots_adjust(bottom=0.05)
cax = plt.axes([0.1, 0, 0.8, 0.01]) #Left,bottom, length, width
clb=plt.colorbar(cax=cax,orientation="horizontal")
clb.ax.tick_params(labelsize=8)
clb.ax.set_title('Your Label',fontsize=8)

Related

Move xlabel text at top using Matplotlib [duplicate]

Based on this question about heatmaps in matplotlib, I wanted to move the x-axis titles to the top of the plot.
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4,4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1])+0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.set_label_position('top') # <-- This doesn't work!
ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
plt.show()
However, calling matplotlib's set_label_position (as notated above) doesn't seem to have the desired effect. Here's my output:
What am I doing wrong?
Use
ax.xaxis.tick_top()
to place the tick marks at the top of the image. The command
ax.set_xlabel('X LABEL')
ax.xaxis.set_label_position('top')
affects the label, not the tick marks.
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
You want set_ticks_position rather than set_label_position:
ax.xaxis.set_ticks_position('top') # the rest is the same
This gives me:
tick_params is very useful for setting tick properties. Labels can be moved to the top with:
ax.tick_params(labelbottom=False,labeltop=True)
You've got to do some extra massaging if you want the ticks (not labels) to show up on the top and bottom (not just the top). The only way I could do this is with a minor change to unutbu's code:
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()
ax.xaxis.set_ticks_position('both') # THIS IS THE ONLY CHANGE
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
Output:

Move Colorbar closer to Heatmap (Seaborn)

My colorbar is very far away from the bottom of my heatmap. Is there a way to move it closer?
My code is:
import seaborn as sns
Granger2 = Granger
Granger2.columns = Granger_colnames
Granger2.index = Granger_rownames
fig, ax = plt.subplots(figsize=(6,25))
sns.heatmap(Granger2, cmap=rvb, cbar=True, ax=ax,linewidths=.5,cbar_kws={"orientation": "horizontal"})
ax.xaxis.tick_top() # x axis on top
ax.xaxis.set_label_position('top')
#Remove ticks
ax.tick_params(axis='both', which='both', length=0)
# Drawing the frame
ax.axhline(y = 0, color='k',linewidth = 1)
ax.axhline(y = Granger2.shape[0], color = 'k',linewidth = 1)
ax.axvline(x = 0, color = 'k', linewidth = 1)
ax.axvline(x = Granger2.shape[1], color = 'k', linewidth = 1)
plt.show()
You can use e.g. cbar_kws={"orientation": "horizontal", "pad":0.02}. The padding is a fraction of the subplot height, so 0.02 is 2%. See the colorbar docs for more information about pad and other parameters.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
sns.set_style('whitegrid')
flights = sns.load_dataset('flights')
flights = flights.pivot('year', 'month').droplevel(0, axis=1)
fig, ax = plt.subplots(figsize=(6, 20))
sns.heatmap(flights, cmap='Greens', cbar=True, ax=ax, linewidths=.5,
cbar_kws={"orientation": "horizontal", "pad": 0.02})
ax.xaxis.tick_top() # x axis on top
ax.xaxis.set_label_position('top')
# Remove ticks
ax.tick_params(axis='both', which='both', length=0)
# Drawing the frame
ax.patch.set_edgecolor('0.15')
ax.patch.set_linewidth(2)
plt.tight_layout()
plt.show()

Filter out certain colors after plotting data using a colormap

Using the below code I have made the data to be plotted using only the upper half (0.5 to 1) of the default 'jet' colormap, the range of the colormap being 0 to 1.
If I want the data to show colors only between the range of 0.7 - 1, how do I do it?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
np.random.seed(1)
# Evaluate an existing colormap from 0.5 (midpoint) to 1 (upper end)
cmap = plt.get_cmap('jet')
colors = cmap(np.linspace(0.5, 1, cmap.N ))
# Create a new colormap from those colors
cmap2 = LinearSegmentedColormap.from_list('Upper Half', colors)
z = np.random.random((4,4))
fig, axes = plt.subplots(ncols=2)
for ax, cmap in zip(axes.flat, [cmap, cmap2]):
cax = ax.imshow(z, cmap=cmap, origin='lower')
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()
Result:
I want to get something looking like
You can use vmin and vmax argument. Define the ranges in a list called vlst which are 0-1 for the left figure and 0.7-1 for the right figure.
vlst = [[0, 1], [0.7, 1]]
fig, axes = plt.subplots(ncols=2)
for ax, cmap, v in zip(axes.flat, [cmap, cmap2], vlst):
cax = ax.imshow(z, cmap=cmap, origin='lower',vmin=v[0], vmax=v[1])
cbar = fig.colorbar(cax, ax=ax, orientation='horizontal')
cbar.set_label(cmap.name)
plt.show()

Why this code for colorbar labeling works with Matplotlib 2.2.3 but not with Matplotlib 3.0.1?

I have the following code:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
arr = np.random.randint(0, 100, (2, 3, 4))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_kws=dict(ticks=(0, 100))
cbar_txt='arb. units'
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
# cbar = ax.figure.colorbar(plot, ax=ax, **dict(cbar_kws))
if cbar_txt is not None:
only_extremes = 'ticks' in cbar_kws and len(cbar_kws['ticks']) == 2
if only_extremes:
cbar.ax.text(
2.0, 0.5, cbar_txt, fontsize='medium', rotation=90,
va='center', ha='left')
else:
cbar.set_label(cbar_txt)
plt.tight_layout()
plt.show()
This works fine for Matplotlib 2.2.3 where I get a text in the middle of the colorbar (on the right):
But does not work the same way for Matplotlib 3.0.1, where the text gets rendered at the bottom of the colorbar:
Why? Any suggestion for obtaining the same behavior with both versions?
How
Using cbar.ax.text seems to be a workaround for some other problem. The recommended way to set a label to the colorbar is either via the colorbar call itself, or via cbar.set_label("label").
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
arr = np.random.randint(0, 100, (2, 3))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_kws=dict(ticks=(0, 100))
cbar_txt='arb. units'
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
cbar.set_label(cbar_txt, labelpad=-12)
plt.tight_layout()
plt.show()
The result is the same in matplotlib 2.2.3 and 3.0.1:
To have the label distance independent of the length of the colorbar labels you may label the left side of the colorbar and shift the label even more.
cbar.set_label(cbar_txt, labelpad=-36)
cbar.ax.yaxis.set_label_position("left")
Finally, you may indeed use a text on the axes, but position it in axes coordinates instead of data coordinates,
cbar.ax.text(2, 0.5, cbar_txt, fontsize='medium', rotation=90,
va='center', ha='left', transform=cbar.ax.transAxes)
Why
As to why cbar.ax.text works differently between the versions: The internal units of the colorbar have changed. This shouldn't affect any external application, but makes it easier to apply different locators to colorbars. In fact it has become more consistent. E.g. if the colorbar range is 0 to 100, and you place a text at y=0.5, it'll appear very close to 0.
Why not use the label directly? Edit: didn't see answer below. See for better explanation.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
arr = np.random.randint(0, 100, (2, 3, 4))
fig, ax = plt.subplots(1, 1)
pax = ax.imshow(arr, vmin=0, vmax=100)
cbar_txt='arb. units'
cbar_kws=dict(ticks=(0, 100))
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad=0.05)
cbar = ax.figure.colorbar(pax, cax=cax, **dict(cbar_kws))
cbar.set_label(cbar_txt, size = 20)
cbar.ax.tick_params(labelsize = 10)
plt.tight_layout()
plt.show()

Move tick marks at the top of the seaborn plot [duplicate]

Based on this question about heatmaps in matplotlib, I wanted to move the x-axis titles to the top of the plot.
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4,4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[0])+0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1])+0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.set_label_position('top') # <-- This doesn't work!
ax.set_xticklabels(row_labels, minor=False)
ax.set_yticklabels(column_labels, minor=False)
plt.show()
However, calling matplotlib's set_label_position (as notated above) doesn't seem to have the desired effect. Here's my output:
What am I doing wrong?
Use
ax.xaxis.tick_top()
to place the tick marks at the top of the image. The command
ax.set_xlabel('X LABEL')
ax.xaxis.set_label_position('top')
affects the label, not the tick marks.
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
You want set_ticks_position rather than set_label_position:
ax.xaxis.set_ticks_position('top') # the rest is the same
This gives me:
tick_params is very useful for setting tick properties. Labels can be moved to the top with:
ax.tick_params(labelbottom=False,labeltop=True)
You've got to do some extra massaging if you want the ticks (not labels) to show up on the top and bottom (not just the top). The only way I could do this is with a minor change to unutbu's code:
import matplotlib.pyplot as plt
import numpy as np
column_labels = list('ABCD')
row_labels = list('WXYZ')
data = np.random.rand(4, 4)
fig, ax = plt.subplots()
heatmap = ax.pcolor(data, cmap=plt.cm.Blues)
# put the major ticks at the middle of each cell
ax.set_xticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[0]) + 0.5, minor=False)
# want a more natural, table-like display
ax.invert_yaxis()
ax.xaxis.tick_top()
ax.xaxis.set_ticks_position('both') # THIS IS THE ONLY CHANGE
ax.set_xticklabels(column_labels, minor=False)
ax.set_yticklabels(row_labels, minor=False)
plt.show()
Output:

Categories

Resources