Chunks: R y Python en el mismo documento

quarto
reproducibilidad
Anatomía de un chunk Quarto. Las opciones que importan (echo, eval, output, error), R con knitr y Python con jupyter, pasar datos entre los dos lenguajes con reticulate y el control fino de figuras.

Anatomía de un chunk

`​`​`{r}
#| label: fig-cars
#| echo: false
#| fig-cap: "Distancia de frenado en función de la velocidad."
#| fig-width: 6
#| fig-height: 4

plot(cars, pch = 16, col = "#5F8575")
`​`​`

Tres partes:

  • {r} (o {python}, {julia}, etc.), el motor.
  • Opciones con #|: configuración del chunk.
  • Código: el cuerpo.

Las opciones #| son la sintaxis moderna de Quarto. Antes (en Rmd) iban dentro de {r, opcion=valor}. Ahora una por línea, comentadas con #|. Mucho más legible cuando hay 4-5 opciones.

Las opciones que importan

echo: mostrar o no el código

#| echo: true     # default: muestra
#| echo: false    # oculta el código, muestra solo el output

Para informes ejecutivos (lector no técnico), echo: false en todos los chunks. Para documentación o tutorial, echo: true. Para reportes mixtos, echo: fenced muestra el chunk completo incluyendo las opciones.

eval: ejecutar o no

#| eval: true     # default
#| eval: false    # muestra código sin ejecutar

Útil para mostrar código de ejemplo sin que se ejecute (porque depende de archivos que no están, o porque es solo ilustrativo).

output: cómo va el output

#| output: true    # default: muestra el output normalmente
#| output: false   # oculta el output
#| output: asis    # interpreta el output como markdown directamente

output: asis es el truco para que un chunk que devuelve texto markdown se integre como markdown. Útil para generar secciones programáticamente.

warning, message, error: el ruido

#| warning: false
#| message: false
#| error: true     # permite que el render continúe aunque haya error

Para informes finales, warning: false y message: false globales en el front matter, son los más usados. El ruido de carga de paquetes no aporta.

error: true es útil cuando el documento enseña errores (un tutorial), el render no muere al primer error.

include: el todo o nada

#| include: false

include: false ejecuta el chunk pero no incluye nada en el output, ni código ni resultado. Útil para setup invisible (cargar paquetes, configurar opciones).

Setup: el primer chunk típico

El chunk de configuración global:

`​`​`{r}
#| label: setup
#| include: false

library(tidyverse)
library(here)

knitr::opts_chunk$set(
    echo = FALSE,
    message = FALSE,
    warning = FALSE,
    fig.align = "center"
)

theme_set(theme_minimal(base_size = 12))
`​`​`
  • label: setup: nombre del chunk. Útil para referencia y para tracking de tiempos.
  • include: false: invisible.
  • Carga de paquetes + opciones globales en un solo bloque.

Quarto respeta knitr::opts_chunk$set() del chunk setup. Es el patrón heredado de Rmd y sigue siendo válido. Alternativa: poner execute: en el front matter (más Quarto-nativo).

Figuras: control fino

`​`​`{r}
#| label: fig-tendencia
#| fig-cap: "Tendencia de ventas mensuales 2024."
#| fig-width: 8
#| fig-height: 5
#| fig-align: center
#| fig-dpi: 300
#| out-width: 80%

ggplot(datos, aes(mes, ventas)) +
    geom_line() +
    geom_point()
`​`​`

Opciones de figura:

  • fig-cap: caption mostrado debajo.
  • fig-width, fig-height: tamaño en pulgadas al renderizar.
  • fig-align: default / left / center / right.
  • fig-dpi: resolución. 300 para PDF print, 96-120 para web.
  • out-width: tamaño al mostrarse (% del contenedor).

Para varias figuras en un chunk (subfiguras):

`​`​`{r}
#| label: fig-multi
#| fig-cap: "Distribución de ventas."
#| fig-subcap:
#|   - "Por región"
#|   - "Por trimestre"
#| layout-ncol: 2

ggplot(datos, aes(region, ventas)) + geom_boxplot()
ggplot(datos, aes(trimestre, ventas)) + geom_boxplot()
`​`​`

Dos figuras lado a lado con caption combinada. Patrón muy útil para reports.

Tablas

Para tablas a partir de un data.frame, knitr::kable() da el formato base:

`​`​`{r}
#| label: tbl-resumen
#| tbl-cap: "Resumen estadístico por grupo."

resumen |>
    knitr::kable(digits = 2,
                 col.names = c("Grupo", "Media", "Desv. típica", "N"))
`​`​`

Mejores: gt para HTML elegante, flextable para Word con control fino, kableExtra para PDF/LaTeX. Veremos esto en el tutorial 4 (figuras y tablas publicables).

Python en Quarto

Para usar Python necesitas:

  • Python instalado (3.10+).
  • Jupyter (pip install jupyter o uv add jupyter).
  • Kernel detectable.

Chunk Python:

`​`​`{python}
import pandas as pd
import seaborn as sns

df = sns.load_dataset("penguins")
df.head()
`​`​`

Mismas opciones (#| echo, #| fig-cap, etc.). Lo único distinto es {python} en lugar de {r}.

Mismo documento, R + Python

Sí, conviven:

`​`​`{r}
library(dplyr)
df_r <- mtcars |> as_tibble()
`​`​`

`​`​`{python}
import pandas as pd
df_py = pd.DataFrame({"x": [1, 2, 3]})
`​`​`

Cada chunk usa su motor. Por defecto los entornos están separados, el df_r de R no es visible desde Python y viceversa.

Pasar datos entre R y Python con reticulate

Si quieres compartir variables:

`​`​`{r}
library(reticulate)
df_r <- mtcars
`​`​`

`​`​`{python}
# acceso al objeto R desde Python
df_py = r.df_r
df_py.head()
`​`​`

`​`​`{r}
# acceso al objeto Python desde R
head(py$df_py)
`​`​`

r.objeto para acceder al espacio de R desde Python. py$objeto para el revés desde R. reticulate hace conversiones razonables (data.frame R ↔︎ DataFrame pandas, vector ↔︎ list, etc.).

Es la forma elegante de tener R y Python en el mismo análisis. Aunque para análisis serio mixto, normalmente se separa en archivos distintos y se exporta vía Parquet.

Engines: knitr vs jupyter

Quarto puede usar dos motores:

  • knitr (default si hay chunks de R), motor histórico, soporta R nativo + Python (vía reticulate).
  • jupyter (default si solo hay Python), motor Jupyter, no soporta R.

Para forzar:

engine: knitr        # o jupyter

Recomendación: si tu documento es R o R+Python, usa knitr. Si es solo Python, jupyter. La diferencia más visible: jupyter reproduce exactamente lo que verías en un notebook Jupyter (incluido el output rico de IPython). knitr es más limpio textualmente.

Cache: evitar recalcular

Si un chunk es lento, cache: true:

`​`​`{r}
#| label: modelo
#| cache: true

modelo <- DESeq(dds)        # toma minutos
`​`​`

knitr guarda el resultado en disco. Render sucesivo: si el código y dependencias no cambian, no se recalcula.

Lo veremos a fondo en el tutorial 8 (cache y freeze). Mención aquí porque resuelve el problema más común al iterar documentos largos.

Chunk hooks: lo que knitr puede hacer

Hooks útiles preconfigurados:

`​`​`{r}
#| label: fig-elegante
#| dev: cairo_pdf
#| fig-format: pdf
#| dpi: 300

ggplot(...) + ...
`​`​`
  • dev: el device gráfico. cairo_pdf para PDFs con transparencia bien gestionada. ragg_png para PNGs con mejor texto.
  • fig-format: formato de archivo. png, pdf, svg. En HTML, svg da vectoriales escalables.

Nombrar chunks: la disciplina que paga

Cada chunk debería tener label:

#| label: limpiar-datos
#| label: fig-distribucion
#| label: tbl-resumen

Convenciones:

  • fig-* para figuras (necesario para cross-references).
  • tbl-* para tablas (idem).
  • Nombre descriptivo para los demás. Sin espacios, en minúsculas, con guiones.

Cuando un chunk falla en render, Quarto te dice “error in chunk X”, con buenos nombres lo encuentras en segundos.

Trampas habituales

  • Mezclar sintaxis vieja ({r, echo=FALSE}) y nueva (#| echo: false) en el mismo doc. Ambas funcionan pero conviene unificar a la nueva.
  • include: false cuando querías echo: false. include: false no muestra nada del chunk. echo: false solo oculta el código pero muestra el output. Confusión frecuente.
  • Olvidar knitr::opts_chunk$set() en setup. Lleva a definir lo mismo en cada chunk. Pon defaults globalmente.
  • Cache habilitado con dependencias mal declaradas. Si tu chunk depende del output de otro y cambias el de arriba, el de abajo no se recalcula. dependson: c("otro_chunk") resuelve.
  • {python} sin Jupyter instalado. Error claro pero confuso si no sabes que necesitas Jupyter. pip install jupyter o equivalente.

En la siguiente entrega

Tienes los chunks bajo control. Lo siguiente: figuras y tablas publicables, gt, flextable, kableExtra, ggplot exportado con calidad, gestión de captions y referencias. Lo que distingue un informe profesional de uno funcional. Lo siguiente.