コード例 #1
0
def _fixup_dates(coord, values):
    if coord.units.calendar is not None and values.ndim == 1:
        # Convert coordinate values into tuples of
        # (year, month, day, hour, min, sec)
        dates = [coord.units.num2date(val).timetuple()[0:6] for val in values]
        if coord.units.calendar == 'gregorian':
            r = [datetime.datetime(*date) for date in dates]
        else:
            try:
                import nc_time_axis
            except ImportError:
                msg = ('Cannot plot against time in a non-gregorian '
                       'calendar, because "nc_time_axis" is not available :  '
                       'Install the package from '
                       'https://github.com/SciTools/nc-time-axis to enable '
                       'this usage.')
                raise IrisError(msg)

            r = [
                nc_time_axis.CalendarDateTime(netcdftime.datetime(*date),
                                              coord.units.calendar)
                for date in dates
            ]
        values = np.empty(len(r), dtype=object)
        values[:] = r
    return values
コード例 #2
0
 def test_360_day_calendar_CalendarDateTime(self):
     datetimes = [cftime.datetime(1986, month, 30) for month in range(1, 6)]
     cal_datetimes = [
         nc_time_axis.CalendarDateTime(dt, '360_day') for dt in datetimes
     ]
     line1, = plt.plot(cal_datetimes)
     result_ydata = line1.get_ydata()
     np.testing.assert_array_equal(result_ydata, cal_datetimes)
コード例 #3
0
def _fixup_dates(coord, values):
    if coord.units.calendar is not None and values.ndim == 1:
        # Convert coordinate values into tuples of
        # (year, month, day, hour, min, sec)
        dates = [coord.units.num2date(val).timetuple()[0:6] for val in values]
        if coord.units.calendar == 'gregorian':
            r = [datetime.datetime(*date) for date in dates]
        else:
            r = [
                nc_time_axis.CalendarDateTime(netcdftime.datetime(*date),
                                              coord.units.calendar)
                for date in dates
            ]
        values = np.empty(len(r), dtype=object)
        values[:] = r
    return values
コード例 #4
0
ファイル: plot.py プロジェクト: jkrasting/gfdlvitals
def plot_timeseries(
    dsets,
    var,
    trend=False,
    align_times=False,
    smooth=None,
    nyears=None,
    labels=None,
    legend=True,
    means=True,
):
    """Standardized function to make a timeseries plot

    Parameters
    ----------
    dsets : gfdlvitals.VitalsDataFrame or list
        Dataframe or list of dataframes to plot
    var : str
        Variable name to plot
    trend : bool, optional
        Plot linear trend line if True, by default False
    align_times : bool, optional
        H, by default False
    smooth : int, optional
        Integer number of years to apply smoothing, by default None
    nyears : int, optional
        Limit the x-axis to nyears number of points, by default None
    labels : str, optional
        Comma-separated list of dataset labels, by default None
    legend : bool, optional
        Display a legend for the plot, by default True
    means : bool, optional
        Add variable means to the legend, by default True

    Returns
    -------
    matplotlib.pyplot.figure, dict
        Matplotlib figure handle and dictionary of axes/dataset mappings
    """

    set_font()

    # Ensure "dsets" is a list
    dsets = [dsets] if not isinstance(dsets, list) else dsets

    # Text Labels
    if labels is None:
        labels = [f"Dataset {x}" for x in range(0, len(dsets))]
        legend = False
    else:
        labels = labels.split(",")

    # Determine max length of time values
    maxlen = max([len(x.index) for x in dsets])

    # Compute trends if asked
    if trend:
        trends = [x.trend()[0:nyears] for x in dsets]

    if align_times:
        dsets = [x.extend(maxlen) for x in dsets]

    # Setup the figure. The top half will have a 16:9 aspect
    # ratio. The bottom half will be used for legend info and
    # the whole figure will be cropped at the end

    fig = plt.figure(figsize=(12, 6.75))
    ax1 = plt.subplot(1, 1, 1)

    # Establish a list of axes in the figure
    axes_dict = {}

    # If smoothing is requested, still plot a faint copy of the full timeseries
    for x, dset in enumerate(dsets):
        dset.attrs["alpha"] = 0.3 if smooth is not None else 1.0
        dset.attrs["color"] = f"C{x}"

    _lines = []

    for i, dset in enumerate(dsets):
        label = labels[i]

        axes_dict[label] = {}
        axes_dict[label]["data"] = dset

        # Determine if we need a twin time axis
        _ax = ax1.twiny() if align_times and i > 0 else ax1
        axes_dict[label]["axis"] = _ax

        axes_list = [axes_dict[x]["axis"] for x in list(axes_dict.keys())]

        # Keep a list of the axes and move new ones to the bottom of the figure
        if _ax not in list(axes_dict.keys()) and align_times:
            # Move twinned axis ticks and label from top to bottom
            _ax.xaxis.set_ticks_position("bottom")
            _ax.xaxis.set_label_position("bottom")

            # Offset the twin axis below the host
            _ax.spines["bottom"].set_position(
                ("axes", -0.10 * (len(axes_dict) - 1)))

            # Make sure frame is displayed
            if i > 0:
                _ax.set_frame_on(True)
                # Turn on the frame for the twin axis, but then hide all
                # but the bottom spine
                _ax.patch.set_visible(False)
                _ = [sp.set_visible(False) for sp in _ax.spines.values()]
                _ax.spines["bottom"].set_visible(True)

        # Convert times to nc_time_axis
        times = [
            nc_time_axis.CalendarDateTime(item, "noleap")
            for item in dset.index.values
        ]

        # Add means to the labels
        _label = labels[i]
        if means:
            _mean = float(dset[var].values[0:nyears].mean())
            _mean = round(_mean, 4)
            _label = f"{_label}  (mean={_mean})"
            labels[i] = _label

        # Make the first plot
        (axes_dict[label]["line"], ) = _ax.plot(
            times[0:nyears],
            dset[var].values[0:nyears],
            color=dset.attrs["color"],
            alpha=dset.attrs["alpha"],
            label=_label,
        )

        _lines.append(axes_dict[label]["line"])

        # After the first plot is established, align time axes if asked
        if align_times:
            _time_index = dset.index[0:nyears]
            _ax.set_xlim(
                cftime.date2num(_time_index[0],
                                calendar="noleap",
                                units="days since 2000-01-01"),
                cftime.date2num(_time_index[-1],
                                calendar="noleap",
                                units="days since 2000-01-01"),
            )

        if trend:
            (axes_dict[label]["trendline"], ) = _ax.plot(
                times[0:len(trends[i])],
                trends[i][var].values[0:nyears],
                linestyle="dashed",
                color=dset.attrs["color"],
                alpha=1.0,
                linewidth=1,
            )
            axes_dict[label]["trend"] = trends[i]

        if smooth:
            (axes_dict[label]["smoothline"], ) = _ax.plot(
                times[0:nyears],
                dset.smooth(smooth)[var].values[0:nyears],
                color=dset.attrs["color"],
                alpha=1.0,
                linewidth=2,
            )

        # Text annotations

        if i == 0:
            axes_dict[label]["topline_label"] = _ax.text(
                0.01,
                1.08,
                var,
                ha="left",
                transform=ax1.transAxes,
                fontsize=22)

            axes_dict[label]["longname_label"] = _ax.text(
                0.01,
                1.03,
                dset[var].attrs["long_name"],
                ha="left",
                transform=ax1.transAxes,
                style="italic",
                fontsize=14,
                fontfamily="Roboto Condensed",
            )

            axes_dict[label]["units_label"] = _ax.set_ylabel(
                dset[var].attrs["units"])

    axes_list = [axes_dict[x]["axis"] for x in list(axes_dict.keys())]
    axes_list = list(set(axes_list))
    maxlim = max([x.get_xlim()[1] - x.get_xlim()[0] for x in axes_list])
    _ = [
        x.set_xlim(x.get_xlim()[0],
                   x.get_xlim()[0] + maxlim) for x in axes_list
    ]

    # Add grid
    _ = [
        x.grid(color="gray", linestyle="--", linewidth=0.3) for x in axes_list
    ]

    if legend:
        plt.legend(
            _lines,
            labels,
            fancybox=True,
            framealpha=1,
            shadow=True,
            borderpad=0.5,
            loc="upper center",
            bbox_to_anchor=(0.5, (-0.10 * (len(axes_dict)) + 0.02)),
        )

    return fig, axes_dict
コード例 #5
0
def fix_time(ds):
    ds = ds.copy()
    ds.time.data = [
        nc_time_axis.CalendarDateTime(item, "360_day") for item in ds.time.data
    ]
    return ds