Esempio n. 1
0
def _frames_to_movie(config, fieldName):
    """
    create a movie from frames using ffmpeg

    Parameters
    ----------
    config : ConfigParser
        config options

    fieldName : str
        A field in the model output that can be plotted as a movie
    """
    section = config['ffmpeg']

    experiment = config['experiment']['name']
    movieFolder = config['movies']['folder']
    try:
        os.makedirs(movieFolder)
    except OSError:
        pass
    framesFolder = config['movies']['framesFolder']
    framesTemplate = '{}/{}/{}_%04d.png'.format(framesFolder, fieldName,
                                                fieldName)

    inputArgs = string_to_list(section['input'], separator=' ')
    outputArgs = string_to_list(section['output'], separator=' ')
    extensions = string_to_list(section['extensions'])

    for extension in extensions:
        args = ['ffmpeg', '-y'] + inputArgs + ['-i', framesTemplate] + \
            outputArgs + ['{}/{}_{}.{}'.format(movieFolder, experiment,
                                               fieldName, extension)]
        subprocess.check_call(args)
Esempio n. 2
0
def plot_movies(config):
    """
    Plot the all requested movies

    Parameters
    ----------
    config : ConfigParser
        config options
    """

    register_custom_colormaps()

    fieldNames = string_to_list(config['movies']['fields'])

    if fieldNames[0] == '':
        # nothing to plot
        return

    for fieldName in fieldNames:
        plot_movie(config, fieldName)
Esempio n. 3
0
def plot_metric_timeseries(config):
    """
    Plot a time series of a given metric for all models.

    Parameters
    ----------
    config : ConfigParser
        config options
    """

    experiment = config['experiment']['name']

    metrics = config['metrics']
    metricNames = string_to_list(metrics['names'])
    if metricNames[0] == '':
        # nothing to plot
        return

    plotFolder = metrics['folder']

    try:
        os.makedirs(plotFolder)
    except OSError:
        pass

    colors = string_to_list(metrics['colors'])
    dpi = metrics.getint('dpi')
    lineWidth = metrics.getint('lineWidth')
    figsize = string_to_list(metrics['figsize'])
    figsize = [float(dim) for dim in figsize]

    datasets, maxTime = load_datasets(config, variableList=metricNames)
    modelNames = list(datasets.keys())

    for metricName in metricNames:
        metricConfig = config[metricName]
        semilog = metricConfig.getboolean('semilog')
        scale = metricConfig.getfloat('scale')
        title = metricConfig['title']

        plt.figure(figsize=figsize)
        for modelIndex, modelName in enumerate(modelNames):
            ds = datasets[modelName]
            if metricName not in ds.data_vars:
                continue

            years = ds.time.values/config['constants'].getfloat('sPerYr')
            field = scale*ds[metricName].values
            if semilog:
                plt.semilogy(years, field, label=modelName,
                             color=colors[modelIndex], linewidth=lineWidth)
            else:
                plt.plot(years, field, label=modelName,
                         color=colors[modelIndex], linewidth=lineWidth)

        plt.ylabel(title)
        plt.xlabel('time (a)')
        plt.legend(loc='best')
        plt.tight_layout()
        plt.draw()
        plt.savefig('{}/{}_{}.png'.format(plotFolder, experiment, metricName),
                    dpi=dpi)
        plt.close()
Esempio n. 4
0
def _plot_time_slice(config, fieldName, datasets, time, timeIndex):
    """
    Plot the frames of a movie from a time-dependent, spatially 2D field and
    then create a movie using ffmpeg

    Parameters
    ----------
    config : ConfigParser
        config options

    fieldName : str
        A field in the model output that can be plotted as a movie

    datasets : dict of xarray.Dataset
        The data sets to plot

    time : float
        The time to plot (by finding the nearest index in the time coordinate)
    """
    framesFolder = config['movies']['framesFolder']
    framesFolder = '{}/{}'.format(framesFolder, fieldName)
    try:
        os.makedirs(framesFolder)
    except OSError:
        pass

    # the file name is the variable followed by the zero-padded time index
    imageFileName = '{}/{}_{:04d}.png'.format(framesFolder, fieldName,
                                              timeIndex)
    if os.path.exists(imageFileName):
        # the image exists so we're going to save time and not replot it
        return

    modelNames = list(datasets.keys())
    modelCount = len(modelNames)
    section = config[fieldName]
    axes = section['axes']
    title = section['title']
    scale = section.getfloat('scale')
    if 'cmap' in section:
        cmap = section['cmap']
    else:
        cmap = 'ferret'

    if 'norm' in section:
        normType = section['norm']
        assert normType in ['linear', 'symlog', 'log']
    else:
        normType = 'linear'

    lower, upper = [float(limit) for limit in
                    string_to_list(section['limits'])]

    timeCoords = [float(coord) for coord in string_to_list(
        config['movies']['{}TimeCoords'.format(axes)])]

    if axes == 'xy':
        columnCount = min(3, modelCount)
        xLabel = 'x (km)'
        yLabel = 'y (km)'
        rowScale = 1.2
    elif axes == 'xz':
        columnCount = min(4, modelCount)
        rowScale = 2.0
        xLabel = 'x (km)'
        yLabel = 'z (m)'
    elif axes == 'yz':
        columnCount = min(4, modelCount)
        rowScale = 2.0
        xLabel = 'y (km)'
        yLabel = 'z (m)'
    else:
        raise ValueError('Unknow axes value {}'.format(axes))

    rowCount = (modelCount+columnCount-1)//columnCount

    modelIndices = numpy.reshape(numpy.arange(rowCount*columnCount),
                                 (rowCount, columnCount))[::-1, :].ravel()

    figsize = [16, 0.5+rowScale*(rowCount+0.5)]
    fig, axarray = plt.subplots(rowCount, columnCount, sharex='col',
                                sharey='row', figsize=figsize, dpi=100,
                                facecolor='w')

    if modelCount == 1:
        axarray = numpy.array(axarray)

    if rowCount == 1:
        axarray = axarray.reshape((rowCount, columnCount))

    lastImage = []
    row = 0
    for panelIndex in range(len(modelIndices)):
        modelIndex = modelIndices[panelIndex]
        row = rowCount-1 - panelIndex//columnCount
        col = numpy.mod(panelIndex, columnCount)

        if modelIndex >= modelCount:
            plt.delaxes(axarray[row, col])
            continue

        modelName = modelNames[modelIndex]
        ds = datasets[modelName]

        validTimes = numpy.nonzero(numpy.isfinite(ds.time.values))[0]
        ds = ds.isel(nTime=validTimes)

        times = ds.time.values
        localTimeIndex = numpy.interp(time, times,
                                      numpy.arange(ds.sizes['nTime']))
        localTimeIndex = int(localTimeIndex + 0.5)
        ds = ds.isel(nTime=localTimeIndex)
        year = times[localTimeIndex]/config['constants'].getfloat('sPerYr')

        ax = axarray[row, col]

        x = ds[axes[0]].values
        if axes[0] in ['x', 'y']:
            # convert to km
            x = 1e-3*x
        y = ds[axes[1]].values
        if axes[1] in ['x', 'y']:
            # convert to km
            y = 1e-3*y

        im = _plot_panel(ax, x, y, ds[fieldName].values, scale, lower, upper,
                         axes, cmap, normType)

        ax.text(timeCoords[0], timeCoords[1], '{:.2f} a'.format(year),
                fontsize=12)

        if row == rowCount-1:
            ax.set_xlabel(xLabel)

        if col == columnCount-1:
            lastImage.append(im)

        if col == 0:
            ax.set_ylabel(yLabel)
            for label in ax.yaxis.get_ticklabels()[0::2]:
                label.set_visible(False)

        ax.set_title(modelNames[modelIndex])

    plt.tight_layout()

    fig.subplots_adjust(right=0.91)
    if rowCount == 1:
        fig.subplots_adjust(top=0.85)
    else:
        fig.subplots_adjust(top=0.9)
    pos0 = axarray[0, -1].get_position()
    pos1 = axarray[-1, -1].get_position()
    top = pos0.y0 + pos0.height
    height = top - pos1.y0
    cbar_ax = fig.add_axes([0.92, pos1.y0, 0.02, height])
    cbar = fig.colorbar(lastImage[row], cax=cbar_ax)
    if rowCount == 1:
        for label in cbar.ax.yaxis.get_ticklabels()[1::2]:
            label.set_visible(False)

    plt.suptitle(title)

    plt.draw()
    plt.savefig(imageFileName)

    plt.close()
Esempio n. 5
0
def load_datasets(config, variableList=None):
    """
    Load model data

    Parameters
    ----------
    config : ConfigParser
        config options

    variableList : list of str, optional
        a list of variables to keep from each model.  By default, all variables
        are kept.

    Returns
    -------
    datasets : OrderedDict of xarray.Dataset
        A dictionary with one data set for each model

    maxTime : int
        The value of nTime from the longest model data set
    """

    modelNames = string_to_list(config['models']['names'])

    experimentName = config['experiment']['name']

    if 'setup' in config['experiment']:
        setupPrefix = '{}_'.format(config['experiment']['setup'])
    else:
        setupPrefix = ''

    datasets = OrderedDict()
    maxTime = None
    for modelName in modelNames:
        fileName = '{}/{}_{}{}.nc'.format(modelName, experimentName,
                                          setupPrefix, modelName)
        print('Reading data for {}'.format(modelName))

        ds = xarray.open_dataset(fileName, mask_and_scale=True, decode_cf=True,
                                 decode_times=False, engine='netcdf4')
        ds = ds.set_coords([coord for coord in ['time', 'x', 'y', 'z']
                            if coord in ds])

        if variableList is not None:
            ds = ds[variableList]
        datasets[modelName] = ds

        # many MISOMIP output files don't have the _FillValue flag set properly
        missingValue = 9.9692099683868690e36
        for variableName in ds.data_vars:
            var = ds[variableName]
            ds[variableName] = var.where(var != missingValue)

        # fix time if the middle of the month was used instead of the beginning
        time = ds.time.values
        secondsInJanuary = 31*24*60*60
        if numpy.abs(time[0]/secondsInJanuary - 0.5) < 1e-3:
            # very close to 1/2 month beyond where it should be, so let's
            # assume a consistant half-month offset
            daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
            for tIndex in range(len(time)):
                month = numpy.mod(tIndex, 12)
                time[tIndex] -= 0.5*daysPerMonth[month]*24*60*60

            ds['time'] = ('time', time)

        if maxTime is None:
            maxTime = numpy.amax(time)
        else:
            maxTime = max(maxTime, numpy.amax(time))

    return datasets, maxTime