爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 11930|回复: 11

[经验总结] Python 实现对数色标并保留绘图细节(避免等值线图变成粗糙色块)

[复制链接]
回帖奖励 17 金钱 回复本帖可获得 1 金钱奖励! 每人限 1 次(中奖概率 70%)

新浪微博达人勋

发表于 2022-4-18 16:08:34 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 阿月浑 于 2022-4-19 10:29 编辑

【菜鸟的一些绘图记录】
#自用笨方法,如有其他方法还望不吝赐教#
在重现一篇文献中的图像时发现原作者用的是对数色标,本人先是直接绘制等值线图(其实已经很接近了):
微信图片_20220418192736.png
原图
微信截图_20220418140250.png
直接绘制
为了精益求精,就想进一步取对数色标。但用了比较常见的直接取对数的方法,图像会变成较大的几个粗糙色块,和原文图像相差甚远,无法看出细节的变化。贴两个常规方法主要代码:
直接设置
  1. pcm = ax.contourf(np.arange(-180,180,resolution), np.arange(-90,90,resolution), a, [1e0,1e1,1e2], cmap = mycm, crs = ccrs.PlateCarree(),  extend = 'both')
  2. cb = fig.colorbar(pcm, orientation = 'vertical', fraction = 0.02, pad = 0.05, aspect = 17)
复制代码
微信截图_20220418141048.png

进一步,使用colors.LogNorm
  1. import matplotlib.colors as colors
  2. from matplotlib.colors import LogNorm

  3. norm = colors.LogNorm(vmin = 1E0, vmax = 1E2)
  4. pcm = ax.contourf(np.arange(-180,180,resolution), np.arange(-90,90,resolution), a, levels = [0.1,1,10,100], norm= norm, cmap = mycm, crs = ccrs.PlateCarree(), extend = 'both')
  5. #使用[0.1,1,10,100],而不能用线性np.arange
  6. cb = fig.colorbar(pcm, orientation = 'vertical', fraction = 0.02, pad = 0.05, aspect = 17)
复制代码
微信截图_20220418182231.png
都不太符合我的需求。因此,我最初的解决方法是图像和色标分别绘制,即用“伪色标”的方法实现绘图细节,并且调节了色标和图像的对应关系。
这里是绘制等高线图后,直接用plt.colorbar或fig.colorbar单独绘制一个对数色标(注意在新版本的Matplotlib中,DivergingNorm更新为TwoSlopeNorm)
  1. import matplotlib.colors as colors
  2. from matplotlib.colors import LogNorm
  3. import matplotlib.cm as cm

  4. norm = colors.DivergingNorm(vmin = 1, vmax = 100, vcenter=10)
  5. #vmax/vmin应相同,中间值vcenter应为对数色标的中间值
  6. im = cm.ScalarMappable(norm = normcb, cmap = mycm)
  7. pcm = ax.contourf(np.arange(-180,180,resolution), np.arange(-90,90,resolution), a, np.arange(1,100,0.5), norm= norm, cmap = mycm, crs = ccrs.PlateCarree(), extend = 'both')
  8. cb = fig.colorbar(im, orientation = 'vertical', fraction = 0.02, pad = 0.05, aspect = 17)#绘制im色标
复制代码
感谢论坛灭火器老师的指出,虽然图像看起来基本没问题,这个方法其实是不对的,contourf和colorbar用的normalization并不同。
因此进行改进:
  1. import matplotlib.colors as colors
  2. from matplotlib.colors import LogNorm
  3. import matplotlib.cm as cm

  4. norm = colors.LogNorm(vmin = 1E0, vmax = 1E2)
  5. levels = np.logspace(0, 2, 100)
  6. pcm = ax.contourf(np.arange(-180,180,resolution), np.arange(-90,90,resolution), a, levels, norm= norm, cmap = mycm, crs = ccrs.PlateCarree(), extend = 'both')
  7. cb = fig.colorbar(pcm, ticks=[1,10,100], orientation = 'vertical', fraction = 0.02, pad = 0.05, aspect = 17)
  8. cb.ax.minorticks_off()
复制代码
微信截图_20220418190720.png

这样应该就比较正确了
参考链接:
关于python:matplotlib等高线图:对数刻度成比例的颜色条水平 | 码农家园 (codenong.com)
做一个学习记录,如有问题或更好的方法,欢迎指出

密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2022-4-18 17:13:46 | 显示全部楼层

回帖奖励 +1 金钱

第一,第三张图中使用 LogNorm 的思路是正确的,但 contourf 的 levels 用的是线性的 np.arange(1,100,0.5),与对数尺度的 colorbar 并不匹配,应该改为 [1, 10, 100] 这种。
第二,解决方案里 contourf 和 colorbar 分开画,二者用的 normalization 并不同,只是看起来比较像罢了,contourf 实际上采用的是分段线性的归一化。
第三,DivergingNorm 在 19 年就改名为了 TwoSlopeNorm,你还能用说明你的 Matplotlib 版本很低……
最后给个示例
  1. cmap = cmaps.WhBlGrYeRe
  2. norm = mcolors.LogNorm(vmin=1E-1, vmax=1E2)
  3. levels = np.logspace(-1, 2, 100)
  4. cticks = np.logspace(-1, 2, 4)

  5. fig, ax = plt.subplots()
  6. im = ax.contourf(X, Y, Z, levels, cmap=cmap, norm=norm, extend='both')
  7. cbar = fig.colorbar(im, ax=ax, ticks=cticks, format='%.0f')
  8. cbar.ax.minorticks_off()
  9. plt.show()
复制代码
Snipaste_2022-04-18_17-13-10.png

密码修改失败请联系微信:mofangbao
回复 支持 1 反对 0

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2022-4-18 17:50:42 | 显示全部楼层
灭火器 发表于 2022-4-18 17:13
第一,第三张图中使用 LogNorm 的思路是正确的,但 contourf 的 levels 用的是线性的 np.arange(1,100,0.5) ...

非常感谢您!因为我搜了下相关内容不多所以自己做了尝试,果然还是有问题,我来按照您的方法尝试一下。另外Matplotlib版本低应该是我之前为了兼容其他版本低的库所以降了版本,谢谢您指出
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2022-4-18 18:10:40 | 显示全部楼层
灭火器 发表于 2022-4-18 17:13
第一,第三张图中使用 LogNorm 的思路是正确的,但 contourf 的 levels 用的是线性的 np.arange(1,100,0.5) ...

非常感谢解决啦!我来编辑一下原帖
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-4-18 21:19:14 | 显示全部楼层
分开画的思路在有些场合也很有用,你发出来大家也可以少踩坑互相学习
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-4-18 21:25:15 | 显示全部楼层

回帖奖励 +1 金钱

好棒好棒,学习一下
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-4-19 08:24:39 | 显示全部楼层
好棒好棒,学习一下
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-4-19 09:12:39 | 显示全部楼层
111111111111111111111111111111
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-4-19 09:47:43 | 显示全部楼层
想请问老师,用对数刻度坐标画的原因是因为它可视化能力更强吗?
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2022-4-19 10:27:43 | 显示全部楼层
LIqy 发表于 2022-4-19 09:47
想请问老师,用对数刻度坐标画的原因是因为它可视化能力更强吗?

按我个人的理解,如果要可视化的数据在很大范围内变化,或者呈指数变化等,这些情况下用对数标度缩放并进行描述就很有用。其实我自己做的这个图不太典型,只是我做的一个例子,今后你遇到更典型的情况应该可以体会到这么做的好处
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

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

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

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