julienmalard/Tikon

View on GitHub
tikon/datos/dibs.py

Summary

Maintainability
A
3 hrs
Test Coverage
import os

import numpy as np
import pandas as pd
from matplotlib.backends.backend_agg import FigureCanvasAgg as TelaFigura
from matplotlib.figure import Figure as Figura
from pandas.plotting import register_matplotlib_converters

from tikon.utils import EJE_PARÁMS, EJE_ESTOC, EJE_TIEMPO

register_matplotlib_converters()


def graficar_res(
        título, directorio, simulado, obs=None, color='#99CC00', promedio=True, incert='confianza',
        etiq_x=None, etiq_y=None
):
    obs = obs or []
    etiq_x = 'Fecha' if etiq_x is None else etiq_x
    etiq_y = '{var} ({unids})'.format(var=simulado.name, unids=simulado.attrs['unids']) if etiq_y is None else etiq_y
    if not os.path.isdir(directorio):
        os.makedirs(directorio)

    fig = Figura()
    TelaFigura(fig)
    ejes = fig.add_subplot(111)

    # El vector de días
    x = simulado[EJE_TIEMPO].values

    # Si necesario, incluir el mediano de todas las repeticiones (estocásticas y paramétricas)
    med_simul = simulado.median(dim=(EJE_ESTOC, EJE_PARÁMS))
    if promedio:
        ejes.plot(x, med_simul, lw=2, color=color, label='Mediano')

    # Si hay observaciones, mostrarlas también
    for o_ in obs:
        e_tiempo = o_[EJE_TIEMPO]

        if not np.issubdtype(e_tiempo, np.datetime64):
            e_tiempo = pd.TimedeltaIndex(e_tiempo.values, unit='D') + x[0]
        másc = (x[0] <= e_tiempo) & (e_tiempo <= x[-1])

        ejes.plot(e_tiempo[másc], o_[másc], marker='o', markersize=3, color='#000000', label='Observaciones')
        ejes.plot(e_tiempo[másc], o_[másc], lw=1, color='#000000')

    # Incluir el incertidumbre si necesario
    if incert is None:
        # Si no quiso el usuario, no poner el incertidumbre
        pass

    elif incert == 'confianza':
        # Mostrar el nivel de confianza en la incertidumbre

        # Los niveles de confianza para mostrar
        centiles = [.50, .75, .95, .99]

        # Mínimo y máximo del centil anterior
        máx_perc_ant = mín_perc_ant = simulado.median(dim=(EJE_ESTOC, EJE_PARÁMS))

        # Para cada centil...
        for n, c in enumerate(centiles):
            # Percentiles máximos y mínimos
            máx_perc = simulado.quantile(0.50 + c / 2, dim=(EJE_ESTOC, EJE_PARÁMS))
            mín_perc = simulado.quantile((1 - c) / 2, dim=(EJE_ESTOC, EJE_PARÁMS))

            # Calcular el % de opacidad y dibujar
            op_máx = 0.6
            op_mín = 0.2
            opacidad = (1 - n / (len(centiles) - 1)) * (op_máx - op_mín) + op_mín

            ejes.fill_between(
                x, máx_perc_ant, máx_perc,
                facecolor=color, alpha=opacidad, linewidth=0.5, edgecolor=color, label='IC {} %'.format(int(c * 100))
            )
            ejes.fill_between(
                x, mín_perc, mín_perc_ant,
                facecolor=color, alpha=opacidad, linewidth=0.5, edgecolor=color
            )

            # Guardar los máximos y mínimos
            mín_perc_ant = mín_perc
            máx_perc_ant = máx_perc

    elif incert == 'componentes':
        # Mostrar la incertidumbre descompuesta por sus fuentes

        # El rango total de las simulaciones
        máx_total = simulado.max(dim=(EJE_ESTOC, EJE_PARÁMS))
        mín_total = simulado.min(dim=(EJE_ESTOC, EJE_PARÁMS))
        rango_total = máx_total - mín_total

        # La desviación estándar de todas las simulaciones (incertidumbre total)
        des_est_total = simulado.std(dim=(EJE_ESTOC, EJE_PARÁMS))

        # El incertidumbre estocástico promedio
        des_est_estóc = simulado.std(dim=EJE_ESTOC).mean(dim=EJE_PARÁMS)

        # Inferir el incertidumbre paramétrico
        des_est_parám = des_est_total - des_est_estóc
        frac_des_est_parám = (des_est_parám / des_est_total).fillna(0)
        incert_parám = rango_total * frac_des_est_parám

        # Límites de la región de incertidumbre paramétrica en el gráfico
        mín_parám = (np.maximum(mín_total, med_simul - incert_parám / 2)).values
        máx_parám = (mín_parám + incert_parám).values

        ejes.fill_between(x, máx_parám, mín_parám, facecolor=color, alpha=0.5, label='Incert paramétrico')

        ejes.fill_between(x, máx_total, mín_total, facecolor=color, alpha=0.3, label='Incert estocástico')

    else:
        raise ValueError('`incert` debe ser "componentes" o "confianza", no  "%s".' % incert)

    ejes.set_xlabel(etiq_x)
    ejes.set_ylabel(etiq_y)
    ejes.set_title(título)

    ejes.legend(loc=2)

    fig.autofmt_xdate()
    if os.path.splitext(directorio)[1] != '.jpg':
        directorio = os.path.join(directorio, título + '.jpg')
    fig.savefig(directorio)