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.

8 Comments

  1. 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

    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


  2. 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

    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
  3. 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.


  4. 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.


  5. 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.

  6. This should work

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