Includes y child documents
Tres formas de descomponer
Cuando un documento Quarto crece, necesitas dividirlo. Tres mecanismos, cada uno para un caso:
| Mecanismo | Para qué |
|---|---|
Include ({{< include >}}) |
Insertar markdown (texto, no chunks ejecutables) reutilizable |
| Child document | Insertar un .qmd completo con sus chunks ejecutables |
| Source de R/Python | Reutilizar funciones en chunks |
Los tres pueden convivir. La regla simple:
- Texto que se repite entre documentos → include.
- Sección compleja del mismo documento → child.
- Lógica de análisis (funciones, transformaciones) → archivo
.Ro.pyconsource()oimport.
{{< include >}}: el shortcode
Sintaxis básica en un .qmd:
## Sobre los autores
{{< include _autores.qmd >}}
## Análisis
Contenido principal...
{{< include _footer.qmd >}}Y en _autores.qmd (nombre con underscore inicial, convención):
**Ana López** — analista de datos en Telómera.
**Carlos Ruiz** — bioinformático freelance.
[Contactar al equipo](mailto:info@ejemplo.com)Quarto sustituye el {{< include >}} por el contenido del archivo, antes de renderizar. El output final es como si todo estuviera en un solo .qmd.
Por qué el underscore
Por convención, los archivos que son partes de otros documentos se nombran con _ inicial. Tres razones:
- Quarto los ignora al renderizar un directorio completo (no genera
_autores.html). - En listings, no aparecen como documentos navegables.
- Convención común en herramientas estáticas, fácil de reconocer.
Cualquier .qmd con _ inicial no se incluye como output. Es la forma idiomática de marcar parciales.
Qué puede ir en un include
Solo markdown. Frente al include, Quarto procesa el texto Markdown del archivo pero no ejecuta chunks del archivo incluido como si fueran chunks propios, los hereda, pero pueden tener problemas con params o variables locales.
Lo seguro a incluir:
- Texto narrativo que se repite (introducción estándar, footer, agradecimientos).
- Tablas Markdown estáticas.
- Imágenes externas con captions.
- Bloques de callout estándar (advertencias legales, disclaimers).
Lo que no conviene incluir:
- Chunks que dependen de
paramsdel documento padre, funcionan pero conceptualmente raro. - Documentos parametrizados que tienen su propio YAML.
Para chunks ejecutables: child documents
{{< include >}} carga markdown. Para incluir chunks que se ejecutan en el contexto del padre, el patrón clásico (heredado de Rmd) es el child document:
```{r}
#| child: "_seccion-resultados.qmd"
```
#| child: le dice a knitr que ejecute el contenido del archivo como si fuera parte del documento padre. Las variables del padre están disponibles, los chunks se ejecutan en orden, todo limpio.
_seccion-resultados.qmd no necesita YAML propio (es fragmento, no documento independiente):
## Resultados
```{r}
#| label: tbl-resumen
#| tbl-cap: "Resumen estadístico."
datos |>
group_by(grupo) |>
summarise(media = mean(x), n = n()) |>
knitr::kable()
```
Como aparece en @tbl-resumen, el grupo A destaca.Al renderizar el padre, el child se inserta y se ejecuta.
Estructura típica de un documento grande
informe-largo.qmd ← documento principal con setup y orquestación
_intro.qmd ← child: introducción
_metodologia.qmd ← child: metodología (suele ser reutilizable)
_resultados.qmd ← child: resultados
_discusion.qmd ← child: discusión
_footer.qmd ← include: footer estándar
R/ ← código auxiliar
├── funciones.R
└── carga-datos.R
informe-largo.qmd:
---
title: "Informe técnico anual"
---
```{r}
#| label: setup
#| include: false
library(tidyverse)
source("R/funciones.R")
source("R/carga-datos.R")
```
```{r}
#| child: "_intro.qmd"
```
```{r}
#| child: "_metodologia.qmd"
```
```{r}
#| child: "_resultados.qmd"
```
```{r}
#| child: "_discusion.qmd"
```
{{< include _footer.qmd >}}
Documento principal legible: la estructura del informe se ve sin scroll infinito. Cada sección en su archivo.
Funciones en archivos .R
Para lógica de análisis, no uses includes ni childs, separa en archivos R/Python normales:
# R/funciones.R
normalizar_ventas <- function(df, divisor = 1e3) {
df |>
mutate(ventas_norm = ventas / divisor)
}
resumen_por_grupo <- function(df, grupo) {
df |>
group_by({{ grupo }}) |>
summarise(
media = mean(valor, na.rm = TRUE),
sd = sd(valor, na.rm = TRUE),
n = n()
)
}Desde el .qmd:
source("R/funciones.R")
datos |>
normalizar_ventas() |>
resumen_por_grupo(region)El .qmd queda narrativo: el “qué” del análisis. Las funciones en .R son el “cómo”, reutilizables, testeables, ordenadas.
Source vs functions inline
Hay quien pone las funciones al principio del .qmd en un chunk grande. Funciona, pero pierde dos cosas:
- Reutilización: si otro
.qmdnecesita la misma función, no la tiene. - Testing: probar funciones en un chunk Quarto es incómodo. En un
.Rpuedes hacertestthat.
Recomendación: funciones en R/, narrativa en .qmd. Como tener clases en archivos separados en cualquier lenguaje.
Headers e indentación
Cuando incluyes un fragmento con secciones (##), las cabeceras se respetan tal cual. Si el child tiene ## Resultados y lo metes bajo # Análisis del padre, la estructura del TOC es:
1. Análisis
1.1. Resultados (del child)
Si te importa que se ajusten dinámicamente al nivel donde se incluyen, Quarto no lo hace automáticamente, diseña los headers del child sabiendo dónde se va a usar. Si un fragmento debe ser flexible, escríbelo sin headers y deja que el padre los añada.
Includes recursivos
Puedes incluir archivos que a su vez incluyen otros. Funciona. Útil para descomponer una “metodología estándar” en sub-fragmentos:
_metodologia.qmd
├─ {{< include _met-datos.qmd >}}
├─ {{< include _met-analisis.qmd >}}
└─ {{< include _met-validacion.qmd >}}
Mantén la profundidad manejable (2-3 niveles). Más se hace difícil de navegar.
Path resolution
Los paths en {{< include >}} y #| child: son relativos al archivo padre. Si el padre está en informes/anual.qmd y quieres incluir _partes/intro.qmd, escribes:
{{< include _partes/intro.qmd >}}Si organizas con subdirectorios, mantén los paths consistentes. Mover archivos rompe includes silenciosamente.
Trampas habituales
- Olvidar el
_inicial. Si llamas a un parcialintro.qmd(sin guión bajo) y renderizas el directorio, Quarto generaintro.htmlhuérfano. - Includes con YAML duplicado. Un archivo incluido no debe tener
---propio, su YAML interfiere con el del padre. Solo el padre tiene front matter. - Chunks en includes sin contexto. Si el include depende de un objeto definido en el padre, asegúrate de que el include va después del chunk que lo define.
- Child documents olvidando el flag.
#| child: "..."necesita la opción. Sin ella, knitr trata el path como un comentario. - Path absoluto vs relativo. Usa siempre paths relativos. Absolutos rompen al mover el proyecto.
En la siguiente entrega
Tienes la estructura modular. La última pieza del bloque editorial: caché y freeze, cómo evitar que el render entero recalcule chunks pesados cada vez. Es lo que distingue iterar rápido un documento grande de pasar 10 minutos por render. Lo siguiente.