#!/usr/bin/env python2.4 #-*- coding: iso8859-15 -*- ########################################################## # R v1.0 # ########################################################## # Autor: Juan Miguel Taboada Godoy # # Fecha: Málaga, 07 de Agosto de 2006 # # Descripción: Genera gráficas con R # # Versión: 2006080700 # # Interpreta los formatos de fichero: # # - DB_MYSQL # # # # Codigo fuente bajo licencia GNU/GPL # # Centrologic (Computational Logistic Center) # # http://www.centrologic.com - info@centrologic.com # ########################################################## # Librerías que voy a usar {{{1 import time import datetime import shutil # Special import for RPy {{{2 class r: pass from rpy import * r.NA=r("NA") # }}}2 from lib.MATH_GRA import calculadora from lib.MATH_EV import sqrtEV, escalarX, filtro_limites, particionar from lib.GRAFICAS import GRAFICADOR_CONFIG, GRAFICADOR from lib.DATE import coste_temporal, tiempo_str, siguientediasemana, epochdate from lib.FILTER import filtrar_texto, separar_operadores from lib.HERENCIA import BASE,DEFAULTCONFIG # }}}1 # ### CONFIG ### ###################################### ## Generador de graficas basadas en R: configuracion por defecto class CONFIG(DEFAULTCONFIG,GRAFICADOR_CONFIG): # Constructor {{{1 def __init__(self): # Cargo las acciones del padre DEFAULTCONFIG.__init__(self,"R") # }}}1 # Config Graficas {{{1 # Directorio con las graficas {{{2 ## Directorio con las graficas ## \param self - ## \param arg Directorio donde poner las graficas (debe ser una lista con rutas donde poner las graficas) def dirdib(self,arg=None): if (arg!=None): self._dirdib=arg return self._dirdib # }}}2 # Resolución de la gráfica {{{2 ## Resolucion de la grafica ## \param self - ## \param x Resolucion del eje X ## \param y Resolucion del eje Y def resolution(self,x=None,y=None): if ((x!=None) and (y!=None)): self._resolution=(x,y) else: # Devuelve el valor return self._resolution # }}}2 # Tamaño de los datos en el eje X (comienza en, termina en) {{{2 ## Tamano de los datos en el eje X ## \param self - ## \param ini Donde comienza el eje X ## \param fin Donde termina el eje X ## \param crece_x Distancia entre dos valores consecutivos ## \param formato Formato de los datos del eje: %Y (anyos), %m (meses), %d (dias), %H (horas), %M (minutos), %S (segundos) ## \sa Para conocer mas sobre los valores posibles de ini y fin, revisar calculadora() ## \sa Para conocer mas sobre el crecimiento del eje X, revisar coste_temporal() def sizex(self,ini=None,fin=None,crece_x=None,formato=None): if ((ini!=None) and (fin!=None) and (crece_x!=None) and (formato!=None)): # Calculo el ajuste temporal entregado minX=calculadora(ini,None) maxX=calculadora(fin,None) tickX=coste_temporal(crece_x) # Almaceno los valores self._sizex=(minX,maxX,tickX,formato) else: # Devuelve el valor return self._sizex # }}}2 # Tamaño de los datos en el eje y (comienza en, termina en) {{{2 ## Tamano de los datos en el eje Y ## \param self - ## \param minY Donde comienza el eje Y ## \param maxY Donde termina el eje Y ## \param decre_y Distancia entre dos valores consecutivos (entre textos) ## \param regilla_distancia Distancia entre las casillas de la regilla (entre marcas) def sizey(self,minY=None,maxY=None,decre_y=None,regilla_distancia=None): if ((minY!=None) and (maxY!=None)): # Calculo el decrecimiento de y si es necesario if (decre_y==None): if (maxY-minY<300): decre_y=-20 elif (maxY-minY<600): decre_y=-40 else: decre_y=-100 # Calculo el decrecimiento de y si es necesario if (regilla_distancia==None): if (maxY-minY<300): regilla_distancia=10 elif (maxY-minY<600): regilla_distancia=20 else: regilla_distancia=50 # Cargo los datos self._sizey=(minY,maxY,decre_y,regilla_distancia) else: return self._sizey # }}}2 # Regilla {{{2 ## Indica si poner la regilla o no ## \param self - ## \param set True/False para poner la regilla en la grafica o no def grid(self,set=None): if (set!=None): self._grid=set else: return self._grid # }}}2 # Margenes {{{2 ## Indica los margenes de la grafica con el papel ## \param self - ## \param a Margen inferior ## \param b Margen izquierdo ## \param c Margen superior ## \param d Margen derecho ## \attention Cada margen es dividido por el valor de inch() def margenes(self,a=None,b=None,c=None,d=None): if ((a!=None) and (b!=None) and (c!=None) and (d!=None)): self._margenes=(a,b,c,d) else: return self._margenes # }}}2 # Inch {{{2 ## Tamano de un inch en la grafica, se usa en el calculo de los margenes() ## \param self - ## \param inch Tamano en pixeles de un inch def inch(self,inch=None): if (inch!=None): self._inch=inch else: return self._inch # }}}2 # Leyenda Crece {{{2 ## Indica la distancia entre dos filas de la leyenda ## \param self - ## \param leyendaCrece Unidades de distancia entre 2 filas de la leyenda def leyendaCrece(self,leyendaCrece=None): if (leyendaCrece!=None): self._leyendaCrece=leyendaCrece else: return self._leyendaCrece # }}}2 # Leyenda Columnas {{{2 ## Numero de leyendas por fila ## \param self - ## \param leyendaColumnas Numero de leyendas por fila def leyendaColumnas(self,leyendaColumnas=None): if (leyendaColumnas!=None): self._leyendaColumnas=leyendaColumnas else: return self._leyendaColumnas # }}}2 # Evento Crece {{{2 ## Indica la distancia entre dos eventos ## \param self - ## \param eventoCrece Unidades de distancia entre dos eventos def eventoCrece(self,eventoCrece=None): if (eventoCrece!=None): self._eventoCrece=eventoCrece else: return self._eventoCrece # }}}2 # Evento Texto {{{2 ## Indica la distancia entre el texto y el evento ## \param self - ## \param eventoTexto Unidades de distancia entre el texto y el evento en si def eventoTexto(self,eventoTexto=None): if (eventoTexto!=None): self._eventoTexto=eventoTexto else: return self._eventoTexto # }}}2 # }}}1 # Checker {{{1 ## Comprueba que el conjunto minimo de datos requeridos por la clase han sido declarados por el usuario: \n ## - resolution() ## - dirdib() ## - sizex() ## - sizey() ## - margenes() ## - inch() ## - eventoCrece() ## - eventoTexto() ## - leyendaCrece() ## - leyendaColumnas() ## - lector() ## - test() ## \param self - def check(self): self._check("resolution") self._check("dirdib") self._check("sizex") self._check("sizey") self._check("margenes") self._check("inch") self._check("eventoCrece") self._check("eventoTexto") self._check("leyendaCrece") self._check("leyendaColumnas") self._check("lector") self._check("test") self._check("memoria") # Test del graficador (clase heredada) self.check_graficador() # Test de la config por defecto (clase heredada) self.check_default() # }}}1 # ### TELEMANDO ### ################################### ## Generador de graficas basadas en R: grafica class GRAFICA(BASE,GRAFICADOR): # Constructor {{{1 ## Constructor ## \param self - ## \param nombre Cadena de texto que representa al nombre interno de la grafica ## \param senales Objeto de tipo src.etcbin.senales_cabecera.SENALES def __init__(self,nombre,senales): # Cargo las acciones del padre BASE.__init__(self,nombre,"R") # Cargo las acciones de la extensión GRAFICADOR.__init__(self,nombre,senales) # Tabla de leyendas self.__leyendas=[] # Total de eventos en la grafica self.__totaleventos=0 # Define un NA self.NA(r.NA) # Inicializo el resto de valores self.__sizex=("date:ayer_06:00:00","date:hoy_06:00:00","horas","%H:%M") self.__sizex_memory=None self.__sizey=(-100,100) self.__grid=False # Inicializo el nombre del fichero creado por R self._fileR=None # Test de existencia self.__existencia=None # }}}1 # Salida {{{1 ## \internal ## Almacena los datos de publicacion de la grafica ## \param self - ## \param arg Datos de publicacion de la grafica (es una tupla) def outvar(self,arg=None): if (arg!=None): self._outvar=arg return self._outvar # }}}1 # Fichero creado por R {{{1 ## \internal ## Almacena el nombre del posible fichero creado por R ## \param self - ## \param arg Nombre del fichero def fileR(self,arg=None): if (arg!=None): self._fileR=arg return self._fileR # }}}1 # Resolución de la gráfica {{{1 ## Resolucion de las graficas ## \param self - ## \param x Resolucion del eje X ## \param y Resolucion del eje Y def resolution(self,x=None,y=None): if ((x!=None) and (y!=None)): self._resolution=(x,y) else: # Devuelve el valor return self._resolution # }}}1 # Tamaño de los datos en el eje X (comienza en, termina en) {{{1 ## Tamano de los datos en el eje X ## \param self - ## \param ini Donde comienza el eje X ## \param fin Donde termina el eje X ## \param crece_x Distancia entre dos valores consecutivos ## \param formato Formato de los datos del eje: %Y (anyos), %m (meses), %d (dias), %H (horas), %M (minutos), %S (segundos) ## \param actualizar Indica si hay que actualiar el sizex(), es solo ultil cuando hay un viaje_temporal() (True/False) ## \sa Para conocer mas sobre los valores posibles de ini y fin, revisar calculadora() ## \sa Para conocer mas sobre el crecimiento del eje X, revisar coste_temporal() def sizex(self,ini=None,fin=None,crece_x=None,formato=None,actualizar=False): # Comprueba que hemos pasado algún parámetro if ((ini!=None) and (fin!=None)): # Si no se recibió el crecimiento de X if (crece_x==None): # Se obtiene el crecimiento general si existe sizex=self.valor("sizex") if (sizex==None): # Si no existe termino return None else: # Si existe lo cargo crece_x=sizex[2] # Se obtiene el formato if (formato==None): # Se obtiene el formato general si existe sizex=self.valor("sizex") if (sizex==None): # Si no existe termino return None else: # Si existe lo cargo formato=sizex[3] # Calculo el ajuste temporal entregado if (actualizar): # Recojo los antiguos valores if (self.__sizex_memory==None): raise IOError,"La memoria de sizex necesita haber sido cargada previamente para poder ser actualizada" else: (ini,fin,crece_x,formato)=self.__sizex_memory # Actualizo los valores minX=calculadora(ini,self.viaje_temporal()) maxX=calculadora(fin,self.viaje_temporal()) tickX=coste_temporal(crece_x) else: # Establezlo los nuevos valores minX=calculadora(ini,self.viaje_temporal()) maxX=calculadora(fin,self.viaje_temporal()) tickX=coste_temporal(crece_x) # Almaceno los valores self._sizex=(minX,maxX,tickX,formato) self.__sizex_memory=(ini,fin,crece_x,formato) else: # Devuelve el valor return self._sizex # }}}1 # Tamaño de los datos en el eje y (comienza en, termina en) {{{1 ## Tamano de los datos en el eje Y ## \param self - ## \param minY Donde comienza el eje Y ## \param maxY Donde termina el eje Y ## \param decre_y Distancia entre dos valores consecutivos (entre textos) ## \param regilla_distancia Distancia entre las casillas de la regilla (entre marcas) def sizey(self,minY=None,maxY=None,decre_y=None,regilla_distancia=None): if ((minY!=None) and (maxY!=None)): # Calculo el decrecimiento de y si es necesario if (decre_y==None): if (maxY-minY<300): decre_y=-20 elif (maxY-minY<600): decre_y=-40 else: decre_y=-100 # Calculo el decrecimiento de y si es necesario if (regilla_distancia==None): if (maxY-minY<300): regilla_distancia=10 elif (maxY-minY<600): regilla_distancia=20 else: regilla_distancia=50 # Cargo los datos self._sizey=(minY,maxY,decre_y,regilla_distancia) else: return self._sizey # }}}1 # Regilla {{{1 ## Indica si poner la regilla o no ## \param self - ## \param set True/False para poner la regilla en la grafica o no def grid(self,set=None): if (set!=None): self._grid=set else: return self._grid # }}}1 # Margenes {{{1 ## Indica los margenes de la grafica con el papel ## \param self - ## \param a Margen inferior ## \param b Margen izquierdo ## \param c Margen superior ## \param d Margen derecho ## \attention Cada margen es dividido por el valor de inch() def margenes(self,a=None,b=None,c=None,d=None): if ((a!=None) and (b!=None) and (c!=None) and (d!=None)): self._margenes=(a,b,c,d) else: return self._margenes # }}}1 # Inch {{{1 ## Tamano de un inch en la grafica, se usa en el calculo de los margenes() ## \param self - ## \param inch Tamano en pixeles de un inch def inch(self,inch=None): if (inch!=None): self._inch=inch else: return self._inch # }}}1 # Leyenda Columnas {{{1 ## Numero de leyendas por fila ## \param self - ## \param leyendaColumnas Numero de leyendas por fila def leyendaColumnas(self,leyendaColumnas=None): if (leyendaColumnas!=None): self._leyendaColumnas=leyendaColumnas else: return self._leyendaColumnas # }}}1 # Directorio con las graficas {{{1 ## Directorio que contiene las graficas ## \param self - ## \param arg Directorio donde se pondran las graficas (debe ser una lista con rutas donde poner las graficas) def dirdib(self,arg=None): if (arg!=None): self._dirdib=arg return self._dirdib # }}}1 # Checker {{{1 ## Comprueba que el conjunto minimo de datos requeridos por la clase han sido declarados por el usuario: \n ## - outvar() ## \param self - def check(self): try: self._check("outvar") except Exception: raise IOError,"No se ha declarado el formato de salida: outpng, outjpg u outpdf" # Chequeo de la configuracion base (Clase herededa) self.check_default() # }}}1 # All config {{{1 ## \internal ## All config: lineas ## \param self - def allconfig(self): dict={} dict["lineas"]=self.tablalineas() return dict # }}}1 # Añadir una linea a la leyenda {{{1 ## Inserta una linea en la leyenda ## \param self - ## \param buscanombre Nombre de la linea def leyenda(self,buscanombre): # Inserta la entrada en la posicion 0 (al principio) self.__leyendas.insert(0,buscanombre) # }}}1 # Ecuación de la recta segun dos puntos dados {{{1 ## \internal ## Ecuacion de la recta segun dos puntos dados ## \param self - ## \param x1 Punto 1, posicion X ## \param y1 Punto 1, posicion Y ## \param x2 Punto 2, posicion X ## \param y2 Punto 2, posicion Y ## \param x Posicion X de la que deseo conocer su Y ## \return Devuelve el resultado de computar la cadena ## \warning Esta funcion solo funciona si se ha importado la libreria rpy que da conexion al lenguaje de programacion R def eq_recta(self,x1,y1,x2,y2,x): if (y1==r.NA): return r.NA elif (y2==r.NA): return r.NA else: r.assign("eq_recta_x1",x1) r.assign("eq_recta_y1",y1) r.assign("eq_recta_x2",x2) r.assign("eq_recta_y2",y2) r.assign("eq_recta_x",x) return r("(((eq_recta_y2-eq_recta_y1)/(eq_recta_x2-eq_recta_x1))*(eq_recta_x-eq_recta_x1))+eq_recta_y1") # }}}1 # Crear gráficas {{{1 # Crea una grafica con formato png {{{2 ## Crear una grafica con formato png ## \param self - ## \param fichero Fichero destino ## \param titulo Titulo de la grafica ## \param ancho Ancho de la grafica (pixeles) ## \param alto Alto de la grafica (pixeles) def outpng(self,fichero,titulo,ancho=None,alto=None): self.outvar(("png",fichero,titulo,ancho,alto)) # }}}2 # Crea una grafica con formato jpg {{{2 ## Crear una grafica con formato jpg ## \param self - ## \param fichero Fichero destino ## \param titulo Titulo de la grafica ## \param ancho Ancho de la grafica (pixeles) ## \param alto Alto de la grafica (pixeles) def outjpg(self,fichero,titulo,ancho=None,alto=None): self.outvar(("jpeg",fichero,titulo,ancho,alto)) # }}}2 # Crea una grafica con formato pdf {{{2 ## Crear una grafica con formato png ## \param self - ## \param fichero Fichero destino ## \param titulo Titulo de la grafica ## \param ancho Ancho de la grafica (pixeles) ## \param alto Alto de la grafica (pixeles) def outpdf(self,fichero,titulo,ancho=None,alto=None): self.outvar(("pdf",fichero,titulo,ancho,alto)) # }}}2 # Crea una gráfica {{{2 ## Crea una grafica ## \param self - ## \param tipo Tipo de grafica a generar (formato: png, jpg and pdf) ## \param fichero Fichero de destino de la grafica ## \param titulo Titulo de la grafica ## \param ancho Ancho de la grafica ## \param alto Alto de la grafica def out(self,tipo=None,fichero=None,titulo=None,ancho=None,alto=None): # Comienzo a trabajar self.debug("Generando salida para la grafica '%s':" % (self.internal_id())) # Extraigo el ancho y alto if ((ancho==None) or (alto==None)): (ancho,alto)=self.valor("resolution") # Compruebo la configuracion self.debug("Comprobando configuracion") self.check() # Compruebo el test de existencia self.debug("Realizando test de existencia") if (not self.dotest()): # Extraigo los datos del test (test_senal_nombre,test_minX,test_maxX,test_minY,test_maxY,linea)=self.valor("test") # Compruebo si es una linea if (linea): # Texto para una linea txt_linea="Nombre de linea" else: # Texto para una senal txt_linea="Nombre de senal" raise NoData,"No existen datos para la grafica: %s. Test: %s - X(%s,%s) Y(%s,%s) - Busqueda:%s" % (self.internal_id(),test_senal_nombre,test_minX,test_maxX,test_minY,test_maxY,txt_linea) # Precarga los datos (tipo,fichero,titulo,ancho,alto)=self.valor("outvar") # Titulo de la grafica if (titulo==None): titulo=fichero # Destinos de los resultados destinos=self.valor("dirdib") # Control de uso {{{3 if ((tipo==None) or (fichero==None)): # Termino con error raise IOError,"No se ha indicado un tipo o nombre de fichero a procesar en la funcion 'out'" # }}}3 # Aplico el filtro {{{3 fichero=filtrar_texto(fichero,self.viaje_temporal()) titulo=filtrar_texto(titulo,self.viaje_temporal()) # }}}3 # Recojo los parámetros para pintar la gráfica {{{3 # Configuración del tipo de fuente ("serif", "sans", "mono" y "symbol", ""=por defecto) fuente_familia="" # Configuracion de los tipo de fuente (1:plano, 2:bold, 3:italic, 4:bold italic y 5:symbol font, ""=por defecto) fuente_tipo_base="" fuente_tipo_ejes="" fuente_tipo_labels="" fuente_tipo_general="" fuente_tipo_subtitulos="" # Configuración del tamano de las fuentes fuente_izq=0.6 fuente_der=0.6 fuente_sup=0.6 fuente_inf=0.6 fuente_titulo=0.8 fuente_labels=0.6 fuente_eventos=0.6 fuente_puntos=0.6 # Posicion del texto texto_punto_maximo=3 texto_punto_minimo=-3 texto_punto_otro=0 # Calculo los datos del eje X sizex=self.valor("sizex") minX=sizex[0] maxX=sizex[1] tickX=sizex[2] formatoX=sizex[3] # Indico que los tickX sean de 366 días en el caso de que los ticks # se pongan a 365 días así obviamos los años bisiestos if (tickX==365*3600*24): # Añado un día más tickX=tickX+3600*24 # Calculo los Tamaño eje y sizey=self.valor("sizey") minY=sizey[0] maxY=sizey[1] tickY=sizey[2] # Regilla regilla_distancia=sizey[3] color_regilla="gray78" # Casillas del gráfico casillas=float(maxX-minX)/float(tickX) # Obtención de márgenes margenes=self.valor("margenes") margen_inf=margenes[0] margen_izq=margenes[1] margen_sup=margenes[2] margen_der=margenes[3] # Cargo el nombre de los ejes izquierdo e inferior texto_eje_izquierdo="" texto_eje_inferior="" for axis in self.axis(): if ((axis[0][0]==':') and (axis[0][-1]==':')): mostrar=("texto" in axis[0][1:-1].split("+")) if (mostrar and (axis[1]=="izq")): texto_eje_izquierdo=axis[2] if (mostrar and (axis[1]=="inf")): texto_eje_inferior=axis[2] # Posicion de inicio de los eventos eventoPosicion=maxY eventoCrece=-float(maxY-minY)/float(alto-margen_inf+margen_sup)*self.valor("eventoCrece") eventoTexto=float(maxY-minY)/float(alto-margen_inf+margen_sup)*self.valor("eventoTexto") # Posición de la leyenda leyendaPosicion=minY leyendaCrece=-float(maxY-minY)/float(alto-margen_inf+margen_sup)*self.valor("leyendaCrece") leyendaColumnas=self.valor("leyendaColumnas") # Pixeles por inch inch=self.valor("inch") # Fecha de inicio ini=datetime.datetime.fromtimestamp(minX) tupla=ini.timetuple() ini_epoch=time.mktime(tupla) r("fecha_ini<-as.POSIXlt(strptime(\"%s-%s-%s %s:%s:%s\",\"%%Y-%%m-%%d %%H:%%M:%%S\"))" % (tupla[0],tupla[1],tupla[2],tupla[3],tupla[4],tupla[5])) # Fecha de fin fin=datetime.datetime.fromtimestamp(maxX) tupla=fin.timetuple() fin_epoch=time.mktime(tupla) r("fecha_fin<-as.POSIXlt(strptime(\"%s-%s-%s %s:%s:%s\",\"%%Y-%%m-%%d %%H:%%M:%%S\"))" % (tupla[0],tupla[1],tupla[2],tupla[3],tupla[4],tupla[5])) # Fecha de inicio extendida (para columna cero) ini_ext=datetime.datetime.fromtimestamp(minX-tickX) tupla=ini_ext.timetuple() r("fecha_ini_ext<-as.POSIXlt(strptime(\"%s-%s-%s %s:%s:%s\",\"%%Y-%%m-%%d %%H:%%M:%%S\"))" % (tupla[0],tupla[1],tupla[2],tupla[3],tupla[4],tupla[5])) # Fecha de fin extendida (para ultima columna) fin_ext=datetime.datetime.fromtimestamp(maxX+tickX) tupla=fin_ext.timetuple() r("fecha_fin_ext<-as.POSIXlt(strptime(\"%s-%s-%s %s:%s:%s\",\"%%Y-%%m-%%d %%H:%%M:%%S\"))" % (tupla[0],tupla[1],tupla[2],tupla[3],tupla[4],tupla[5])) # }}}3 # Abro el fichero de salida {{{3 self.debug("1: Iniciando fichero %s: %s [%sx%s]" % (tipo.upper(),fichero,ancho,alto)) r("%s(\"%s%s\",width=%s,height=%s)" % (tipo.lower(),destinos[0],fichero,ancho,alto)) self.fileR("%s%s" % (destinos[0],fichero)) self.debug(" eventoCrece:%s" % (eventoCrece)) self.debug(" eventoTexto:%s" % (eventoTexto)) # }}}3 # Calculo el ajuste perimetral {{{3 self.debug("2: Calculando ajuste perimetral") ancho_caja=ancho-margen_izq-margen_der-1 ancho_casilla=float(ancho_caja)/float(casillas+2) resolucion_recomendada=float(ancho_casilla)*float(casillas+2)+float(margen_izq)+float(margen_der)+1.0 valor_pixel=(float(casillas+2)*float(tickX))/float(ancho_caja) self.debug(" Casillas:%s" % (casillas)) self.debug(" Margen izq:%s" % (margen_izq)) self.debug(" Margen der:%s" % (margen_der)) self.debug(" Ancho caja:%s" % (ancho_caja)) self.debug(" Tick eje X:%s" % (tickX)) self.debug(" Ancho casilla:%s" % (ancho_casilla)) if (resolucion_recomendada!=ancho): self.debug(" Resolucion recomendada:%s <---" % (int(resolucion_recomendada))) self.debug(" Valor de cada pixel:%s" % (tiempo_str(valor_pixel))) # Reescribe el texto del eje inferior #texto_eje_inferior="%s (Valor de cada pixel: %s)" % (texto_eje_inferior,tiempo_str(valor_pixel,True)) texto_eje_inferior="%s" % (texto_eje_inferior) # }}}3 # Pinto la gráfica {{{3 self.debug("3: Generando graficas x(%s,%s) y(%s,%s)" % (ini,fin,minY,maxY)) # Doy parámetros a la ventana (PAR) {{{4 self.debug(" 1/8 PAR") # Parametros por defecto #r("par(mai=c(1.02,0.82,0.82,0.42))") #r("par(pin=c(10.086354,7.390788))") #r("par(plt=c(0.07809524,0.96000000,0.12750000,0.89750000))") # Parametros de configuracion r("par(mai=c(%s,%s,%s,%s)/%s)" % (margen_inf,margen_izq,margen_sup,margen_der,inch)) if (fuente_familia!=""): r("par(family=\"%s\")" % (fuente_familia)) if (fuente_tipo_base!=""): r("par(font=%s)" % (fuente_tipo_base)) if (fuente_tipo_ejes!=""): r("par(font.axis=%s)" % (fuente_tipo_ejes)) if (fuente_tipo_labels!=""): r("par(font.lab=%s)" % (fuente_tipo_labels)) if (fuente_tipo_general!=""): r("par(font.main=%s)" % (fuente_tipo_general)) if (fuente_tipo_subtitulos!=""): r("par(font.sub=%s)" % (fuente_tipo_subtitulos)) # }}}4 # Genero la ventana (PLOT+LABELS) {{{4 self.debug(" 2/8 PLOT+LABELS") # Anulo las columnas de autoajuste de R r("par(xaxs='i')") # Cargo el plot con LABEL para el eje Y / mgp=c(0.8,0.8,0) r("plot(c(fecha_ini_ext,fecha_fin),c(%s,%s),ylim=c(%s,%s),type='n',axes=FALSE,frame.plot=TRUE,cex.lab=%s,mgp=c(1.2,1.2,0),tck=-0.005,xlab=\"\",ylab=\"%s\",xaxt='n')" % (minY,maxY,minY,maxY,fuente_labels,texto_eje_izquierdo)) # Indico que el siguiente plot va anadido r("par(new=TRUE)") # Cargo el plot con LABEL para el eje X / mgp=c(0.4,0.4,0) r("plot(c(fecha_ini_ext,fecha_fin_ext),c(%s,%s),ylim=c(%s,%s),type='n',axes=FALSE,frame.plot=TRUE,cex.lab=%s,mgp=c(1.4,1.4,0),tck=-0.005,xlab=\"%s\",ylab=\"\",yaxt='n')" % (minY,maxY,minY,maxY,fuente_labels,texto_eje_inferior)) # }}}4 # Añado el título (TITLE) {{{4 self.debug(" 3/8 TITLE") r("title(\"%s\",cex.main=%s)" % (titulo,fuente_titulo)) # }}}4 # Añado la regilla (GRID) {{{4 self.debug(" 4/8 GRID") nx=casillas+1 desviacion=(int(nx)*tickX+minX-maxX)%tickX if (self.valor("grid")): r("abline(v=seq(%s,%s,len=%s),col=\"%s\",lty=5,lwd=NULL)" % (minX,maxX+desviacion,nx,color_regilla)) if ((minY>0) or (maxY<0)): ny=int(float(maxY-minY)/float(regilla_distancia)+1) r("abline(h=seq(%s,%s,len=%s),col=\"%s\",lty=5,lwd=NULL)" % (minY,maxY,ny,color_regilla)) else: ny_superior=int(float(maxY-0)/float(regilla_distancia)+1) ny_inferior=int(float(0-minY)/float(regilla_distancia)+1) r("abline(h=c(seq(%s,%s,len=%s),seq(%s,%s,len=%s)),col=\"%s\",lty=5,lwd=NULL)" % (minY,0,ny_inferior,0,maxY,ny_superior,color_regilla)) # }}}4 # Añado los ejes (AXIS) {{{4 self.debug(" 5/8 AXIS") # Pinto el eje inferior (horas) / mgp=(-0.3,-0.3,0) r("axis.POSIXct(1, at=seq(fecha_ini,fecha_fin+%s,by=%s), format=\"%s\",las=0,mgp=c(0.3,0.3,0),tck=-0.005,cex.axis=%s)" % (desviacion,tickX,formatoX,fuente_inf)) # Pinto los ejes derecho que tengamos for axis in self.axis(): if (axis[1]=="izq"): if ((axis[0][0]==':') and (axis[0][-1]==':')): mostrar=("escala" in axis[0][1:-1].split("+")) if (mostrar): # Pinto el eje izquiedo / mgp=c(0.2,0.2,0) if ((minY>0) or (maxY<0)): r("axis(2,c(%s,%s),at=c(seq(%s,%s,by=%s)),labels=c(seq(%s,%s,by=%s)),las=1,mgp=c(0.2,0.2,0),tck=-0.005,cex.axis=%s)" % (minY,maxY,minY,maxY,tickY,minY,maxY,tickY,fuente_izq)) else: r("axis(2,c(%s,%s),at=c(seq(%s,%s,by=%s),seq(%s,%s,by=%s)),labels=c(seq(%s,%s,by=%s),seq(%s,%s,by=%s)),las=1,mgp=c(0.2,0.2,0),tck=-0.005,cex.axis=%s)" % (minY,maxY,minY,0,tickY,0,maxY,tickY,minY,0,tickY,0,maxY,tickY,fuente_izq)) else: # Recoje los datos del eje (aid,aorilla,atexto,aposicion,acolor,atick,atransformador)=axis # Carga el transformador (aminY,amaxY,astep,alabelmin,alabelmax,alabelstep)=self._transformar(atransformador,minY,maxY,tickY) # Genera el eje r("axis(2,c(%s,%s),at=c(seq(%s,%s,by=%s)),labels=c(seq(%s,%s,by=%s)),las=1,mgp=c(%s,%s,0),tck=%s,cex.axis=%s,col=%s,col.axis=%s)" % (aminY,amaxY,aminY,amaxY,astep,alabelmin,alabelmax,alabelstep,aposicion,aposicion,atick,fuente_der,acolor,acolor)) elif (axis[1]=="der"): # Recoje los datos del eje (aid,aorilla,atexto,aposicion,acolor,atick,atransformador)=axis # Carga el transformador (aminY,amaxY,astep,alabelmin,alabelmax,alabelstep)=self._transformar(atransformador,minY,maxY,tickY) # Genera el eje r("axis(4,c(%s,%s),at=c(seq(%s,%s,by=%s)),labels=c(seq(%s,%s,by=%s)),las=1,mgp=c(%s,%s,0),tck=%s,cex.axis=%s,col=%s,col.axis=%s)" % (aminY,amaxY,aminY,amaxY,astep,alabelmin,alabelmax,alabelstep,aposicion,aposicion,atick,fuente_der,acolor,acolor)) elif (axis[1]=="sup"): # Recoje los datos del eje (aid,aorilla,atexto,aposicion,acolor,atick,aenlace)=axis # Carga el transformador (afechaini,afechafin,aini,acrece,astep)=aenlace # Creo los límites limini=calculadora(afechaini,self.viaje_temporal()) limfin=calculadora(afechafin,self.viaje_temporal()) limstep=calculadora(astep,self.viaje_temporal()) # Creo los nombres temp=limini labels="" # Para todo el array que he de crear while (temp<=limfin): # Creo el label if (type(aini)==type("a")): # Supongo que es un día de la semana for i in range(0,acrece): (aini,label)=siguientediasemana(aini) else: # Supongo que es un número label=aini aini=aini+acrece # Añado el elemento a la lista de labels if (labels==""): labels="\"%s\"" % (label) else: labels="%s,\"%s\"" % (labels,label) temp=temp+limstep # Genera el eje r("axis(3,c(fecha_ini,fecha_fin+%s),at=c(seq(%s,%s,by=%s)),labels=c(%s),las=1,mgp=c(%s,%s,0),tck=%s,cex.axis=%s,col=%s,col.axis=%s)" % (desviacion,limini,limfin,limstep,labels,aposicion,aposicion,atick,fuente_sup,acolor,acolor)) # Genero la limpieza del eje label="" for i in range(0,int(maxY-minY)/tickY): label="%s,\"\"" % (label) #r("axis(4,c(%s,%s),at=c(seq(%s,%s,by=%s)),labels=c(\"\"%s),las=1,mgp=c(0,0,0),tck=0,cex.axis=0.001)" % (minY,maxY,minY,maxY,tickY,label)) r("axis(4,c(%s,%s),at=c(seq(%s,%s,by=%s)),labels=c(\"\"%s),las=1,tck=0)" % (minY,maxY,minY,maxY,tickY,label)) # }}}4 # Añado las señales (SIGNAL) {{{4 self.debug(" 6/8 SIGNAL") lector=self.valor("lector") for senal in self.tablalineas(): # Descompongo la senal (nombre,(senalnombre,senaltipo),(linea_tipo,linea_argumento,color,grosor,tipo),filtro,leyenda)=senal if ((senaltipo=='a') or (senaltipo=='d')): solo_operaciones_digitales=(senaltipo=='d') # Proceso el calculo de la senal acumulador=self.calculadora_senales(senalnombre,solo_operaciones_digitales,ini_epoch,fin_epoch,casillas,minX,maxX,desviacion,minY,maxY,tickY) else: acumulador=None # Compruebo que hay datos para pintar if ((acumulador==None) and (linea_tipo!="evento") and (linea_tipo!="texto")): # Anotamos el error y seguimos self.debug(" No se pinta la linea por falta de datos en el acumulador") else: # Pintamos el gráfico (usando acumulador) # Decido el tipo lista_lineas=[] texto_punto=None if (linea_tipo=="texto"): # Recojo los datos (x,y)=linea_argumento (colorfg,colorbg)=color # Muestro el texto del evento r("text(%s,%s,\"%s\",col=\"%s\",cex=%s,adj=0)" % (calculadora(x,None),y,nombre,colorfg,grosor)) # Calculo la lista de eventos lista_lineas=None elif (linea_tipo=="escaleraFuturo"): # Escalera normal (entre A y B, el valor es A) tipol="s" elif (linea_tipo=="escaleraPasado"): # Escalera de pasado (entre A y B el valor es B) tipol="S" elif (linea_tipo=="lineal"): # Líneas tipol="l" elif (linea_tipo=="puntos"): # Puntos tipol="p" lista_lineas.append((acumulador,"1,pch=%s,bg=\"%s\"," % (tipo,color),grosor,color)) elif (linea_tipo=="evento"): # Evento: gradual(rango_inf,rango_sup) -> evento_gradual tipol="l" (colorEvento,colorLista,colorNegativo)=color # Muestro el texto del evento r("text(%s,%s,\"%s\",col=\"%s\",cex=%s,adj=0)" % (minX,eventoPosicion,nombre,colorEvento,fuente_eventos)) # Calculo la lista de eventos if (acumulador!=None): lista_lineas=self.eventualizar(acumulador,tipo,colorLista,colorNegativo,grosor,filtro,senalnombre,eventoPosicion-eventoTexto) if (lista_lineas==[]): lista_lineas=None else: lista_lineas=None # Actualiza la posicion del evento eventoPosicion=eventoPosicion+eventoCrece elif (linea_tipo=="max"): # Máximo: Calculo el nuevo plotx y ploty (extremos) tipol="p" (tipo1,tipo2,ponertexto)=tipo if (ponertexto): texto_punto="up" (acumulaout,acumulain)=filtro_limites(acumulador,'>',maxY) lista_lineas.append((acumulain,"1,pch=%s,bg=\"%s\"," % (tipo1,color),grosor,color)) lista_lineas.append((acumulaout,"1,pch=%s,bg=\"%s\"," % (tipo2,color),grosor,color)) elif (linea_tipo=="min"): # Mínimo: Calculo el nuevo plotx y ploty (extremos) tipol="p" (tipo1,tipo2,ponertexto)=tipo if (ponertexto): texto_punto="down" (acumulaout,acumulain)=filtro_limites(acumulador,'<',minY) lista_lineas.append((acumulain,"1,pch=%s,bg=\"%s\"," % (tipo1,color),grosor,color)) lista_lineas.append((acumulaout,"1,pch=%s,bg=\"%s\"," % (tipo2,color),grosor,color)) elif (linea_tipo=="med"): # Media: Calculo el nuevo plotx y ploty (extremos) tipol="p" (tipo1,ponertexto)=tipo if (ponertexto): texto_punto="down" lista_lineas.append((acumulador,"1,pch=%s,bg=\"%s\"," % (tipo1,color),grosor,color)) else: # Por defecto se usa la línea normal tipol="l" # Si la lista de líneas no ha sido alterada (sigue vacía) if (lista_lineas==[]): lista_lineas.append((acumulador,tipo,grosor,color)) elif (lista_lineas==None): lista_lineas=[] # Para cada línea a pintar for senal in lista_lineas: # Obtengo los datos (acumulador,tipo,grosor,color)=senal if ((acumulador!=None) and (acumulador!=[])): # Inserto los textos if (texto_punto!=None): if (texto_punto=="up"): incremento=texto_punto_maximo elif (texto_punto=="down"): incremento=texto_punto_minimo else: incremento=texto_punto_otro # Pinto el texto y reviso los límites del acumulador en caso de que se salga de la pantalla (corrijo el ejeY) new_acumulador=[] for dato in acumulador: if (dato[1]>maxY): new_acumulador.append((dato[0],maxY)) posY=maxY elif (dato[1]