def load_cubes(filenames, obs_filename, metadata):
    """
    Organize data provided by recipe.

    Parameters
    ----------
    filenames: dict
        input files listed in the recipe
    obs_filename: str
        the preprocessed observations file.
    metadata: dict
        the input files dictionary
    """
    # check if observations are provided
    if obs_filename:
        obsname = metadata[obs_filename]['dataset']
        filenames.remove(obs_filename)
        filenames.insert(0, obs_filename)
    else:
        obsname = ''
        logger.info('Observations not provided. Plot each model data.')

    # Load the data for each layer as a separate cube
    layers = {}
    cubes = {}
    for thename in filenames:
        logger.debug('loading: \t%s', thename)
        cube = iris.load_cube(thename)
        cube = diagtools.bgc_units(cube, metadata[thename]['short_name'])
        model_name = metadata[thename]['dataset']
        cubes[model_name] = diagtools.make_cube_layer_dict(cube)
        for layer in cubes[model_name]:
            layers[layer] = True

    logger.debug('layers: %s', layers)
    logger.debug('cubes: %s', ', '.join(cubes.keys()))

    return cubes, layers, obsname
def multi_model_contours(
    cfg,
    metadatas,
):
    """
    Make a multi model comparison plot showing several transect contour plots.

    This tool loads several cubes from the files, checks that the units are
    sensible BGC units, checks for layers, adjusts the titles accordingly,
    determines the ultimate file name and format, then saves the image.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadatas: dict
        The metadatas dictionairy for a specific model.

    """
    ####
    # Load the data for each layer as a separate cube
    model_cubes = {}
    regions = {}
    thresholds = {}
    set_y_logscale = True

    for filename in sorted(metadatas):
        cube = iris.load_cube(filename)
        cube = diagtools.bgc_units(cube, metadatas[filename]['short_name'])
        cube = make_depth_safe(cube)
        cubes = make_cube_region_dict(cube)
        model_cubes[filename] = cubes
        for region in model_cubes[filename]:
            regions[region] = True

        # Determine y log scale.
        set_y_logscale = determine_set_y_logscale(cfg, metadatas[filename])

        # Load threshold/thresholds.
        tmp_thresholds = diagtools.load_thresholds(cfg, metadatas[filename])
        for threshold in tmp_thresholds:
            thresholds[threshold] = True

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Make a plot for each layer and each threshold
    for region, threshold in itertools.product(regions, thresholds):
        logger.info('plotting threshold: \t%s', threshold)
        title = ''
        plot_details = {}

        # Plot each file in the group
        for index, filename in enumerate(sorted(metadatas)):
            color = diagtools.get_colour_from_cmap(index, len(metadatas))
            linewidth = 1.
            linestyle = '-'
            # Determine line style for MultiModel statistics:
            if 'MultiModel' in metadatas[filename]['dataset']:
                linewidth = 2.
                linestyle = ':'
            # Determine line style for Observations
            if metadatas[filename]['project'] in diagtools.get_obs_projects():
                color = 'black'
                linewidth = 1.7
                linestyle = '-'

            qplt.contour(model_cubes[filename][region], [
                threshold,
            ],
                         colors=[
                             color,
                         ],
                         linewidths=linewidth,
                         linestyles=linestyle,
                         rasterized=True)

            plot_details[filename] = {
                'c': color,
                'ls': linestyle,
                'lw': linewidth,
                'label': metadatas[filename]['dataset']
            }

            if set_y_logscale:
                plt.axes().set_yscale('log')

            title = metadatas[filename]['long_name']
            units = str(model_cubes[filename][region].units)

            add_sea_floor(model_cubes[filename][region])

        # Add title, threshold, legend to plots
        title = ' '.join([
            title,
            str(threshold), units,
            determine_transect_str(model_cubes[filename][region], region)
        ])
        titlify(title)
        plt.legend(loc='best')

        # Saving files:
        if cfg['write_plots']:
            path = diagtools.get_image_path(
                cfg,
                metadatas[filename],
                prefix='MultipleModels',
                suffix='_'.join([
                    'contour_tramsect', region,
                    str(threshold) + image_extention
                ]),
                metadata_id_list=[
                    'field', 'short_name', 'preprocessor', 'diagnostic',
                    'start_year', 'end_year'
                ],
            )

        # Resize and add legend outside thew axes.
        plt.gcf().set_size_inches(9., 6.)
        diagtools.add_legend_outside_right(plot_details,
                                           plt.gca(),
                                           column_width=0.15)

        logger.info('Saving plots to %s', path)
        plt.savefig(path)
        plt.close()
def make_transect_contours(
    cfg,
    metadata,
    filename,
):
    """
    Make a contour plot of the transect for an indivudual model.

    This tool loads the cube from the file, checks that the units are
    sensible BGC units, checks for layers, adjusts the titles accordingly,
    determines the ultimate file name and format, then saves the image.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    cube = diagtools.bgc_units(cube, metadata['short_name'])
    cube = make_depth_safe(cube)

    # Load threshold/thresholds.
    plot_details = {}
    colours = []
    thresholds = diagtools.load_thresholds(cfg, metadata)
    linewidths = [1 for thres in thresholds]
    linestyles = ['-' for thres in thresholds]

    cubes = make_cube_region_dict(cube)
    for region, cube in cubes.items():
        for itr, thres in enumerate(thresholds):
            colour = diagtools.get_colour_from_cmap(itr, len(thresholds))
            label = str(thres) + ' ' + str(cube.units)
            colours.append(colour)
            plot_details[thres] = {
                'c': colour,
                'lw': 1,
                'ls': '-',
                'label': label
            }

        qplt.contour(cube,
                     thresholds,
                     colors=colours,
                     linewidths=linewidths,
                     linestyles=linestyles,
                     rasterized=True)

        # Determine y log scale.
        if determine_set_y_logscale(cfg, metadata):
            plt.axes().set_yscale('log')

        add_sea_floor(cube)

        # Add legend
        diagtools.add_legend_outside_right(plot_details,
                                           plt.gca(),
                                           column_width=0.08,
                                           loc='below')

        # Add title to plot
        title = ' '.join([
            metadata['dataset'], metadata['long_name'],
            determine_transect_str(cube, region)
        ])
        titlify(title)

        # Load image format extention
        image_extention = diagtools.get_image_format(cfg)

        # Determine image filename:
        if metadata['dataset'].find('MultiModel') > -1:
            path = diagtools.folder(
                cfg['plot_dir']) + os.path.basename(filename)
            path.replace('.nc', region + '_transect_contour' + image_extention)
        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix=region + 'transect_contour' + image_extention,
            )

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
def make_transects_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make a simple plot of the transect for an indivudual model.

    This tool loads the cube from the file, checks that the units are
    sensible BGC units, checks for layers, adjusts the titles accordingly,
    determines the ultimate file name and format, then saves the image.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    cube = diagtools.bgc_units(cube, metadata['short_name'])

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    cube = make_depth_safe(cube)
    cubes = make_cube_region_dict(cube)

    # Determine y log scale.
    set_y_logscale = determine_set_y_logscale(cfg, metadata)

    for region, cube in cubes.items():
        # Make a dict of cubes for each layer.
        qplt.contourf(cube, 15, linewidth=0, rasterized=True)

        if set_y_logscale:
            plt.axes().set_yscale('log')

        if region:
            region_title = region
        else:
            region_title = determine_transect_str(cube, region)

        # Add title to plot
        title = ' '.join(
            [metadata['dataset'], metadata['long_name'], region_title])
        titlify(title)

        # Load image format extention
        image_extention = diagtools.get_image_format(cfg)

        # Determine image filename:
        if multi_model:
            path = diagtools.folder(
                cfg['plot_dir']) + os.path.basename(filename).replace(
                    '.nc', region + '_transect' + image_extention)
        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix=region + 'transect' + image_extention,
            )

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
def make_map_extent_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make an extent map plot showing several times for an individual model.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    iris.coord_categorisation.add_year(cube, 'time')
    cube = diagtools.bgc_units(cube, metadata['short_name'])
    cube = agregate_by_season(cube)

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Load threshold, pole and season
    threshold = float(cfg['threshold'])
    pole = get_pole(cube)
    season = get_season(cube)

    # Start making figure
    for layer_index, (layer, cube_layer) in enumerate(cubes.items()):

        fig = plt.figure()
        fig.set_size_inches(7, 7)

        if pole == 'North':  # North Hemisphere
            projection = cartopy.crs.NorthPolarStereo()
            ax1 = plt.subplot(111, projection=projection)
            ax1.set_extent([-180, 180, 50, 90], cartopy.crs.PlateCarree())

        if pole == 'South':  # South Hemisphere
            projection = cartopy.crs.SouthPolarStereo()
            ax1 = plt.subplot(111, projection=projection)
            ax1.set_extent([-180, 180, -90, -50], cartopy.crs.PlateCarree())
        try:
            ax1.add_feature(cartopy.feature.LAND,
                            zorder=10,
                            facecolor=[0.8, 0.8, 0.8])
        except ConnectionRefusedError:
            logger.error('Cartopy was unable add coastlines due to  a '
                         'connection error.')

        ax1.gridlines(linewidth=0.5,
                      color='black',
                      zorder=20,
                      alpha=0.5,
                      linestyle='--')

        try:
            plt.gca().coastlines()
        except AttributeError:
            logger.warning('make_polar_map: Not able to add coastlines')

        times = np.array(cube.coord('time').points.astype(float))
        plot_desc = {}
        for time_itr, time in enumerate(times):
            cube = cube_layer[time_itr]
            line_width = 1
            color = plt.cm.jet(float(time_itr) / float(len(times)))
            label = get_year(cube)
            plot_desc[time] = {
                'label': label,
                'c': [
                    color,
                ],
                'lw': [
                    line_width,
                ],
                'ls': [
                    '-',
                ]
            }

            layer = str(layer)
            qplt.contour(cube, [
                threshold,
            ],
                         colors=plot_desc[time]['c'],
                         linewidths=plot_desc[time]['lw'],
                         linestyles=plot_desc[time]['ls'],
                         rasterized=True)

        # Add legend
        legend_size = len(plot_desc) + 1
        ncols = int(legend_size / 25) + 1
        ax1.set_position([
            ax1.get_position().x0,
            ax1.get_position().y0,
            ax1.get_position().width * (1. - 0.1 * ncols),
            ax1.get_position().height
        ])

        fig.set_size_inches(7 + ncols * 1.2, 7)

        # Construct dummy plots.
        for i in sorted(plot_desc):
            plt.plot(
                [],
                [],
                c=plot_desc[i]['c'][0],
                lw=plot_desc[i]['lw'][0],
                ls=plot_desc[i]['ls'][0],
                label=plot_desc[i]['label'],
            )

        legd = ax1.legend(loc='center left',
                          ncol=ncols,
                          prop={'size': 10},
                          bbox_to_anchor=(1., 0.5))
        legd.draw_frame(False)
        legd.get_frame().set_alpha(0.)

        # Add title to plot
        title = ' '.join([
            metadata['dataset'],
        ])
        if layer:
            title = ' '.join([
                title, '(', layer,
                str(cube_layer.coords('depth')[0].units), ')'
            ])
        plt.title(title)

        # Determine image filename:
        suffix = '_'.join(['ortho_map', pole, season, str(layer_index)])
        suffix = suffix.replace(' ', '') + image_extention
        if multi_model:
            path = diagtools.folder(cfg['plot_dir'])
            path = path + os.path.basename(filename)
            path = path.replace('.nc', suffix)
        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix=suffix,
            )

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)
        plt.close()
def make_map_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make a simple map plot for an individual model.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    iris.coord_categorisation.add_year(cube, 'time')
    cube = diagtools.bgc_units(cube, metadata['short_name'])
    cube = agregate_by_season(cube)

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention and threshold.
    image_extention = diagtools.get_image_format(cfg)
    threshold = float(cfg['threshold'])

    # Making plots for each layer
    plot_types = ['Fractional cover', 'Ice Extent']
    plot_times = [0, -1]
    for plot_type, plot_time in product(plot_types, plot_times):
        for layer_index, (layer, cube_layer) in enumerate(cubes.items()):
            layer = str(layer)

            if plot_type == 'Fractional cover':
                cmap = 'Blues_r'
            if plot_type == 'Ice Extent':
                cmap = create_ice_cmap(threshold)

            cube = cube_layer[plot_time]

            # use cube to determine which hemisphere, season and year.
            pole = get_pole(cube)
            time_str = get_time_string(cube)

            # Make the polar map.
            make_polar_map(cube, pole=pole, cmap=cmap)

            # Add title to plot
            title = ' '.join([metadata['dataset'], plot_type, time_str])
            if layer:
                title = ' '.join([
                    title, '(', layer,
                    str(cube_layer.coords('depth')[0].units), ')'
                ])
            plt.title(title)

            # Determine image filename:
            suffix = '_'.join(
                ['ortho_map', plot_type, time_str,
                 str(layer_index)])
            suffix = suffix.replace(' ', '') + image_extention
            if multi_model:
                path = diagtools.folder(cfg['plot_dir'])
                path = path + os.path.basename(filename)
                path = path.replace('.nc', suffix)
            else:
                path = diagtools.get_image_path(
                    cfg,
                    metadata,
                    suffix=suffix,
                )

            # Saving files:
            if cfg['write_plots']:
                logger.info('Saving plots to %s', path)
                plt.savefig(path)

            plt.close()
def make_ts_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make a ice extent and ice area time series plot for an individual model.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    iris.coord_categorisation.add_year(cube, 'time')
    cube = diagtools.bgc_units(cube, metadata['short_name'])
    cube = agregate_by_season(cube)

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # # Load threshold, pole, season.
    threshold = float(cfg['threshold'])
    pole = get_pole(cube)
    season = get_season(cube)

    # Making plots for each layer
    for plot_type in ['Ice Extent', 'Ice Area']:
        for layer_index, (layer, cube_layer) in enumerate(cubes.items()):
            layer = str(layer)

            times, data = calculate_area_time_series(cube_layer, plot_type,
                                                     threshold)

            plt.plot(times, data)

            # Add title to plot
            title = ' '.join(
                [metadata['dataset'], pole, 'hemisphere', season, plot_type])
            if layer:
                title = ' '.join([
                    title, '(', layer,
                    str(cube_layer.coords('depth')[0].units), ')'
                ])
            plt.title(title)

            # y axis label:
            plt.ylabel(' '.join([plot_type, 'm^2']))

            # Determine image filename:
            suffix = '_'.join(['ts', metadata['preprocessor'], season, pole,
                               plot_type, str(layer_index)])\
                     + image_extention
            suffix = suffix.replace(' ', '')
            if multi_model:
                path = diagtools.folder(
                    cfg['plot_dir']) + os.path.basename(filename)
                path = path.replace('.nc', suffix)
            else:
                path = diagtools.get_image_path(
                    cfg,
                    metadata,
                    suffix=suffix,
                )

            # Saving files:
            if cfg['write_plots']:
                logger.info('Saving plots to %s', path)
                plt.savefig(path)

            plt.close()
def multi_model_time_series(
    cfg,
    metadata,
):
    """
    Make a time series plot showing several preprocesssed datasets.

    This tool loads several cubes from the files, checks that the units are
    sensible BGC units, checks for layers, adjusts the titles accordingly,
    determines the ultimate file name and format, then saves the image.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.

    """

    ####
    # Load the data for each layer as a separate cube
    model_cubes = {}
    layers = {}
    for filename in sorted(metadata):
        if metadata[filename]['frequency'] != 'fx':
            cube = iris.load_cube(filename)
            cube = diagtools.bgc_units(cube, metadata[filename]['short_name'])

            cubes = diagtools.make_cube_layer_dict(cube)
            model_cubes[filename] = cubes
            for layer in cubes:
                layers[layer] = True

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Make a plot for each layer
    for layer in layers:

        title = ''
        z_units = ''
        plot_details = {}
        cmap = plt.cm.get_cmap('viridis')

        # Plot each file in the group
        for index, filename in enumerate(sorted(metadata)):
            if len(metadata) > 1:
                color = cmap(index / (len(metadata) - 1.))
            else:
                color = 'blue'

            # Take a moving average, if needed.
            if 'moving_average' in cfg:
                cube = moving_average(model_cubes[filename][layer],
                                      cfg['moving_average'])
            else:
                cube = model_cubes[filename][layer]

            if 'MultiModel' in metadata[filename]['dataset']:
                timeplot(
                    cube,
                    c=color,
                    # label=metadata[filename]['dataset'],
                    ls=':',
                    lw=2.,
                )
                plot_details[filename] = {
                    'c': color,
                    'ls': ':',
                    'lw': 2.,
                    'label': metadata[filename]['dataset']
                }
            else:
                timeplot(
                    cube,
                    c=color,
                    # label=metadata[filename]['dataset'])
                    ls='-',
                    lw=2.,
                )
                plot_details[filename] = {
                    'c': color,
                    'ls': '-',
                    'lw': 2.,
                    'label': metadata[filename]['dataset']
                }

            title = metadata[filename]['long_name']
            if layer != '':
                if model_cubes[filename][layer].coords('depth'):
                    z_units = model_cubes[filename][layer].coord('depth').units
                else:
                    z_units = ''
        # Add title, legend to plots
        if layer:
            title = ' '.join([title, '(', str(layer), str(z_units), ')'])
        plt.title(title)
        plt.legend(loc='best')
        plt.ylabel(str(model_cubes[filename][layer].units))

        # Saving files:
        if cfg['write_plots']:
            path = diagtools.get_image_path(
                cfg,
                metadata[filename],
                prefix='MultipleModels_',
                suffix='_'.join(['timeseries',
                                 str(layer) + image_extention]),
                metadata_id_list=[
                    'field', 'short_name', 'preprocessor', 'diagnostic',
                    'start_year', 'end_year'
                ],
            )

        # Resize and add legend outside thew axes.
        plt.gcf().set_size_inches(9., 6.)
        diagtools.add_legend_outside_right(plot_details,
                                           plt.gca(),
                                           column_width=0.15)

        logger.info('Saving plots to %s', path)
        plt.savefig(path)
        plt.close()
def make_time_series_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make a simple time series plot for an indivudual model 1D cube.

    This tool loads the cube from the file, checks that the units are
    sensible BGC units, checks for layers, adjusts the titles accordingly,
    determines the ultimate file name and format, then saves the image.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        The metadata dictionairy for a specific model.
    filename: str
        The preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    cube = diagtools.bgc_units(cube, metadata['short_name'])

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Making plots for each layer
    for layer_index, (layer, cube_layer) in enumerate(cubes.items()):
        layer = str(layer)
        if 'moving_average' in cfg:
            cube_layer = moving_average(cube_layer, cfg['moving_average'])

        if multi_model:
            timeplot(cube_layer, label=metadata['dataset'], ls=':')
        else:
            timeplot(cube_layer, label=metadata['dataset'])

        # Add title, legend to plots
        title = ' '.join([metadata['dataset'], metadata['long_name']])
        if layer != '':
            if cube_layer.coords('depth'):
                z_units = cube_layer.coord('depth').units
            else:
                z_units = ''
            title = ' '.join([title, '(', layer, str(z_units), ')'])
        plt.title(title)
        plt.legend(loc='best')
        plt.ylabel(str(cube_layer.units))

        # Determine image filename:
        if multi_model:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                prefix='MultiModel',
                suffix='_'.join(['timeseries',
                                 str(layer) + image_extention]),
                metadata_id_list=[
                    'field', 'short_name', 'preprocessor', 'diagnostic',
                    'start_year', 'end_year'
                ],
            )

        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix='timeseries_' + str(layer_index) + image_extention,
            )

        # Saving files:
        if cfg['write_plots']:

            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
def make_map_plots(
    cfg,
    metadata,
    filename,
):
    """
    Make a simple map plot for an individual model.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionary, passed by ESMValTool.
    metadata: dict
        the metadata dictionary
    filename: str
        the preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    cube = diagtools.bgc_units(cube, metadata['short_name'])

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Making plots for each layer
    for layer_index, (layer, cube_layer) in enumerate(cubes.items()):
        layer = str(layer)

        qplt.contourf(cube_layer, 25, linewidth=0, rasterized=True)

        try:
            plt.gca().coastlines()
        except AttributeError:
            logger.warning('Not able to add coastlines')

        # Add title to plot
        title = ' '.join([metadata['dataset'], metadata['long_name']])
        if layer:
            title = ' '.join([
                title, '(', layer,
                str(cube_layer.coords('depth')[0].units), ')'
            ])
        plt.title(title)

        # Determine image filename:
        if multi_model:
            path = diagtools.folder(
                cfg['plot_dir']) + os.path.basename(filename).replace(
                    '.nc', '_map_' + str(layer_index) + image_extention)
        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix='map_' + str(layer_index) + image_extention,
            )

        # Saving files:
        if cfg['write_plots']:

            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
def multi_model_contours(
    cfg,
    metadata,
):
    """
    Make a contour map showing several models.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionary, passed by ESMValTool.
    metadata: dict
        the metadata dictionary.

    """
    ####
    # Load the data for each layer as a separate cube
    model_cubes = {}
    layers = {}
    for filename in sorted(metadata):
        cube = iris.load_cube(filename)
        cube = diagtools.bgc_units(cube, metadata[filename]['short_name'])

        cubes = diagtools.make_cube_layer_dict(cube)
        model_cubes[filename] = cubes
        for layer in cubes:
            layers[layer] = True

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Load threshold/thresholds.
    thresholds = diagtools.load_thresholds(cfg, metadata)

    # Make a plot for each layer and each threshold
    for layer, threshold in itertools.product(layers, thresholds):

        title = ''
        z_units = ''
        plot_details = {}
        cmap = plt.cm.get_cmap('jet')
        land_drawn = False

        # Plot each file in the group
        for index, filename in enumerate(sorted(metadata)):

            if len(metadata) > 1:
                color = cmap(index / (len(metadata) - 1.))
            else:
                color = 'blue'
            linewidth = 1.
            linestyle = '-'

            # Determine line style for Observations
            if metadata[filename]['project'] in diagtools.get_obs_projects():
                color = 'black'
                linewidth = 1.7
                linestyle = '-'

            # Determine line style for MultiModel statistics:
            if 'MultiModel' in metadata[filename]['dataset']:
                color = 'black'
                linestyle = ':'
                linewidth = 1.4

            cube = model_cubes[filename][layer]
            qplt.contour(cube, [
                threshold,
            ],
                         colors=[
                             color,
                         ],
                         linewidths=linewidth,
                         linestyles=linestyle,
                         rasterized=True)
            plot_details[filename] = {
                'c': color,
                'ls': linestyle,
                'lw': linewidth,
                'label': metadata[filename]['dataset']
            }

            if not land_drawn:
                try:
                    plt.gca().coastlines()
                except AttributeError:
                    logger.warning('Not able to add coastlines')
                plt.gca().add_feature(cartopy.feature.LAND,
                                      zorder=10,
                                      facecolor=[0.8, 0.8, 0.8])
                land_drawn = True

            title = metadata[filename]['long_name']
            if layer != '':
                z_units = model_cubes[filename][layer].coords('depth')[0].units
            units = str(model_cubes[filename][layer].units)

        # Add title, threshold, legend to plots
        title = ' '.join([title, str(threshold), units])
        if layer:
            title = ' '.join([title, '(', str(layer), str(z_units), ')'])
        plt.title(title)
        plt.legend(loc='best')

        # Saving files:
        if cfg['write_plots']:
            path = diagtools.get_image_path(
                cfg,
                metadata[filename],
                prefix='MultipleModels_',
                suffix='_'.join([
                    '_contour_map_',
                    str(threshold),
                    str(layer) + image_extention
                ]),
                metadata_id_list=[
                    'field', 'short_name', 'preprocessor', 'diagnostic',
                    'start_year', 'end_year'
                ],
            )

        # Resize and add legend outside thew axes.
        plt.gcf().set_size_inches(9., 6.)
        diagtools.add_legend_outside_right(plot_details,
                                           plt.gca(),
                                           column_width=0.15)

        logger.info('Saving plots to %s', path)
        plt.savefig(path)
        plt.close()
def make_map_contour(
    cfg,
    metadata,
    filename,
):
    """
    Make a simple contour map plot for an individual model.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionary, passed by ESMValTool.
    metadata: dict
        the metadata dictionary
    filename: str
        the preprocessed model file.

    """
    # Load cube and set up units
    cube = iris.load_cube(filename)
    cube = diagtools.bgc_units(cube, metadata['short_name'])

    # Is this data is a multi-model dataset?
    multi_model = metadata['dataset'].find('MultiModel') > -1

    # Make a dict of cubes for each layer.
    cubes = diagtools.make_cube_layer_dict(cube)

    # Load image format extention and threshold.thresholds.
    image_extention = diagtools.get_image_format(cfg)

    # Load threshold/thresholds.
    plot_details = {}
    colours = []
    thresholds = diagtools.load_thresholds(cfg, metadata)

    for itr, thres in enumerate(thresholds):
        if len(thresholds) > 1:
            colour = plt.cm.jet(float(itr) / float(len(thresholds) - 1.))
        else:
            colour = plt.cm.jet(0)
        label = str(thres) + ' ' + str(cube.units)
        colours.append(colour)
        plot_details[thres] = {'c': colour, 'lw': 1, 'ls': '-', 'label': label}

    linewidths = [1 for thres in thresholds]
    linestyles = ['-' for thres in thresholds]
    # Making plots for each layer
    for layer_index, (layer, cube_layer) in enumerate(cubes.items()):
        layer = str(layer)
        qplt.contour(cube_layer,
                     thresholds,
                     colors=colours,
                     linewidths=linewidths,
                     linestyles=linestyles,
                     rasterized=True)

        try:
            plt.gca().coastlines()
        except AttributeError:
            logger.warning('Not able to add coastlines')
        try:
            plt.gca().add_feature(cartopy.feature.LAND,
                                  zorder=10,
                                  facecolor=[0.8, 0.8, 0.8])
        except AttributeError:
            logger.warning('Not able to add coastlines')
        # Add legend
        diagtools.add_legend_outside_right(plot_details,
                                           plt.gca(),
                                           column_width=0.02,
                                           loc='below')

        # Add title to plot
        title = ' '.join([metadata['dataset'], metadata['long_name']])
        depth_units = str(cube_layer.coords('depth')[0].units)
        if layer:
            title = '{} ({} {})'.format(title, layer, depth_units)
        plt.title(title)

        # Determine image filename:
        if multi_model:
            path = os.path.join(diagtools.folder(cfg['plot_dir']),
                                os.path.basename(filename))
            path = path.replace('.nc', '_contour_map_' + str(layer_index))
            path = path + image_extention
        else:
            path = diagtools.get_image_path(
                cfg,
                metadata,
                suffix='_contour_map_' + str(layer_index) + image_extention,
            )

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
Exemple #13
0
def make_scatter(cfg, metadata, model_filename, obs_filename):
    """
    Makes Scatter plots of model vs observational data.

    Make scatter plot showing the matched model and observational data with the
    model data as the x-axis coordinate and the observational data as the
    y-axis coordinate. A linear regression is also applied to the matched
    data and the result of the fit is shown on the figure.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        the input files dictionairy
    model_filename: str
        the preprocessed model file.
    obs_filename: str
        the preprocessed observations file.
    """

    filenames = {'model': model_filename, 'obs': obs_filename}
    logger.debug('make_model_vs_obs_plots: \t%s', filenames)
    # ####
    # Load the data for each layer as a separate cube
    layers = {}
    cubes = {}
    for model_type, input_file in filenames.items():
        logger.debug('loading: \t%s, \t%s', model_type, input_file)
        cube = iris.load_cube(input_file)
        cube = diagtools.bgc_units(cube, metadata[input_file]['short_name'])
        cubes[model_type] = diagtools.make_cube_layer_dict(cube)
        for layer in cubes[model_type]:
            layers[layer] = True

    logger.debug('layers: %s', layers)
    logger.debug('cubes: %s', ', '.join(cubes))

    # ####
    # load names:
    model = metadata[filenames['model']]['dataset']
    obs = metadata[filenames['obs']]['dataset']

    long_name = cubes['model'][list(layers.keys())[0]].long_name

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Make a plot for each layer
    for layer in layers:

        fig = plt.figure()
        fig.set_size_inches(7, 6)

        # Create the cubes
        model_data = np.ma.array(cubes['model'][layer].data)
        obs_data = np.ma.array(cubes['obs'][layer].data)

        mask = model_data.mask + obs_data.mask
        model_data = np.ma.masked_where(mask, model_data).compressed()
        obs_data = np.ma.masked_where(mask, obs_data).compressed()

        colours = 'gist_yarg'
        zrange = diagtools.get_array_range([model_data, obs_data])
        plotrange = [zrange[0], zrange[1], zrange[0], zrange[1]]

        x_scale = 'log'
        if np.min(zrange) * np.max(zrange) < -1:
            x_scale = 'linear'
        if np.min(zrange) < 0.:
            logger.info('Skip scatter for %s. Min is < 0', long_name)
            return

        pyplot.hexbin(
            model_data,
            obs_data,
            xscale=x_scale,
            yscale=x_scale,
            bins='log',
            # extent=np.log10(plotrange),
            gridsize=50,
            cmap=pyplot.get_cmap(colours),
            mincnt=0)
        cbar = pyplot.colorbar()
        cbar.set_label('log10(N)')

        pyplot.gca().set_aspect("equal")
        pyplot.axis(plotrange)

        add_linear_regression(pyplot.gca(),
                              model_data,
                              obs_data,
                              showtext=True,
                              add_diagonal=True,
                              extent=plotrange)

        pyplot.title(long_name)
        pyplot.xlabel(model)
        pyplot.ylabel(obs)

        # Determine image filename:
        fn_list = [
            'model_vs_obs', long_name, model, obs,
            str(layer), 'scatter'
        ]
        path = diagtools.folder(cfg['plot_dir']) + '_'.join(fn_list)
        path = path.replace(' ', '') + image_extention

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()
Exemple #14
0
def make_model_vs_obs_plots(cfg, metadata, model_filename, obs_filename):
    """
    Make a figure showing four maps and the other shows a scatter plot.

    The four pane image is a latitude vs longitude figures showing:

    * Top left: model
    * Top right: observations
    * Bottom left: model minus observations
    * Bottom right: model over observations

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    metadata: dict
        the input files dictionairy
    model_filename: str
        the preprocessed model file.
    obs_filename: str
        the preprocessed observations file.

    """
    filenames = {'model': model_filename, 'obs': obs_filename}
    logger.debug('make_model_vs_obs_plots filenames: %s', filenames)
    # ####
    # Load the data for each layer as a separate cube
    input_file = None
    layers = {}
    cubes = {}
    for model_type, input_file in filenames.items():
        logger.debug('loading: \t%s, \t%s', model_type, input_file)
        cube = iris.load_cube(input_file)
        cube = diagtools.bgc_units(cube, metadata[input_file]['short_name'])
        cubes[model_type] = diagtools.make_cube_layer_dict(cube)
        for layer in cubes[model_type]:
            layers[layer] = True

    logger.debug('layers: %s', layers)
    logger.debug('cubes: %s', ', '.join(cubes.keys()))

    # ####
    # load names:
    model = metadata[filenames['model']]['dataset']
    obs = metadata[filenames['obs']]['dataset']

    long_name = cubes['model'][list(layers.keys())[0]].long_name
    units = str(cubes['model'][list(layers.keys())[0]].units)

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Make a plot for each layer
    for layer in layers:

        fig = plt.figure()
        fig.set_size_inches(9, 6)

        # Create the cubes
        cube221 = cubes['model'][layer]
        cube222 = cubes['obs'][layer]
        cube223 = cubes['model'][layer] - cubes['obs'][layer]
        cube224 = cubes['model'][layer] / cubes['obs'][layer]

        # create the z axis for plots 2, 3, 4.
        extend = 'neither'
        zrange12 = diagtools.get_cube_range([cube221, cube222])
        if 'maps_range' in metadata[input_file]:
            zrange12 = metadata[input_file]['maps_range']
            extend = 'both'
        zrange3 = diagtools.get_cube_range_diff([cube223])
        if 'diff_range' in metadata[input_file]:
            zrange3 = metadata[input_file]['diff_range']
            extend = 'both'

        cube224.data = np.ma.clip(cube224.data, 0.1, 10.)

        n_points = 12
        linspace12 = np.linspace(zrange12[0],
                                 zrange12[1],
                                 n_points,
                                 endpoint=True)
        linspace3 = np.linspace(zrange3[0],
                                zrange3[1],
                                n_points,
                                endpoint=True)
        logspace4 = np.logspace(-1., 1., 12, endpoint=True)

        # Add the sub plots to the figure.
        add_map_subplot(221,
                        cube221,
                        linspace12,
                        cmap='viridis',
                        title=model,
                        extend=extend)
        add_map_subplot(222,
                        cube222,
                        linspace12,
                        cmap='viridis',
                        title=' '.join([obs]),
                        extend=extend)
        add_map_subplot(223,
                        cube223,
                        linspace3,
                        cmap='bwr',
                        title=' '.join([model, 'minus', obs]),
                        extend=extend)
        if np.min(zrange12) > 0.:
            add_map_subplot(224,
                            cube224,
                            logspace4,
                            cmap='bwr',
                            title=' '.join([model, 'over', obs]),
                            log=True)

        # Add overall title
        fig.suptitle(long_name + ' [' + units + ']', fontsize=14)

        # Determine image filename:
        fn_list = ['model_vs_obs', long_name, model, obs, str(layer), 'maps']
        path = diagtools.folder(cfg['plot_dir']) + '_'.join(fn_list)
        path = path.replace(' ', '') + image_extention

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path, dpi=200)

        plt.close()
def multi_model_maps(
    cfg,
    input_files,
):
    """
    Make the four pane model vs model vs obs comparison plot.

    Parameters
    ----------
    cfg: dict
        the opened global config dictionairy, passed by ESMValTool.
    input_files: dict
        the metadata dictionairy

    """
    filenames = {}
    ctl_key = 'control_model'
    exp_key = 'exper_model'
    obs_key = 'observational_dataset'
    model_types = [ctl_key, exp_key, obs_key]
    for model_type in model_types:
        logger.debug(model_type, cfg[model_type])
        filenames[model_type] = diagtools.match_model_to_key(
            model_type, cfg[model_type], input_files)

    # ####
    # Load the data for each layer as a separate cube
    layers = {}
    cubes = {}
    for model_type, input_file in filenames.items():
        cube = iris.load_cube(input_file)
        cube = diagtools.bgc_units(cube, input_files[input_file]['short_name'])

        cubes[model_type] = diagtools.make_cube_layer_dict(cube)
        for layer in cubes[model_type]:
            layers[layer] = True

    logger.debug('layers: %s', ', '.join(layers))
    logger.debug('cubes: %s', ', '.join(cubes.keys()))

    # ####
    # load names:
    exper = input_files[filenames[exp_key]]['dataset']
    control = input_files[filenames[ctl_key]]['dataset']
    obs = input_files[filenames[obs_key]]['dataset']
    long_name = cubes[exp_key][list(layers.keys())[0]].long_name

    # Load image format extention
    image_extention = diagtools.get_image_format(cfg)

    # Make a plot for each layer
    for layer in layers:
        fig = plt.figure()
        fig.set_size_inches(9, 6)

        # Create the cubes
        cube221 = cubes[exp_key][layer]
        cube222 = cubes[exp_key][layer] - cubes[ctl_key][layer]
        cube223 = cubes[ctl_key][layer] - cubes[obs_key][layer]
        cube224 = cubes[exp_key][layer] - cubes[obs_key][layer]

        # create the z axis for plots 2, 3, 4.
        zrange1 = diagtools.get_cube_range([
            cube221,
        ])
        zrange2 = diagtools.get_cube_range_diff([cube222, cube223, cube224])

        linspace1 = np.linspace(zrange1[0], zrange1[1], 12, endpoint=True)
        linspace2 = np.linspace(zrange2[0], zrange2[1], 12, endpoint=True)

        # Add the sub plots to the figure.
        add_map_subplot(221, cube221, linspace1, cmap='viridis', title=exper)
        add_map_subplot(222,
                        cube222,
                        linspace2,
                        cmap='bwr',
                        title=' '.join([exper, 'minus', control]))
        add_map_subplot(223,
                        cube223,
                        linspace2,
                        cmap='bwr',
                        title=' '.join([control, 'minus', obs]))
        add_map_subplot(224,
                        cube224,
                        linspace2,
                        cmap='bwr',
                        title=' '.join([exper, 'minus', obs]))

        # Add overall title
        fig.suptitle(long_name, fontsize=14)

        # Determine image filename:
        fn_list = [long_name, exper, control, obs, str(layer)]
        path = diagtools.folder(cfg['plot_dir']) + '_'.join(fn_list)
        path = path.replace(' ', '') + image_extention

        # Saving files:
        if cfg['write_plots']:
            logger.info('Saving plots to %s', path)
            plt.savefig(path)

        plt.close()