5 Creando mis primeras funciones

Instructora: Joselyn Chávez

29 de octubre de 2024

5.1 Diapositivas

5.2 Nombre de la función

  • Cortos pero descriptivos
  • Recomendable: Separar las palabras con _
  • Establecer una palabra en común al inicio para familias de funciones
use_bioc_citation() # es mejor que

citation()
bioc_cit()
usebioccitation()
useBiocCitation()
use.bioc.citation()

5.3 Estructura de la función

  • Indentar las líneas de código.
  • Agregar comentarios para separar/describir las secciones importantes.
  • Usar la sintaxis paquete::funcion() cuando hacemos llamado a funciones de otros paquetes.
usethis::use_r("subset_heatmap")

Generemos el código de manera regular.

Simulemos una matriz con diversas mediciones y grafiquemos los datos en un heatmap.

mi_matriz <- matrix(rnorm(100), nrow = 10)
rownames(mi_matriz) <- paste0("medicion_",letters[1:10])
colnames(mi_matriz) <- paste0("grupo_",letters[1:10])

library(ComplexHeatmap)

Heatmap(mi_matriz,
        cluster_columns = FALSE,
        heatmap_legend_param = list(title = "valores"))

Escribamos una función que permita seleccionar algunos grupos de interés y genere el heatmap.

No la mejor opción:

library(ComplexHeatmap)

subset_heatmap <- function(x,mediciones=NULL,grupos=NULL) {
x_subset <- x[mediciones,grupos]
Heatmap(mi_matriz,
        cluster_columns=FALSE,
        heatmap_legend_param=list(title="valores"))
}

Un poco mejor:

library(ComplexHeatmap)
subset_heatmap <- function(x, mediciones = NULL, 
                           grupos = NULL) {
    x_subset <- x[mediciones,grupos]
    Heatmap(mi_matriz,
            cluster_columns = FALSE,
            heatmap_legend_param = list(title = "valores"))
}

Mucho mejor:

subset_heatmap <- function(x, mediciones = NULL, 
                           grupos = NULL) {
    # subset matrix
    x_subset <- x[mediciones, grupos]
    
    # plot heatmap
    ComplexHeatmap::Heatmap(
      x_subset,
      cluster_columns = FALSE,
      heatmap_legend_param = list(title = "valores"))
}

Ejecutemos la función:

subset_heatmap(
  mi_matriz,
  mediciones = c("medicion_a", "medicion_b", "medicion_c"),
  grupos = c("grupo_d","grupo_e","grupo_f"))

5.4 ¡Tu turno!

Escribe una función que:

  • Filtre la matriz y mantenga sólo los valores por encima de cierto valor.
  • Genere el heatmap filtrado.

Recuerda seguir las recomendaciones para escribir funciones.

5.5 Argumentos

  • Los argumentos deben tener un nombre descriptivo y bien documentado.

No la mejor opción:

subset_heatmap <- function(x, m, g) {

  # subset matrix
    x_subset <- x[mediciones, grupos]
}

Una mejor opción:

subset_heatmap <- function(x, mediciones, 
                           grupos) {
    # subset matrix
    x_subset <- x[mediciones, grupos]
    
    # plot heatmap
    ComplexHeatmap::Heatmap(
      x_subset,
      cluster_columns = FALSE,
      heatmap_legend_param = list(title = "valores"))
}
  • Los argumentos generalmente deben tener valores default.
subset_heatmap <- function(x, mediciones = NULL, 
                           grupos = NULL, return_plot = TRUE) {
    # subset matrix
    x_subset <- x[mediciones, grupos]
    
    # plot heatmap
    ComplexHeatmap::Heatmap(
      x_subset,
      cluster_columns = FALSE,
      heatmap_legend_param = list(title = "valores"))
}
  • Evalúa la validez de los argumentos
subset_heatmap <- function(x, mediciones = NULL, 
                           grupos = NULL, return_plot = TRUE) {
  
    stopifnot(is.matrix(x))
  
    # subset matrix
    x_subset <- x[mediciones, grupos]
    
    # plot heatmap
    heatmap <- ComplexHeatmap::Heatmap(
      x_subset,
      cluster_columns = FALSE,
      heatmap_legend_param = list(title = "valores"))
    
    if(return_plot == TRUE) {return(heatmap)}
}

Este código no debe funcionar:

subset_heatmap(
    as.data.frame(mi_matriz),
    mediciones = c("medicion_a", "medicion_b", "medicion_c"),
    grupos = c("grupo_d","grupo_e","grupo_f"))

Nota: Usa las funciones is() para evaluar la clase de los objects, no uses class() == ni class() !=.

  • Proporciona pistas para entender los errores.
subset_heatmap <- function(x, mediciones = NULL, 
                           grupos = NULL, return_plot = TRUE) {
  
    if(!is.matrix(x)) {stop("x debe ser una matriz")}
  
    # subset matrix
    x_subset <- x[mediciones, grupos]
    
    # plot heatmap
    heatmap <- ComplexHeatmap::Heatmap(
      x_subset,
      cluster_columns = FALSE,
      heatmap_legend_param = list(title = "valores"))
    
    if(return_plot == TRUE) {return(heatmap)}
}

Este código debe dar un error, más un mensaje de ayuda.

subset_heatmap(
    as.data.frame(mi_matriz),
    mediciones = c("medicion_a", "medicion_b", "medicion_c"),
    grupos = c("grupo_d","grupo_e","grupo_f"))

5.6 ¡Tu turno!

  • Agrega pasos de evaluación para los otros argumentos de la función.
  • Incluye mensajes de ayuda cuando el formato de los argumentos no es el esperado.

5.7 Indentación

  • Usa 4 espacios para indentar, evita los tabs.
  • No uses líneas de más de 80 caracteres.

5.8 Uso de espacios

  • Usa un espacio después de la coma: a, b, c.
  • Usa espacio después de operadores binarios: a == b.

5.9 Comentarios

  • Usa “##” para comenzar las líneas de comentarios.
  • Los comentarios deben usarse como notas y documentación solamente.
  • No dejes código comentado que no se va a usar.
  • Evita los TODO’s comentados cuando vayas a publicar el paquete.

5.10 Mensajes para el usuario

Si deseas imprimir mensajes para el usuario, como el progreso del análisis en la función o advertir sobre los valores de los argumentos, evita el uso de cat(), mejor usa:

  • message() comunica mensajes diagnóstico, como el progreso de la función.
message("Paso 1: completo")
## Paso 1: completo
  • warning() comunica situaciones inusuales que pueden ser manejadas por tu código.
warning("El número de elementos esperados es mayor a uno, se tomará el primer valor del vector")
## Warning: El número de elementos esperados es mayor a uno, se tomará
## el primer valor del vector
  • stop() indica una condición errónea.
stop("x debe ser numérico")