matplotlib 合理设置colorbar和子图的对应关系

matplotlib 合理设置colorbar和子图的对应关系

1. 介绍

在有些情况下,需要画同一个变量不同时刻的等值面图。考虑到不同时刻的数值有大小差异,因而生成的图的colorbar的标签范围也是不一样的。为了方便比较,最好多个时刻共享一个colorbar,方便比较。下面会依次使用 plt.contourf() 和 plt.imshow()函数进行画图介绍。

2 plt.contourf ()

2.1 错误示范
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

#生成一定整数范围内的随机数
a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

fig = plt.figure(figsize = (22,6))

plt.subplot(1,3,1)
h1 = plt.contourf(a1,cmap = plt.cm.coolwarm)
c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.contourf(a2,cmap = plt.cm.coolwarm)
c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.contourf(a3,cmap = plt.cm.coolwarm)
c3 = plt.colorbar(h3) 

plt.show()

在这里插入图片描述
如上图,每个图上的相同的颜色表示的数值不一样,不方便比较;

2.2 使用 norm实现颜色和数值之间的对应关系
a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

fig = plt.figure(figsize = (22,6))

#将颜色映射到 vmin~vmax 之间
norm = matplotlib.colors.Normalize(vmin=0, vmax=15)

plt.subplot(1,3,1)
h1 = plt.contourf(a1,cmap = plt.cm.coolwarm,norm = norm)
c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.contourf(a2,cmap = plt.cm.coolwarm,norm = norm)
c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.contourf(a3,cmap = plt.cm.coolwarm,norm = norm)
c3 = plt.colorbar(h3)

plt.show()

在这里插入图片描述
如上图,可以实现相同数值大小对应相同的颜色;

但是这样还是不太好看。最好是能够 每个子图的 colorbar的范围都一样(即从0-15);

2.3 只显示最后一个的colorbar

那有同学想,是否可以只显示最后一个子图的colorbar,作为全局colorbar呢;这个当然也是可以的。

但是会带来一个问题,由于每个子图的大小(无论是否包含colorbar)是一样的,会使得图形大小看起来不一样,很不美观;

如下图:
在这里插入图片描述

2.4 使用 levels 参数设置
a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

fig = plt.figure(figsize = (22,6))

# norm = matplotlib.colors.Normalize(vmin=0, vmax=15)
#设置固定显示的colorbar刻度
levels = np.arange(0,17,2)

plt.subplot(1,3,1)
h1 = plt.contourf(a1,cmap = plt.cm.coolwarm,levels = levels)
c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.contourf(a2,cmap = plt.cm.coolwarm,levels = levels)
c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.contourf(a3,cmap = plt.cm.coolwarm,levels = levels)
c3 = plt.colorbar(h3)

plt.show()

在这里插入图片描述

3. 使用plt.imshow()

上面虽然设置了 norm,但是使用plt.contourf还是达不到我们的要求。链接3 给了我们一个示例,使用plt.imshow() + norm可以解决这个问题。按照他的思路,我们重复上面的试验。

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

# matplotlib.rcParams['xtick.direction'] = 'out'
# matplotlib.rcParams['ytick.direction'] = 'out'

a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

fig = plt.figure(figsize = (22,6),dpi=72, facecolor="white")

#将横纵坐标都映射到(0,1)的范围内
extent=(0,1,0,1)

vmin=0
vmax=15
#将颜色映射到 vmin~vmax 之间
norm = matplotlib.colors.Normalize(vmin=0, vmax=15)

ax1 = plt.subplot(1,3,1)
ax1.cla()
h1 = plt.imshow(a1,extent = extent,origin='lower',cmap = plt.cm.coolwarm,norm = norm)
c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.imshow(a2,extent = extent,origin='lower',cmap = plt.cm.coolwarm,norm = norm)
c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.imshow(a3,extent = extent,origin='lower',cmap = plt.cm.coolwarm,norm = norm)
c3 = plt.colorbar(h3)

font = {'family' : 'serif',
        'color'  : 'darkred',
        'weight' : 'normal',
        'size'   : 16,
        }

c3.set_label('$T_B(K)$',fontdict=font)
c3.set_ticks(np.arange(vmin,vmax,2))
c3.set_ticklabels(np.arange(vmin,vmax,2))

plt.show()

在这里插入图片描述

如上图,虽然使用plt.imshow可以解决这个问题,但是用带来了一些新问题:

  • 在画子图的时候,colorbar的长度和子图的长度不一致;在单独画一个图的时候,并不存在这样的问题
  • plt.imshow()是逐像素画图的,相比plt.contourf,分辨率很低,并不适合科研上的等值线作图。

4 单独设置colorbar

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

a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

#也可以通过这样 levels 进行设置
#h = plt.contourf(a1,levels = [0,1,2,3,4,5,6,7,8,9,10], cmap = plt.cm.coolwarm)

fig = plt.figure(figsize = (22,6))

norm = matplotlib.colors.Normalize(vmin=0, vmax=15)

plt.subplot(1,3,1)
h1 = plt.contourf(a1,cmap = plt.cm.coolwarm,norm = norm)
# c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.contourf(a2,cmap = plt.cm.coolwarm,norm = norm)
# c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.contourf(a3,cmap = plt.cm.coolwarm,norm = norm)
# c3 = plt.colorbar(h3)
# c3.set_clim(vmax = 15)

#前面三个子图的总宽度 为 全部宽度的 0.9;剩下的0.1用来放置colorbar
fig.subplots_adjust(right=0.9)

#colorbar 左 下 宽 高 
l = 0.92
b = 0.12
w = 0.015
h = 1 - 2*b 

#对应 l,b,w,h;设置colorbar位置;
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect) 
cb = plt.colorbar(h3, cax=cbar_ax)

#设置colorbar标签字体等
cb.ax.tick_params(labelsize=16)  #设置色标刻度字体大小。
font = {'family' : 'serif',
#       'color'  : 'darkred',
    'color'  : 'black',
    'weight' : 'normal',
    'size'   : 16,
    }
cb.set_label('T' ,fontdict=font) #设置colorbar的标签字体及其大小

plt.show()

在这里插入图片描述
如上,是不是很漂亮了。后续适当做一些 坐标、字体等的基本设置,就完成了一张科研图的绘制!

4.1 方式一
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

a1 = np.random.randint(1,10,size=(10,10))
a2 = np.random.randint(1,13,size=(10,10))
a3 = np.random.randint(1,16,size=(10,10))

#也可以通过这样 levels 进行设置
#h = plt.contourf(a1,levels = [0,1,2,3,4,5,6,7,8,9,10], cmap = plt.cm.coolwarm)

fig = plt.figure(figsize = (22,6))

norm = matplotlib.colors.Normalize(vmin=0, vmax=15)

plt.subplot(1,3,1)
h1 = plt.contourf(a1,cmap = plt.cm.coolwarm,norm = norm)
# c1 = plt.colorbar(h1)

plt.subplot(1,3,2)
h2 = plt.contourf(a2,cmap = plt.cm.coolwarm,norm = norm)
# c2 = plt.colorbar(h2)

plt.subplot(1,3,3)
h3 = plt.contourf(a3,cmap = plt.cm.coolwarm,norm = norm)
# c3 = plt.colorbar(h3)
# c3.set_clim(vmax = 15)

#前面三个子图的总宽度 为 全部宽度的 0.9;剩下的0.1用来放置colorbar
fig.subplots_adjust(right=0.9)

#colorbar 左 下 宽 高 
l = 0.92
b = 0.12
w = 0.015
h = 1 - 2*b 

#对应 l,b,w,h;设置colorbar位置;
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect) 
cb = plt.colorbar(h3, cax=cbar_ax)

#设置colorbar标签字体等
cb.ax.tick_params(labelsize=16)  #设置色标刻度字体大小。
font = {'family' : 'serif',
#       'color'  : 'darkred',
    'color'  : 'black',
    'weight' : 'normal',
    'size'   : 16,
    }
cb.set_label('T' ,fontdict=font) #设置colorbar的标签字体及其大小

plt.show()

在这里插入图片描述
如上,是不是很漂亮了。后续适当做一些 坐标、字体等的基本设置,就完成了一张科研图的绘制!

4.2 方式二
import numpy as np
import matplotlib.pyplot as plt
import matplotlib

#设置子图个数 和 整个图片的大小
fig, axes = plt.subplots(nrows=2, ncols=2,figsize = (12,10))

a_list = [5,10,15,20]

#设置colorbar的范围
vmin = 0
vmax = 20

norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)

for a,ax in zip(a_list,axes.flat):
    
    #设置每个子图
    data = np.random.randint(0,a,size = (20,20))
    im = ax.contourf(data,norm = norm)

#fig 的位置为[0,1],设置前面4个子图的占的位置为[0,0.8]
fig.subplots_adjust(right=0.8)

#在原fig上添加一个子图句柄为cbar_ax, 设置其位置为[0.85,0.15,0.05,0.7]
#colorbar 左 下 宽 高 
l = 0.85
b = 0.12
w = 0.05
h = 1 - 2*b 
#对应 l,b,w,h;设置colorbar位置;
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect)

cb = fig.colorbar(im, cax = cbar_ax) 

#设置colorbar标签字体等
cb.ax.tick_params(labelsize=16)  #设置色标刻度字体大小。
font = {'family' : 'serif',
#       'color'  : 'darkred',
    'color'  : 'black',
    'weight' : 'normal',
    'size'   : 16,
    }
cb.set_label('T' ,fontdict=font) #设置colorbar的标签字体及其大小

plt.show()

在这里插入图片描述

4.3 问题

上述两种方式都存在一个潜在的问题。

在这里插入图片描述

​ 在添加colorbar的时,是使用最后一个子图的所在的数值范围。我们来看几种情况。

  • 情况一:

    norm = [5,20], 对应colorbar上 5以下颜色一致。

在这里插入图片描述

在这里插入图片描述

  • 情况二:

    最后一张子图的数值范围为 [0,15),colorbar范围只能在15以内。

在这里插入图片描述

在这里插入图片描述

结论:

最后一张子图的数据范围决定了colorbar上显示的刻度的范围。

norm范围决定了colorbar颜色变化范围。

4.4 解决方法1:plt.contourf()

为了保证colorbar能覆盖所有子图的范围,应该使得 norm范围与设置colorbar时对应的子图im 的数值范围一致,并且所有子图的数值范围应该都在norm范围之内。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bI7GRXmn-1582701105492)(matplotlib 合理设置colorbar和子图的对应关系.assets/image-20200226135804785.png)]

因此有一个蠢办法:

  • 即另外建一个fig2 , 这个fig2对应的数据范围包括fig1的数据范围。

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib
    
    #设置子图个数 和 整个图片的大小
    fig1, axes = plt.subplots(nrows=2, ncols=2,figsize = (10,8))
    
    a_list = [5,10,20,15]
    
    #设置colorbar的范围
    vmin = 0
    vmax = 20
    norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)
    
    for a,ax in zip(a_list,axes.flat):
        
        #设置每个子图的数据范围
        data = np.random.randint(0,a,size = (20,20))
        im = ax.contourf(data,norm = norm)
    
    #fig1 的位置为[0,1],设置前面4个子图的占的位置为[0,0.8]
    fig1.subplots_adjust(right=0.8)
    
    #在原fig1上添加一个子图句柄为cbar_ax, 设置其位置为[0.85,0.15,0.05,0.7]
    #colorbar 左 下 宽 高 
    l = 0.85
    b = 0.12
    w = 0.05
    h = 1 - 2*b 
    #对应 l,b,w,h;设置colorbar位置;
    rect = [l,b,w,h] 
    cbar_ax = fig1.add_axes(rect)
    
    ##设置一个fig2,其数值范围涵括fig1所有子图的数值范围
    fig2 = plt.figure(figsize = (18,6))
    all_data = np.random.randint(vmin,vmax,size = (20,20))
    h4 = plt.contourf(all_data,norm = norm)
    
    #设置fig1的colorbar对应fig2的数据范围
    cb = fig1.colorbar(h4, cax = cbar_ax) 
    
    #设置colorbar标签字体等
    cb.ax.tick_params(labelsize=16)  #设置色标刻度字体大小。
    font = {'family' : 'serif',
    #       'color'  : 'darkred',
        'color'  : 'black',
        'weight' : 'normal',
        'size'   : 16,
        }
    cb.set_label('T' ,fontdict=font) #设置colorbar的标签字体及其大小
    
    plt.show()
    

在这里插入图片描述

对比上述情况2的图片,情况有所改善,但是吊了一个尾巴。

4.5 解决办法2:plt.imshow()
import numpy as np
import matplotlib.pyplot as plt

a_list = [5,10,20,15]

#设置colorbar的范围
vmin = 0
vmax = 20
norm = matplotlib.colors.Normalize(vmin=vmin, vmax=vmax)

fig, axes = plt.subplots(nrows=2, ncols=2)
for a,ax in zip(a_list,axes.flat):
    
    #设置每个子图
    data = np.random.randint(0,a,size = (20,20))
    im = ax.imshow(data , vmin = vmin, vmax = vmax )

fig.colorbar(im, ax=axes.ravel().tolist())

plt.show()

在这里插入图片描述

使用这个方法可以解决上述情况2的问题,不需要吊个尾巴啦!

至于使用plt.imshow 和 plt.contourf,看各自喜好!另外,建议多看看官网例子。

参考链接

[1] 解决python画图中colorbar设置刻度和标签字体大小

[2] 使用matplotlib的示例:调整字体-设置刻度、坐标、colormap和colorbar等

[3] matplotlib官网例子

  • 82
    点赞
  • 300
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 如果你需要将多个子图的颜色映射图合并成一个大的颜色映射图,可以使用 Matplotlib 的 GridSpec 和 Colorbar 的 pad 参数实现。 GridSpec 可以将一个大的区域划分成若干个小区域,而 pad 参数可以控制每个子图与颜色映射图之间的距离。 下面是一个示例代码,展示了如何将两个子图的颜色映射图拼接成一个大的颜色映射图: ```python import numpy as np import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpec # 数据 x = np.linspace(-5, 5, 100) y = np.linspace(-5, 5, 100) X, Y = np.meshgrid(x, y) Z1 = np.exp(-X**2 - Y**2) Z2 = np.exp(-(X-1)**2 - (Y-1)**2) # 子图1 fig = plt.figure(figsize=(10, 5)) gs = GridSpec(1, 2, width_ratios=[1, 0.05], wspace=0.05) ax1 = fig.add_subplot(gs[0]) im1 = ax1.imshow(Z1, cmap='viridis') ax1.set_title('Subplot 1') ax1.set_xticks([]) ax1.set_yticks([]) # 子图2 ax2 = fig.add_subplot(gs[1]) im2 = ax2.imshow(Z2, cmap='viridis') ax2.set_title('Subplot 2') ax2.set_xticks([]) ax2.set_yticks([]) # 颜色映射图 cax = fig.add_axes([0.9, 0.1, 0.02, 0.8]) fig.colorbar(im1, cax=cax, pad=0) plt.show() ``` 上述代码中,我们使用了 GridSpec 将画布分成 1 行 2 列,即两个子图。然后,在第一个子图中使用 imshow 方法绘制了第一个颜色映射图,在第二个子图中绘制了第二个颜色映射图。最后,使用 add_axes 方法添加了一个新的轴,用于显示颜色映射图,并将其 pad 参数设置为 0,以达到紧密拼接的效果。 你可以根据具体需求调整 GridSpec 和 pad 参数,以达到理想的效果。 ### 回答2: colorbar拼接是指将多个colorbar(颜色条)组合在一起,形成一个大的颜色条,用于展示画图中多个数据的颜色对应关系。拼接颜色条的目的是使多个数据的颜色范围一致,方便比较和对比。 在Matplotlib库中,可以通过subplots()函数创建多个子图,并在每个子图上添加不同的颜色条。首先,我们需要用subplot()函数创建多个子图,例如subplot(1, 3, 1)可以创建一个1行3列的子图,当前操作的是第一个子图。然后,我们可以在每个子图上绘制图像或者绘制颜色条。在绘制颜色条时,可以通过设置orientation参数来控制颜色条的方向(水平或垂直),通过设置label参数来添加颜色条的标签。最后,通过调用colorbar()函数,可以将颜色条添加到当前的子图上。 具体拼接颜色条的代码如下所示: ```python import matplotlib.pyplot as plt # 创建3个子图 fig, axs = plt.subplots(1, 3, figsize=(10, 3)) # 第一个子图 axs[0].imshow(image1, cmap='jet') axs[0].set_title('Image 1') # 添加第一个子图的颜色条 cbar1 = plt.colorbar(axs[0].imshow(image1, cmap='jet'), ax=axs[0], orientation='horizontal', label='Value') # 第二个子图 axs[1].imshow(image2, cmap='jet') axs[1].set_title('Image 2') # 添加第二个子图的颜色条 cbar2 = plt.colorbar(axs[1].imshow(image2, cmap='jet'), ax=axs[1], orientation='horizontal', label='Value') # 第三个子图 axs[2].imshow(image3, cmap='jet') axs[2].set_title('Image 3') # 添加第三个子图的颜色条 cbar3 = plt.colorbar(axs[2].imshow(image3, cmap='jet'), ax=axs[2], orientation='horizontal', label='Value') # 拼接颜色条 fig.subplots_adjust(bottom=0.2, wspace=0.5) fig.colorbar(cbar1, ax=axs, location='bottom') # 显示图形 plt.show() ``` 以上代码中,我们创建了一个包含3个子图的图形对象,并在每个子图上显示了不同的图像和颜色条。最后,通过subplots_adjust()函数调整子图之间的间距,并使用colorbar()函数将三个子图上的颜色条拼接在一起放在底部展示。 ### 回答3: colorbar拼接是指将不同颜色条(colorbar)进行组合拼接,以形成一个整体颜色条。拼接可以采用水平拼接或垂直拼接的方式,可以根据需要自定义拼接的方式和颜色条的数量。 拼接的过程可以通过编程语言来实现,比如Matlab、Python等。对于Matlab来说,可以使用colormap函数来创建颜色条,并通过colorbar函数来显示和放置颜色条。在拼接颜色条时,可以使用使用不同的colormap函数来创建多个颜色条,然后通过使用subplot、figure和axes等函数来控制颜色条的位置和布局。 在Python中,可以使用matplotlib库的colorbar函数来创建和拼接颜色条。通过设置orientation参数可以控制拼接的方向,设置pad参数可以控制颜色条之间的间距。同时,还可以使用其他库如seaborn、Plotly等来进行更高级的colorbar拼接操作。 通过拼接不同颜色条,可以实现更丰富的数据可视化效果。例如,可以将热度图和标注图的颜色条进行水平拼接,以同时显示温度和标注信息。拼接后的颜色条可以提供更全面、直观的信息展示,方便观察数据的变化和趋势。 总而言之,colorbar拼接是一种数据可视化的技术,可以将不同颜色条进行组合拼接,以展示更全面、直观的信息。无论是在Matlab还是Python中,我们都可以利用相应的库函数来实现拼接,以满足不同可视化需求。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值