library(tidyverse)
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.path = "man/figures/README-",
  out.width = "100%"
)
set.seed(0)

Instalación

El paquete se puede instalar desde GitHub:

# install.packages("devtools")
devtools::install_github("jumanbar/siabox", build_vignettes = TRUE)

Nota: se puede instalar con la opción build_vignettes = FALSE, pero en ese caso no tendrá acceso a las viñetas, que son parte importante de la documentación. De todas formas, puede ver las viñetas en formato markdown, en la carpeta vignettes

Ver actualizaciones: log.md

Introducción

Se trata de un paquete pensado para trabajar con datos del SIA, especialmente en realizar gráficos, tablas e informes, usando datos incluidos en el mismo, o descargados desde iSIA.

Incluye varias tablas (data.frames) con datos tomados directamente del SIA, que sirven para correr ejemplos. En principio, si estos ejemplos funcionan en los datos contenidos en el paquete, también lo harán con datos nuevos del SIA y, por lo tanto, servirán para confeccionar informes automatizados.

Para usar el paquete se recomienda el uso de tidyverse en general (algunos esos paquetes son necesarios, de hecho). Además, los ejemplos mostrados aquí y en las distintas viñetas, usan funciones de tidyverse extensivamente.

En este documento se muestra lo básico del paquete. Se recomienda visitar las viñetas para profundizar:

vignette('graficos', package = 'siabox')
vignette('datos-incluidos', package = 'siabox')

Modo de uso

La idea es que el paquete trabaje en conjunto con la aplicación iSIA. En la práctica, el flujo puede tomar dos caminos:

  1. Se puede trabajar con datos extraidos de la aplicación iSIA en el momento.

  2. Se pueden usar datos que ya están en el paquete para analizar o hacer pruebas. El código así generado luego se puede utilizar para datos descargados desde iSIA.

Uno de los objetivos más importantes es que las herramientas del paquete sirvan para elaborar informes automatizados, mediante Rmarkdown. Hay un ejemplo (en construcción) con datos del programa Laguna Merín para tomar de referencia:

siabox::demo_lm()      # HTML
siabox::demo_lm('pdf') # PDF
siabox::demo_lm('doc') # DOC

Nota: si no funciona el ejemplo, siempre se pueden acceder a los archivos del repositorio, en la carpeta inst/examples

Con extracciones de iSIA

El siguiente es un ejemplo que usa datos extraídos de iSIA (formato 'largo'):

Una vez que descargamos el archivo desde iSIA, que se podría llamar, por ejemplo extraccion_20210630.rds, la forma de importarlos es con la función readRDS de R:

d <- readRDS("extraccion_20210630.rds")

Afortunadamente, no es necesario descargar estos datos en particular, ya que se encuentran en el paquete mismo. Vamos a crear una data.frame llamada d, usando la función filtrar_datos, que simula los filtros de iSIA:

library(tidyverse)
library(siabox)
d <- filtrar_datos(datos_sia, 
                   id_programa = 10L,
                   id_matriz = 6L,
                   rango_fechas = c('2019-01-01', '2019-12-31'),
                   tipo_punto_id = 1L, # 1 = Superficie; 2 = Fondo
                   id_parametro = c(2098, 2101, 2099, 2097, 2102, 2032,
                                    2018, 2090, 2021, 2017))

Se puede, por ejemplo, crear un gráfico de IET como el siguiente:

d %>% iet_tabla() %>% g_iet_pto()

Nota: estos datos fueron extraídos en noviembre de 2020, por lo que cualquier corrección o inclusión de datos que se haya hecho desde esa fecha hasta hoy, estarán ausentes.

En este caso se están usando las funciones iet_tabla y g_iet_pto del paquete. Aquí no se muestra, pero el paquete incluye una tercer función relacionada: iet.

Hay otros cálculos frecuentes que ya están incluidos en el paquete. Uno de ellos es el del Amoníaco Libre. Para una tabla de datos como la mencionada, la función amoniaco_libre_add permite agregar al parámetro NH3L (siempre y cuando hayan datos de T, pH y NH4):

# Agregar NH3L:
d <- amoniaco_libre_add(d)

# Se pueden ver algunos valores aquí:
d %>%
  filter(id_parametro == 2091) %>%
  select(codigo_pto, fecha_muestra, param, valor)

# Gráficos de nutrientes:
g_mes_pto_all(d, id_parametro = c(2098, 2101, 2099, 2097, 2102, 2091), ncol = 3)

Para ver detalles del cálculo en sí, ver ?amoniaco_libre.

Las etiquetas del gráfico se pueden mejorar aún con la función t_eti_add (ver viñeta 'gráficos').

El paquete cuenta con otras funciones listas para crear gráficos de informes: ver ?g_mes_pto o ?g_lon_pto para más ejemplos, pero se recomienda especialmente leer la viñeta 'graficos':

vignette('graficos', package = 'siabox')

Con datos incluidos en el paquete

El paquete viene con dos conjuntos de datos extraídos del SIA: ver ?datos_sia o ?datos_sia_sed para acceder a la documentación de estas tablas, con datos de aguas superficiales y de sedimentos, respectivamente.

Dichas tablas tienen todos los datos encontrados en SIA, a la fecha en que fueron extraidos, para todos los programas y parámetros disponibles. El objetivo de estas tablas es el de hacer pruebas, ejemplos y código que luego se puede aplicar a datos más actualizados (extraídos con iSIA).

Dado que se trata de tablas de gran tamaño (datos_sia tiene r nrow(datos_sia) filas y r ncol(datos_sia) columnas), es conveniente filtrarlos según el subconjunto de interés. Para esto es que el paquete cuenta con la función filtrar_datos, que replica las funcionalidades de filtro de iSIA, como ya se mencionó.

El siguiente es un ejemplo datos similares al ejemplo usado anteriormente (la diferencia es el rango de fechas):

d <- filtrar_datos(datos_sia, 
                   id_programa = 10L, 
                   id_matriz = 6L,
                   rango_fechas = c('2015-01-01', '2019-12-31'),
                   tipo_punto_id = 1L,
                   id_parametro = c(2098, 2101, 2099, 2097, 2102, 2032,
                                    2018, 2090, 2021, 2017))

g_lon_pto(d, 2098, anio = 2019)

La idea de replicar la funcionalidad de iSIA es de poder hacer pruebas antes de descargar datos, incluso pensando en la automatización de reportes.

Para profundizar sobre los contenidos y usos de los datos incluidos en el paquete, se recomienda visitar la viñeta datos-incluidos:

vignette('datos-incluidos', package = 'siabox')

Cálculos útiles

El paquete cuenta con algunas funciones relativamente simples que son de ayuda para realizar cálculos frecuentes: iet, iet_tabla, amoniaco_libre, amoniaco_libre_add, media_geom, raiz y tsummary .

Índice de estado trófico (IET)

La función iet calcula el IET para valores de Fósforo Total (en microgramos por litro):

iet(c(25, 50, 75, 250))
PT <- seq(0, 300, by=5)
plot(PT, iet(PT), ylab = "IET", xlab = "PT (ug/L)", pch = 20)

Tabla con categorías de IET

Agrupa valores de IET por estación de monitoreo (codigo_pto), asignando categorías a los valores según su IET (Oligotrófico, Mesotrófico, etc...). Usa la media geométrica para agrupar los valores encontrados.

d <- filtrar_datos(datos_sia, 
                   id_programa = 10L, 
                   id_matriz = 6L,
                   rango_fechas = c('2019-01-01', '2019-12-31'),
                   tipo_punto_id = 1L,
                   id_parametro = 2098)
iet_tabla(d)

La función puede, además, agrupar por otras columnas, como por ejemplo, mes, año, etc...

d <- filtrar_datos(datos_sia, 
                   id_programa = 10L, 
                   id_matriz = 6L,
                   rango_fechas = c('2017-01-01', '2019-12-31'),
                   tipo_punto_id = 1L,
                   id_parametro = 2098)

IET x Estación x Mes:

iet_tabla(d, mes)

IET x Estación x Año x Mes:

iet_tabla(d, anio, mes)

Esta función se puede combinar con herramientas de dplyr fácilmente (en el ejemplo también se usa tsummary, de siabox):

iet_tabla(d, anio) %>%
  group_by(anio, categ) %>%
  tsummary(IET)

Estadísticas resumen

La función tsummary, usada en el ejemplo anterior, es una ayuda para obtener cálculos similares a los de summary, que permite agrupar según distintas variables (i.e.: columnas). Hay que tener en cuenta que sólamente puede hacer cálculos con variables numéricas.

Uso de tsummary para resumir datos de Clorofila-A en el programa Río Cuareim:

datos_sia %>% 
  filter(param == 'Clo_a', id_programa == 5) %>% 
  tsummary(valor)

Lo mismo, pero agrupando por estación de monitoreo:

datos_sia %>% 
  filter(id_parametro == 2000, id_programa == 5) %>% 
  group_by(codigo_pto) %>% 
  tsummary(valor)

Notas: el primer ejemplo y el segundo difieren en 2 aspectos:

  • el agrupamiento (con la función group_by, de dplyr) y

  • se filtra parámetro por nombre y luego por id (id_parametro).

Parámetros y otras categorías importantes (programas, estaciones, unidades, ...), tienen varias formas de ser identificados, siendo id la única permanente.

Otra función incluida en el paquete es raiz, que calcula la raíz enésima de un valor dado, incluso cuando ese valor es negativo (en cuyo caso, n debe ser impar). La misma es usada, a su vez, por media_geom (la Media Geométrica).

Cálculo de la raíz enésima:

tibble(x = c(4, -4, 4, -4), n = c(2, 2, 3, 3)) %>%
  mutate(raiz(x, n), x ^ (1 / n), abs(x) ^ (1 / n))

Cálculo de una media geométrica, usando valores aleatorios:

x <- rnorm(100, 8)
mean(x)
media_geom(x)

Construcción colectiva

Al momento del lanzamiento de este paquete, el universo de funciones será limitado, naturalmente. Por esta razón es de interés considerar posibles aportes de usaries a la construcción del mismo.

Para esto hay que tener en cuenta que todo lo que se incorpore al paquete será en forma de tablas o funciones: código que sirva para un rango de situaciones.

Para aportar esta construcción, pueden haber infinidad de formas, desde comentarios sobre problemas, mejoras, etc, hasta aportes de código original. En este último caso me quiero concentrar. En principio se pueden imaginar dos formas 'extremas':

El segundo caso es un ideal, seguramente poco realista, aunque deseable. A continuación paso a describir algunas posibles formas de contribuir, que estarían entre estos extremos.

Enviar código 'suelto'

Este caso sería simplemente enviando código que creado para hacer una gráfica o tabla, por ejemplo. Hay algunos detalles a tener en cuenta:

En primer lugar, el contexto. Para qué se utilizaría? En qué situaciones? Es para algún programa de monitoreo en particular? Etc. Es deseable que estas cosas se expresen con la mayor claridad posible.

También es importante estar atento a que lo enviado sea suficiente para tener un ejemplo mínimo reproducible, lo cual suele implicar datos, código, etc. En otras palabras: todo lo necesario para que otra persona pueda obtener exactamente el mismo resultado.

Contribuir a la documentación

No solamente el código ejecutable aporta, sino que mejoras a la documentación siempre son bienvenidas. Esto puede ser con sugerencias a lás páginas de ayuda de las funciones o datos, sugerencias o texto para incluir en el README.Rmd del paquete (el documento que está leyendo en este momento), o incluso en las viñetas y ejemplos de informes automatizados.

Crear una función nueva

Las funciones implican un incremento de abstracción en relación a lo que es el código suelto. Y además requiere pensar situaciones diferentes a las que llevaron a la creación del código original. Esto puede ser complejo, especialmente si se trata de creación de gráficos, aunque no necesariamente dificil.

Algunas preguntas importantes a tener en cuenta son:

Modificar una función existente

Pueden ser muy importantes aportes para mejorar las funciones incluidas en el paquete. Para esto será necesario acceder al cuerpo de la función (i.e.: el ćodigo que tiene adentro) y crear un ambiente de desarrollo (es decir: reproducir todos los objetos que existen al momento en que se ejecuta la función, de forma que se puedan hacer pruebas y experimentos).

Para obtener el código de una función, se puede simplemente escibir el nombre de la función en la consola (sin paréntesis al final!) y dar enter:

iet

Otra opción es usar edit:

edit(iet)

Incluso se puede ir directametne al código en el repositorio de Github (subcarpeta 'R'): https://github.com/jumanbar/siabox/blob/master/R/informes.R

Para lograr un ambiente de desarrollo, usualmente es necesario tener definidos objetos con los nombres de los argumentos, en nuestro espacio de trabajo. En el caso de iet hay un único argumento, PT, entonces con definir un vector numérico alcanza:

PT <- c(23, 44, 2.5)
# Esta línea es equivalente a todo el cuerpo de la función:
10 * (6 - (0.42 - 0.36 * log(PT)) / log(2)) - 20

Generalmente las funciones que nos interesará modificar son mucho más complejas (mirar g_mes_pto o g_lon_pto por ejemplo). Al método de crear objetos con los nombres de los argumentos, que funciona perfectamente, se suman alternativas como debug:

debug(g_lon_pto)
g_lon_pto(d, 2098)

El uso de debug es una opción bastante práctica y poderosa, pero no es recomendable si no se conoce el procedimiento! (siepre se puede aprender; dejamos aquí un video instructivo)

Código listo para incorporar

Este caso aplica para les desarrolladores más avanzados. Algunas consideraciones importantes:

  1. Al incluir, en el cuerpo de una función del paquete, funciones de paquetes externos, se debe evitar el uso de require o library. Usar en cambio los operadores :: o :::.

Ejemplo: dplyr::filter. Eso evita afectar el ambiente de trabajo del usuario final (o sea, no hay que cargar todo el paquete siabox para usar una única función; tsummary es un ejemplo de función útil en sí misma). En este paquete las excepciones son ggplot2 y %>%, ya que de otra forma el código se vuelve muy engorroso rápidamente.

  1. En el caso de tablas internas de siabox, es preciso usar ::. Por ejemplo, la tabla sia_parametro es llamada siempre así: siabox::sia_parametro (por ejemplo, ver el codigo de unipar).

  2. La documentación es fundamental. El paquete roxygen2 facilita muchísimo esta tarea. En RStudio, el comando "Insert Roxygen Skeleton" (Ctrl+Alt+Shift+R) hace el camino más llano aún.

  3. Es parte de la documentación, pero merece un lugar aparte: crear ejemplos que funcionen e ilustren el rango de funcionalidades, es siempre un gran aporte y facilita mucho al aprendizaje de les usuaries.

Vías de comunicación

En un principio, recibiré contribuciones, críticas y comentarios al correo: juan.manuel.barreneche@ambiente.gub.uy. En principio es posible también usar Github para hacer aportes directamente desde allí, en el repositorio del paquete: https://github.com/jumanbar/siabox

Sobre el desarrollo de paquetes en general

(Sección que, al menos en parte, escribo para refrescar mi propia memoria.)

Este paquete se creó siguiendo de forma aproximada los consejos del libro R Packages de Hadley Wickham. El libro entero es importante para entender el desarrollo de paquetes (o la documentación original de CRAN), pero para referencia rápida de quien ya sabe la teoría y sólo tiene que recordar el flujo, ir directamente al capítulo 5: Fundamental development workflows.

Algunas notas:



jumanbar/siabox documentation built on April 25, 2022, 1:37 p.m.