Repository: matplotlib/matplotlib
File: galleries/users_explain/colors/colormapnorms.py (Python)

Code before:
ax.set_title('TwoSlopeNorm(x)')
cb = fig.colorbar(pcm, shrink=0.6)
cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000])
plt.show()

# %%
# Using a linear scale on the colormap
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# By default, the colorbar for a `.TwoSlopeNorm` is divided into two equal
# parts for the two branches. As a result, the scaling in the two segments
# is different, i.e. the screen-space per data range. You can override this
# to get linear scaling by calling ``cb.ax.set_yscale('linear')``. This
# redistributes the colors and values on the colorbar, but leaves the
# color-to-value mapping unchanged.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

# Left plot: Default scaled colorbar (centered at midpoint)
divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000)
pcm1 = ax1.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm,
                      cmap=terrain_map, shading='auto')
ax1.set_aspect(1 / np.cos(np.deg2rad(49)))
ax1.set_title('Default: Scaled colorbar')
cb1 = fig.colorbar(pcm1, ax=ax1, shrink=0.6)
cb1.set_ticks([-500, 0, 1000, 2000, 3000, 4000])

# Right plot: Linear colorbar spacing
pcm2 = ax2.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm,
                      cmap=terrain_map, shading='auto')
ax2.set_aspect(1 / np.cos(np.deg2rad(49)))
ax2.set_title('Linear colorbar spacing')
cb2 = fig.colorbar(pcm2, ax=ax2, shrink=0.6)
cb2.ax.set_yscale('linear')  # Set linear scale for colorbar
cb2.set_ticks([-500, 0, 1000, 2000, 3000, 4000])

plt.show()

# %%
# FuncNorm: Arbitrary function normalization
# ------------------------------------------
#
# If the above norms do not provide the normalization you want, you can use
# `~.colors.FuncNorm` to define your own.  Note that this example is the same
# as `~.colors.PowerNorm` with a power of 0.5:


def _forward(x):
    return np.sqrt(x)



Review comment (suggestion):
```suggestion
cb1.set_ticks([np.arange(-500, 4001, 500))
```
will make it more clear that the spacing is different.

Code after:
ax.set_title('TwoSlopeNorm(x)')
cb = fig.colorbar(pcm, shrink=0.6)
cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000])
plt.show()

# %%
# Using a linear scale on the colormap
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# By default, colorbars adopt the same axis scaling as their associated norm.
# For example, for a `.TwoSlopeNorm`, colormap segments are distributed
# linearly and the colorbar ticks positions are spaced non-linearly (as above,
# and the left-hand colorbar below). To make the tick spacing linear instead,
# you can change the scale by calling ``cb.ax.set_yscale('linear')``, as shown
# in the right-hand colorbar below. The ticks will then be evenly spaced, the
# colormap will appear compressed in the smaller of the two slope regions.

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000)

for ax, title in zip([ax1, ax2],
                     ['Default: Scaled colorbar', 'Linear colorbar spacing']):
    pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm,
                        cmap=terrain_map, shading='auto')
    ax.set_aspect(1 / np.cos(np.deg2rad(49)))
    ax.set_title(title)
    cb = fig.colorbar(pcm, ax=ax, shrink=0.6)
    cb.set_ticks(np.arange(-500, 4001, 500))

# Set linear scale for the right colorbar
cb.ax.set_yscale('linear')

# %%
# FuncNorm: Arbitrary function normalization
# ------------------------------------------
#
# If the above norms do not provide the normalization you want, you can use
# `~.colors.FuncNorm` to define your own.  Note that this example is the same
# as `~.colors.PowerNorm` with a power of 0.5:


def _forward(x):
    return np.sqrt(x)


def _inverse(x):
    return x**2

N = 100
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
Z1 = (1 + np.sin(Y * 10.)) * X**2