爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1096|回复: 9

[源代码] matplotlib中设置色标colorbar与图等高或等宽

[复制链接]
发表于 2025-1-7 21:29:33 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
本帖最后由 沐雨淋觞 于 2025-1-8 09:00 编辑

这份代码,我是参照气象家园某位兄台的思路制作的,后面翻找的时候,包括查浏览历史记录找了很久没找到。如果读者们知道麻烦引个路,我好引用一下。
本篇首发CSDN,原文https://blog.csdn.net/weixin_48458238/article/details/144993624
函数
让 colorbar 与主图等高的方法,其实是应用于 colorbar 中的 cax 参数来达到精确控制它的位置和长宽。
用这个方法后,会导致原先具备的部分可选参数'fraction', 'pad', 'shrink', 'aspect', 'anchor','panchor'失去效果。
但不包括修改刻度的方向以及修改刻度标签等等。
以下代码设计思路,设计一个空类,用于承装sameLength_colorbar函数的动态参数,其中包括:方位location 和 距主图边距margin。
用这个方法,主要方便于后续如果有新变量的再添加。
由于局限于(也不习惯)论坛上对函数及类的排版与编写,关于参数的介绍及代码以图片的形式,详见如下。
QQ截图20250107211251.png
使用
基于以上sameLength_colorbar设置,我们可以放置在一个新的py文件内,如sLcolorbar.py,当作调用的一个库包。
  1. from sLcolorbar import sameLength_colorbar
复制代码

位于右侧
在调用的时候,跟原本使用fig.colorbar或者plt.colorbar的方法一样。
  1. cb = sameLength_colorbar(ct,'vertical')
复制代码

只是修改了气象绘图—模仿绘制风速水汽通量图文中colorbar的部分,则得到:
水汽通量-vertical_right.png

                               
登录/注册后可看大图
位于底部
如果希望色标colorbar在底部,这里建议间距调成0.1,即间距为10%的主图高度,因为主图还有经纬度,所以要间隔更大些:
  1. cb = sameLength_colorbar(ct,'horizontal',margin=0.1)
  2. cb.ax.set_xticklabels([''] + [str(tick) for tick in cb.get_ticks()[1:-1]] + [''])
复制代码

水汽通量-horizontal_bottom.png

                               
登录/注册后可看大图
位于顶部
方向orientation 选择 水平horizontal ,同时 方位location 默认为0,则为底部,需修改成1,代表放置于顶部。与主图距离:8%的主图高度,以方便空出地方展现色标的刻度及刻度标签。
  1. cb = sameLength_colorbar(ct,'horizontal',location=1,margin=0.08)
  2. cb.ax.set_xticklabels([''] + [str(tick) for tick in cb.get_ticks()[1:-1]] + [''])
复制代码

水汽通量-horizontal_top.png

                               
登录/注册后可看大图
位于左侧
方向orientation 选择 垂直vertical ,同时 方位location 默认为0,则为右侧,需修改成1,代表放置于左侧。与主图距离:8%的主图宽度。同时调整色标的刻度和刻度标签的朝向。
  1. cb = sameLength_colorbar(ct,'horizontal',location=1,margin=0.08)
  2. cb.ax.set_yticklabels([''] + [str(tick) for tick in cb.get_ticks()[1:-1]] + [''])
  3. cb.ax.tick_params('y',left=True,right=False,labelleft=True,labelright=False)
复制代码

水汽通量-vertical_left.png

                               
登录/注册后可看大图



sLcolorbar.py

4.18 KB, 下载次数: 1, 下载积分: 金钱 -5

源代码

密码修改失败请联系微信:mofangbao
发表于 2025-1-8 10:47:03 | 显示全部楼层
本帖最后由 灭火器 于 2025-1-8 10:49 编辑

本来 colorbar 会根据 orientation,自动跟 Axes 等高或等宽。但因为 GeoAxes 的 aspect 强制为 1,所以等高不一定成立。

楼主的方法是根据 GeoAxes 实际的高宽(通过 get_position)决定 cax 的高宽,缺陷是在创建 cax 后如果调整了 GeoAxes 的 xlim 和 ylim,或者通过 fig.add_subplot 添加了新的子图,cax 的位置又跟实时布局不符了。

主楼方法还有一个缺陷:如果传入的 mappable 是独立于 Axes 的,例如直接通过 ScalarMappable 创建,而不是 contourf、pcolormesh 等方法的返回结果,那么 mappable 的 axes 和 fig 属性是 None,会报错。

下面提供三种自动确定 cax 位置的方法:

1. Axes.inset_axes

  1. import cartopy.crs as ccrs
  2. import matplotlib.pyplot as plt
  3. from matplotlib.cm import ScalarMappable

  4. mappable = ScalarMappable()

  5. data_crs = ccrs.PlateCarree()
  6. map_crs = ccrs.AzimuthalEquidistant(central_longitude=105, central_latitude=35)

  7. fig = plt.figure()
  8. ax = fig.add_subplot(projection=map_crs)
  9. cax = ax.inset_axes([1.05, 0, 0.025, 1], transform=ax.transAxes)
  10. fig.colorbar(mappable, cax=cax)
  11. ax.set_extent((70, 120, 0, 20), crs=data_crs)
复制代码

2. axes_grid1 的 inset_axes

  1. from mpl_toolkits.axes_grid1.inset_locator import inset_axes

  2. fig = plt.figure()
  3. ax = fig.add_subplot(projection=map_crs)
  4. cax = inset_axes(
  5.     ax,
  6.     width='5%',
  7.     height='100%',
  8.     loc='center right',
  9.     bbox_to_anchor=(0, 0, 1.1, 1),
  10.     bbox_transform=ax.transAxes,
  11.     borderpad=0,
  12. )
  13. fig.colorbar(mappable, cax=cax)
  14. ax.set_extent((70, 120, 0, 20), crs=data_crs)
复制代码

3. make_axes_locatable

  1. from matplotlib.axes import Axes
  2. from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable

  3. fig = plt.figure()
  4. ax = fig.add_subplot(projection=map_crs)
  5. divider = make_axes_locatable(ax)
  6. cax = divider.append_axes('right', size='5%', pad='2%', axes_class=Axes)
  7. fig.colorbar(mappable, cax=cax)
  8. ax.set_extent((70, 120, 0, 20), crs=data_crs)
复制代码

其中最好理解的是 Axes.inset_axes,这个方法从 matplotlib 3.9 开始不再是实验性的,大概可以放心使用。

可以在这些方法的基础上做进一步包装,比如指定 left、right、bottom、top 之类的,用相对单位、英寸指定 cax 大小等。
密码修改失败请联系微信:mofangbao
回复 支持 2 反对 0

使用道具 举报

发表于 2025-1-7 22:44:18 来自手机 | 显示全部楼层
fig.colorbar()即可。还可以使用AxesDivider。参考https://matplotlib.org/stable/users/explain/axes/colorbar_placement.html#colorbar-placement。
密码修改失败请联系微信:mofangbao
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2025-1-7 21:35:25 | 显示全部楼层
这里排版真难,无法显示的图,是网络图片,跟贴着的图是一样的。无视了就好,重新编辑也看不到它在哪。
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-8 09:11:30 | 显示全部楼层
edwardli 发表于 2025-1-7 22:44
fig.colorbar()即可。还可以使用AxesDivider。参考https://matplotlib.org/stable/users/explain/axes/colo ...

好像也并非如此,这是代码,然后出来的图也没有就跟主图等宽

                               
登录/注册后可看大图


                               
登录/注册后可看大图
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

发表于 2025-1-8 09:46:14 | 显示全部楼层
考虑一下ax.inset_axes吧,像我这篇http://bbs.06climate.com/forum.php?mod=viewthread&tid=104913 所讲,ax.inset_axes创建的axe可以指定相对于原axe的坐标的位置

微信截图_20250108094551.png
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

发表于 2025-1-8 09:58:28 | 显示全部楼层
墨家大宝 发表于 2025-1-8 09:46
考虑一下ax.inset_axes吧,像我这篇http://bbs.06climate.com/forum.php?mod=viewthread&tid=104913 所讲, ...

和2楼李老师给的链接里后半部分一样。我之前也琢磨比较了好久,觉得这是最简单的方案了,没想到官方竟然有教程
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-8 10:01:11 | 显示全部楼层
墨家大宝 发表于 2025-1-8 09:46
考虑一下ax.inset_axes吧,像我这篇http://bbs.06climate.com/forum.php?mod=viewthread&tid=104913 所讲, ...

有道理,这个参数我第一次接触,我再研究研究。
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

 楼主| 发表于 2025-1-8 12:01:49 | 显示全部楼层
灭火器 发表于 2025-1-8 10:47
本来 colorbar 会根据 orientation,自动跟 Axes 等高或等宽。但因为 GeoAxes 的 aspect 强制为 1,所以等 ...

受教了,感谢大佬的指点。
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

发表于 2025-1-8 18:33:49 | 显示全部楼层
本帖最后由 一大碗年糕 于 2025-1-8 18:35 编辑

学习了
密码修改失败请联系微信:mofangbao
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表