为什么一些正刊子刊关于水文学气候变化的配图这么好看?我们用几个示例来说明这一点。图1是关于IPCC报告中的气候变化带来的危机,排版配色都很精美;图2介绍了几个城市受海平面上涨的影响,整体排版比较舒适;图3介绍了气温升高背景下海冰融化,视觉感官很不错。图2和图3分别来自Nature和Science正刊,内容都不复杂,但看起来很舒服。这是为什么呢,我想一个重要原因是配色导致了整体版面的美观,原来是使用了IPCC配色!
图1 IPCC配色使用(图源:IPCC AR6)
图2 示例分享1
图源:https://doi.org/10.1038/s41586-024-07038-3
图3 示例分享2
图源:https://doi.org/10.1126/science.abo1324
01配色介绍
其实IPCC也有自己推荐的配色,只是大多数人都不知道。有一个专门的Python包叫做pyam(综合评估和宏观能源情景的分析和可视化)提供了IPCC一系列情景建议的配色,其实整个IPCC AR6报告中,配色都是一贯且整体风格不变的,研究人员将各个情境下的配色提取出来,供大家参考,具体配色表调用代码:
import pandas as pd
import pyam
colors = pyam.plotting.PYAM_COLORS
pd.DataFrame({"name": list(colors.keys()), "color": list(colors.values())})
在各个情境下和各个IPCC报告中都提取了对应的颜色供大家参考。为了大家方便使用(因为有些读者不熟悉Python)我们手搓了整个颜色代码表,感兴趣的同学可以后台回复【IPCC配色】获取。
图4 IPCC配色表
02案例复现
接下来,我们通过一个IPCC示例来展示我们的配色方法。这里我们复现IPCC AR6中的第9章的图9.22,这张图展示了冻土层在各个升温情景下是如何变化的。这里我们复现图9.22b,这是一张经典的IPCC气候变化风格图。其中灰点代表观测,而有颜色的点代表各个情景,整张图美观且清晰。
第一步,这里我们把原数据下载下来,然后给予不同的情境建议的配色:
scenarios = ["ssp585", "ssp370", "ssp245", "ssp126"]
colors = {"ssp585": "#840b22", "ssp370": "#f21111", "ssp245": "#eadd3d", "ssp126": "#1d3354"}
第二步,接下来我们绘制主图,在不同情境下,先提取数据中所有的年份平均值:
for scenario in scenarios:
color = colors.get(scenario, "black")
files = sorted(glob.glob(f"pfvolbin-{depth}m/*{scenario}*"))
nmod = len(files)
# Model and data initialization
pfbinarr = []
tbin, ibin, p1, p2 = None, -1, 0, 0
GSATave = np.zeros((len(years), nmod), dtype=float)
for imod, filepath in enumerate(files):
model = filepath.split("/")[-1].split("_")[1]
with netCDF4.Dataset(filepath) as f:
tbin = f.variables['bin'][:]
dGSAT = f.variables['dGMAT'][:]
pfbin = f.variables['pfbin'][:] / 1000 # Convert to km³
# Locate the reference bin
if ibin == -1:
for i in range(len(tbin) - 1):
if tbin[i] <= 0 <= tbin[i + 1]:
ibin = i
p1 = tbin[ibin + 1] / (tbin[ibin + 1] - tbin[ibin])
p2 = 1 - p1
break
# Normalize permafrost volume
pfref = p1 * pfbin[ibin] + p2 * pfbin[ibin + 1]
pfbin = (pfbin - pfref) / pfref * 100
pfbinarr.append(pfbin)
# Calculate GSAT averages for specified years
for iyear, year in enumerate(years):
mon1 = int((year - Year0) * 12)
nmext = int((nyrave - 1) * mpy / 2)
mon_range = slice(max(mon1 - nmext, 0), min(mon1 + nmext + 1, len(dGSAT)))
GSATave[iyear, imod] = np.mean(dGSAT[mon_range])
第三步,继续利用for循环绘制点,这里分为历史观测和未来projections并读取colors列表中的颜色:
# Historical (tbin <= 0)
for pfbin in pfbinarr:
if model not in outliers:
mask = (tbin <= 0.1) & (np.abs(pfbin) < 100)
ax1.scatter(tbin[mask], pfbin[mask], c='gray', s=9, alpha=1)
# Projections (tbin >= 0)
xrt, yrt = [], []
for pfbin in pfbinarr:
if model not in outliers:
mask_proj = (tbin >= -0.1) & (np.abs(pfbin) < 100)
ax1.scatter(tbin[mask_proj], pfbin[mask_proj], c=color, s=9, alpha=1)
# Collect data for regression
mask_reg = mask_proj & (tbin <= tlimreg)
xrt.extend(tbin[mask_reg])
yrt.extend(pfbin[mask_reg])
最后,绘制结果如图所示,学习了IPCC配色方案后,我们也能创造出子刊正刊风格的图绘。
图5 IPCC配色的可视化复现图
一图胜千言!水文图绘改版后致力于分享水文相关的精美图表,为读者提供作图思路和经验,帮助大家制作更漂亮丰富的图表。同时欢迎留言咨询绘图难点,我们会针对性地分享相关绘制经验。另外也期待读者踊跃来稿,分享更好的构图思维和技巧,稿件可发送至邮箱hydro90@126.com, 或者联系微信17339888901投稿。
编辑:王龙浩 马孟良|校稿:hydro90编委团