2. Tu primera herramienta

Introducción

Un script R para Processing R Provider no es diferente que un script normal de R. Las pequeñas diferencias entre ambos son simplemente estructuras lógicas para que el complemento en QGIS pueda interpretarlos correctamente. A continuación se listan las particularidades de los R scripts para QGIS:

  • Tienen la extensión .rsx y pueden estar acompañados de un fichero de ayuda de extensión .rsx.help.
  • Tienen por lo menos dos secciones importantes, un encabezado y un cuerpo, que se repasan en un sección posterior.
  • Tanto el .rsx como el .rsx.help deben estar en un directorio predefinido en la configuración del complemento.

Todas las instrucciones de R que se escriban en el script serán internamente reescritas en un Rscript (.r|.R) temporal que será ejecutado en la consola de R.

Estructura de un script

Un script R para processing tiene dos partes principales. Un encabezado que contiene la configuración de la herramienta; y un cuerpo que contiene el código R que ejecutará el proceso. El ejemplo que estudiaremos a continuación es tomado de los scripts incorporados en la instalación del complemento Processing R provider.

1##Example scripts=group
2##Scatterplot=name
3##Layer=vector
4##X=Field Layer
5##Y=Field Layer
6##output_plots_to_html
7
8# simple scatterplot
9plot(Layer[[X]], Layer[[Y]])

Las líneas que empiezan con doble signo numeral (##) conforman el encabezado del script. Por ejemplo: ##Layer=vector. Debe diferenciarse las líneas de encabezado (##) y de las líneas de comentarios (#) de modo que no causen confusión al algoritmo de Processing R Prvider. En tal caso, para los comentarios se recomienda usar un solo signo numeral # cuando este empieza en una línea nueva: Por ejemplo # simple scatterplot.

Las líneas de encabezado serán internamente convertidas en instrucciones de distintos tipos para que funcionen correctamente como una herramienta. Estas líneas condicionarán la estructura de la interfaz de la herramienta y el comportamiento de la misma.

Una línea de encabezado está conformada por dos partes: Identificador y Tipo.

1##nombre_parametro=tipo [valor_por_defecto/desde_variable]

...del script anterior podemos tomar cualquiera de las cinco primeras líneas como ejemplo, y veremos que tiene la estructura mencionada. Sin embargo algunos parámetros del encabezado pueden estar conformados simplemente por una etiqueta (por ejemplo ##output_plots_to_html) que se usan internamente para indicar comportamientos específicos de la herramienta. Más detalles se verá en una sección posterior.

Los comentarios y las demás instrucciones de R no forman parte del encabezado, por lo tanto serán consideradas como cuerpo del script. Estas líneas serán transcritas a un Rscript temporal, que será ejecutado línea por línea en la consola de R, mediante un subproceso stdin/stdout.

Tipos de parámetros

El encabezado puede contener distintos tipos de parámetros. Y de acuerdo con ellos la herramienta se comportará de una forma u otra:

Metadatos

Son parámetros que permiten organizar el script en el índice de processing. Entre ellos tenemos:

  • name Permite definir un nombre corto para el script
  • display_name Permite definir un nombre largo para el script. Este se mostrará en el índice y en la barra de título de la herramienta
  • group nombre del grupo al que pertenece el script. Permite organizar la nueva herramienta como parte de un grupo específico de herramientas.
1##Example scripts=group
2##Scatterplot=name
3##Scatterplot from selected fields=display_name

Parámetros de comportamiento

Sirven para definir el comportamiento general del script. Estos parámetros se configuran en el encabezado, pero el usuario no interactúa con estos. Entre ellos tenemos

  • load_raster_using_rgdal
  • load_vector_using_rgdal
  • pass_filenames
  • dont_load_any_packages
  • github_install
  • expression
  • output_plots_to_html

Parámetros de entrada

Estas líneas de parámetros especifican la apariencia de la interfaz del script. A partir de la estructura básica ##nombre_parametro=tipo [valor_por_defecto/desde_variable] podemos destacar que nombre_parámetro será el nombre del objeto que contenga esa variable en la sesión de R. Mientras que tipo será el tipo de datos de entrada, de los posibles tipos de entrada (vector, raster, point, number, string, boolean, Field).

Parámetro Valor por defecto Desde variable
vector Si No
raster Si No
point Si No
number Si No
string Si No
boolean Si No
Field No definida en vector
color Si No
range Si No
datetime Si No
Band No definida en raster
extent No No
crs No No
enum No No
enum literal No No

Parámetros de salida

Se trata de líneas que permiten definir el tipo de resultado que tendrá el script. Visualmente estos parámetros generan interfaces gráficas para guardar ficheros, mientras que internamente se traducen como instrucciones para escribir objetos R como ficheros.

La especificación de estos parámetros es la siguiente:

1##<Nombre_de_salida> =output <tipo>

Entre las salidas posibles tenemos las siguientes:

  • Salidas de capas: vector, raster, table
  • Salidas de valores: string number
  • Directorios y ficheros: folder y file. El el caso de file, se puede especificar una extensión para el fichero de salida. Por ejemplo csv.
👌 Tip!

Opcionalmente se puede usar la palabra clave noprompt al final de cada parámetro de salida, para especificar que no genere el widget en la interfaz de la herramienta.

Ejercicio

Imagina que tienes una capa de puntos de donde necesitas calcular distintas medidas de tendencia central espacial. Tus datos están cargados en la sesión de QGIS, pero QGIS no tiene una herramienta que te permita calcular puntos centrales a partir de tus datos.

El ejercicio consiste en hacer una herramienta para QGIS que haga el cálculo del punto central, con diferentes estadísticos. Por ejemplo, "Mean center", "Median center", "Central feature" o "Weighted mean center" (ver más detalles).

Tiempo de intentarlo, tómate un tiempo de 3 minutos para analizar el siguiente código de R. Las porciones de código entre los signos < y > corresponden a los nombres de variables de los parámetros de entrada. Los signos < y > no son necesarios en un script válido, solo se han usado para resaltar el ejemplo.

 1# Funciones y objetos para calcular punto medio ----
 2
 3  # < Aquí el código de 4 funciones de ayuda para el cálculo. >
 4  # < no son importantes por ahora. >
 5
 6# Calcular punto medio ----
 7  # extraer matriz de coordenadas de los puntos ----
 8  xy <- st_coordinates(< CAPA >)
 9  
10  # Control para el campo de pesos ----
11  < CAMPO DE PESOS > <- if(!is.null(< CAMPO DE PESOS >)) < CAPA >[[< CAMPO DE PESOS >]]
12 
13  # obtener el punto medio ----
14  mc <- switch(< CENTRO ESPACIAL >,
15               mean.center = mean_mc(),
16               weighted.mean.center = mean_mc(< CAMPO DE PESOS >),
17               median.center = median_mc(),
18               central.feature = central_feature(),
19               all = all_features()
20  )
21  
22  # Convertir a Simple Feature y asignar CRS ----
23  < PUNTO CENTRAL > <- st_as_sf(st_geometry(mc), crs = st_crs(< CAPA >))
24  
25  # Asignar nombres como atributos del punto medio ----
26  < PUNTO CENTRAL >$Name <- if(< CENTRO ESPACIAL > == "all") nms else nms[< CENTRO ESPACIAL >]
27

Cuando estés listo:

  • Crea un nuevo script para QGIS Processing desde :inline/Create New R Script.

  • Escribe el encabezado de tu script para QGIS Processing, basándote en el código de R que revisaste

    • Empieza asignando un nombre al script con el parámetro name
    • Agrega un grupo al script con el parámetro group
    • Opcionalmente, también se puede agregar el parámetro display_name para poner un título más explicativo para la herramienta.
    • Agrega un parámetro para una capa vectorial de tipo punto usando el parámetro vector point
    • Agrega una lista desplegable (enum literal) con las opciones de selección all;mean.center;weighted.mean.center;median.center;central.feature. Nótese que cada elemento de la lista está separado por un punto y coma (;).
    • Agrega un parámetro para campo de pesos opcional que se despliegue desde la capa vectorial, mediante el parámetro Field seguido del nombre de la variable que asignaste en el parámetro de la capa de entrada.
    • Agrega el nombre de la capa de saluda usando el parámetro output vector.
  • Copia y pega el código R que te mostramos a continuación, en tu nuevo script:

    Clic aquí para ver el código completo y funcional de este mismo ejercicio.
     1# Funciones y objetos para calcular punto medio ----
     2nms <- c(mean.center = "Mean center", 
     3         median.center = "Median center", 
     4         central.feature = "Central feature", 
     5         weighted.mean.center = "Weighted mean center")
     6  
     7mean_mc <- function(w = NULL){
     8  if(is.null(w) && Centro_espacial == "weighted.mean.center")
     9    warning("Weights field is null. Mean center instead!")
    10    
    11  if(!is.null(w)) {
    12    m <- apply(xy, 2, weighted.mean, w = w)
    13  } else {m <- apply(xy, 2, mean)}
    14  st_point(m)
    15  }
    16  
    17median_mc <- function() st_point(apply(xy, 2, median))
    18  
    19central_feature <- function(){
    20  d <- st_distance(Capa)
    21  d <- apply(d, 1, sum)
    22  st_point(xy[which.min(d),])
    23}
    24  
    25all_features <- function(){
    26  if(!is.null(Campo_de_pesos))
    27    st_sfc(mean_mc(), median_mc(), central_feature(), mean_mc(Campo_de_pesos))
    28  else 
    29    st_sfc(mean_mc(), median_mc(), central_feature())
    30}
    31  
    32# Calcular punto medio ----
    33  # extraer matriz de coordenadas de los puntos ----
    34  xy <- st_coordinates(Capa)
    35  # Control para el campo de pesos ----
    36  Campo_de_pesos <- if(!is.null(Campo_de_pesos)) Capa[[Campo_de_pesos]]
    37  # obtener el punto medio ----
    38  mc <- switch(Centro_espacial,
    39               mean.center = mean_mc(),
    40               weighted.mean.center = mean_mc(Campo_de_pesos),
    41               median.center = median_mc(),
    42               central.feature = central_feature(),
    43               all = all_features()
    44  )
    45  # Convertir a Simple Feature y asignar CRS ----
    46  Punto_central <- st_as_sf(st_geometry(mc), crs = st_crs(Capa))
    47  # Asignar nombres como atributos del punto medio ----
    48  Punto_central$Name <- if(Centro_espacial == "all") nms else nms[Centro_espacial]
    
  • Finalmente guarda tu script en el directorio de scripts definido en la configuración del complemento.

🤞 Ayuda

El contenido a continuación ha sido ocultado intencionalmente. Despliégalo solo si sientes que no puedes realizar el ejercicio por tu cuenta.

Haz clic para mostrar el contenido de ayuda.
 1##Taller UseR!2022=group
 2##centrality=name
 3##Centralidad espacial=display_name
 4##Capa=vector point
 5##Centro_espacial=enum literal  all
 6##Campo_de_pesos=optional field Capa
 7##Punto_central=output vector
 8
 9# FUNCIONES Y OBJETOS AUXILIARES PARA CALCULAR PUNTO MEDIO ----
10nms <- c(mean.center = "Mean center", 
11         median.center = "Median center", 
12         central.feature = "Central feature", 
13         weighted.mean.center = "Weighted mean center")
14
15mean_mc <- function(w = NULL){
16    if(is.null(w) && Centro_espacial == "weighted.mean.center")
17        warning("Weights field is null. Mean center instead!")
18    
19    if(!is.null(w)) {
20        m <- apply(xy, 2, weighted.mean, w = w)
21    } else {m <- apply(xy, 2, mean)}
22    st_point(m)
23}
24
25median_mc <- function() st_point(apply(xy, 2, median))
26
27central_feature <- function(){
28    d <- st_distance(Capa)
29    d <- apply(d, 1, sum)
30    st_point(xy[which.min(d),])
31}
32
33all_features <- function(){
34    if(!is.null(Campo_de_pesos))
35        st_sfc(mean_mc(), median_mc(), central_feature(), mean_mc(Campo_de_pesos))
36    else 
37        st_sfc(mean_mc(), median_mc(), central_feature())
38}
39
40# CALCULAR PUNTO MEDIO ----
41# extraer matriz de coordenadas de los puntos ----
42xy <- st_coordinates(Capa)
43
44# Control para el campo de pesos ----
45Campo_de_pesos <- if(!is.null(Campo_de_pesos)) Capa[[Campo_de_pesos]]
46
47# obtener el punto medio ----
48mc <- switch(Centro_espacial,
49             mean.center = mean_mc(),
50             weighted.mean.center = mean_mc(Campo_de_pesos),
51             median.center = median_mc(),
52             central.feature = central_feature(),
53             all = all_features()
54)
55
56# Convertir a Simple Feature y asignar CRS ----
57Punto_central <- st_as_sf(st_geometry(mc), crs = st_crs(Capa))
58
59# Asignar nombres como atributos del punto medio ----
60Punto_central$Name <- if(Centro_espacial == "all") nms else nms[Centro_espacial]
61

Traducciones: