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

Code before:
    'terrain_map', all_colors)

# make the norm:  Note the center is offset so that the land has more
# dynamic range:
divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000)

pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm,
                    cmap=terrain_map, shading='auto')
# Simple geographic plot, set aspect ratio because distance between lines of
# longitude depends on latitude.
ax.set_aspect(1 / np.cos(np.deg2rad(49)))
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

Review comment (suggestion):
```suggestion
# By default, colorbars adopt the same scaling as their associated norm. 
# This means the colormap segments are distributed linearly according to the norm, 
# so the tick positions also follow that nonlinear scaling. 
# For example, with a `.TwoSlopeNorm`, the colormap is split evenly between the two 
# sides of the center value, but the tick spacing is uneven (as above and the left-hand colorbar below). 
# To make the tick spacing linear instead, call ``cb.ax.set_yscale('linear')``, as 
# shown in the right-hand colorbar below. The ticks will then be evenly spaced, and 
# the colormap will appear compressed in the smaller of the two slope regions.
```

Code after:
    'terrain_map', all_colors)

# make the norm:  Note the center is offset so that the land has more
# dynamic range:
divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000)

pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm,
                    cmap=terrain_map, shading='auto')
# Simple geographic plot, set aspect ratio because distance between lines of
# longitude depends on latitude.
ax.set_aspect(1 / np.cos(np.deg2rad(49)))
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: