Toolbox subplots

Is there any way to create subplots? (like in matplotlib). For example, I would like to have a 2x2 figure and use geomap in each panel.

Hi Raul,

Here is an example of code to make a figure with subplots

import cdstoolbox as ct

@ct.application(title=‘Plot Map’)
@ct.output.figure()
def plot_map():

data = ct.catalogue.retrieve(
    'reanalysis-era5-single-levels',
    {
        'variable': '2m_temperature',
        'product_type': 'reanalysis',
        'year': '2010',
        'month': '08',
        'day': '15',
        'time': '12:00',
    }
)

# Define the desired projection (available projections here https://scitools.org.uk/cartopy/docs/latest/crs/projections.html)
projection = ct.cdsplot.crs.Robinson()

# Define a figure with 2 columns and 2 rows
fig = ct.cdsplot.figure(ncols=2, nrows=2, subplot_kw={'projection': projection})

# Plot four subfigures
ct.cdsplot.geomap(data, fig=fig, figrow=1, figcol=1, title='Plot 1')
ct.cdsplot.geomap(data, fig=fig, title='Plot 2')
ct.cdsplot.geomap(data, fig=fig, title='Plot 3')
ct.cdsplot.geomap(data, fig=fig, title='Plot 4')

return fig</pre>

Note that you can can specify which figure goes in which subplot (figrow, figcol) but you there is also a default order.

You also need to define a projection. The available projections are documented here: https://scitools.org.uk/cartopy/docs/latest/crs/projections.html


Hi Vivien,

Thanks for your answer. I'm trying to follow your code with data from the pressure level dataset:

import cdstoolbox as ct

@ct.application(title=‘Winds’)
@ct.output.figure()
def application():

uwind_var = ['u_component_of_wind']
vwind_var = ['v_component_of_wind']

pressure_levels = ['500','700','900','1000']

year = '2020'
month = '1'
day = '18'
time = '00:00'

data_uwind_500 = ct.catalogue.retrieve(
    'reanalysis-era5-pressure-levels',
    {
        'variable': uwind_var,
        'product_type': 'reanalysis',
        'year': year,
        'month': month,
        'day': day,
        'time': time,
        'pressure_level':pressure_levels[0],
        'grid': ['0.25', '0.25'],
        'area': ['-10', '-80', '-30', '-66']
    }
)

data_vwind_500 = ct.catalogue.retrieve(
    'reanalysis-era5-pressure-levels',
    {
        'variable': vwind_var,
        'product_type': 'reanalysis',
        'year': year,
        'month': month,
        'day': day,
        'time': time,
        'pressure_level':pressure_levels[0],
        'grid': ['0.25', '0.25'],
        'area': ['-10', '-80', '-30', '-66']
    }
)
    
proj = ct.cdsplot.crs.PlateCarree()

# Define a figure with 2 columns and 2 rows
fig = ct.cdsplot.figure(ncols=2, nrows=1, subplot_kw={'projection': proj})
 
# Plot four subfigures
ct.cdsplot.geomap(data_uwind_500, fig=fig, figrow=1, figcol=1, title='Uwind 500')
ct.cdsplot.geomap(data_vwind_500, fig=fig, figrow=1, figcol=2, title='Vwind 500')

return fig</pre>

However, I'm getting the following error:


Traceback (most recent call last):
  File "/src/jsonrequest/jsonrequest/requests.py", line 71, in jsonrequestcall
    resp = coding.encode(req.callable(*req.args, **req.kwargs), register=encoders, **context)
  File "/src/cdsworkflows-image/cdsworkflows/submit_workflow.py", line 20, in submit_workflow
    return workflow_bare_func(**kwargs)
  File "/workflows/internal/code/1672c56811468243c431d51a3ea398672ca1631307e86664d8ac049b/workflows.py", line 79, in application
    ct.cdsplot.geomap(data_uwind_500, fig=fig, figrow=1, figcol=1, title='Uwind 500')
  File "/src/cdsworkflows-image/cdsworkflows/local.py", line 27, in wrapped
    return func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 237, in conversion_decorator
    return func(source, *args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 257, in select_dimensions
    return func(source, *args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 267, in xlabel_decorator
    fig = func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 288, in ylabel_decorator
    fig = func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 403, in ticks_decorator
    fig = func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 351, in legend_decorator
    fig = func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 366, in title_decorator
    fig = func(*args, **kwargs)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 505, in _subplot_decorator
    f.ax = _select_subfigure(f, row, col)
  File "/src/cdsplot/cdsplot/cdsmatplotlib.py", line 478, in _select_subfigure
    ax = fig.ax[row, col]
IndexError: too many indices for array

It seem to work if you do not specify figrow and figcol

    # Plot four subfigures
    ct.cdsplot.geomap(data_uwind_500, fig=fig, title='Uwind 500')
    ct.cdsplot.geomap(data_vwind_500, fig=fig, title='Vwind 500')

I will try to understand why it fails with figrow and figcol, for the time being I hope you can do without.


It works! Thanks!

Hi Raul,

For your interest, in case you have only a single row or a single column you should only specify figcol or figrow respectively.

So in your initial code the following should work too:

    # Plot four subfigures
    ct.cdsplot.geomap(data_uwind_500, fig=fig, figcol=0, title='Uwind 500')
    ct.cdsplot.geomap(data_vwind_500, fig=fig, figcol=1, title='Vwind 500')

Note that figcol and figrow are 0 based.

If both nrows and ncols are larger or equal to 2 you can specify both figcol and figrow.


Thanks Vivien.

What would be the keyword for controlling the figure size? I tried subplot_kw={'projection': proj,'figsize':[8,6]} in cdsplot.figure but is not working.

This should work

fig = ct.cdsplot.figure(ncols=2, nrows=1, subplot_kw={'projection': proj}, figsize=[8, 6])

Thanks!