Material suplementario · Anexo C Código abierto · R & Excel

Galería de scripts

Fragmentos listos para adaptar, cada uno con un ejemplo visual del resultado: visualización, clasificación, supervivencia, meta-análisis, análisis multivariado y utilidades de manejo de datos. Todos probados en proyectos reales de investigación y consultoría.

«El código de este estudio se encuentra disponible… aquí mismo, sin tener que escribirle al autor.»

Declaración de disponibilidad
C.1 Visualización

Función de densidad por grupos

Densidades superpuestas con transparencia para comparar la distribución de una variable continua entre grupos.

ggplot2
Ejemplo de salida: Función de densidad por grupos
Figura 1. Densidades por grupo con relleno translúcido. Fuente: elaboración propia (datos simulados).
Ver script+
library(ggplot2)

DensityPlot <- ggplot(datos, aes(x = VariableY, fill = FactorX)) +
  geom_density(alpha = .50) +
  theme_classic() +
  labs(x = "VariableY", y = "Relative frequency",
       colour = "FactorX", fill = "FactorX") +
  theme(legend.position = "top") +
  scale_fill_discrete(name = "Title", labels = c("Group1", "Group2"))
DensityPlot
C.2 Visualización

Dispersión con recta de regresión y correlación

Puntos con jitter y transparencia, recta de mínimos cuadrados con banda de confianza, y el coeficiente de Spearman anotado en el gráfico. Incluye cómo combinar varios paneles con ggarrange.

tidyverse · ggpubr
Ejemplo de salida: Dispersión con recta de regresión y correlación
Figura 2. Dispersión con jitter, recta de regresión y r de Spearman. Fuente: elaboración propia (datos simulados).
Ver script+
library(tidyverse)
library(ggpubr)

# Quitar notación científica (si es necesario)
options(scipen = 999)

fig1 <- ggplot(datos, aes(x = VICTIM.MEAN, y = DTM)) +
  geom_point(position = position_jitter(width = 0.5, height = 0.5),
             alpha = .3) +
  geom_smooth(method = lm, color = "black") +
  theme_classic() +
  labs(x = "Bullying", y = "TMD") +
  stat_cor(method = "spearman",
           r.digits = 2, p.accuracy = .001,
           alternative = "greater", cor.coef.name = "r")
fig1

# Exportar varias figuras en un solo lienzo
png(file = "Scatter.png", width = 18, height = 6, units = "cm", res = 600)
ggarrange(fig1, fig2, fig3,
          labels = c("A", "B", "C"),
          ncol = 3, nrow = 1)
dev.off()
C.3 Visualización

Diagrama de caja con prueba de comparación

Caja y bigotes por grupo con el valor p de la comparación de medias anotado directamente en el gráfico, listo para exportar en alta resolución.

tidyverse · ggpubr
Ejemplo de salida: Diagrama de caja con prueba de comparación
Figura 3. Comparación entre grupos con valor p anotado. Fuente: elaboración propia (datos simulados).
Ver script+
library(tidyverse)
library(ggpubr)

# Poner etiquetas a los códigos numéricos
datos$Sexo <- factor(datos$Sexo, levels = c("1", "2"),
                     labels = c("Hombre", "Mujer"))

plot1 <- ggplot(datos, aes(x = Sexo, y = MedCon)) +
  geom_boxplot() +
  theme_classic() +
  stat_compare_means(aes(label = sprintf("p = %5.3f",
                                         as.numeric(..p.format..)))) +
  labs(x = "Sexo", y = "Conocimiento")

# Exportar en alta resolución
png(file = "Grafica1.png", width = 10, height = 7, units = "cm", res = 600)
plot1
dev.off()
C.4 Visualización

Diagrama aluvial (alluvial plot)

Flujos entre dos variables categóricas — por ejemplo, de grados de dolor crónico a clasificación de bruxismo — con paleta tipo semáforo y etiquetas con porcentajes.

tidyverse · ggalluvial · scales
Ejemplo de salida: Diagrama aluvial (alluvial plot)
Figura 4. Flujos entre categorías con paleta semáforo. Fuente: elaboración propia (datos simulados).
Ver script+
library(tidyverse)
library(ggalluvial)
library(scales)

# 1. Preparar datos (contar y calcular porcentajes)
df_flow <- datos %>%
  filter(!is.na(CPGSgrados) & !is.na(CBA)) %>%
  mutate(
    CPGS = factor(CPGSgrados, levels = 1:4,
                  labels = c("Grado I", "Grado II", "Grado III", "Grado IV")),
    CBA_fac = as_factor(CBA)
  ) %>%
  count(CPGS, CBA_fac, name = "n") %>%
  mutate(p = n / sum(n))

# 2. Colores tipo semáforo
cols_cpgs <- c("Grado I" = "#2E7D32", "Grado II" = "#FDD835",
               "Grado III" = "#F57C00", "Grado IV" = "#C62828")

# 3. Gráfico
ggplot(df_flow, aes(axis1 = CPGS, axis2 = CBA_fac, y = p)) +
  geom_alluvium(aes(fill = CPGS), alpha = 0.85, color = NA, width = 1/3) +
  geom_stratum(aes(fill = after_stat(stratum)), color = "black",
               linewidth = 0.6, width = 1/3) +
  geom_text(stat = "stratum",
            aes(label = ifelse(after_stat(prop) < 0.05, "",
                               paste0(after_stat(stratum), "\n",
                                      percent(after_stat(prop), accuracy = 1)))),
            size = 3, lineheight = 0.85) +
  scale_fill_manual(
    values = c(cols_cpgs,
               "Improbables" = "#2E7D32",
               "Probables"   = "#F9A825",
               "Definitivos" = "#C62828"),
    breaks = names(cols_cpgs)) +
  scale_x_discrete(limits = c("Dolor Crónico", "Síntomas de Bruxismo"),
                   expand = c(0.15, 0.15)) +
  scale_y_continuous(labels = percent_format(accuracy = 1), limits = c(0, 1)) +
  labs(x = NULL, y = "Porcentaje") +
  theme_classic(base_size = 12) +
  theme(legend.position = "none")
C.5 Clasificación

Curvas ROC múltiples en un solo gráfico

Varias curvas ROC superpuestas, distinguidas por tipo de línea (apto para impresión en blanco y negro), con diagonal de referencia.

pROC · ggplot2
Ejemplo de salida: Curvas ROC múltiples en un solo gráfico
Figura 5. Tres curvas ROC distinguidas por tipo de línea. Fuente: elaboración propia (datos simulados).
Ver script+
library(pROC)

# Modelos ROC para varios predictores a la vez
rocmodel <- roc(MUERTE ~ MDA + TEAC + Puntuacion3, data = datos)

ROC1 <- ggroc(rocmodel, aes = c("color", "linetype"))

# Versión de publicación (líneas distinguibles en B/N)
ROCbetter <- ROC1 + theme_bw() +
  theme(text = element_text(size = 10, family = "Arial"),
        legend.title = element_text(size = 10),
        legend.text  = element_text(size = 10)) +
  labs(x = "Specificity", y = "Sensitivity") +
  scale_colour_manual(name = "Measure",
    values = c("#000000", "#000000", "#000000"),
    labels = c("MDA", "TEAC", "Score")) +
  scale_linetype_manual(values = c("solid", "longdash", "dotdash"),
    name = "Measure",
    labels = c("MDA", "TEAC", "Score")) +
  geom_segment(aes(x = 1, xend = 0, y = 0, yend = 1),
               color = "darkgrey", linetype = "dashed")
ROCbetter

png(file = "ROC_multiple.png", width = 13, height = 9, units = "cm", res = 900)
ROCbetter
dev.off()
C.6 Supervivencia

Curva de supervivencia (Kaplan–Meier)

Curvas de supervivencia estratificadas con intervalos de confianza, línea de mediana y estética de publicación, usando survminer.

survival · survminer
Ejemplo de salida: Curva de supervivencia (Kaplan–Meier)
Figura 6. Kaplan–Meier por estratos con IC y mediana. Fuente: elaboración propia (datos simulados).
Ver script+
library(survival)
library(survminer)

# Objeto de supervivencia y modelo por estrato
tiempo_evento <- Surv(datos$Days, datos$MUERTE == 1)
Model1 <- survfit(tiempo_evento ~ datos$MDA50)
Model1

Fig1A <- ggsurvplot(Model1, data = datos,
  risk.table = FALSE,
  palette = "grey",
  censor = FALSE,
  ggtheme = theme_classic(),
  surv.median.line = "hv",
  conf.int = TRUE, break.time.by = 5,
  legend.title = "Percentile",
  legend.labs = c("<50th", ">50th"),
  xlab = "Overall survival (days)",
  ylab = "Survival probability",
  xlim = c(0, 45))
Fig1A
C.7 Meta-análisis

Meta-análisis de eventos binarios (OR / RR) con forest plot

Modelos de odds ratio y risk ratio con el paquete meta, forest plot con columnas personalizadas, prueba de Egger y funnel plot para riesgo de sesgo.

meta · metafor
Ejemplo de salida: Meta-análisis de eventos binarios (OR / RR) con forest plot
Figura 7. Forest plot de odds ratios con diamante de efecto global. Fuente: elaboración propia (datos simulados).
Ver script+
library(meta)
library(metafor)

# Base: eventos y N de experimental, eventos y N de control
datos_meta <- read.csv("meta_analisis.csv")

# Modelos
ModelOR <- metabin(ne.death, ne, nc.death, nc, Autor,
                   data = datos_meta, sm = "OR")
ModelRR <- metabin(ne.death, ne, nc.death, nc, Autor,
                   data = datos_meta, sm = "RR")

# Redondear decimales si es necesario
ModelOR$zval <- round(ModelOR$zval, digits = 3)
ModelOR$pval <- round(ModelOR$pval, digits = 3)

# Forest plot (colocar el modelo a graficar: OR o RR)
forest(ModelOR, comb.fixed = FALSE,
  lab.e = "Surgical", lab.c = "Control",
  leftcols = c("studlab", "event.e", "n.e", "event.c", "n.c",
               "zval", "pval"),
  just = "center",
  leftlabs = c("Study", "Deaths", "N", "Deaths", "N",
               "Z-Value", "p-Value"),
  overall = TRUE, layout = "meta")

# Riesgo de sesgo: prueba de Egger + funnel plot
metabias(ModelOR, method = "linreg", k.min = 8)
funnel(ModelOR)

# Exportar en alta resolución
png(file = "forest_OR.png", width = 30, height = 10, units = "cm", res = 600)
forest(ModelOR, comb.fixed = FALSE, layout = "meta")
dev.off()
C.8 Meta-análisis

Meta-análisis de promedios (una media por estudio)

Síntesis de medias simples entre estudios con metamean — útil, por ejemplo, para estimar una ingesta calórica promedio combinada.

meta
Ejemplo de salida: Meta-análisis de promedios (una media por estudio)
Figura 8. Forest plot de medias con efecto combinado. Fuente: elaboración propia (datos simulados).
Ver script+
library(readxl)
library(meta)

# Base con columnas: Study, n, Kcal (media), sd
datos_meta <- read_excel("ingesta.xlsx")

# Objeto de meta-análisis de medias
meta1 <- metamean(n, Kcal, sd, data = datos_meta, studlab = Study)
meta1

# Forest plot
forest(meta1)
C.9 Meta-análisis

Meta-análisis de medias de grupos independientes

Comparación experimental vs. control con metacont (diferencia de medias estandarizada), forest plot con etiquetas de grupos y exportación en alta resolución.

meta
Ejemplo de salida: Meta-análisis de medias de grupos independientes
Figura 9. Diferencias de medias estandarizadas entre grupos. Fuente: elaboración propia (datos simulados).
Ver script+
library(meta)

# Base con: n, media y sd de cada grupo, por estudio
meta1 <- metacont(n.exp, mean.exp, sd.exp,
                  n.cont, mean.cont, sd.cont,
                  studlab = Study, data = datos_meta)
meta1

# Gráfico de bosque
forest(meta1, common = FALSE,
       label.e = "Grupo experimental", label.c = "Grupo control",
       digits = 2, digits.mean = 2, digits.sd = 2, overall = TRUE)

# Exportar
png(file = "meta_grupos.png", width = 30, height = 10, units = "cm", res = 600)
forest(meta1, common = FALSE,
       label.e = "Grupo experimental", label.c = "Grupo control",
       digits = 2, digits.mean = 2, digits.sd = 2, overall = TRUE)
dev.off()
C.10 Multivariado

Análisis de Correspondencias Múltiples (biplot)

Mapa de dimensiones con puntos por variable (formas y colores distintos), ejes de referencia en cero, etiquetas sin encimarse con ggrepel, paneles individuales por variable y gráfico de clusters con elipses.

ggplot2 · ggrepel · readxl
Ejemplo de salida: Análisis de Correspondencias Múltiples (biplot)
Figura 10. Biplot de correspondencias múltiples con formas por variable. Fuente: elaboración propia (datos simulados).
Ver script+
library(readxl)
library(ggplot2)
library(ggrepel)

# Base con coordenadas D1, D2, Variable y Categorias
ACM <- read_excel("ACM.xlsx")

# Gráfico conjunto
png(file = "ACM-FINAL.png", width = 18, height = 15, units = "cm", res = 600)
ggplot() +
  geom_point(aes(x = D1, y = D2), data = ACM) +
  geom_point(aes(x = D1, y = D2, shape = Variable,
                 colour = Variable, size = 3), data = ACM) +
  scale_shape_manual(values = c(15, 16, 17, 18, 5, 6, 7, 8, 9, 1)) +
  geom_vline(data = ACM, xintercept = 0.0) +
  geom_hline(data = ACM, yintercept = 0.0) +
  xlab('Dimensión 1 (36.9%)') + ylab('Dimensión 2 (31.5%)') +
  theme_classic() +
  geom_text_repel(aes(x = D1, y = D2, label = Categorias),
                  data = ACM, parse = FALSE)
dev.off()

# Paneles individuales por variable
ggplot() +
  geom_point(aes(x = D1, y = D2), data = ACM) +
  geom_vline(data = ACM, xintercept = 0.0) +
  geom_hline(data = ACM, yintercept = 0.0) +
  geom_text_repel(aes(x = D1, y = D2, label = Categorias), data = ACM) +
  facet_wrap(~ Variable, ncol = 4)

# Clusters con elipses
ggplot(aes(x = OBSCO1_1, y = OBSCO2_1, color = Clusters), data = ACM) +
  geom_point() +
  geom_vline(xintercept = 0.0) + geom_hline(yintercept = 0.0) +
  stat_ellipse(type = "norm") +
  theme_classic()

# Si las variables vienen etiquetadas de SPSS (haven_labelled):
ACM$OBSCO1_1 <- as.numeric(ACM$OBSCO1_1)
ACM$OBSCO2_1 <- as.numeric(ACM$OBSCO2_1)
ACM$Clusters <- as.factor(ACM$Clusters)
C.11 Utilidades · Excel

Cambiar multientradas a variables dummy

Cuando una celda guarda varias respuestas juntas ("opción A; opción C…"), esta fórmula crea columnas indicadoras 1/0 buscando cada texto. Funciona mejor y de manera automática dentro de una tabla de Excel.

Excel · SI · ENCONTRAR
Ver fórmula+
=SI(ESNUMERO(ENCONTRAR("TEXTO", CELDA)), "1", "0")

' Ejemplo: columna dummy para la opción "Deporte"
' con las respuestas múltiples en B2:
=SI(ESNUMERO(ENCONTRAR("Deporte", B2)), "1", "0")
C.12 Utilidades

Exportar bases de datos a .sav

Convierte bases de Stata (.dta) u otros formatos a SPSS (.sav) conservando las etiquetas de variables y valores — ideal para compartir con colegas que trabajan en SPSS.

haven
Ver script+
library(haven)

# Leer base en formato Stata
datos <- read_dta("base_original.dta")

# Exportar a formato .sav manteniendo etiquetas
write_sav(datos, "base_exportada.sav")
C.13 Utilidades

Etiquetar códigos numéricos

El clásico de dos líneas: convierte una variable codificada (1, 2, …) en factor con etiquetas legibles, para que tablas y gráficos muestren nombres en lugar de números.

base R
Ver script+
# Poner nombre a los códigos
datos$Sexo <- factor(datos$Sexo, levels = c("1", "2"),
                     labels = c("Hombre", "Mujer"))

Nota. Las figuras de esta galería se generaron con datos simulados para ilustrar el tipo de salida de cada script; los resultados con datos reales varían.

C.14

En prensa

El resto de la colección se irá incorporando a la galería.