source: LMDZ6/trunk/libf/phylmd/ecrad/practical/ecradplot/plot.py @ 5450

Last change on this file since 5450 was 4773, checked in by idelkadi, 13 months ago
  • Update of Ecrad in LMDZ The same organization of the Ecrad offline version is retained in order to facilitate the updating of Ecrad in LMDZ and the comparison between online and offline results. version 1.6.1 of Ecrad (https://github.com/lguez/ecrad.git)
  • Implementation of the double call of Ecrad in LMDZ


File size: 87.8 KB
Line 
1"""
2Filename:     plot.py
3Author:       Shannon Mason, shannon.mason@ecmwf.int
4Description:  Plotting functions
5"""
6
7import pandas as pd
8import numpy as np
9
10#For loading and handling netCDF data
11import xarray as xr
12
13#Use seaborn to control matplotlib visual style
14import matplotlib.pyplot as plt
15import seaborn as sns
16
17#For log-scaled colormaps
18from matplotlib.colors import LogNorm#, DivergingNorm
19
20#Plot formatting functions
21from ecradplot.general import *
22
23#I/O functions
24from ecradplot.io import *
25import os
26
27#### Set plotting style ####
28sns.set_style('ticks')
29sns.set_context('poster')
30
31def warn(*args, **kwargs):
32    pass
33import warnings
34warnings.warn = warn
35warnings.simplefilter(action = "ignore", category = RuntimeWarning)
36
37
38def get_vextents(da, q=0.01, symmetric=False):
39    vmin = da.quantile(q=0.01).values
40    vmax = da.quantile(q=1-q).values
41
42    #All negative
43    if (vmin < 0) & (vmax < 0) & ~symmetric:
44        return vmin, 0
45    #All positive
46    elif (vmin > 0) & (vmax > 0) & ~symmetric:
47        return 0, vmax
48    else:
49        v = max(np.abs(vmin), np.abs(vmax))
50        return -1*v, v
51
52def irregular_pcolor(ax, X, Y, C, args, cbar_kwargs=None):
53    _X, _Y, _C = xr.broadcast(X, Y, C)
54    _cm = ax.pcolor(_X.values, _Y.values, _C.values, **args)
55
56    if cbar_kwargs:
57        try:
58            _cb = plt.colorbar(_cm, ax=ax, **cbar_kwargs)
59        except:
60            print("Bug with colorbars")
61
62    if 'level' in C.dims:
63        ax.fill_between(_X.max('level'), _Y.max('level'), y2=1100e2, facecolor='0.67',
64                        hatch='////', edgecolor='k', lw=0.0, zorder=-10)
65    elif 'half_level' in C.dims:
66        ax.fill_between(_X.max('half_level'), _Y.max('half_level'), y2=1100e2, facecolor='0.67',
67                        hatch='////', edgecolor='k', lw=0.0, zorder=-10)
68    return _cm
69
70def irregular_contour(ax, X, Y, C, args, cbar_kwargs=None):
71    _X, _Y, _C = xr.broadcast(X, Y, C)
72    _cm = ax.contour(_X, _Y, _C, **args)
73    if cbar_kwargs:
74        _cb = plt.colorbar(_cm, ax=ax, **cbar_kwargs)
75    return _cm
76
77def add_temperature_contours(ax, ds, x_dim='latitude'):
78    """
79    Draw contours of temperature (from ds) to ax.
80    """
81
82    _cn = irregular_contour(ax, ds.latitude, ds.pressure_hl, ds.temperature_hl-273.15,
83                     dict(levels=np.arange(-80,41,20),
84                          colors=['k'],
85                          linewidths=[1.5, 0.5, 1.5, 0.5, 2.5, 0.5, 1.5]))
86    _labels = ax.clabel(_cn, [l for l in [-80,-60,-40,-20,0,20,40] if l in _cn.levels], inline=1, fmt='$%.0f^{\circ}$C', fontsize='xx-small', colors=['k'])
87
88    for l in _labels:
89        l.set_rotation(0)
90
91
92def plot_inputs_noncloud(IFS_srcfile, dstfile=None, line_ds='default'):
93    """
94    Plot multiple-panel figure describing non-cloud inputs to ecRAD.
95    """
96
97    _ds = load_inputs(IFS_srcfile)
98
99    #Set up figure and axes
100    nrows=4
101
102    fig, axes= plt.subplots(figsize=(25,4*nrows), nrows=nrows, sharex=True)
103
104    #First panel: SW & surface fields
105    i=0
106    _ds.cos_solar_zenith_angle.where(_ds.cos_solar_zenith_angle >= 0).plot(ax=axes[i], x='latitude', color='k', lw=3)
107    axes[i].set_xlabel('')
108    axes[i].set_ylabel(r'$\cos \theta_s$ [-]')
109    axes[i].set_yticks([0,0.5,1.])
110    axes[i].set_title('Solar zenith angle and shortwave albedo')
111    if 'solar_irradiance' in _ds:
112        axes[i].text(0.001, 1.01, f"Solar irradiance\n$Q={_ds.solar_irradiance.values:5.1f}$ W m$^{{-2}}$", ha='left', va='bottom', fontsize='small', transform=axes[i].transAxes)
113    _ax0 = axes[i].twinx()
114    _ax0.yaxis.set_label_position("right")
115    _ax0.yaxis.tick_right()
116
117    if hasattr(_ds, 'sw_albedo_band'):
118        _ds.sw_albedo.isel(sw_albedo_band=2).plot.step(ax=_ax0, x='latitude', color=sns.color_palette()[0], lw=4, drawstyle=line_ds)
119    else:
120        _ds.sw_albedo.plot(ax=_ax0, x='latitude', color=sns.color_palette()[0], lw=4, drawstyle=line_ds)
121    _ax0.set_yticks([0,0.5,1.0])
122    _ax0.set_yticklabels([0,0.5,1.0],  color=sns.color_palette()[0])
123    _ax0.set_ylabel(r'$\alpha_{SW}$ [-]', color=sns.color_palette()[0])
124
125    #Second panel: LW surface fields
126    i+=1
127    _ds.skin_temperature.plot(ax=axes[i], x='latitude', color='k', lw=3)
128    axes[i].set_xlabel('')
129    axes[i].set_ylabel(r'$T_s$ [K]')
130    axes[i].set_title('Skin temperature and longwave emissivity')
131
132    _ax1 = axes[i].twinx()
133    _ax1.yaxis.set_label_position("right")
134    _ax1.yaxis.tick_right()
135    if hasattr(_ds, 'lw_emissivity_band'):
136        _ds.lw_emissivity.isel(lw_emissivity_band=1).plot.step(ax=_ax1, x='latitude', color=sns.color_palette()[3], lw=4, drawstyle=line_ds)
137    else:
138        _ds.lw_emissivity.plot(ax=_ax1, x='latitude', color=sns.color_palette()[3], lw=4, drawstyle=line_ds)
139    _ax1.set_yticks([0.9,0.95,1.0])
140    _ax1.set_ylim(0.89,1.0)
141    _ax1.set_yticklabels([0.9,0.95,1.0],  color=sns.color_palette()[3])
142    _ax1.set_ylabel(r'$\epsilon_{LW}$ [-]', color=sns.color_palette()[3])
143
144    #Specific humidity
145    i+=1
146    irregular_pcolor(axes[i], _ds.latitude, _ds.pressure_fl, _ds.q,
147                     dict(norm=LogNorm(1e-6, 1e-2), cmap='Greens'),
148                     cbar_kwargs={'pad':0.01, 'label':'mass mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-5,1e-4,1e-3,1e-2]})
149
150    axes[i].set_title('Specific humidity')
151    axes[i].set_xlabel('')
152
153    axes[i].set_yscale('linear')
154    axes[i].set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
155    axes[i].set_ylim(1050e2,1)
156
157    #Ozone
158    i+=1
159    irregular_pcolor(axes[i], _ds.latitude, _ds.pressure_fl, _ds.o3_mmr,
160                     dict(norm=LogNorm(1e-8, 1e-5), cmap='Blues'),
161                     cbar_kwargs={'pad':0.01, 'label':'mass mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-8,1e-7,1e-6,1e-5]})
162
163    axes[i].set_title('Ozone')
164    axes[i].set_xlabel('')
165
166    axes[i].set_yscale('log')
167    axes[i].set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
168    axes[i].set_ylim(1.1e5,1)
169
170    for ax in axes[-2:]:
171        add_temperature_contours(ax, _ds)
172        format_pressure(ax)
173
174    for ax in axes[:-2]:
175        snap_to_axis(ax, axes[-1])
176
177    axes[-1].set_xlim(-90,90)
178    axes[-1].set_xticks(np.arange(-90,91,15))
179    format_latitude(axes[-1])
180    axes[-1].set_xlabel('Latitude')
181
182    add_subfigure_labels(axes)
183
184    if hasattr(_ds, 'experiment'):
185        fig.suptitle(_ds.attrs['experiment'] + "\nsurface properties and atmospheric composition", x=get_figure_center(axes[0]), y=get_figure_top(fig, axes[0]), va='bottom')
186    else:
187        fig.suptitle("surface properties and atmospheric composition", x=get_figure_center(axes[0]), y=get_figure_top(fig, axes[0]), va='bottom')
188
189    if dstfile:
190        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
191    else:
192        return fig, axes
193
194
195def plot_inputs_cloud(IFS_srcfile, include_effective_radius=False, dstfile=None):
196    _ds = load_inputs(IFS_srcfile)
197
198    if include_effective_radius:
199        nrows=5
200    else:
201        nrows=3
202
203    fig, axes = plt.subplots(figsize=(25,4*nrows), nrows=nrows, sharex=True, sharey=True,  subplot_kw={'facecolor':sns.xkcd_rgb['earth']})
204
205    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_fl, _ds.cloud_fraction,
206                     dict(vmin=0, vmax=1, cmap='gray_r'),
207                     cbar_kwargs={'pad':0.01, 'label':'fraction', 'ticks':[0, 0.2, 0.4, 0.6, 0.8, 1.0]})
208    axes[0].set_title('Cloud fraction')
209    axes[0].set_xlabel('')
210
211    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_fl, _ds.q_ice.where(_ds.q_ice > 1e-10).fillna(1e-10),
212                     dict(norm=LogNorm(1e-8, 0.5e-2), cmap='Blues'),
213                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-7, 1e-5, 1e-3]})
214    axes[1].set_title('Cloud ice water content')
215    axes[1].set_xlabel('')
216
217    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_fl, _ds.q_liquid.where(_ds.q_liquid > 1e-10).fillna(1e-10),
218                     dict(norm=LogNorm(1e-8, 0.5e-2), cmap='Reds'),
219                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-7, 1e-5, 1e-3]})
220    axes[2].set_title('Cloud liquid water content')
221    format_latitude(axes[-1])
222
223    if include_effective_radius:
224        axes[2].set_xlabel('')
225
226        irregular_pcolor(axes[3], _ds.latitude, _ds.pressure_fl, _ds.re_ice.where(_ds.q_ice > 1e-10).fillna(1e-10),
227                         dict(norm=LogNorm(3e-6, 1e-4), cmap='Blues'),
228                         cbar_kwargs={'pad':0.01, 'label':'$r_{\mathrm{eff}}$ [m]'})
229        axes[3].set_title('Ice effective radius')
230        axes[3].set_xlabel('')
231
232        irregular_pcolor(axes[4], _ds.latitude, _ds.re_liquid.where(_ds.q_liquid > 1e-10).fillna(1e-10),
233                         dict(norm=LogNorm(3e-6, 1e-4), cmap='Reds'),
234                         cbar_kwargs={'pad':0.01, 'label':'$r_{\mathrm{eff}}$ [m]'})
235        axes[4].set_title('Liquid effective radius')
236
237    for ax in axes:
238        add_temperature_contours(ax, _ds)
239        format_pressure(ax)
240
241    axes[-1].set_xlim(-90,90)
242    axes[-1].set_xticks(np.arange(-90,91,15))
243    axes[-1].set_xlabel('Latitude')
244
245    axes[0].set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
246    axes[0].set_ylim(1050e2,1)
247
248    add_subfigure_labels(axes)
249
250    if hasattr(_ds, 'experiment'):
251        fig.suptitle(_ds.attrs['experiment'] + "\ncloud fields", x=get_figure_center(axes[0]), y=get_figure_top(fig, axes[0])+ 0.1, va='bottom')
252    else:
253        fig.suptitle("cloud fields", x=get_figure_center(axes[0]), y=get_figure_top(fig, axes[0])+ 0.1, va='bottom')
254
255    if dstfile:
256        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
257    else:
258        return fig, axes
259
260def plot_inputs_aerosols(IFS_srcfile, dstfile=None):
261    _ds = load_inputs(IFS_srcfile)
262
263    nrows=5
264
265    fig, axes = plt.subplots(figsize=(25,4*nrows), nrows=nrows, sharex=True, sharey=True, )
266
267    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_fl, _ds.sea_salt.where(_ds.sea_salt > 1e-12).fillna(1e-12),
268                     dict(norm=LogNorm(1e-12, 1e-6), cmap='Blues'),
269                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-9, 1e-6]})
270    axes[0].set_title('Sea salt')
271    axes[0].set_xlabel('')
272
273    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_fl, _ds.dust.where(_ds.dust > 1e-12).fillna(1e-12),
274                     dict(norm=LogNorm(1e-12, 1e-6), cmap='OrRd'),
275                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-9, 1e-6]})
276    axes[1].set_title('Dust')
277    axes[1].set_xlabel('')
278
279    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_fl, _ds.organics.where(_ds.organics > 1e-12).fillna(1e-12),
280                     dict(norm=LogNorm(1e-12, 1e-7), cmap='Greens'),
281                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]})
282    axes[2].set_title('Organics')
283    format_latitude(axes[-1])
284    axes[2].set_xlabel('')
285
286    irregular_pcolor(axes[3], _ds.latitude, _ds.pressure_fl, _ds.black_carbon.where(_ds.black_carbon > 1e-12).fillna(1e-12),
287                     dict(norm=LogNorm(1e-12, 1e-7), cmap='Greys'),
288                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]})
289    axes[3].set_title('Black carbon')
290    axes[3].set_xlabel('')
291
292    irregular_pcolor(axes[4], _ds.latitude, _ds.pressure_fl, _ds.sulphate.where(_ds.sulphate > 1e-12).fillna(1e-12),
293                     dict(norm=LogNorm(1e-12, 1e-7), cmap='Reds'),
294                     cbar_kwargs={'pad':0.01, 'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]})
295    axes[4].set_title('Sulphates')
296
297    for ax in axes:
298        add_temperature_contours(ax, _ds)
299        format_pressure(ax)
300
301    axes[-1].set_xlim(-90,90)
302    axes[-1].set_xticks(np.arange(-90,91,15))
303    axes[-1].set_xlabel('Latitude')
304
305    axes[0].set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
306    axes[0].set_ylim(1050e2,1)
307
308    add_subfigure_labels(axes)
309
310    if hasattr(_ds, 'experiment'):
311        fig.suptitle(_ds.attrs['experiment'] + "\naerosols", x=get_figure_center(axes[0]), y=0.95, va='top')
312    else:
313        fig.suptitle("aerosols", x=get_figure_center(axes[0]), y=0.95, va='top')
314
315    if dstfile:
316        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
317    else:
318        return fig, axes
319
320def plot_inputs(IFS_srcfile, dstfile=None, line_ds='default'):
321    with sns.plotting_context('notebook', font_scale=1.1), sns.axes_style('ticks'):
322
323        _ds = load_inputs(IFS_srcfile)
324
325        #Set up figure and axes
326        nrows=6
327        ncols=2
328
329        cbar_kwargs = {'pad':0.0125, 'aspect':10}
330
331        fig, axes= plt.subplots(figsize=(25,2.25*nrows), nrows=nrows, ncols=ncols, gridspec_kw={'wspace':0.0, 'hspace':0.25})
332
333        #First row
334        j=0
335
336        ###ATMOSPHERE AND RADIATION
337        #First panel SW & surface fields
338        i=0
339        _ds.cos_solar_zenith_angle.where(_ds.cos_solar_zenith_angle >= 0).plot(ax=axes[i,j], x='latitude', color='k', lw=3)
340        axes[i,j].set_xlabel('')
341        axes[i,j].set_ylabel(r'$\cos \theta_s$ [-]')
342        axes[i,j].set_yticks([0,0.5,1.])
343        axes[i,j].set_title('Solar zenith angle and shortwave albedo')
344        if 'solar_irradiance' in _ds:
345            axes[i,j].text(0.001, 1.01, f"Solar irradiance\n$Q={_ds.solar_irradiance.values:5.1f}$ W m$^{{-2}}$", ha='left', va='bottom', fontsize='small', transform=axes[i,j].transAxes)
346
347        _ax0 = axes[i,j].twinx()
348        _ax0.yaxis.set_label_position("right")
349        _ax0.yaxis.tick_right()
350        if hasattr(_ds, 'sw_albedo_band'):
351            _ds.sw_albedo.isel(sw_albedo_band=2).plot.step(ax=_ax0, x='latitude', color=sns.color_palette()[0], lw=4, drawstyle=line_ds)
352        else:
353            _ds.sw_albedo.plot(ax=_ax0, x='latitude', color=sns.color_palette()[0], lw=4, drawstyle=line_ds)
354        _ax0.set_yticks([0,0.5,1.0])
355        _ax0.set_yticklabels([0,0.5,1.0],  color=sns.color_palette()[0])
356        _ax0.set_ylabel(r'$\alpha_{SW}$ [-]', color=sns.color_palette()[0])
357
358        #Second panel: LW surface fields
359        i+=1
360        _ds.skin_temperature.plot(ax=axes[i,j], x='latitude', color='k', lw=3)
361        axes[i,j].set_xlabel('')
362        axes[i,j].set_ylabel(r'$T_s$ [K]')
363        axes[i,j].set_title('Skin temperature and longwave emissivity')
364
365        _ax1 = axes[i,j].twinx()
366        _ax1.yaxis.set_label_position("right")
367        _ax1.yaxis.tick_right()
368        if hasattr(_ds, 'lw_emissivity_band'):
369            _ds.lw_emissivity.isel(lw_emissivity_band=1).plot.step(ax=_ax1, x='latitude', color=sns.color_palette()[3], lw=4, drawstyle=line_ds)
370        else:
371            _ds.lw_emissivity.plot(ax=_ax1, x='latitude', color=sns.color_palette()[3], lw=4, drawstyle=line_ds)
372        _ax1.set_yticks([0.9,0.95,1.0])
373        _ax1.set_ylim(0.89,1.0)
374        _ax1.set_yticklabels([0.9,0.95,1.0],  color=sns.color_palette()[3])
375        _ax1.set_ylabel(r'$\epsilon_{LW}$ [-]', color=sns.color_palette()[3])
376
377        #Specific humidity
378        i+=1
379        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.q,
380                         dict(norm=LogNorm(1e-6, 1e-2), cmap='Greens'),
381                         cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-5,1e-4,1e-3,1e-2]}})
382
383        axes[i,j].set_title('Specific humidity')
384        axes[i,j].set_xlabel('')
385
386        axes[i,j].set_yscale('linear')
387        axes[i,j].set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
388        axes[i,j].set_ylim(1050e2,1)
389
390        ### CLOUD
391        i+=1
392        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.cloud_fraction,
393                             dict(vmin=0, vmax=1, cmap='gray_r'),
394                             cbar_kwargs={**cbar_kwargs, **{'label':'fraction [-]', 'ticks':[0, 0.2, 0.4, 0.6, 0.8, 1.0]}})
395        axes[i,j].set_title('Cloud fraction')
396        axes[i,j].set_xlabel('')
397
398        i+=1
399        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.q_ice.where(_ds.q_ice > 1e-10).fillna(1e-10),
400                             dict(norm=LogNorm(1e-8, 0.5e-2), cmap='Blues'),
401                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-7, 1e-5, 1e-3]}})
402        axes[i,j].set_title('Cloud ice water content')
403        axes[i,j].set_xlabel('')
404
405        i+=1
406        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.q_liquid.where(_ds.q_liquid > 1e-10).fillna(1e-10),
407                             dict(norm=LogNorm(1e-8, 0.5e-2), cmap='Reds'),
408                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-7, 1e-5, 1e-3]}})
409        axes[i,j].set_title('Cloud liquid water content')
410
411        ####SECOND COLUMN
412        j+=1
413
414        #Ozone
415        i=0
416        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.o3_mmr,
417                         dict(norm=LogNorm(1e-8, 1e-5), cmap='Blues'),
418                         cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-8,1e-7,1e-6,1e-5]}})
419
420        axes[i,j].set_title('Ozone')
421        axes[i,j].set_xlabel('')
422
423        axes[i,j].set_yscale('log')
424        axes[i,j].set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
425        axes[i,j].set_ylim(1.1e5,1)
426
427        #Aerosols
428
429        i+=1
430        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.sea_salt.where(_ds.sea_salt > 1e-12).fillna(1e-12),
431                             dict(norm=LogNorm(1e-12, 1e-6), cmap='Blues'),
432                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-9, 1e-6]}})
433        axes[i,j].set_title('Sea salt')
434        axes[i,j].set_xlabel('')
435
436        i+=1
437        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.dust.where(_ds.dust > 1e-12).fillna(1e-12),
438                             dict(norm=LogNorm(1e-12, 1e-6), cmap='OrRd'),
439                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-9, 1e-6]}})
440        axes[i,j].set_title('Dust')
441        axes[i,j].set_xlabel('')
442
443        i+=1
444        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.organics.where(_ds.organics > 1e-12).fillna(1e-12),
445                             dict(norm=LogNorm(1e-12, 1e-7), cmap='Greens'),
446                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]}})
447        axes[i,j].set_title('Organics')
448        axes[i,j].set_xlabel('')
449
450        i+=1
451        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.black_carbon.where(_ds.black_carbon > 1e-12).fillna(1e-12),
452                             dict(norm=LogNorm(1e-12, 1e-7), cmap='Greys'),
453                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]}})
454        axes[i,j].set_title('Black carbon')
455        axes[i,j].set_xlabel('')
456
457        i+=1
458        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, _ds.sulphate.where(_ds.sulphate > 1e-12).fillna(1e-12),
459                             dict(norm=LogNorm(1e-12, 1e-7), cmap='Reds'),
460                             cbar_kwargs={**cbar_kwargs, **{'label':'mixing ratio\n[kg kg$^{-1}$]', 'ticks':[1e-12, 1e-10, 1e-8]}})
461        axes[i,j].set_title('Sulphates')
462
463        for ax in axes[2:,0]:
464            add_temperature_contours(ax, _ds)
465            format_pressure(ax)
466            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
467            ax.set_ylim(1050e2,1)
468
469        for ax in axes[:2,0]:
470            snap_to_axis(ax, axes[-1,0])
471
472        for ax in axes[1:,1]:
473            add_temperature_contours(ax, _ds)
474            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
475            ax.set_ylim(1050e2,1)
476            ax.set_yticklabels([])
477            ax.set_ylabel("")
478
479        format_pressure(axes[0,1])
480        add_temperature_contours(axes[0,1], _ds)
481
482        for ax in axes.flatten():
483            ax.set_xlim(-90,90)
484            ax.set_xticks(np.arange(-90,91,15))
485            ax.set_xlabel('')
486            ax.set_xticklabels([])
487
488        for ax in axes[-1,:].flatten():
489            format_latitude(ax)
490            ax.set_xlabel('Latitude')
491
492        import string
493        add_subfigure_labels(axes)
494
495        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
496
497        x = (get_figure_center(axes[0,0]) + get_figure_center(axes[0,1]))/2
498        y = get_figure_top(fig, axes[0,0], include_hspace=True)
499
500        #fig.suptitle(f"{name_string}\nIFS cloud, aerosol and radiation fields", x=x, y=y-0.025, va='top', fontsize=30)
501
502        fig.suptitle(f"{name_string}\nIFS cloud, aerosol and radiation fields", x=x, y=y-0.07, va='bottom', fontsize=25)
503
504        if dstfile:
505            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
506        else:
507            return fig, axes
508
509def plot_LW_flux(IFS_srcfile, ecRAD_srcfile, dstfile=None, clearsky=False):
510    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
511
512    # LW fluxes
513    nrows=3
514    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
515
516    if clearsky:
517        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_lw_clear,
518                         dict(cmap='Reds', vmin=0, vmax=500),
519                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
520        axes[0].set_title("Clear-sky downwelling")
521    else:
522        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_lw,
523                         dict(cmap='Reds', vmin=0, vmax=500),
524                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
525        axes[0].set_title("Downwelling")
526    axes[0].set_xlabel('')
527
528    if clearsky:
529        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, _ds.flux_up_lw_clear,
530                         dict(cmap='Reds', vmin=0, vmax=500),
531                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
532        axes[1].set_title("Clear-sky upwelling")
533    else:
534        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, _ds.flux_up_lw,
535                         dict(cmap='Reds', vmin=0, vmax=500),
536                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
537        axes[1].set_title("Upwelling")
538    axes[1].set_xlabel('')
539
540    if clearsky:
541        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_lw_clear,
542                         dict(cmap='RdBu_r', norm=DivergingNorm(vcenter=0)),#, center=0, robust=True),
543                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
544        axes[2].set_title("Clear-sky net")
545    else:
546        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_lw,
547                         dict(cmap='RdBu_r', norm=DivergingNorm(vcenter=0)),#, center=0, robust=True),
548                         cbar_kwargs={'pad':0.01, 'label':'flux [W m$^{-2}$]'})
549        axes[2].set_title("Net")
550
551    for ax in axes:
552        add_temperature_contours(ax, _ds)
553        format_pressure(ax)
554
555    for ax in axes:
556        if True:
557            ax.set_yscale('linear')
558            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
559            ax.set_ylim(1050e2,1)
560        else:
561            ax.set_yscale('log')
562            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
563            ax.set_ylim(1.1e5,1)
564        format_pressure(ax)
565
566    axes[-1].set_xlim(-90,90)
567    axes[-1].set_xticks(np.arange(-90,91,15))
568    format_latitude(axes[-1])
569    axes[-1].set_xlabel('Latitude')
570
571    if hasattr(_ds, 'experiment'):
572        place_suptitle(fig, axes, _ds.attrs['experiment'] + "\nLongwave fluxes", y=1.0)
573    else:
574        place_suptitle(fig, axes, "Longwave fluxes")
575
576    add_subfigure_labels(axes)
577
578    if dstfile:
579        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
580    else:
581        return fig, axes
582
583def plot_LW_flux_difference(IFS_srcfile, ecRAD_srcfile, reference_ecRAD_srcfile, title=None, dstfile=None, clearsky=False):
584    ds = load_ecRAD(reference_ecRAD_srcfile, IFS_srcfile)
585    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
586
587    # LW fluxes
588    nrows=3
589    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
590
591    cbar_kwargs = {'pad':0.01, 'label':'$\Delta$ flux [W m$^{-2}$]'}
592
593    if clearsky:
594        da = (_ds.flux_dn_lw_clear - ds.flux_dn_lw_clear)
595        vmin, vmax = get_vextents(da)
596        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
597                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
598                         cbar_kwargs=cbar_kwargs)
599        axes[0].set_title("Clear-sky downwelling")
600    else:
601        da = (_ds.flux_dn_lw - ds.flux_dn_lw)
602        vmin, vmax = get_vextents(da)
603        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
604                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
605                         cbar_kwargs=cbar_kwargs)
606        axes[0].set_title("Downwelling")
607    axes[0].set_xlabel('')
608
609    if clearsky:
610        da = (_ds.flux_up_lw_clear - ds.flux_up_lw_clear)
611        vmin, vmax = get_vextents(da)
612        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
613                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
614                         cbar_kwargs=cbar_kwargs)
615        axes[1].set_title("Clear-sky upwelling")
616    else:
617        da = (_ds.flux_up_lw - ds.flux_up_lw)
618        vmin, vmax = get_vextents(da)
619        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
620                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
621                              cbar_kwargs=cbar_kwargs)
622        axes[1].set_title("Upwelling")
623    axes[1].set_xlabel('')
624
625    if clearsky:
626        da = (_ds.flux_net_lw_clear - ds.flux_net_lw_clear)
627        vmin, vmax = get_vextents(da)
628        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
629                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
630                         cbar_kwargs=cbar_kwargs)
631        axes[2].set_title("Clear-sky net")
632    else:
633        da = (_ds.flux_net_lw - ds.flux_net_lw)
634        vmin, vmax = get_vextents(da)
635        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
636                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
637                              cbar_kwargs=cbar_kwargs)
638        axes[2].set_title("Net ")
639
640    for ax in axes:
641        add_temperature_contours(ax, _ds)
642        format_pressure(ax)
643
644    for ax in axes:
645        if True:
646            ax.set_yscale('linear')
647            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
648            ax.set_ylim(1050e2,1)
649        else:
650            ax.set_yscale('log')
651            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
652            ax.set_ylim(1.1e5,1)
653        format_pressure(ax)
654
655    axes[-1].set_xlim(-90,90)
656    axes[-1].set_xticks(np.arange(-90,91,15))
657    format_latitude(axes[-1])
658    axes[-1].set_xlabel('Latitude')
659
660    if hasattr(_ds, 'experiment'):
661        place_suptitle(fig, axes, f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\nLongwave fluxes", y=1.0)
662    else:
663        place_suptitle(fig, axes, "Longwave fluxes")
664
665    add_subfigure_labels(axes)
666
667    if dstfile:
668        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
669    else:
670        return fig, axes
671
672def plot_SW_flux(IFS_srcfile, ecRAD_srcfile, title=None, dstfile=None, clearsky=False):
673    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
674
675    # SW fluxes
676    nrows=3
677    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
678
679    cbar_kwargs = {'pad':0.01, 'label':'flux [W m$^{-2}$]'}
680
681    if clearsky:
682        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_sw_clear,
683                         dict(cmap='Blues', vmin=0),
684                         cbar_kwargs=cbar_kwargs)
685        axes[0].set_title("Clear-sky downwelling")
686    else:
687        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_sw,
688                         dict(cmap='Blues', vmin=0),
689                         cbar_kwargs=cbar_kwargs)
690        axes[0].set_title("Downwelling")
691    axes[0].set_xlabel('')
692
693    if clearsky:
694        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, _ds.flux_up_sw_clear,
695                         dict(cmap='Blues', vmin=0),
696                         cbar_kwargs=cbar_kwargs)
697        axes[1].set_title("Clear-sky upwelling")
698    else:
699        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, _ds.flux_up_sw,
700                         dict(cmap='Blues', vmin=0),
701                         cbar_kwargs=cbar_kwargs)
702        axes[1].set_title("Upwelling")
703    axes[1].set_xlabel('')
704
705    if clearsky:
706        if (_ds.flux_net_sw_clear.quantile(q=0.01) < 0) & (0 < _ds.flux_net_sw_clear.quantile(q=0.99)):
707            irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_sw_clear,
708                             dict(cmap='RdBu_r', norm=DivergingNorm(vcenter=0, vmin=_ds.flux_net_sw_clear.quantile(q=0.01), vmax=_ds.flux_net_sw_clear.quantile(q=0.99))),
709                             cbar_kwargs=cbar_kwargs)
710        else:
711            irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_sw_clear,
712                             dict(cmap='Blues_r', vmax=0),
713                             cbar_kwargs=cbar_kwargs)
714        axes[2].set_title("Clear-sky net")
715    else:
716        if (_ds.flux_net_sw_clear.quantile(q=0.01) < 0) & (0 < _ds.flux_net_sw_clear.quantile(q=0.99)):
717            irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_sw,
718                             dict(cmap='RdBu_r', norm=DivergingNorm(vcenter=0, vmin=_ds.flux_net_sw.quantile(q=0.01), vmax=_ds.flux_net_sw.quantile(q=0.99))),
719                             cbar_kwargs=cbar_kwargs)
720        else:
721            irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, _ds.flux_net_sw,
722                             dict(cmap='Blues_r', vmax=0),
723                             cbar_kwargs=cbar_kwargs)
724        axes[2].set_title("Net")
725
726    for ax in axes:
727        add_temperature_contours(ax, _ds)
728        format_pressure(ax)
729
730    for ax in axes:
731        if True:
732            ax.set_yscale('linear')
733            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
734            ax.set_ylim(1050e2,1)
735        else:
736            ax.set_yscale('log')
737            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
738            ax.set_ylim(1.1e5,1)
739        format_pressure(ax)
740
741    axes[-1].set_xlim(-90,90)
742    axes[-1].set_xticks(np.arange(-90,91,15))
743    format_latitude(axes[-1])
744    axes[-1].set_xlabel('Latitude')
745
746    if hasattr(_ds, 'experiment'):
747        place_suptitle(fig, axes, _ds.attrs['experiment'] + "\nShortwave fluxes", y=1.0)
748    else:
749        place_suptitle(fig, axes, "Shortwave fluxes")
750
751    add_subfigure_labels(axes)
752
753    if dstfile:
754        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
755    else:
756        return fig, axes
757
758
759def plot_SW_flux_difference(IFS_srcfile, ecRAD_srcfile, reference_ecRAD_srcfile, title=None, dstfile=None, clearsky=False):
760    ds = load_ecRAD(reference_ecRAD_srcfile, IFS_srcfile).load()
761    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile).load()
762
763    cbar_kwargs = {'pad':0.01, 'label':'$\Delta$ flux [W m$^{-2}$]'}
764
765    nrows=3
766    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
767
768    if clearsky:
769        da = (_ds.flux_dn_sw_clear - ds.flux_dn_sw_clear)
770        vmin, vmax = get_vextents(da)
771        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
772                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
773                         cbar_kwargs=cbar_kwargs)
774        axes[0].set_title("Clear-sky downwelling")
775
776    else:
777        da = (_ds.flux_dn_sw - ds.flux_dn_sw)
778        vmin, vmax = get_vextents(da)
779        irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
780                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
781                         cbar_kwargs=cbar_kwargs)
782        axes[0].set_title("Downwelling")
783    axes[0].set_xlabel('')
784
785    if clearsky:
786        da = (_ds.flux_up_sw_clear - ds.flux_up_sw_clear)
787        vmin, vmax = get_vextents(da)
788        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
789                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
790                         cbar_kwargs=cbar_kwargs)
791
792        axes[1].set_title("Clear-sky upwelling")
793
794    else:
795        da = (_ds.flux_up_sw - ds.flux_up_sw)
796        vmin, vmax = get_vextents(da)
797        irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
798                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
799                         cbar_kwargs=cbar_kwargs)
800        axes[1].set_title("Upwelling")
801    axes[1].set_xlabel('')
802
803    if clearsky:
804        da = (_ds.flux_net_sw_clear - ds.flux_net_sw_clear)
805        vmin, vmax = get_vextents(da)
806        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
807                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
808                         cbar_kwargs=cbar_kwargs)
809        axes[2].set_title("Clear-sky net")
810
811    else:
812        da = (_ds.flux_net_sw - ds.flux_net_sw)
813        vmin, vmax = get_vextents(da)
814        irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
815                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
816                         cbar_kwargs=cbar_kwargs)
817        axes[2].set_title("Net")
818
819    for ax in axes:
820        add_temperature_contours(ax, _ds)
821        format_pressure(ax)
822
823    for ax in axes:
824        if True:
825            ax.set_yscale('linear')
826            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
827            ax.set_ylim(1050e2,1)
828        else:
829            ax.set_yscale('log')
830            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
831            ax.set_ylim(1.1e5,1)
832        format_pressure(ax)
833
834    axes[-1].set_xlim(-90,90)
835    axes[-1].set_xticks(np.arange(-90,91,15))
836    format_latitude(axes[-1])
837    axes[-1].set_xlabel('Latitude')
838
839    if hasattr(_ds, 'experiment'):
840        place_suptitle(fig, axes, f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\nShortwave fluxes", y=1.0)
841    else:
842        place_suptitle(fig, axes, "Shortwave fluxes")
843
844    add_subfigure_labels(axes)
845
846    if dstfile:
847        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
848    else:
849        return fig, axes
850
851
852def plot_CRE(IFS_srcfile, ecRAD_srcfile, title=None, dstfile=None):
853    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
854
855    nrows=3
856    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
857
858    da = _ds.cloud_radiative_effect_sw
859    vmin, vmax = get_vextents(da)
860    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
861                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
862                         cbar_kwargs={'pad':0.01, 'label':'CRE$_{\mathrm{SW}}$ [W m$^{-2}$]'})
863
864    axes[0].set_xlabel('')
865    axes[0].set_title("Shortwave")
866
867    da = _ds.cloud_radiative_effect_lw
868    vmin, vmax= get_vextents(da)
869    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
870                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
871                         cbar_kwargs={'pad':0.01, 'label':'CRE$_{\mathrm{LW}}$ [W m$^{-2}$]'})
872    axes[1].set_xlabel('')
873    axes[1].set_title("Longwave")
874
875    da = (_ds.cloud_radiative_effect_sw + _ds.cloud_radiative_effect_lw)
876    vmin, vmax= get_vextents(da)
877    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
878                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
879                     cbar_kwargs={'pad':0.01, 'label':'CRE$_{\mathrm{net}}$ [W m$^{-2}$]'})
880    axes[2].set_title("Net")
881
882    for ax in axes:
883        add_temperature_contours(ax, _ds)
884        format_pressure(ax)
885
886    for ax in axes:
887        if True:
888            ax.set_yscale('linear')
889            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
890            ax.set_ylim(1050e2,1)
891        else:
892            ax.set_yscale('log')
893            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
894            ax.set_ylim(1.1e5,1)
895        format_pressure(ax)
896
897    axes[-1].set_xlim(-90,90)
898    axes[-1].set_xticks(np.arange(-90,91,15))
899    format_latitude(axes[-1])
900    axes[-1].set_xlabel('Latitude')
901
902    if hasattr(_ds, 'experiment'):
903        place_suptitle(fig, axes, _ds.attrs['experiment'] + "\nCloud radiative effects", y=1.0)
904    else:
905        place_suptitle(fig, axes, "Cloud radiative effects")
906
907    add_subfigure_labels(axes)
908
909    if dstfile:
910        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
911    else:
912        return fig, axes
913
914
915def plot_CRE_difference(IFS_srcfile, ecRAD_srcfile, reference_ecRAD_srcfile, title=None, dstfile=None):
916    name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
917
918    ds = load_ecRAD(reference_ecRAD_srcfile, IFS_srcfile)
919    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
920
921    nrows=3
922    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
923
924    da = (_ds.cloud_radiative_effect_sw - ds.cloud_radiative_effect_sw)
925    vmin, vmax= get_vextents(da)
926    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_hl, da,
927                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
928                     cbar_kwargs={'pad':0.01, 'label':'$\Delta$ CRE$_{\mathrm{SW}}$ [W m$^{-2}$]'})
929    axes[0].set_xlabel('')
930    axes[0].set_title("Shortwave")
931
932    da = (_ds.cloud_radiative_effect_lw - ds.cloud_radiative_effect_lw)
933    vmin, vmax= get_vextents(da)
934    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_hl, da,
935                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
936                     cbar_kwargs={'pad':0.01, 'label':'$\Delta$ CRE$_{\mathrm{SW}}$ [W m$^{-2}$]'})
937    axes[1].set_xlabel('')
938    axes[1].set_title("Longwave")
939
940    da = ((_ds.cloud_radiative_effect_sw + _ds.cloud_radiative_effect_lw) - (ds.cloud_radiative_effect_sw + ds.cloud_radiative_effect_lw))
941    vmin, vmax= get_vextents(da)
942    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_hl, da,
943                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
944                     cbar_kwargs={'pad':0.01, 'label':'$\Delta$ CRE$_\mathrm{net}$ [W m$^{-2}$]'})
945    axes[2].set_title("Net")
946
947    for ax in axes:
948        add_temperature_contours(ax, _ds)
949        format_pressure(ax)
950
951    for ax in axes:
952        if True:
953            ax.set_yscale('linear')
954            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
955            ax.set_ylim(1050e2,1)
956        else:
957            ax.set_yscale('log')
958            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
959            ax.set_ylim(1.1e5,1)
960        format_pressure(ax)
961
962    axes[-1].set_xlim(-90,90)
963    axes[-1].set_xticks(np.arange(-90,91,15))
964    format_latitude(axes[-1])
965    axes[-1].set_xlabel('Latitude')
966
967    if hasattr(_ds, 'experiment'):
968        place_suptitle(fig, axes, f"{name_string}\n{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\nCloud radiative effects", y=1.0)
969    else:
970        place_suptitle(fig, axes, "Cloud radiative effects")
971
972    add_subfigure_labels(axes)
973
974    if dstfile:
975        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
976    else:
977        return fig, axes
978
979
980def plot_heating_rate(IFS_srcfile, ecRAD_srcfile, title=None, linear_pressure=True, dstfile=None):
981    name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
982
983    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
984
985    if linear_pressure:
986        vmax = 10
987    else:
988        vmax = 30
989
990    nrows=3
991    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
992
993    cbar_kwargs = {'pad':0.01, 'label':'$\dfrac{dT}{dt}$ [K d$^{-1}$]'}
994
995    da = _ds.heating_rate_lw
996    if linear_pressure:
997        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
998    else:
999        vmin, vmax= get_vextents(da)
1000    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_fl, da,
1001                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1002                     cbar_kwargs=cbar_kwargs)
1003    axes[0].set_xlabel('')
1004    axes[0].set_title("Longwave")
1005
1006    da = _ds.heating_rate_sw
1007    if linear_pressure:
1008        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1009    else:
1010        vmin, vmax= get_vextents(da)
1011    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_fl, da,
1012                     dict(cmap='RdBu_r',vmin=vmin, vmax=vmax),
1013                     cbar_kwargs=cbar_kwargs)
1014    axes[1].set_xlabel('')
1015    axes[1].set_title("Shortwave")
1016
1017    da = (_ds.heating_rate_sw + _ds.heating_rate_lw)
1018    if linear_pressure:
1019        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1020    else:
1021        vmin, vmax= get_vextents(da)
1022    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_fl, da,
1023                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1024                     cbar_kwargs=cbar_kwargs)
1025    axes[2].set_title("Net")
1026
1027    for ax in axes:
1028        add_temperature_contours(ax, _ds)
1029        format_pressure(ax)
1030
1031    for ax in axes:
1032        if linear_pressure:
1033            ax.set_yscale('linear')
1034            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
1035            ax.set_ylim(1050e2,1)
1036        else:
1037            ax.set_yscale('log')
1038            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
1039            ax.set_ylim(1.1e5,1)
1040        format_pressure(ax)
1041
1042    axes[-1].set_xlim(-90,90)
1043    axes[-1].set_xticks(np.arange(-90,91,15))
1044    format_latitude(axes[-1])
1045    axes[-1].set_xlabel('Latitude')
1046
1047    if hasattr(_ds, 'experiment'):
1048        place_suptitle(fig, axes, f"{name_string}\n{_ds.attrs['experiment']}\nHeating rates", y=1.0)
1049    else:
1050        place_suptitle(fig, axes, "Heating rates")
1051
1052    add_subfigure_labels(axes)
1053
1054    if dstfile:
1055        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1056    else:
1057        return fig, axes
1058
1059
1060def plot_heating_rate_difference(IFS_srcfile, ecRAD_srcfile, reference_ecRAD_srcfile, title=None, linear_pressure=True, dstfile=None):
1061    name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
1062
1063    ds = load_ecRAD(reference_ecRAD_srcfile, IFS_srcfile)
1064    _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
1065
1066    if linear_pressure:
1067        vmax = 10
1068    else:
1069        vmax = 30
1070
1071    nrows=3
1072    fig, axes = plt.subplots(figsize=(25,nrows*4), nrows=nrows, sharex=True, sharey=True)
1073
1074    cbar_kwargs = {'pad':0.01, 'label':'$\Delta \dfrac{dT}{dt}$ [K d$^{-1}$]'}
1075
1076    da = (_ds.heating_rate_lw - ds.heating_rate_lw)
1077    if linear_pressure:
1078        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1079    else:
1080        vmin, vmax= get_vextents(da)
1081    irregular_pcolor(axes[0], _ds.latitude, _ds.pressure_fl, da,
1082                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1083                     cbar_kwargs=cbar_kwargs)
1084    axes[0].set_xlabel('')
1085    axes[0].set_title("Longwave")
1086
1087    da = (_ds.heating_rate_sw - ds.heating_rate_sw)
1088    if linear_pressure:
1089        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1090    else:
1091        vmin, vmax= get_vextents(da)
1092    irregular_pcolor(axes[1], _ds.latitude, _ds.pressure_fl, da,
1093                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1094                     cbar_kwargs=cbar_kwargs)
1095    axes[1].set_xlabel('')
1096    axes[1].set_title("Shortwave")
1097
1098    da = ((_ds.heating_rate_sw + _ds.heating_rate_lw) - (ds.heating_rate_sw + ds.heating_rate_lw))
1099    if linear_pressure:
1100        vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1101    else:
1102        vmin, vmax= get_vextents(da)
1103    irregular_pcolor(axes[2], _ds.latitude, _ds.pressure_fl, da,
1104                     dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1105                     cbar_kwargs=cbar_kwargs)
1106    axes[2].set_title("Net")
1107
1108    for ax in axes:
1109        add_temperature_contours(ax, _ds)
1110        format_pressure(ax)
1111
1112    for ax in axes:
1113        if linear_pressure:
1114            ax.set_yscale('linear')
1115            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
1116            ax.set_ylim(1050e2,1)
1117        else:
1118            ax.set_yscale('log')
1119            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
1120            ax.set_ylim(1.1e5,1)
1121        format_pressure(ax)
1122
1123    axes[-1].set_xlim(-90,90)
1124    axes[-1].set_xticks(np.arange(-90,91,15))
1125    format_latitude(axes[-1])
1126    axes[-1].set_xlabel('Latitude')
1127
1128    if hasattr(_ds, 'experiment'):
1129        place_suptitle(fig, axes, f"{name_string}\n{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\nHeating rates", y=1.0)
1130    else:
1131        place_suptitle(fig, axes, "Heating rates")
1132
1133    add_subfigure_labels(axes)
1134
1135    if dstfile:
1136        fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1137    else:
1138        return fig, axes
1139
1140
1141def plot_output(IFS_srcfile, ecRAD_srcfile, dstfile=None):
1142
1143    with sns.plotting_context('notebook', font_scale=1.1), sns.axes_style('ticks'):
1144
1145        _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
1146
1147        # LW fluxes
1148        nrows=5
1149        ncols=2
1150
1151        fig, axes = plt.subplots(figsize=(25,2.5*nrows), nrows=nrows, ncols=ncols, sharex=True, sharey='row', gridspec_kw={'hspace':0.25, 'wspace':0.0})
1152
1153        ### LW fluxes
1154        j=0
1155        i=0
1156        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_lw,
1157                             dict(cmap='Reds', vmin=0, vmax=500),
1158                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1159        axes[i,j].set_title("Downwelling longwave flux")
1160        axes[i,j].set_xlabel('')
1161
1162        i+=1
1163        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, _ds.flux_up_lw,
1164                             dict(cmap='Reds', vmin=0, vmax=500),
1165                             cbar_kwargs={'pad':0.0125, 'aspect':10,'label':'flux [W m$^{-2}$]'})
1166        axes[i,j].set_title("Upwelling longwave flux")
1167        axes[i,j].set_xlabel('')
1168
1169        #SW fluxes
1170        j=1
1171        i=0
1172        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, _ds.flux_dn_sw,
1173                             dict(cmap='Reds', vmin=0, vmax=1300),
1174                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1175        axes[i,j].set_title("Downwelling shortwave flux")
1176        axes[i,j].set_xlabel('')
1177
1178        i+=1
1179        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, _ds.flux_up_sw,
1180                             dict(cmap='Reds', vmin=0, vmax=1300),
1181                             cbar_kwargs={'pad':0.0125, 'aspect':10,'label':'flux [W m$^{-2}$]'})
1182        axes[i,j].set_title("Upwelling shortwave flux")
1183        axes[i,j].set_xlabel('')
1184
1185        #Cloud radiative effects
1186        j=0
1187        i+=1
1188        da = _ds.cloud_radiative_effect_lw
1189        vmin, vmax = get_vextents(da)
1190        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1191                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1192                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'CRE$_{\mathrm{LW}}$ [W m$^{-2}$]'})
1193
1194        axes[i,j].set_xlabel('')
1195        axes[i,j].set_title("Longwave cloud radiative effect")
1196
1197        j+=1
1198        da = _ds.cloud_radiative_effect_sw
1199        vmin, vmax= get_vextents(da)
1200        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1201                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1202                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'CRE$_{\mathrm{SW}}$ [W m$^{-2}$]'})
1203        axes[i,j].set_xlabel('')
1204        axes[i,j].set_title("Shortwave cloud radiative effect")
1205
1206        #Heating rates
1207        cbar_kwargs = {'pad':0.0125, 'aspect':10, 'label':'$\dfrac{dT}{dt}$ [K d$^{-1}$]'}
1208        j=0
1209        i+=1
1210
1211        linear_pressure=True
1212
1213        da = _ds.heating_rate_lw
1214        if linear_pressure:
1215            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1216        else:
1217            vmin, vmax= get_vextents(da)
1218        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1219                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1220                         cbar_kwargs=cbar_kwargs)
1221        axes[i,j].set_xlabel('')
1222        axes[i,j].set_title("Longwave heating rate (troposphere)")
1223
1224        j+=1
1225        da = _ds.heating_rate_sw
1226        if linear_pressure:
1227            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1228        else:
1229            vmin, vmax= get_vextents(da)
1230        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1231                         dict(cmap='RdBu_r',vmin=vmin, vmax=vmax),
1232                         cbar_kwargs=cbar_kwargs)
1233        axes[i,j].set_xlabel('')
1234        axes[i,j].set_title("Shortwave heating rate (troposphere)")
1235
1236        j=0
1237        i+=1
1238
1239        linear_pressure=False
1240
1241        da = _ds.heating_rate_lw
1242        if linear_pressure:
1243            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1244        else:
1245            vmin, vmax= get_vextents(da)
1246        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1247                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1248                         cbar_kwargs=cbar_kwargs)
1249        axes[i,j].set_xlabel('')
1250        axes[i,j].set_title("Longwave heating rate (stratosphere)")
1251
1252        j+=1
1253        da = _ds.heating_rate_sw
1254        if linear_pressure:
1255            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1256        else:
1257            vmin, vmax= get_vextents(da)
1258        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1259                         dict(cmap='RdBu_r',vmin=vmin, vmax=vmax),
1260                         cbar_kwargs=cbar_kwargs)
1261        axes[i,j].set_xlabel('')
1262        axes[i,j].set_title("Shortwave heating rate (stratosphere)")
1263
1264        for ax in axes[:-1,:].flatten():
1265            add_temperature_contours(ax, _ds)
1266            ax.set_yscale('linear')
1267            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
1268            ax.set_ylim(1050e2,1)
1269
1270        for ax in axes[-1,:].flatten():
1271            add_temperature_contours(ax, _ds)
1272            ax.set_yscale('log')
1273            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
1274            ax.set_ylim(1.1e5,1)
1275
1276            ax.set_xlim(-90,90)
1277            ax.set_xticks(np.arange(-90,91,15))
1278            format_latitude(ax)
1279            ax.set_xlabel('Latitude')
1280
1281        for ax in axes[:,0]:
1282            format_pressure(ax)
1283
1284        x = (get_figure_center(axes[0,0]) + get_figure_center(axes[0,1]))/2
1285        y = get_figure_top(fig, axes[0,0], include_hspace=True)
1286
1287        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
1288        fig.suptitle(f"{name_string}\n{_ds.attrs['experiment']}\nFluxes, cloud radiative effects and heating rates", x=x, y=y-0.025, va='bottom', fontsize='xx-large')
1289
1290        add_subfigure_labels(axes, flatten_order='C')
1291
1292        if dstfile:
1293            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1294        else:
1295            return fig, axes
1296
1297
1298def compare_output(IFS_srcfile, ctrl_srcfile, ecRAD_srcfile, dstfile=None):
1299
1300    ds = load_ecRAD(ctrl_srcfile, IFS_srcfile)
1301
1302    with sns.plotting_context('notebook', font_scale=1.1), sns.axes_style('ticks'):
1303
1304        _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile)
1305
1306        # LW fluxes
1307        nrows=5
1308        ncols=2
1309
1310        fig, axes = plt.subplots(figsize=(25,2.5*nrows), nrows=nrows, ncols=ncols, sharex=True, sharey='row', gridspec_kw={'hspace':0.25, 'wspace':0.0})
1311
1312        ### LW fluxes
1313        j=0
1314        i=0
1315        da = _ds.flux_dn_lw - ds.flux_dn_lw
1316        vmin, vmax = get_vextents(da, symmetric=True)
1317        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1318                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1319                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1320        axes[i,j].set_title("Change to downwelling longwave flux")
1321        axes[i,j].set_xlabel('')
1322
1323        i+=1
1324        da = _ds.flux_up_lw - ds.flux_up_lw
1325        vmin, vmax = get_vextents(da, symmetric=True)
1326        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1327                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1328                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1329        axes[i,j].set_title("Change to upwelling longwave flux")
1330        axes[i,j].set_xlabel('')
1331
1332        #SW fluxes
1333        j=1
1334        i=0
1335        da = _ds.flux_dn_sw - ds.flux_dn_sw
1336        vmin, vmax = get_vextents(da, symmetric=True)
1337        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1338                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1339                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1340        axes[i,j].set_title("Change to downwelling shortwave flux")
1341        axes[i,j].set_xlabel('')
1342
1343        i+=1
1344        da = _ds.flux_up_sw - ds.flux_up_sw
1345        vmin, vmax = get_vextents(da, symmetric=True)
1346        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1347                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1348                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'flux [W m$^{-2}$]'})
1349        axes[i,j].set_title("Change to upwelling shortwave flux")
1350        axes[i,j].set_xlabel('')
1351
1352        #Cloud radiative effects
1353        j=0
1354        i+=1
1355        da = _ds.cloud_radiative_effect_lw - ds.cloud_radiative_effect_lw
1356        vmin, vmax = get_vextents(da, symmetric=True)
1357        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1358                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1359                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'CRE$_{\mathrm{LW}}$ [W m$^{-2}$]'})
1360
1361        axes[i,j].set_xlabel('')
1362        axes[i,j].set_title("Change to longwave cloud radiative effect")
1363
1364        j+=1
1365        da = _ds.cloud_radiative_effect_sw - ds.cloud_radiative_effect_sw
1366        vmin, vmax= get_vextents(da, symmetric=True)
1367        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_hl, da,
1368                             dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1369                             cbar_kwargs={'pad':0.0125, 'aspect':10, 'label':'CRE$_{\mathrm{SW}}$ [W m$^{-2}$]'})
1370        axes[i,j].set_xlabel('')
1371        axes[i,j].set_title("Change to shortwave cloud radiative effect")
1372
1373        #Heating rates
1374        cbar_kwargs = {'pad':0.0125, 'aspect':10, 'label':'$\dfrac{dT}{dt}$ [K d$^{-1}$]'}
1375        j=0
1376        i+=1
1377
1378        linear_pressure=True
1379
1380        da = _ds.heating_rate_lw - ds.heating_rate_lw
1381        if linear_pressure:
1382            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1383        else:
1384            vmin, vmax= get_vextents(da)
1385        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1386                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1387                         cbar_kwargs=cbar_kwargs)
1388        axes[i,j].set_xlabel('')
1389        axes[i,j].set_title("Change to longwave heating rate (troposphere)")
1390
1391        j+=1
1392        da = _ds.heating_rate_sw - ds.heating_rate_sw
1393        if linear_pressure:
1394            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1395        else:
1396            vmin, vmax= get_vextents(da)
1397        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1398                         dict(cmap='RdBu_r',vmin=vmin, vmax=vmax),
1399                         cbar_kwargs=cbar_kwargs)
1400        axes[i,j].set_xlabel('')
1401        axes[i,j].set_title("Change to shortwave heating rate (troposphere)")
1402
1403        j=0
1404        i+=1
1405
1406        linear_pressure=False
1407
1408        da = _ds.heating_rate_lw - ds.heating_rate_lw
1409        if linear_pressure:
1410            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1411        else:
1412            vmin, vmax= get_vextents(da)
1413        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1414                         dict(cmap='RdBu_r', vmin=vmin, vmax=vmax),
1415                         cbar_kwargs=cbar_kwargs)
1416        axes[i,j].set_xlabel('')
1417        axes[i,j].set_title("Change to longwave heating rate (stratosphere)")
1418
1419        j+=1
1420        da = _ds.heating_rate_sw - ds.heating_rate_sw
1421        if linear_pressure:
1422            vmin, vmax= get_vextents(da.where(_ds.pressure_fl > 100e2))
1423        else:
1424            vmin, vmax= get_vextents(da)
1425        irregular_pcolor(axes[i,j], _ds.latitude, _ds.pressure_fl, da,
1426                         dict(cmap='RdBu_r',vmin=vmin, vmax=vmax),
1427                         cbar_kwargs=cbar_kwargs)
1428        axes[i,j].set_xlabel('')
1429        axes[i,j].set_title("Change to shortwave heating rate (stratosphere)")
1430
1431        for ax in axes[:-1,:].flatten():
1432            add_temperature_contours(ax, _ds)
1433            ax.set_yscale('linear')
1434            ax.set_yticks([1000e2,800e2,600e2,400e2,200e2,1])
1435            ax.set_ylim(1050e2,1)
1436
1437        for ax in axes[-1,:].flatten():
1438            add_temperature_contours(ax, _ds)
1439            ax.set_yscale('log')
1440            ax.set_yticks([1e5,1e4,1e3,1e2,1e1,1e0])
1441            ax.set_ylim(1.1e5,1)
1442
1443            ax.set_xlim(-90,90)
1444            ax.set_xticks(np.arange(-90,91,15))
1445            format_latitude(ax)
1446            ax.set_xlabel('Latitude')
1447
1448        for ax in axes[:,0]:
1449            format_pressure(ax)
1450
1451        x = (get_figure_center(axes[0,0]) + get_figure_center(axes[0,1]))/2
1452        y = get_figure_top(fig, axes[0,0], include_hspace=True)
1453
1454        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
1455        fig.suptitle(f"{name_string}\n{_ds.attrs['experiment']} minus {ds.attrs['experiment']}\nFluxes, cloud radiative effects and heating rates",
1456                     x=x, y=y-0.025, va='bottom', fontsize='xx-large')
1457
1458        add_subfigure_labels(axes, flatten_order='C') # This will go across columns, then down rows
1459
1460        if dstfile:
1461            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1462        else:
1463            return fig, axes
1464
1465
1466def plot_output_scalar(IFS_srcfile, ecRAD_srcfiles, ecRAD_styles, dstfile=None, latitudes_to_highlight=None, line_ds='default', title=None):
1467
1468    with sns.axes_style("ticks", {"xtick.major.size": 6, "ytick.major.size": 6}):
1469
1470        nrows=4
1471        ncols=2
1472        fig, axes = plt.subplots(figsize=(11.0*ncols,3.*nrows), nrows=nrows, ncols=ncols, sharex=True, gridspec_kw={'wspace':0.05, 'hspace':0.25})
1473
1474        main_legend_labels = []
1475        main_legend_handles = []
1476        for i, (_style, _srcfile) in enumerate(zip(ecRAD_styles, ecRAD_srcfiles)):
1477            _ds = load_ecRAD(_srcfile, IFS_srcfile)
1478
1479            if i == 0:
1480
1481                # LW upwelling at surface
1482                _line = (_ds.flux_up_lw.isel(half_level=-1)).plot(ax=axes[0,0], color='0.85', zorder=-1, lw=3, **{'label':'Upwelling longwave\nflux at surface'})[0]
1483                minor_legend_ax0 = axes[0,0].legend([_line], ['Longwave upwelling\nflux at surface'], loc='upper left', frameon=False, fontsize='x-small')
1484                for text in minor_legend_ax0.get_texts():
1485                    text.set_color("0.75")
1486
1487                #SW downwelling at TOA
1488                _line = (_ds.flux_dn_direct_sw_clear.isel(half_level=0)).plot(ax=axes[1,1], color='0.85', zorder=-1, lw=3, **{'label':'Shortwave downwelling\nflux at TOA'})[0]
1489                minor_legend_ax1 = axes[1,1].legend([_line], ['Shortwave downwelling\nflux at TOA'], loc='upper left', frameon=False, fontsize='x-small')
1490                for text in minor_legend_ax1.get_texts():
1491                    text.set_color("0.75")
1492
1493            main_legend_labels.append(_ds.attrs['experiment'])
1494
1495            # LW up at TOA
1496            main_legend_handles.append(_ds.flux_up_lw.isel(half_level=0).plot(ax=axes[0,0], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}}))
1497
1498            # LW down at surface
1499            _ds.flux_dn_lw.isel(half_level=-1).plot(ax=axes[1,0], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1500
1501            # LW CRE at TOA
1502            _ds.cloud_radiative_effect_lw.isel(half_level=0).plot(ax=axes[2,0], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1503
1504            # Cloud cover
1505            _ds.cloud_cover_sw.plot(ax=axes[3,0], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1506
1507            #SW up at TOA
1508            _ds.flux_up_sw.isel(half_level=0).plot(ax=axes[0,1], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1509
1510            #SW down at surface
1511            _ds.flux_dn_sw.isel(half_level=-1).plot(ax=axes[1,1], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1512
1513            # SW CRE at TOA
1514            _ds.cloud_radiative_effect_sw.isel(half_level=0).plot(ax=axes[2,1], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1515
1516            # SW direct dn at surface
1517            _ds.flux_dn_direct_sw.isel(half_level=-1).plot(ax=axes[3,1], x='latitude', drawstyle=line_ds, **{**_style, **{'label':_ds.attrs['experiment']}})
1518
1519        for ax in axes[:,1]:
1520            ax.yaxis.set_label_position("right")
1521            ax.yaxis.tick_right()
1522
1523        axes[0,0].set_ylabel('flux [W m$^{-2}$]')
1524        axes[0,0].set_title('Longwave upwelling flux at TOA', color=sns.color_palette()[3])
1525        axes[0,0].set_xlabel('')
1526        axes[0,0].add_artist(minor_legend_ax0)
1527        axes[0,0].set_ylim(0, None)
1528
1529        axes[1,0].set_ylabel('flux [W m$^{-2}$]')
1530        axes[1,0].set_title('Longwave downwelling flux at surface', color=sns.color_palette()[3])
1531        axes[1,0].set_xlabel('')
1532        axes[1,0].set_ylim(0, None)
1533
1534        axes[2,0].set_ylabel('CRE [W m$^{-2}$]')
1535        axes[2,0].set_title("Longwave cloud radiative effect at TOA", color=sns.color_palette()[3])
1536        axes[2,0].set_xlabel('')
1537
1538        axes[0,1].set_ylabel('flux [W m$^{-2}$]')
1539        axes[0,1].set_title('Shortwave upwelling flux at TOA', color=sns.color_palette()[0])
1540        axes[0,1].set_xlabel('')
1541
1542        axes[1,1].set_ylabel('flux [W m$^{-2}$]')
1543        axes[1,1].set_title('Shortwave downwelling flux at surface', color=sns.color_palette()[0])
1544        axes[1,1].set_xlabel('')
1545        axes[1,1].add_artist(minor_legend_ax1)
1546
1547        axes[2,1].set_ylabel('CRE [W m$^{-2}$]')
1548        axes[2,1].set_title("Shortwave cloud radiative effect at TOA", color=sns.color_palette()[0])
1549        axes[2,1].set_xlabel('')
1550
1551        axes[3,0].set_ylabel('$f_c$ [-]')
1552        axes[3,0].set_title("Cloud cover", color='0.33')
1553        axes[3,0].set_ylim(-0.1, 1.1)
1554        axes[3,0].set_yticks([0, 0.5, 1])
1555        format_latitude(axes[3,0])
1556        axes[3,0].set_xlabel('Latitude')
1557
1558        axes[3,1].set_ylabel('flux [W m$^{-2}$]')
1559        axes[3,1].set_title("Shortwave direct downwelling at surface", color=sns.color_palette()[0])
1560        axes[3,1].set_xlabel('')
1561        format_latitude(axes[3,1])
1562        axes[3,1].set_xlabel('Latitude')
1563
1564        add_subfigure_labels(axes, yloc=1.04)
1565
1566        if len(ecRAD_srcfiles) > 3:
1567            legend = axes[0,1].legend(frameon=False, loc='upper right', bbox_to_anchor=(1,1.75), fontsize='xx-small', ncol=2)
1568        else:
1569            legend = axes[0,1].legend(frameon=False, loc='upper right', bbox_to_anchor=(1,1.75), fontsize='xx-small', ncol=1)
1570
1571        fig.suptitle("Fluxes and cloud radiative effects\nat top-of-atmosphere and the surface", y=0.985, fontsize='large')
1572
1573        axes[-1,0].set_xlim(-90,90)
1574        axes[-1,0].set_xticks(np.arange(-90,91,30)[:-1])
1575        format_latitude(axes[-1,0])
1576        axes[-1,0].set_xlabel('Latitude')
1577
1578
1579        if dstfile:
1580            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1581        else:
1582            return fig, axes
1583
1584
1585def compare_output_scalar(IFS_srcfile, ecRAD_srcfiles, reference_ecRAD_srcfile, ecRAD_styles, reference_label="", latitudes_to_highlight=None, line_ds='default', title=None, dstfile=None):
1586
1587    with sns.axes_style("ticks", {"xtick.major.size": 8, "ytick.major.size": 8}):
1588
1589        nrows=3
1590        ncols=2
1591
1592        fig, axes = plt.subplots(figsize=(11.0*ncols,3.67*nrows), nrows=nrows, ncols=ncols, sharex=True, gridspec_kw={'hspace':0.4, 'wspace':0.05})
1593
1594        for ax in axes[:,1]:
1595            ax.yaxis.set_label_position("right")
1596            ax.yaxis.tick_right()
1597
1598        ds = load_ecRAD(reference_ecRAD_srcfile, IFS_srcfile)
1599
1600        for _style, _srcfile in zip(ecRAD_styles, ecRAD_srcfiles):
1601            _ds = load_ecRAD(_srcfile, IFS_srcfile)
1602
1603            #Longwave net flux at TOA
1604            (_ds.flux_net_lw - ds.flux_net_lw).isel(half_level=0).plot(ax=axes[0,0], x='latitude', drawstyle=line_ds,
1605                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1606
1607            #Longwave net flux at surface
1608            (_ds.flux_net_lw - ds.flux_net_lw).isel(half_level=-1).plot(ax=axes[1,0], x='latitude', drawstyle=line_ds,
1609                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1610
1611            #Change to cloud cover
1612            (_ds.cloud_cover_sw - ds.cloud_cover_sw).plot(ax=axes[2,0], x='latitude', drawstyle=line_ds,
1613                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1614
1615            #Shortwave net flux at TOA
1616            (_ds.flux_net_sw - ds.flux_net_sw).isel(half_level=0).plot(ax=axes[0,1], x='latitude', drawstyle=line_ds,
1617                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1618
1619            #Shortwave net flux at surface
1620            (_ds.flux_net_sw - ds.flux_net_sw).isel(half_level=-1).plot(ax=axes[1,1], x='latitude', drawstyle=line_ds,
1621                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1622
1623            #Shortwave direct downward at surface
1624            (_ds.flux_dn_direct_sw - ds.flux_dn_direct_sw).isel(half_level=-1).plot(ax=axes[2,1], x='latitude', drawstyle=line_ds,
1625                                                          **{**_style, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1626
1627        axes[0,0].set_ylabel('$\Delta$ flux [W m$^{-2}$]')
1628        axes[0,0].set_title('Change in net\nlongwave flux at TOA', color=sns.color_palette()[3])
1629        axes[0,0].set_xlabel('')
1630
1631        axes[1,0].set_ylabel('$\Delta$ flux [W m$^{-2}$]')
1632        axes[1,0].set_title('Change in net\nlongwave flux at surface', color=sns.color_palette()[3])
1633        axes[1,0].set_xlabel('')
1634
1635        axes[2,0].set_ylabel('$\Delta$ cloud cover [-]')
1636        axes[2,0].set_title("Change in cloud cover", color='0.33')
1637        #axes[2,0].set_ylim(0,None)
1638
1639        axes[0,1].set_ylabel('$\Delta$ flux [W m$^{-2}$]')
1640        axes[0,1].set_title('Change in net\nshortwave flux at TOA', color=sns.color_palette()[0])
1641        axes[0,1].set_xlabel('')
1642        if len(ecRAD_srcfiles) > 2:
1643            legend = axes[0,1].legend(frameon=False, loc='upper right', bbox_to_anchor=(1.2,1.67), fontsize='xx-small', ncol=2)
1644        else:
1645            legend = axes[0,1].legend(frameon=False, loc='upper right', bbox_to_anchor=(1.2,1.67), fontsize='xx-small', ncol=1)
1646
1647        axes[1,1].set_ylabel('$\Delta$ flux [W m$^{-2}$]')
1648        axes[1,1].set_title('Change in net\nshortwave flux at surface', color=sns.color_palette()[0])
1649        axes[1,1].set_xlabel('')
1650
1651        axes[2,1].set_ylabel('$\Delta$ flux [W m$^{-2}$]')
1652        axes[2,1].set_title("Change in direct downwelling\nshortwave flux at surface", color=sns.color_palette()[0])
1653
1654        axes[2,0].set_xlim(-90,90)
1655        axes[2,0].set_xticks(np.arange(-90,90,30))
1656        format_latitude(axes[2,0])
1657        axes[2,0].set_xlabel('Latitude')
1658        axes[2,1].set_xlabel('Latitude')
1659
1660        add_subfigure_labels(axes, yloc=1.04)
1661
1662        fig.suptitle("Fluxes and cloud radiative effects\nat top-of-atmosphere and the surface", y=1.025, fontsize='large')
1663
1664        if dstfile:
1665            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1666        else:
1667            return fig, axes
1668
1669
1670
1671def plot_on_hybrid_pressure_axis(_axes, x, y, linedict, overwriting=False):
1672    #Log part of the plot
1673    _axes[0].plot(x, y, **linedict)
1674    _axes[1].plot(x, y, **linedict)
1675
1676    if not overwriting:
1677        _axes[0].set_yscale('log')
1678        format_pressure(_axes[0], label='')
1679        _axes[0].set_yticks([1000,100,10,1])
1680        _axes[0].set_ylim(10000,1)
1681
1682        #Linear part of the plot
1683        format_pressure(_axes[1], label='')
1684        _axes[1].set_yticks(np.linspace(9e4,1e4,5, dtype='float'))
1685        _axes[1].set_ylim(101000,10000)
1686
1687        # Hide the right and top spines
1688        _axes[0].spines['bottom'].set_visible(False)
1689        _axes[1].spines['top'].set_visible(False)
1690        _axes[0].spines['bottom'].set_visible(False)
1691        _axes[1].spines['top'].set_visible(False)
1692
1693        _axes[0].axhline(10000, lw=3.5, color='0.67', ls='-', zorder=-11)
1694        _axes[0].text(0.99, 0.03, 'log', color='0.67', fontsize='small', va='bottom', ha='right', transform=_axes[0].transAxes, zorder=-10)
1695        _axes[1].text(0.99, 0.99, 'linear', color='0.67', fontsize='small', va='top', ha='right', transform=_axes[1].transAxes, zorder=-10)
1696
1697
1698def label_hybrid_pressure_axes(_axes):
1699    l = _axes[0].set_ylabel('Pressure [hPa]')
1700    x, y = l.get_position()
1701    l.set_position((x, y - 1))
1702
1703
1704def plot_input_profile(latitude, IFS_srcfile, dstfile=None, title=None):
1705
1706    from ecradplot import io as eio
1707    from ecradplot import plot as eplt
1708
1709    with sns.plotting_context('talk'):
1710        ncols=4
1711        nrows=5
1712        fig, axes = plt.subplots(figsize=(4.5*ncols,11.5), ncols=ncols, nrows=nrows, gridspec_kw={'hspace':0, 'height_ratios':[1,2,1,1,2]})
1713
1714        _ds = eio.load_inputs(IFS_srcfile).sel(latitude=latitude, method='nearest')
1715
1716        #Temperature
1717        i=0
1718        plot_on_hybrid_pressure_axis(axes[:2,i], _ds.temperature_hl, _ds.pressure_hl, {'lw':5, 'color':sns.color_palette()[3]})
1719
1720        #Specific humidity
1721        i+=1
1722        plot_on_hybrid_pressure_axis(axes[:2,i], _ds.q, _ds.pressure_fl, {'lw':5, 'color':sns.color_palette()[0]})
1723
1724        #Cloud fraction
1725        i+=1
1726        plot_on_hybrid_pressure_axis(axes[:2,i], _ds.cloud_fraction, _ds.pressure_fl, {'lw':5, 'color':'0.5'})
1727
1728        #Water content
1729        i+=1
1730        plot_on_hybrid_pressure_axis(axes[:2,i], 1e6*_ds.q_liquid.where(_ds.q_liquid > 1e-10).fillna(0), _ds.pressure_fl,
1731                                     {'lw':5, 'color':sns.color_palette()[3], 'label':'liquid'})
1732        plot_on_hybrid_pressure_axis(axes[:2,i], 1e6*_ds.q_ice.where(_ds.q_ice > 1e-10).fillna(0), _ds.pressure_fl,
1733                                     {'lw':5, 'color':sns.color_palette()[0], 'label':'ice'}, overwriting=True)
1734
1735        #Ozone
1736        i=0
1737        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.o3_mmr, _ds.pressure_fl, {'label':'O$_3$', 'lw':5, 'color':sns.color_palette()[1]})
1738
1739        #O2 + C02 + CH4 + N20 + CFC
1740        i+=1
1741        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.ch4_vmr, _ds.pressure_fl, {'label':'CH$_4$', 'lw':5, 'color':sns.color_palette()[0]})
1742        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.n2o_vmr, _ds.pressure_fl, {'label':'N$_2$O', 'lw':5, 'color':sns.color_palette()[3]}, overwriting=True)
1743
1744        i+=1
1745        plot_on_hybrid_pressure_axis(axes[-2:,i], 1e6*_ds.co2_vmr, _ds.pressure_fl, {'label':'CO$_2$', 'lw':5, 'color':sns.color_palette()[2]})
1746
1747        #Aerosols
1748        i+=1
1749        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.sea_salt, _ds.pressure_fl, {'label':'sea salt', 'lw':5, 'color':sns.color_palette()[0]})
1750        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.dust, _ds.pressure_fl, {'label':'dust', 'lw':5, 'color':sns.color_palette()[1]}, overwriting=True)
1751        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.organics, _ds.pressure_fl, {'label':'org.', 'lw':5, 'color':sns.color_palette()[2]}, overwriting=True)
1752        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.black_carbon, _ds.pressure_fl, {'label':'carbon', 'lw':5, 'color':'0.5'}, overwriting=True)
1753        plot_on_hybrid_pressure_axis(axes[-2:,i], _ds.sulphate, _ds.pressure_fl, {'label':'sulph.', 'lw':5, 'color':sns.color_palette()[3]}, overwriting=True)
1754
1755        axes[0,0].set_title('Temperature')
1756        axes[1,0].set_xlabel("$T$ [K]")
1757        for ax in axes[:2,0]:
1758            ax.set_xlim(170,320)
1759
1760        axes[0,1].set_title('Specific\nhumidity')
1761        axes[1,1].set_xlabel("$q$ [kg kg$^{-1}$]")
1762        for ax in axes[:2,1]:
1763            ax.set_xlim(1e-6,1e-1)
1764            ax.set_xscale('log')
1765
1766        axes[0,2].set_title('Cloud fraction')
1767        axes[1,2].set_xlabel('$f_c$ [-]')
1768        for ax in axes[:2,2]:
1769            ax.set_xlim(0,1)
1770
1771        axes[0,3].set_title('Cloud\nwater content')
1772        axes[1,3].set_xlabel('$q$ [kg kg$^{-1}$]')
1773
1774        axes[3,0].set_title('Ozone')
1775        axes[4,0].set_xlabel("$q_i$ [kg kg$^{-1}$]")
1776        for ax in axes[3:,0]:
1777            ax.set_xscale('log')
1778            ax.set_xticks([1e-7,1e-6,1e-5])
1779
1780        axes[3,1].set_title('Other gases')
1781        axes[4,1].set_xlabel('$q_i$ [ppm]')
1782        for ax in axes[3:,1]:
1783            ax.set_xscale('log')
1784            ax.set_xticks([1e-7,1e-6,1e-5])
1785
1786        axes[3,2].set_title('Other gases')
1787        axes[4,2].set_xlabel('$q_i$ [ppm]')
1788        for ax in axes[3:2]:
1789            ax.set_xlim(395,415)
1790
1791        axes[3,3].set_title('Aerosols')
1792        for ax in axes[3:,3]:
1793            ax.set_xscale('log')
1794            ax.set_xticks([1e-12,1e-9,1e-6])
1795        axes[4,3].set_xlabel('mixing ratio\n[kg kg$^{-1}$]')
1796
1797        axes[0,3].legend(frameon=False, fontsize='small')
1798        axes[3,1].legend(frameon=False, loc='upper right', fontsize='small')
1799        axes[3,2].legend(frameon=False, loc='upper right', fontsize='small')
1800        axes[3,3].legend(frameon=False, loc='upper left', fontsize='x-small', handlelength=1.01, bbox_to_anchor=(1,1))
1801
1802        for ax in axes[2,:]:
1803            ax.set_axis_off()
1804            ax.get_xaxis().set_visible(False)
1805            ax.get_xaxis().set_visible(False)
1806
1807        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
1808
1809        label_hybrid_pressure_axes(axes[:2,0])
1810        label_hybrid_pressure_axes(axes[-2:,0])
1811
1812        for ax in axes[:, 1:].flatten():
1813            ax.set_ylabel("")
1814            ax.set_yticklabels([])
1815
1816        for ax in axes[0, :].flatten():
1817            ax.set_xlabel("")
1818            ax.set_xticklabels([])
1819
1820        for ax in axes[3, :].flatten():
1821            ax.set_xlabel("")
1822            ax.set_xticklabels([])
1823
1824        add_subfigure_labels(axes[0,:], xloc=0.015, yloc=0.85, zorder=10, flatten_order='C')
1825        add_subfigure_labels(axes[3,:], xloc=0.015, yloc=0.85, zorder=10, flatten_order='C', label_list=['e','f','g','h'])
1826
1827        fig.suptitle(f"{name_string}\nIFS cloud, aerosol and radiation fields\nProfile at {fancy_format_latitude(latitude)}", y=0.95, va='bottom', fontsize='x-large')
1828
1829        if dstfile:
1830            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1831        else:
1832            return fig, axes
1833
1834
1835
1836def plot_output_profile(latitude, IFS_srcfile, ecRAD_srcfiles, linedicts, dstfile=None,
1837                       clearsky_linedict={ 'ls':'--'}):
1838
1839    with sns.plotting_context('talk'):
1840
1841        ncols=4
1842        nrows=5
1843        fig, axes = plt.subplots(figsize=(4.5*ncols,12), nrows=nrows, ncols=ncols, gridspec_kw={'hspace':0, 'height_ratios':[1,2,1.1,1,2]})
1844
1845        for j, ecRAD_srcfile in enumerate(ecRAD_srcfiles):
1846            _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile).sel(latitude=latitude, method='nearest')
1847
1848            i = 0
1849            if j == 0:
1850                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1851                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw_clear, _ds.pressure_hl, {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
1852                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw, _ds.pressure_hl, {**linedicts[j], **{'label':'__nolabel__', 'alpha':0.0}}, overwriting=True)
1853            else:
1854                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1855
1856            i+=1
1857            if j == 0:
1858                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1859                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw_clear, _ds.pressure_hl, {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
1860                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw, _ds.pressure_hl, {**linedicts[j], **{'label':'__nolabel__', 'alpha':0.0}}, overwriting=True)
1861            else:
1862                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1863
1864            i+=1
1865            if j == 0:
1866                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.cloud_radiative_effect_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1867            else:
1868                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.cloud_radiative_effect_lw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1869
1870            i+=1
1871            if j == 0:
1872                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.heating_rate_lw, _ds.pressure_fl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1873                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.heating_rate_lw_clear, _ds.pressure_fl, {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
1874            else:
1875                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.heating_rate_lw, _ds.pressure_fl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1876
1877
1878            i=0
1879            if j == 0:
1880                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1881                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw_clear, _ds.pressure_hl, {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
1882                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw, _ds.pressure_hl, {**linedicts[j], **{'label':'__nolabel__', 'alpha':0.0}}, overwriting=True)
1883            else:
1884                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1885
1886            i+=1
1887            if j == 0:
1888                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1889                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw_clear, _ds.pressure_hl, {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
1890                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw, _ds.pressure_hl, {**linedicts[j], **{'label':'__nolabel__', 'alpha':0.0}}, overwriting=True)
1891            else:
1892                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw,  _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1893
1894            i+=1
1895            if j == 0:
1896                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.cloud_radiative_effect_sw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1897            else:
1898                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.cloud_radiative_effect_sw, _ds.pressure_hl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1899
1900            i+=1
1901            if j == 0:
1902                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.heating_rate_sw, _ds.pressure_fl, {**linedicts[j], **{'label':_ds.attrs['experiment']}})
1903                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.heating_rate_sw_clear, _ds.pressure_fl, {**linedicts[j], **clearsky_linedict, **{'label':_ds.attrs['experiment']}}, overwriting=True)
1904            else:
1905                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.heating_rate_sw,  _ds.pressure_fl, {**linedicts[j], **{'label':_ds.attrs['experiment']}}, overwriting=True)
1906
1907        heating_rate_min = np.floor(np.min(axes[0,-1].get_xlim() + axes[1,-1].get_xlim() + axes[3,-1].get_xlim() + axes[4,-1].get_xlim()))
1908        heating_rate_max = np.ceil(np.max(axes[0,-1].get_xlim() + axes[1,-1].get_xlim() + axes[3,-1].get_xlim() + axes[4,-1].get_xlim()))
1909        heating_rate_abs_lim = np.max([np.abs(heating_rate_min), heating_rate_max])
1910
1911        for ax in axes[:,:2].flatten():
1912            ax.set_xlim(0,None)
1913
1914        axes[0,-1].set_xlim(-1*heating_rate_abs_lim, None)
1915        axes[1,-1].set_xlim(-1*heating_rate_abs_lim, None)
1916        axes[3,-1].set_xlim(None, heating_rate_abs_lim)
1917        axes[4,-1].set_xlim(None, heating_rate_abs_lim)
1918
1919        axes[0,0].set_title('Downwelling\nlongwave flux', color=sns.color_palette()[3])
1920        axes[0,1].set_title('Upwelling\nlongwave flux', color=sns.color_palette()[3])
1921        axes[0,2].set_title('Longwave CRE', color=sns.color_palette()[3])
1922        axes[0,3].set_title('Longwave\nheating rate', color=sns.color_palette()[3])
1923
1924        axes[3,0].set_title('Downwelling\nshortwave flux', color=sns.color_palette()[0])
1925        axes[3,1].set_title('Upwelling\nshortwave flux', color=sns.color_palette()[0])
1926        axes[3,2].set_title('Shortwave CRE', color=sns.color_palette()[0])
1927        axes[3,3].set_title('Shortwave\nheating rate', color=sns.color_palette()[0])
1928
1929        for ax in axes[1,:3]:
1930            ax.set_xlabel('[W m$^{-2}$]')
1931        for ax in axes[1,3:]:
1932            ax.set_xlabel('[K d$^{-1}$]')
1933
1934        for ax in axes[4,:3]:
1935            ax.set_xlabel('[W m$^{-2}$]')
1936        for ax in axes[4,3:]:
1937            ax.set_xlabel('[K d$^{-1}$]')
1938
1939        for ax in axes[2,:]:
1940            ax.set_axis_off()
1941            ax.get_xaxis().set_visible(False)
1942            ax.get_xaxis().set_visible(False)
1943
1944        axes[0,-1].legend(loc='upper left', frameon=False, bbox_to_anchor=(1,1))
1945
1946        label_hybrid_pressure_axes(axes[:2,0])
1947        label_hybrid_pressure_axes(axes[-2:,0])
1948
1949        for ax in axes[:, 1:].flatten():
1950            ax.set_ylabel("")
1951            ax.set_yticklabels([])
1952
1953        for ax in axes[0, :].flatten():
1954            ax.set_xlabel("")
1955            ax.set_xticklabels([])
1956
1957        for ax in axes[3, :].flatten():
1958            ax.set_xlabel("")
1959            ax.set_xticklabels([])
1960
1961        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
1962        fig.suptitle(f'{name_string}\nProfile at {fancy_format_latitude(latitude)}', y=0.95, va='bottom', fontsize='x-large')
1963
1964        add_subfigure_labels(axes[0,:], xloc=0.025, yloc=0.85, zorder=10)
1965        add_subfigure_labels(axes[3,:], xloc=0.025, yloc=0.85, zorder=10, label_list=['e','f','g','h'])
1966
1967        if dstfile:
1968            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
1969        else:
1970            return fig, axes
1971
1972
1973def compare_output_profile(latitude, IFS_srcfile, ecRAD_reference_srcfile, ecRAD_srcfiles, linedicts, dstfile=None,
1974                       clearsky_linedict={'ls':'--'}):
1975
1976    with sns.plotting_context('talk'):
1977
1978        ncols=4
1979        nrows=5
1980        fig, axes = plt.subplots(figsize=(4.5*ncols,12), nrows=nrows, ncols=ncols, gridspec_kw={'hspace':0, 'height_ratios':[1,2,1.2,1,2]})
1981
1982        ds = load_ecRAD(ecRAD_reference_srcfile, IFS_srcfile).sel(latitude=latitude, method='nearest')
1983
1984        for j, ecRAD_srcfile in enumerate(ecRAD_srcfiles):
1985            _ds = load_ecRAD(ecRAD_srcfile, IFS_srcfile).sel(latitude=latitude, method='nearest')
1986
1987            i = 0
1988            plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw - ds.flux_dn_lw, _ds.pressure_hl,
1989                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1990            if j == 0:
1991                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_dn_lw_clear - ds.flux_dn_lw_clear, _ds.pressure_hl,
1992                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}},  overwriting=True)
1993
1994            i+=1
1995            plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw - ds.flux_up_lw, _ds.pressure_hl,
1996                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
1997            if j == 0:
1998                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.flux_up_lw_clear - ds.flux_up_lw_clear, _ds.pressure_hl,
1999                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}},  overwriting=True)
2000
2001            i+=1
2002            plot_on_hybrid_pressure_axis(axes[:2,i], _ds.cloud_radiative_effect_lw - ds.cloud_radiative_effect_lw, _ds.pressure_hl,
2003                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2004
2005            i+=1
2006            plot_on_hybrid_pressure_axis(axes[:2,i], _ds.heating_rate_lw - ds.heating_rate_lw, _ds.pressure_fl,
2007                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2008            if j == 0:
2009                plot_on_hybrid_pressure_axis(axes[:2,i], _ds.heating_rate_lw_clear - ds.heating_rate_lw_clear, _ds.pressure_fl,
2010                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
2011
2012
2013            i=0
2014            plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw - ds.flux_dn_sw, _ds.pressure_hl,
2015                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2016            if j == 0:
2017                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_dn_sw_clear - ds.flux_dn_sw_clear, _ds.pressure_hl,
2018                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}}, overwriting=True)
2019
2020            i+=1
2021            plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw - ds.flux_up_sw, _ds.pressure_hl,
2022                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2023            if j == 0:
2024                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.flux_up_sw_clear - ds.flux_up_sw_clear, _ds.pressure_hl,
2025                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}},  overwriting=True)
2026
2027            i+=1
2028            plot_on_hybrid_pressure_axis(axes[3:,i], _ds.cloud_radiative_effect_sw - ds.cloud_radiative_effect_sw, _ds.pressure_hl,
2029                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2030
2031            i+=1
2032            plot_on_hybrid_pressure_axis(axes[3:,i], _ds.heating_rate_sw - ds.heating_rate_sw, _ds.pressure_fl,
2033                                         {**linedicts[j], **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}"}})
2034            if j == 0:
2035                plot_on_hybrid_pressure_axis(axes[3:,i], _ds.heating_rate_sw_clear - ds.heating_rate_sw_clear, _ds.pressure_fl,
2036                                         {**linedicts[j], **clearsky_linedict, **{'label':f"{_ds.attrs['experiment']} $-$ {ds.attrs['experiment']}\n(clearsky)"}},  overwriting=True)
2037
2038
2039        axes[0,0].set_title('Change to downwelling\nlongwave flux', color=sns.color_palette()[3])
2040        axes[0,1].set_title('Change to upwelling\nlongwave flux', color=sns.color_palette()[3])
2041        axes[0,2].set_title('Change to \nlongwave CRE', color=sns.color_palette()[3])
2042        axes[0,3].set_title('Change to longwave\nheating rate', color=sns.color_palette()[3])
2043
2044        axes[3,0].set_title('Change to downwelling\nshortwave flux', color=sns.color_palette()[0])
2045        axes[3,1].set_title('Change to upwelling\nshortwave flux', color=sns.color_palette()[0])
2046        axes[3,2].set_title('Change to\nshortwave CRE', color=sns.color_palette()[0])
2047        axes[3,3].set_title('Change to shortwave\nheating rate', color=sns.color_palette()[0])
2048
2049        for ax in axes[1,:3]:
2050            ax.set_xlabel('[W m$^{-2}$]')
2051        for ax in axes[1,3:]:
2052            ax.set_xlabel('[K d$^{-1}$]')
2053
2054        for ax in axes[4,:3]:
2055            ax.set_xlabel('[W m$^{-2}$]')
2056        for ax in axes[4,3:]:
2057            ax.set_xlabel('[K d$^{-1}$]')
2058
2059        for ax in axes[2,:]:
2060            ax.set_axis_off()
2061            ax.get_xaxis().set_visible(False)
2062            ax.get_xaxis().set_visible(False)
2063
2064        axes[0,-1].legend(loc='upper left', frameon=False, bbox_to_anchor=(1,1))
2065
2066        label_hybrid_pressure_axes(axes[:2,0])
2067        label_hybrid_pressure_axes(axes[-2:,0])
2068
2069        for ax in axes[:, 1:].flatten():
2070            ax.set_ylabel("")
2071            ax.set_yticklabels([])
2072
2073        for ax in axes[0, :].flatten():
2074            ax.set_xlabel("")
2075            ax.set_xticklabels([])
2076
2077        for ax in axes[3, :].flatten():
2078            ax.set_xlabel("")
2079            ax.set_xticklabels([])
2080
2081        name_string = os.path.splitext(os.path.basename(IFS_srcfile))[0]
2082        fig.suptitle(f'{name_string}\nProfile at {fancy_format_latitude(latitude)}', y=0.95, va='bottom', fontsize='x-large')
2083
2084        add_subfigure_labels(axes[0,:], xloc=0.015, yloc=0.85, zorder=10)
2085        add_subfigure_labels(axes[3,:], xloc=0.015, yloc=0.85, zorder=10, label_list=['e','f','g','h'])
2086
2087        if dstfile:
2088            fig.savefig(dstfile, dpi=90, bbox_inches='tight')
2089        else:
2090            return fig, axes
Note: See TracBrowser for help on using the repository browser.