source: LMDZ6/branches/LMDZ_ECRad/libf/phylmd/ecrad/practical/ecradplot/plot.py @ 4758

Last change on this file since 4758 was 4728, checked in by idelkadi, 13 months ago

Update of ecrad in the LMDZ_ECRad branch of LMDZ:

  • version 1.6.1 of ecrad
  • files are no longer grouped in the same ecrad directory.
  • the structure of ecrad offline is preserved to facilitate updating in LMDZ
  • cfg.bld modified to take into account the new added subdirectories.
  • the interface routines and those added in ecrad are moved to the phylmd directory
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.