python -- how to realize the unequal spacing display of colorbar

python -- how to realize the unequal spacing display of colorbar

First show the result:

To achieve the above colorbar, mainly use a function, as follows:

  • matplotlib.colors.TwoSlopeNorm
    Function description:
  • Generally contains three parameters: matplotlib.colors.TwoSlopeNorm(vcenter, vmin=None, vmax=None)
    • vmin: minimum range
    • vmax: maximum range
    • vcenter: middle range

Function Description:

  • Normalized data using a fixed center. Useful when mapping data with varying rates of change around a conceptual center, for example, data ranging from -20 to 40 with a midpoint of 0.

code show as below:

# -*- coding: utf-8 -*-
"""
Created on Wed Dec  7 10:12:20 2022

@author: jianpu

@blog :  https://blog.csdn.net/weixin_44237337?spm=1000.2115.3001.5343

@email: 211311040008@hhu.edu.cn

introduction : keep learning althongh walk slowly
"""

import cmaps
from matplotlib.colors import ListedColormap 
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl  
import matplotlib.cm as cm
import matplotlib.colors as mcolors
newcmap=(plt.get_cmap('RdBu_r')) 
bins = np.array( [-20,-10,0,10,20,30,40])
fig=plt.figure(figsize=(10,10),dpi=150)
norm = mcolors.TwoSlopeNorm(vmin=-20, vcenter=0,vmax=40) 
ax=fig.add_axes([0,0,0.5,0.05])  
fc1=fig.colorbar(
    mpl.cm.ScalarMappable(norm=norm,cmap=newcmap,),   
                 cax=ax,       
                  ticks = bins,                                               
                 orientation='horizontal',                          
                 )      
##### Set different display positions of colorbar label
ax2=fc1.ax
ax2.xaxis.set_ticks_position('top')  #Move the numeric scale to the top
ax3=ax2.secondary_xaxis('bottom')    #Create a new ax3, make ax3 exactly the same as ax2, but in the lower part
ax3.set_xticks([-10,0,10,20,30])
# The label name here can be customized and modified to what you want
ax3.set_xticklabels(['a','b','c','d','e'],ha="center") 
# f1.ax.set_xscale('linear')

Example demonstration 2:

  • Sometimes we want to have different colormaps on either side of the conceptual center point, and we want the two colormaps to have different linear scales. For example, in a topographic map, land and ocean are centered at zero, but land often has a greater range of elevation than water does, and they are often represented by different colormaps.

code show as below:

"""
Created on Wed Dec  7 10:12:20 2022

@author: jianpu

@blog :  https://blog.csdn.net/weixin_44237337?spm=1000.2115.3001.5343

@email: 211311040008@hhu.edu.cn

introduction : keep learning althongh walk slowly
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cbook as cbook
from matplotlib import cm
dem = cbook.get_sample_data('topobathy.npz', np_load=True)
topo = dem['topo']
longitude = dem['longitude']
latitude = dem['latitude']

fig, ax = plt.subplots(dpi=200)
# make a colormap that has land and ocean clearly delineated and of the
# same length (256 + 256)
colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 256))
colors_land = plt.cm.terrain(np.linspace(0.25, 1, 256))
all_colors = np.vstack((colors_undersea, colors_land))
terrain_map = colors.LinearSegmentedColormap.from_list(
    '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.9)
cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000])
plt.show()

Example demonstration 3:

This one is suitable for the colormap obtained by splicing through different rgb color gamuts. The main function used is:

  • matplotlib.colors.BoundaryNorm(boundaries, ncolors, clip=False, *, extend='neither')

  • Official website description

  • Mainly used to generate colormap indexes based on discrete intervals

  • Unlike Normalize or LogNorm, BoundaryNorm maps values ​​to integers rather than the interval 0-1.

    • boundaries: A monotonically increasing sequence of at least 2 bin edges: the data in the nth bin will be mapped to the nth color.
    • ncolors: The number of colors in the colormap to use.
    • clip: If True, out-of-range values ​​are mapped to 0 if below bounds[0] and ncolor-1 if above bounds[-1]. If False, out-of-range values ​​are mapped to -1 if below bounds[0] and to ncolor if above bounds[-1]. These indices are then converted into valid indices by a Colormap.
# -*- coding: utf-8 -*-
"""
Created on Wed Dec  7 10:12:20 2022

@author: jianpu

@blog :  https://blog.csdn.net/weixin_44237337?spm=1000.2115.3001.5343

@email: 211311040008@hhu.edu.cn

introduction : keep learning althongh walk slowly
"""

import cmaps
from matplotlib.colors import ListedColormap 
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl  
import matplotlib.cm as cm
import matplotlib.colors as mcolors
rgb=(
     [0,0,255],
     [39,39,255],
     [78,78,255],
     [91,118,255],
     [118,130,255],
     
     [ 255,255,255],
     [ 255,255,255],
     
     [ 255,190,190],
     [ 255,142,142],
     [ 255,122,122],
     [ 255,99,99],
     [ 255,58,58],
     [ 248,19,8],
     [ 153,33,20],
     )
rgb=np.array(rgb)/255.0
newcmap=ListedColormap(rgb) 
bins = [-600,-500,-400,-300,-200,-100,0,100,200,300,400,500,600,800,1000]
nbin = len(bins) - 1
cmap = cm.get_cmap('bwr', nbin)
norm4 = mcolors.BoundaryNorm(bins, nbin)
im4 = cm.ScalarMappable(norm=norm4, cmap=newcmap)

fig=plt.figure(figsize=(10,10),dpi=150)

ax=fig.add_axes([0,0,0.5,0.05])  
f1 = fig.colorbar(
    im4, cax=ax, orientation='horizontal',
   
)    



Example demonstration 4:

The logarithmic colorbar display is used here, and the most important principle is to keep the color synchronization of the line graph and ScalarMapable. This means that the colors of the lines should not be taken from a separate color list, but from the same colormap, using the same normalization as the colorbar to be displayed. A major problem then is deciding what to do with 0s that cannot be part of lognormalization. Below is a solution using SymLogNorm assuming a linear range between 0 and 2 and the log range above.

code show as below:

# -*- coding: utf-8 -*-
"""
Created on Mon Feb  6 21:24:46 2023

@author: win10
"""

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

"""Creating the data"""
time_vector = [0, 1, 2, 4, 8, 16, 32, 64, 128, 256]
amplitudes = [t ** 2 * np.exp(-t * np.power(np.linspace(-0.5, 0.5, 100), 2)) for t in time_vector]

"""Getting the non-zero minimum of the data"""
data = np.concatenate(amplitudes).ravel()
data_min = np.min(data[np.nonzero(data)])

"""Creating K-space data"""
k_vector = np.linspace(0,1,100)

"""Plotting"""
cmap = plt.cm.get_cmap("jet")
norm = mpl.colors.SymLogNorm(2, vmin=time_vector[0], vmax=time_vector[-1])

sm = mpl.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])
fig =plt.figure(dpi=200)
for i in range(len(time_vector)):
    plt.plot(k_vector, amplitudes[i], color=cmap(norm(time_vector[i])), label=time_vector[i])

#c = np.arange(1, number_of_plots + 1)
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.yscale('symlog')
plt.xscale('log')
plt.legend(loc=3)

cbar = plt.colorbar(sm, ticks=time_vector, format=mpl.ticker.ScalarFormatter(), 
                    shrink=1.0, fraction=0.1, pad=0)

plt.show()

A single record 5:

  • This is just another way to document how to place the colorbar's label in the middle of each color stop
  • I have tried other methods before, the specific tutorial is here: Click here
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors

n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1., n_lines + 1)

cmap = plt.get_cmap("jet", len(c))
norm = matplotlib.colors.BoundaryNorm(np.arange(len(c)+1)+0.5,len(c))
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])  # this line may be ommitted for matplotlib >= 3.1

fig, ax = plt.subplots(dpi=200)
for i, yi in enumerate(y.T):
    ax.plot(x, yi, c=cmap(i))
fig.colorbar(sm, ticks=c)
plt.show()

The reference is as follows:

  • https://matplotlib.org/stable/tutorials/colors/colormapnorms.html#twoslopenorm-different-mapping-on-either-side-of-a-center
  • https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.TwoSlopeNorm.html
  • https://matplotlib.org/stable/api/_as_gen/matplotlib.colors.BoundaryNorm.html
  • https://zhajiman.github.io/post/matplotlib_colormap/
  • https://stackoverflow.com/questions/54513247/matplotilb-how-to-set-colorbar-for-line-plot-with-log-scale
  • https://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots/49374315#49374315

Tags: Python matplotlib programming language

Posted by zbee on Thu, 09 Feb 2023 13:01:21 +0530