Reutilizar diapositivas con Xaringan y Rmarkdown

Herramientas: rmarkdown, xaringan

TL;DR

cómo gestionar un proyecto para poder reutilizar contenido de diapositivas, imágenes y otros contenidos usando proyectos de R, el paquete here (para referenciar archivos dentro del proyecto y de forma independiente al ordenador o al SO) y el argumento child de los bloques de código de Rmarkdown.

Preámbulo

En los últimos meses he impartido varias charlas y asignaturas sobre visualización de datos. Todos los cursos son introductorios, por lo que hay muchos conceptos básicos que repito de curso a curso; por ejemplo, al tratar sobre la importancia de ver los datos (y no limitarnos a la información proporcionada por estadísticos de resumen) suelo usar el famoso cuarteto de Anscombe.

Cuarteto de Anscombe

Sin embargo, la duración de cada curso varía desde las cinco horas a los 3 créditos, por lo que en algunos casos puedo profundizar más que en otros. Cuando dispongo de más tiempo me gusta añadir también alguna diapo sobre el datasaurus de Alberto Cairo, e incluso alguna sobre el algoritmo creado por Justin Matejka y George Fitzmaurice: “Same Stats, Different Graphs: Generating Datasets with Varied Appearance and Identical Statistics through Simulated Annealing”.

El ya famoso datasaurus de Alberto Cairo

De tal forma que parto de una serie de conceptos y ejemplos principales que aparecen en prácticamente en todos los materiales que creo, mientras que otros los añado en aquellos cursos en los que dispongo de más tiempo para profundizar.

Además de los conceptos básicos propiamente dichos, también reutilizo otro tipo de recursos (especialmente imágenes con ejemplos), por lo que me interesa disponer de algún tipo de repositorio central, sin tener que andar creando copias del mismo archivo en distintas carpetas.

Por lo que al apartado técnico se refiere, hace unos años que utilizo el paquete de R xaringan para crear las presentaciones; este paquete combina la librería remark.js (para crear presentaciones HTML a partir de código markdown) con rmarkdown, por lo que además de todo lo que puede hacer remark, podemos incluir código R.

Aunque no todas las presentaciones que preparo se centran en enseñar código R (por lo que en principio no necesitaría Rmarkdown, y podría usar simplemente remark.js con markdown normal), el ecosistema de Rstudio, Rmarkdown/Knitr y Xaringan aporta una serie de funcionalidades que facilitan gestionar este tipo de proyectos.

Documentos hijos (child documents)

El paquete knitr, que se encarga de convertir los documentos .Rmd (que combinan lenguaje markdown con código ejecutable R —o de otros lenguajes—) en documentos .md (markdown plano) permite, entre otras cosas, combinar varios documentos .Rmd/.md en un único documento.

Para incrustar un documento externo tenemos que usar la opción child de los bloques de código R de Rmarkdown, por lo que mientras que los documentos externos pueden ser tanto .Rmd como .md (e incluso otros formatos), el documento principal tiene que ser .Rmd

La idea es crear las diapositivas en documentos independientes, e ir componiendo cada una de las presentaciones incrustando únicamente aquellas que necesitemos.

Ejemplo de organización de diapositivas y presentaciones

El sistema de documentos hijos puede llegar a ser muy versátil:

  • Podemos generar un archivo para cada diapositiva, o bien tener una serie de dispositivas en un único documento (por ejemplo, una secuencia de 4 pasos en los que añadimos un idea o ejemplo en cada paso).
  • La carga de archivos externos se puede teniendo en cuenta parámetros que hayamos definido para el documento, o incluso de forma condicional junto con la opción eval de los bloques de código R.
  • Otro posible uso consiste en crear varias presentaciones con el mismo contenido pero con diferentes estilos gráficos (por cuestiones de marca, por ejemplo).

Organización general del proyecto

El proyecto, o casi mejor dicho, el metaproyecto (que incluye materiales para varios cursos y asignaturas) parte de una carpeta principal y de un archivo de proyecto de Rstudio.

El archivo de proyecto es necesario para poder trabajar con la librería here. Esta librería permite compartir fácilmente proyectos de R en ordenadores con distinta estructura de carpetas o incluso distintos sistemas operativos, siempre que todos los archivos con los que vayamos a trabajar estén dentro de la carpeta principal.

In contrast to using setwd(), which is fragile and dependent on the way you organize your files, here uses the top-level directory of a project to easily build paths to files

En mi caso, la carpeta principal está en dropbox, y accedo al proyecto tanto desde ordenadores distintos (sobremesa y portátil) como desde SOs distintos (windows y linux), por lo que here es de gran ayuda.

A partir de la carpeta principal, la organización de los archivos en subcarpetas depende en gran medida de nuestras preferencias y forma de trabajo habitual. A modo de ejemplo, podemos crear una organización como esta:

    Proyecto
    │   presentacion_corta.Rmd
    │   presentacion_larga.Rmd    
    └───recursos
    │   └───imagenes
    │   │      ejemplo_anscombe.png
    │   │      ejemplo_datasaurio.png
    │   │      ...
    │   └───css
    │          mi_tema.css
    │          ...
    └───diapos
        └───marcas_y_canales
        │      marcas_graficas.Rmd
        │      canales_graficos.md
        │      ...
        └───problemas_de_percepcion
               solapamiento_de_marcas.md
               escalas.Rmd
               ...

Algunas notas sobre los archivos con contenido

Dado que estamos diseñando un sistema para reutilizar diapositivas con Xaringan, hemos de pensar dónde colocaremos los delimitadores de cada diapositiva (---), en cada uno de los archivos

  • Cabeceras YAML: si tenemos definiciones distintas (YAML), la única que se aplica es la definida en el documento matriz (no hay herencia; por ejemplo, si el documento con el contenido de la diapositiva tiene una resolución de 4:3 y el documento matriz una de 16:9, la resolución que se aplica es esta última).
  • xaringanthemer: por el contrario, si aplicamos un mismo estilo de xaringanthemer con dos configuraciones distintas (por ejemplo, color de los encabezados), se mantiene el del documento original, no el del documento matriz. Por eso, es mejor no declarar ningún estilo en los documentos originales).
  • Nombres de los bloques de código: no puede haber bloques con el mismo id, aunque estén en documentos distintos. Los casos más habituales son:
    • xaringan crea por defecto un bloque setup al inicio del documento, por lo que nos encontraremos con un mensaje similar a este:
Error in parse_block(g[-1], g[1], params.src, markdown_mode) : 
  Duplicate chunk label 'setup', which has been used for the chunk:
  • debemos poner un nombre distinto a cada bloque que usemos en todos los documentos .Rmd; si los dejamos vación, recibirán los nombres por defecto unnamed-chunk-1, por lo que podemos generar conflictos al cargar bloques anónimos de distintos archivos.
  • Delimitadores de las diapositivas: ¿dónde incluimos los delimitadores de las diapositivas (---)? En principio pueden ir en el documento matriz o en los documentos de diapositivas; sin embargo, si cargamos varios archivos originales en una sola llamada del documento matriz (ver ejemplos más adelante) será necesario que el delimitador esté en los documentos originales, ya que no tenemos forma de intercalarlo.

Recomendación: incluir el delimitador de diapositiva al final de cada documento original.

Ejemplo

Contenido del archivo marcas_graficas.Rmd:

---
title: "Marcas gráficas"
subtitle: "Documentación"
author: "Mikel Madina"
output:
  xaringan::moon_reader:
    lib_dir: libs
    nature:
      ratio: 4:3
---
```{r setup_marcas_graficas, include=FALSE}
options(htmltools.dir.version = FALSE)
library(xaringanthemer)
style_mono_light(
  header_color = "red"
)
```
## Marcas gráficas diapo 1 --- ## Marcas gráficas diapo 2 ---

Contenido del archivo canales_graficos.Rmd:

---
title: "Canales gráficos"
subtitle: "Documentación"
author: "Mikel Madina"
output:
  xaringan::moon_reader:
    lib_dir: libs
    nature:
      ratio: 4:3
---
```{r setup_marcas_graficas, include=FALSE}
options(htmltools.dir.version = FALSE)
library(xaringanthemer)
style_mono_light(
  header_color = "red"
)
```
## Canales gráficos diapo 1
---

Pogamos que estamos trabajando en la presentación_corta.Rmd y queremos incrustar la(s) diapositivas de la carpeta marcas_y_canales. Podemos hacerlo de varias formas.

Un archivo en cada bloque.

La forma más simple de incluir documentos externos consiste en llamarlos uno a uno en bloques de código R:

```{r metodo_a, child = here('diapos','marcas_y_canales','marcas_graficas.Rmd')}
```

```{r metodo_a, child = here('diapos','marcas_y_canales','canales_graficos.Rmd')}
```

No he incluido un divisor (---) entre las dos llamadas a los documentos externos, ya que está incluido al final de cada uno de dichos documentos.

Varios archivos en un bloque.

También podemos incluir varios archivos externos en una única llamada; en este caso es necesario cada documento que vayamos a incluir tenga el divisor de diapositivas al inicio o al final del documento (pero no en los dos, ya que de esa forma se crearían diapositivas en blanco entre el contenido de un archivo y el del siguiente):

```{r metodo_a, child = c(here('diapos','marcas_y_canales','marcas_graficas.Rmd'), here('diapos','marcas_y_canales','marcas_graficas.Rmd'))}
```

También podemos crear vectores que recojan los nombres de archivo que queremos cargar

```{r include = FALSE}
diapos <- c(here('diapos','marcas_y_canales','marcas_graficas.Rmd'),  
here('diapos','marcas_y_canales','marcas_graficas.Rmd'))
```

```{r metodo_a, child = diapos}
```

Carga condicional

En un documento Rmarkdown los bloques de código R pueden ejecutarse de forma condicional, aprovechando la opción eval. Generalmente se suele indicar el valor TRUE o FALSE, pero podemos usar cualquier expresión de R que devuelva como resultado un valor lógico.

Este tipo de condiciones suele usarse habitualmente en combinación con parámetros predefinidos en la cabecera YAML del documento en cuestión. Por ejemplo, podemos tener dos versiones de las diapositivas, una larga y otra corta, y usar una misma plantilla para cargar y maquetar las diapositivas tanto para la versión larga como para la corta.

---
params:
  version: "corta"
---
```{r include = FALSE}
diapos <- c(here('diapos','marcas_y_canales','marcas_graficas.Rmd'),  
here('diapos','marcas_y_canales','marcas_graficas.Rmd'))
```

```{r metodo_a, eval = (params$version == "corta"), child = diapos}

# este bloque se ejecutará

```

```{r metodo_a, eval = (params$version == "larga"), child = diapos}

# este bloque NO se ejecutará

```

Recursos


Más posts