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')
-
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