Source code for plots.temporal.chrono

# -*- coding: utf-8 -*-

"""
Created on 4 déc. 2018

This script contains classes allowing to make matplotlib graphs with an automatic formatting of the temporal axis in
order to adapt to simulation temporal extent.

@author: lafaysse
"""

from matplotlib import pyplot as plt
from matplotlib.dates import HourLocator, DayLocator, MonthLocator, YearLocator, DateFormatter

from snowtools.plots.abstracts.figures import Mplfigure


class temporalplot_abstract(Mplfigure):

    def __init__(self, **kwargs):
        """Constructor for temporalplot_abstract class, redefinied for the child class"""
        super(temporalplot_abstract, self).__init__(**kwargs)
        self.plot = None
        #self.draw = None

    def finalize(self, timeOut, **kwargs):

        self.set_xaxis(timeOut)
        self.set_yaxis(**kwargs)
        kwargs.setdefault("fontsize", "x-small")
        self.plot.legend(loc="upper left", fontsize=kwargs["fontsize"])

    def set_yaxis(self, **kwargs):

        if 'forcemin' in kwargs.keys() and 'forcemax' in kwargs.keys():
            self.plot.set_ylim([kwargs['forcemin'], kwargs['forcemax']])
        self.plot.set_ylim(top=self.plot.get_ylim()[1] * 1.05)

        if 'ylabel' in kwargs.keys():
            label = kwargs.pop('ylabel')
            if 'ycolor' in kwargs.keys():
                color = kwargs['ycolor']
            else:
                color = 'black'
            self.plot.set_ylabel(label, color=color)

#    def draw(self, timeOut, *args, **kwargs):
#        self.finalize(timeOut, **kwargs)

    def add_line(self, timeOut, varOut, **kwargs):

        linesargs = {}
        for key, value in kwargs.items():
            if key not in ['forcemin', 'forcemax', 'ylabel', 'fillcolor']:
                linesargs[key] = value

        self.set_default("fmt", "-", linesargs)
        self.set_default("color", "red", linesargs)
        self.plot.plot_date(timeOut, varOut, **linesargs)

    def add_points(self, timeOut, varOut, **kwargs):
        self.set_default("fmt", "s", kwargs)
        self.set_default("color", "black", kwargs)
        self.set_default("markersize", 3, kwargs)
        self.add_line(timeOut, varOut, **kwargs)

    def set_default(self, varname, value, kwargs):
        if varname not in kwargs.keys():
            kwargs[varname] = value

    def set_xaxis(self, timeOut):

        duration = timeOut[-1] - timeOut[0]
        ndays = duration.days

        if ndays <= 2:
            self.plot.xaxis.set_major_locator(HourLocator([0, 6, 12, 18]))
            formatDate = '%d/%m\n%Hh'
        if ndays <= 4:
            self.plot.xaxis.set_major_locator(HourLocator([0, 12]))
            formatDate = '%d/%m\n%Hh'
        elif ndays <= 10:
            self.plot.xaxis.set_major_locator(DayLocator(range(1, 31, 1)))
            formatDate = '%d %b\n%Y'
        elif ndays <= 30:
            self.plot.xaxis.set_major_locator(DayLocator(range(1, 31, 3)))
            formatDate = '%d %b\n%Y'
        elif ndays <= 90:
            self.plot.xaxis.set_major_locator(DayLocator([1, 11, 21]))
            formatDate = '%d %b\n%Y'
        elif ndays <= 366:
            self.plot.xaxis.set_major_locator(MonthLocator(range(1, 13, 2), 1))
            formatDate = '%d %b'
        elif ndays <= (5 * 365):
            interval = int(ndays / 365) + 1
            self.plot.xaxis.set_major_locator(MonthLocator(range(1, 13, interval), 1))
            formatDate = '%d %b\n%Y'
        elif ndays >= (30 * 365):
            interval = int(ndays / 365) + 1
            self.plot.xaxis.set_major_locator(YearLocator(interval))
            formatDate = '%Y'
        else:
            interval = int(ndays / 365) + 1
            self.plot.xaxis.set_major_locator(YearLocator(interval))
            formatDate = '%Y'

        self.plot.xaxis.set_major_formatter(DateFormatter(formatDate))

    def save(self, *args, **kwargs):
        super(temporalplot_abstract, self).save(*args, **kwargs)
        self.plot.cla()


class temporalplot(temporalplot_abstract):

    figsize = (5, 4)

    def __init__(self,  *args, **kwargs):
        super(temporalplot, self).__init__(**kwargs)
        self.fig = plt.figure(figsize=self.figsize)
        self.plot = plt.subplot(111)


class temporalsubplot(temporalplot_abstract):
    def __init__(self, subplots, i, j, **kwargs):
        super(temporalsubplot, self).__init__(**kwargs)
        if hasattr(subplots, "shape"):
            if len(subplots.shape) == 2:
                self.plot = subplots[i, j]
            elif len(subplots.shape) == 1:
                self.plot = subplots[i * j]
            else:
                raise Exception
        else:
            self.plot = subplots


[docs] class temporalplotSim(temporalplot): """ Class for 1D variable temporal plot Example : .. code-block:: python from snowtools.utils.prosimu import prosimu from snowtools.plots.temporal.chrono import temporalplotSim # read data with prosimu('/rd/cenfic3/cenmod/home/viallonl/testbase/PRO/PRO_LaPlagne_2000-2001.nc') as p: sd = p.read('DSN_T_ISBA') sd2 = p.read('SNOWTEMP') time = p.readtime() plot = temporalplotSim() plot.draw(time, sd,label='prout') plot.finalize(time) # pour gérer les dates correctement plot.save('EX-temporalplotSim.png') .. figure:: /images/EX-temporalplotSim.png :align: center """ figsize=(5, 4)
[docs] def draw(self, timeSim, varSim, *args, **kwargs): """ Method of temporalplotSim class. Used for generating a 1D plot with time formatting. :param timeSim: Array of simulation duration usually given by prosimu.readtime() :param varSim: Array of simulation data usially given by prosimu.read() :param args: (optional) :param kwargs: optional ( matplotlib.pyplot key arguments ) :return: """ if 'label' in kwargs.keys(): label = kwargs.pop('label') else: label = 'S2M' self.add_line(timeSim, varSim, label=label, **kwargs) self.finalize(timeSim, **kwargs)
[docs] class temporalplotObsSim(temporalplot): """ Class for 1D variable temporal plot comparaison with observation Example : .. code-block:: python from snowtools.utils.prosimu import prosimu from snowtools.plots.temporal.chrono import temporalplotObsSim # read data with prosimu('/rd/cenfic3/cenmod/home/viallonl/testbase/PRO/PRO_LaPlagne_2000-2001.nc') as p: sd = p.read('DSN_T_ISBA') sd2 = p.read('SNOWTEMP') time = p.readtime() plot = temporalplotObsSim() plot.draw(time, sd,time,sd,label='prout') # comparaison of sd with sd during the same time plot.finalize(time) # pour gérer les dates correctement plot.save('EX-temporalplotObsSim.png') .. figure:: /images/EX-temporalplotObsSim.png :align: center """
[docs] def draw(self, timeObs, varObs, timeSim, varSim, *args, **kwargs): """ Method of temporalplotObsSim class. Used for generating comparative 1D plot with time formatting. :param timeObs: Array of Observation duration usually given by prosimu.readtime() :param varObs: Array of Observation data usially given by prosimu.read() :param timeSim: Array of simulation duration usually given by prosimu.readtime() :param varSim: Array of simulation data usially given by prosimu.read() :param args: (optional) :param kwargs: optional ( matplotlib.pyplot key arguments ) :return: """ self.add_points(timeObs, varObs, label="Observations") if 'label' in kwargs.keys(): label = kwargs['label'] else: label = 'S2M' self.add_line(timeSim, varSim, label=label) self.finalize(timeSim, **kwargs)
[docs] class temporalplotObsMultipleSims(temporalplot): """ Kept for bakward compatibility , please refer to temporalplotObsSim Similar to temporalplotObsSim but UGLIER """
[docs] def draw(self, timeObs, varObs, timeSim, varSim, *args, **kwargs): """Method of temporalplotObsMultipleSims class. Used for generating comparative 1D plot with time formatting. Similar to temporalplotObsSim but UGLIER :param timeObs: Array of Observation duration usually given by prosimu.readtime() :param varObs: Array of Observation data usially given by prosimu.read() :param timeSim: Array of simulation duration usually given by prosimu.readtime() :param varSim: Array of simulation data usially given by prosimu.read() :param args: (optional) :param kwargs: optional ( matplotlib.pyplot key arguments ) :return: """ self.add_points(timeObs, varObs, label="Observations") self.set_default("label", "S2M", kwargs) self.add_line(timeSim, varSim, **kwargs)
[docs] class temporalplot2Axes(temporalplot): """ Kept for bakward compatibility LM2B = Looks Broken to Me """
[docs] def addAx2(self, labelAx2, color='black', **kw): """ :param labelAx2: str of label :param color: :param kw: :return: """ self.ax2 = self.plot.twinx() if 'forcemin' in kw.keys() and 'forcemax' in kw.keys(): self.ax2.set_ylim(kw['forcemin'], kw['forcemax']) self.ax2.tick_params('y', colors=color) self.ax2.set_ylabel(labelAx2, color=color)
def addVarAx2(self, timeOut, varAx2, label, color='red', linestyle="-", **kw): self.ax2.plot_date(timeOut, varAx2, linestyle, label=label, color=color, **kw) def addLegendAx2(self, location="upper right"): self.ax2.legend(loc=location, fontsize="x-small")
class prettyensemble(temporalplot): figsize = (15, 4.5) def __init__(self, *args, **kwargs): super(prettyensemble, self).__init__(*args, **kwargs) # self.fig.subplots_adjust(top=0.85) self.fig.subplots_adjust() def draw(self, timeSim, qmin, qmed, qmax, *args, **kwargs): if 'colorquantiles' not in kwargs.keys(): kwargs['colorquantiles'] = 'red' if 'colormembers' not in kwargs.keys(): kwargs['colormembers'] = 'blue' medianlabel = u"Median" quantileslabel = u"Q10-Q90" if 'commonlabel' in kwargs.keys(): medianlabel += " " + kwargs['commonlabel'] quantileslabel += " " + kwargs['commonlabel'] self.plot.plot_date(timeSim, qmed, "-", color=kwargs['colorquantiles'], linewidth=kwargs['linewidth'], label=medianlabel) self.plot.fill_between(timeSim, qmin, qmax, color=kwargs['colorquantiles'], alpha=kwargs['alpha'], label=quantileslabel) self.finalize(timeSim, **kwargs) class spaghettis(temporalplot): figsize = (10, 3.5) def __init__(self, *args, **kwargs): super(spaghettis, self).__init__( *args, **kwargs) self.fig.subplots_adjust(top=0.85) def draw(self, timeSim, ensemble, qmin, qmed, qmax, *args, **kwargs): if 'colorquantiles' not in kwargs.keys(): kwargs['colorquantiles'] = 'red' if 'colormembers' not in kwargs.keys(): kwargs['colormembers'] = 'blue' medianlabel = u"Médiane" quantileslabel = u"Q20-Q80" if 'commonlabel' in kwargs.keys(): medianlabel += " " + kwargs['commonlabel'] quantileslabel += " " + kwargs['commonlabel'] self.add_line(timeSim, ensemble, color=kwargs['colormembers'], linewidth=0.5) self.plot.plot(timeSim, qmed, "-", color=kwargs['colorquantiles'], linewidth=2, label=medianlabel) self.plot.fill_between(timeSim, qmin, qmax, color=kwargs['colorquantiles'], alpha=0.25, label=quantileslabel) self.finalize(timeSim, **kwargs) class spaghettis_with_det(spaghettis): def draw(self, timeSim, ensemble, qmin, qmed, qmax, deterministic=None, *args, **kwargs): # super(spaghettis_with_det, self).draw(timeSim, ensemble, qmin, qmed, qmax, deterministic, *args, **kwargs) if 'commonlabel' in kwargs.keys(): detlabel = u"Dét." + " " + kwargs['commonlabel'] else: detlabel = u"Déterministe" self.add_line(timeSim, deterministic, color="black", linewidth=2, label=detlabel, zorder=100) super(spaghettis_with_det, self).draw(timeSim, ensemble, qmin, qmed, qmax, **kwargs)