Colorbars¶
Colorbars provide a visual legend mapping colors to data values, essential for interpreting heatmaps and other color-coded visualizations.
Mental Model
A colorbar is a legend for continuous color scales. It shows the mapping from data values to colors so readers can decode heatmaps, scatter plots, and contour fills. Always add a colorbar when using imshow, pcolormesh, contourf, or scatter with color mapping -- without it, the colors are meaningless.
The deeper truth: the colorbar is the scale of a color-based plot, just as axes are the scale of a line plot. Colors without a colorbar are just decoration — the colorbar defines what colors mean.
Color Encoding Pipeline
All color-based visualization in this section follows one pipeline:
text
Data → Normalization → Colormap → Color → Perception
↓
Colorbar (decoding)
The colorbar is the decoder — it lets the viewer reverse the pipeline and
read values back from colors. This is why vmin/vmax and normalization
matter so much: they define the encoding, and the colorbar must match.
The Key Idea: Normalization
A colorbar visualizes a normalization — the function that maps data values to colors. By default, matplotlib uses linear normalization between vmin and vmax. Changing the normalization (e.g., LogNorm, TwoSlopeNorm) changes what colors mean. This is why vmin/vmax matter so much: they define the mapping, and shared subplots must share the same normalization or the colors become incomparable.
Misleading Scales
Changing vmin/vmax between subplots makes identical colors represent different values. When comparing multiple heatmaps, always use the same normalization — pass the same vmin, vmax, and norm to each plot, and share a single colorbar. Otherwise, readers will misinterpret differences.
Basic Colorbar¶
Add a colorbar to a plot.
1. Simple Addition¶
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) data = np.random.rand(10, 10)
fig, ax = plt.subplots() im = ax.imshow(data) plt.colorbar(im) plt.show() ```
2. Specify Axes¶
python
fig, ax = plt.subplots()
im = ax.imshow(data)
plt.colorbar(im, ax=ax)
3. Using Figure Method¶
python
fig, ax = plt.subplots()
im = ax.imshow(data)
fig.colorbar(im, ax=ax)
Colorbar Label¶
Add descriptive labels to the colorbar.
1. Label Parameter¶
python
fig, ax = plt.subplots()
im = ax.imshow(data, cmap='viridis')
plt.colorbar(im, label='Intensity')
plt.show()
2. LaTeX Label¶
python
plt.colorbar(im, label=r'Temperature ($^\circ$C)')
3. Set Label After Creation¶
python
cbar = plt.colorbar(im)
cbar.set_label('Value', fontsize=12, rotation=270, labelpad=15)
Colorbar Position¶
Control where the colorbar appears.
1. Location Parameter¶
```python fig, ax = plt.subplots() im = ax.imshow(data)
Options: 'right', 'left', 'top', 'bottom'¶
plt.colorbar(im, location='right') plt.show() ```
2. Horizontal Colorbar¶
python
fig, ax = plt.subplots()
im = ax.imshow(data)
plt.colorbar(im, orientation='horizontal')
plt.show()
3. Custom Position with cax¶
```python from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, ax = plt.subplots() im = ax.imshow(data)
divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.1) plt.colorbar(im, cax=cax) plt.show() ```
Colorbar Size¶
Adjust colorbar dimensions.
1. Shrink Parameter¶
python
fig, ax = plt.subplots()
im = ax.imshow(data)
plt.colorbar(im, shrink=0.8) # 80% of default height
plt.show()
2. Aspect Ratio¶
python
plt.colorbar(im, aspect=30) # Length / width ratio
3. Fraction and Pad¶
python
plt.colorbar(im, fraction=0.046, pad=0.04)
Tick Customization¶
Control colorbar tick positions and labels.
1. Set Ticks¶
python
fig, ax = plt.subplots()
im = ax.imshow(data, vmin=0, vmax=1)
cbar = plt.colorbar(im, ticks=[0, 0.25, 0.5, 0.75, 1])
plt.show()
2. Custom Labels¶
python
cbar = plt.colorbar(im, ticks=[0, 0.5, 1])
cbar.ax.set_yticklabels(['Low', 'Medium', 'High'])
3. Tick Parameters¶
python
cbar = plt.colorbar(im)
cbar.ax.tick_params(labelsize=10, length=5, width=1)
Discrete Colorbars¶
Create colorbars for categorical or binned data.
1. Boundaries and Values¶
```python import matplotlib.colors as mcolors
bounds = [0, 0.2, 0.4, 0.6, 0.8, 1.0] norm = mcolors.BoundaryNorm(bounds, plt.cm.viridis.N)
fig, ax = plt.subplots() im = ax.imshow(data, cmap='viridis', norm=norm) plt.colorbar(im, boundaries=bounds, ticks=bounds) plt.show() ```
2. Fixed Number of Colors¶
```python from matplotlib.colors import BoundaryNorm
n_colors = 5 cmap = plt.cm.get_cmap('viridis', n_colors) bounds = np.linspace(0, 1, n_colors + 1) norm = BoundaryNorm(bounds, cmap.N)
fig, ax = plt.subplots() im = ax.imshow(data, cmap=cmap, norm=norm) plt.colorbar(im, ticks=bounds[:-1] + 0.1) plt.show() ```
3. Categorical Colorbar¶
```python categories = ['A', 'B', 'C', 'D'] cat_data = np.random.randint(0, 4, (10, 10))
cmap = plt.cm.get_cmap('Set1', len(categories))
fig, ax = plt.subplots() im = ax.imshow(cat_data, cmap=cmap, vmin=-0.5, vmax=len(categories)-0.5) cbar = plt.colorbar(im, ticks=range(len(categories))) cbar.ax.set_yticklabels(categories) plt.show() ```
Colorbar with Subplots¶
Handle colorbars in multi-plot layouts.
1. Individual Colorbars¶
```python fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for ax in axes: data = np.random.rand(10, 10) im = ax.imshow(data) plt.colorbar(im, ax=ax, shrink=0.8)
plt.tight_layout() plt.show() ```
2. Shared Colorbar¶
```python fig, axes = plt.subplots(1, 3, figsize=(12, 4))
vmin, vmax = 0, 1 for ax in axes: data = np.random.rand(10, 10) im = ax.imshow(data, vmin=vmin, vmax=vmax)
fig.colorbar(im, ax=axes, shrink=0.8, label='Shared Scale') plt.tight_layout() plt.show() ```
3. Colorbar Axes List¶
```python fig, axes = plt.subplots(2, 2, figsize=(8, 8))
for ax in axes.flat: data = np.random.rand(10, 10) im = ax.imshow(data, vmin=0, vmax=1)
fig.colorbar(im, ax=axes.ravel().tolist(), shrink=0.6) plt.tight_layout() plt.show() ```
Logarithmic Colorbar¶
Display data with logarithmic color scaling.
1. LogNorm¶
```python from matplotlib.colors import LogNorm
data_log = np.random.rand(10, 10) * 1000 + 1
fig, ax = plt.subplots() im = ax.imshow(data_log, norm=LogNorm(vmin=1, vmax=1000)) plt.colorbar(im, label='Log Scale') plt.show() ```
2. SymLogNorm for Negative Values¶
```python from matplotlib.colors import SymLogNorm
data_sym = np.random.randn(10, 10) * 100
fig, ax = plt.subplots() im = ax.imshow(data_sym, cmap='RdBu', norm=SymLogNorm(linthresh=1, vmin=-100, vmax=100)) plt.colorbar(im) plt.show() ```
3. PowerNorm¶
```python from matplotlib.colors import PowerNorm
fig, ax = plt.subplots() im = ax.imshow(data, norm=PowerNorm(gamma=0.5)) plt.colorbar(im) plt.show() ```
Colorbar Styling¶
Customize colorbar appearance.
1. Outline¶
python
cbar = plt.colorbar(im)
cbar.outline.set_edgecolor('black')
cbar.outline.set_linewidth(2)
2. Extension Arrows¶
```python
Show arrows when data exceeds vmin/vmax¶
plt.colorbar(im, extend='both') # 'min', 'max', 'both', 'neither' ```
3. Draw Edges¶
python
cbar = plt.colorbar(im, drawedges=True)
Complete Example¶
Create a polished heatmap with customized colorbar.
1. Setup Data¶
python
np.random.seed(42)
data = np.random.randn(12, 12)
2. Create Figure¶
```python fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(data, cmap='RdBu', vmin=-3, vmax=3)
ax.set_xticks(np.arange(12)) ax.set_yticks(np.arange(12)) ax.set_xticklabels([f'C{i}' for i in range(12)], rotation=45, ha='right') ax.set_yticklabels([f'R{i}' for i in range(12)]) ax.set_title('Heatmap with Custom Colorbar') ```
3. Add Colorbar¶
```python cbar = plt.colorbar(im, shrink=0.8, aspect=30, pad=0.02) cbar.set_label('Z-Score', fontsize=12) cbar.set_ticks([-3, -2, -1, 0, 1, 2, 3]) cbar.ax.tick_params(labelsize=10)
plt.tight_layout() plt.show() ```
Exercises¶
Exercise 1. Write code that creates a heatmap from a 10x10 random array and adds a colorbar with a custom label. Use the 'viridis' colormap.
Solution to Exercise 1
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) data = np.random.rand(10, 10)
fig, ax = plt.subplots() im = ax.imshow(data, cmap='viridis') cbar = fig.colorbar(im, ax=ax, label='Random Values') ax.set_title('Heatmap with Colorbar') plt.show() ```
Exercise 2. Explain the difference between fig.colorbar() and plt.colorbar(). When would you use each?
Solution to Exercise 2
fig.colorbar(mappable, ax=ax) adds a colorbar to a specific axes within the figure. plt.colorbar() adds a colorbar to the current axes using the pyplot state machine. Use fig.colorbar() when working with the OOP style (explicit Figure and Axes objects), and plt.colorbar() only when using the pyplot style. The OOP version is preferred for multi-subplot figures because you can control exactly which axes the colorbar is associated with.
Exercise 3. Create a figure with two heatmaps side by side, each with its own colorbar. Use shrink=0.8 to reduce the colorbar height.
Solution to Exercise 3
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) data1 = np.random.rand(8, 8) data2 = np.random.randn(8, 8)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
im1 = ax1.imshow(data1, cmap='hot') fig.colorbar(im1, ax=ax1, shrink=0.8, label='Values') ax1.set_title('Uniform Random')
im2 = ax2.imshow(data2, cmap='coolwarm') fig.colorbar(im2, ax=ax2, shrink=0.8, label='Values') ax2.set_title('Normal Random')
plt.tight_layout() plt.show() ```
Exercise 4. Write code that creates a heatmap and customizes the colorbar with discrete tick values using cbar.set_ticks() and cbar.set_ticklabels().
Solution to Exercise 4
```python import matplotlib.pyplot as plt import numpy as np
np.random.seed(42) data = np.random.rand(10, 10) * 100
fig, ax = plt.subplots() im = ax.imshow(data, cmap='YlOrRd') cbar = fig.colorbar(im, ax=ax) cbar.set_ticks([0, 25, 50, 75, 100]) cbar.set_ticklabels(['Low', '25%', 'Mid', '75%', 'High']) cbar.set_label('Custom Scale') ax.set_title('Heatmap with Custom Colorbar Ticks') plt.show() ```