Plasticidad del área foliar de Bauhinia
picta frente a la exposición lumínica en un bosque urbano de
Cali
Un estudio observacional jerárquico con el árbol
como unidad experimental
Juan Manuel Cordoba Castillo (2520820) Valentina
Noguera Velasquez (2521094) — Grupo 1 - Facultad de Ciencias Naturales y
Exactas, Universidad del Valle
05/11/2026
Resumen
Contexto y objetivo. Las hojas son los principales
órganos captadores de luz y su tamaño condiciona la luz que el árbol
puede interceptar. Evaluamos si el área foliar de Bauhinia
picta difiere entre árboles a pleno sol y a la sombra en el Bosque
Urbano Multicentro (Cali, Valle del Cauca; 987 m s. n. m.), contrastando
dos hipótesis opuestas planteadas por los dos autores: H1, el área
foliar promedio por árbol es mayor a pleno sol; H2, es mayor en la
sombra.
Diseño. Se registraron 60 hojas en 6 árboles (3 de
sol y 3 de sombra); el área de cada hoja se obtuvo de su fotografía
escalada con un marco rectangular de lados conocidos. Como la exposición
es una propiedad del árbol y no de la hoja, la unidad de análisis fue el
árbol. Las 60 hojas tienen área medida.
Resultados. Con el árbol como unidad de análisis (3
de sol y 3 de sombra), la razón de áreas sombra/sol fue 1,19 (IC 95 %:
0,61–2,33; p = 0,448). El 68 % de la variación del tamaño de las hojas
se debió a diferencias entre árboles (CCI = 0,68; IC 95 %: 0,41–0,93).
Un análisis independiente basado en el área del marco de cada hoja dio
razón 1,24, IC 95 % 0,67–2,27.
Conclusión. La dirección es la de H2 (hojas algo
mayores en sombra), pero el intervalo de confianza incluye la ausencia
de efecto: no hay evidencia suficiente ni a favor de H1 ni a favor de
H2. Con tan pocos árboles, el diseño tiene una potencia limitada: los
resultados son estimaciones preliminares y generadoras de hipótesis, no
una confirmación.
6
Árboles
3 sol · 3 sombra
60
Hojas registradas
60 con área medida
1,19
Razón sombra/sol
IC 95 %: [0,61; 2,33]
68 %
Variación entre árboles
CCI (tamaño de la hoja)
Introducción
Bauhinia picta, conocida comúnmente como pata de vaca, es
una especie de la familia Fabaceae cultivada en Colombia, México,
Panamá, Venezuela y Ecuador. Presenta hojas simples, con lóbulos ovados
y acuminados o algo caudados en el ápice, y es semicaducifolia, es
decir, pierde parcialmente su follaje durante la época seca. Se utiliza
como planta ornamental, como barrera rompevientos y en procesos de
restauración ecológica, y su rango altitudinal va desde 0 hasta 2000 m
s. n. m.1
Las hojas son los principales órganos captadores de luz solar y el
sitio donde ocurre la mayor parte de la fotosíntesis. El tamaño y la
forma de una hoja determinan la cantidad de luz que la planta puede
interceptar, por lo que el área foliar es un rasgo útil para evaluar
cómo responde un árbol a su ambiente lumínico.2,3
En este estudio se buscó responder cómo cambia el área foliar de
B. picta según la exposición a la luz (sol o sombra). El
trabajo se realizó en el Bosque Urbano Multicentro, ubicado en el área
forestal protectora del río Meléndez, comuna 22, Cali, Valle del Cauca,
a 987 m s. n. m., donde se comparó el área foliar de árboles expuestos a
pleno sol con la de árboles en sombra.
Hipótesis. Cada uno de los dos autores planteó una
hipótesis distinta sobre cómo cambia el área foliar promedio por árbol
con la luz (H0: no hay diferencia, razón de áreas sombra/sol = 1).
H1: mayor área a pleno sol (razón sombra/sol <
1). Uno de los autores propone que el área de la hoja aumenta con una
mayor exposición al sol: más radiación aporta más energía para la
fotosíntesis y podría favorecer una superficie foliar mayor, en línea
con el patrón global en que las hojas grandes predominan en ambientes
cálidos, húmedos y soleados.4
H2: mayor área en la sombra (razón sombra/sol >
1). El otro autor propone lo contrario: que el área de la hoja aumenta
en la sombra, porque con poca luz las plantas suelen desplegar rasgos
que favorecen la captura de luz, como láminas más
extensas.5,6
Una hoja más grande no siempre significa mayor producción. Con exceso
de calor o poca disponibilidad de agua la planta puede reducir su
actividad fotosintética, y una lámina mayor engrosa la capa límite de
aire y dificulta disipar calor.7,8 Por eso el sentido del
efecto no es evidente de antemano y este estudio pone a prueba ambas
hipótesis. Además, el verdadero aprovechamiento de la luz depende de
cómo se organiza todo el follaje y de las condiciones ambientales que
rodean al árbol.
Objetivos.
Estimar la razón de áreas sombra/sol con el árbol como unidad
experimental y valorar cuál de las dos hipótesis (H1 o H2) respalda
mejor.
Repartir la variación entre árboles y entre hojas.
Comprobar la robustez de la conclusión frente a la prueba empleada,
la influencia de árboles individuales y los valores atípicos.
Cuantificar qué diferencia podría detectar este diseño.
1 Diseño muestral y
datos
1.1 Diseño jerárquico y
flujo de medición
La base contiene 60 hojas de 6 árboles de Bauhinia picta (3
de sol y 3 de sombra), con 10–10 hojas por árbol. La exposición se
asignó al árbol y las hojas son submuestras (Fig. 1);
por eso el árbol es la unidad de análisis. La Tabla 1
resume los árboles de cada exposición.
caja <- function(x, y, w, h, lab, fill = "white", col = "grey25", face = "plain", size = 3.2)
list(annotate("rect", xmin = x - w/2, xmax = x + w/2, ymin = y - h/2, ymax = y + h/2, fill = fill, colour = col, linewidth = .5),
annotate("text", x = x, y = y, label = lab, size = size, fontface = face, lineheight = .95))
flecha <- function(x, y, xe, ye) annotate("segment", x = x, xend = xe, y = y, yend = ye, colour = "grey35", linewidth = .5, arrow = arrow(length = unit(2.2, "mm"), type = "closed"))
capa <- list()
cs <- comp[comp$exposicion == "sol", ]; cb <- comp[comp$exposicion == "sombra", ]
pos_arbol <- function(k) if (k == 0) numeric(0) else seq(50, 50 + 6.5 * (k - 1), length.out = k)
alt_txt <- if (length(R$altitud)) paste0(fx(R$altitud[1], 0), " m s. n. m.") else ""
capa <- c(capa, caja(11, 30, 20, 17, paste0("Bosque Urbano\nMulticentro, Cali\n", alt_txt), fill = "#f1f3f4", face = "bold"))
capa <- c(capa, caja(33, 44, 17, 10, paste0("A pleno sol\n(", nrow(cs), " árboles)"), fill = adjustcolor(COL["sol"], .25)),
caja(33, 16, 17, 10, paste0("A la sombra\n(", nrow(cb), " árboles)"), fill = adjustcolor(COL["sombra"], .22)))
capa <- c(capa, list(flecha(21, 33, 24.4, 41), flecha(21, 27, 24.4, 19)))
for (ex in list(list(d = cs, y = 44, c = COL["sol"]), list(d = cb, y = 16, c = COL["sombra"]))) {
if (nrow(ex$d) == 0) next
xs <- pos_arbol(nrow(ex$d))
capa <- c(capa, list(flecha(41.8, ex$y, min(xs) - 3.3, ex$y),
annotate("point", x = xs, y = ex$y, shape = 21, size = 11, fill = ifelse(ex$d$n_medida == 0, "white", ex$c), colour = "grey15", stroke = .7),
annotate("text", x = xs, y = ex$y, label = ex$d$arbol, size = 3.1, fontface = "bold"),
annotate("text", x = xs, y = ex$y - 6.4, label = paste0(ex$d$n_medida, "/", ex$d$n_total), size = 2.7, colour = "grey30")))
}
capa <- c(capa, caja(89, 30, 20, 22, "Hojas por árbol\n(unidad de muestreo)\n\ncontorno → marco → foto\n→ área (cm²)", fill = "#f1f3f4"))
capa <- c(capa, list(flecha(77.5, 40, 78.8, 34.5), flecha(77.5, 20, 78.8, 25.5)))
cab <- data.frame(x = c(11, 33, 59, 89), l = c("SITIO", "FACTOR (fijo)", "UNIDAD EXPERIMENTAL: el árbol", "SUBMUESTRA"))
ggplot() + capa + geom_text(data = cab, aes(x, 57, label = l), size = 3, fontface = "bold", colour = "grey20") +
coord_cartesian(xlim = c(0, 100), ylim = c(4, 60), clip = "off") + theme_void()
Fig. 1 | Diseño jerárquico del estudio y flujo de
medición. El factor fijo (exposición) se asigna a árboles, que
son la unidad experimental; las hojas son submuestras. Círculos:
árboles, con el número de hojas con área medida sobre el total. Las
áreas se obtienen de la fotografía de cada hoja: un marco rectangular
dibujado con regla alrededor de su contorno fija la escala para
convertir píxeles a cm² con un script en R. Un círculo vacío indica que
el árbol aún no tiene ninguna área medida.
car_df <- merge(geo[, c("arbol", "exposicion", "x_m", "y_m")], comp[, c("arbol", "n_total", "n_medida")], by = "arbol")
car_df <- merge(car_df, desc_all[, c("arbol", "media", "cv")], by = "arbol", all.x = TRUE)
car_df <- merge(car_df, aggregate(cbind(marco_cm2, aspecto) ~ arbol, data = datos, FUN = mean), by = "arbol", all.x = TRUE)
car_df$dist <- sqrt(car_df$x_m^2 + car_df$y_m^2)
car_df$expo <- factor(as.character(car_df$exposicion), levels = c("sol", "sombra"), labels = c("A pleno sol", "A la sombra"))
cat(tcap("car", "Características de los árboles según su exposición lumínica",
"Cada fila resume los árboles de la columna (<i>N</i> = número de árboles); datos como media (DE) y mediana [mín.–máx.]. DE, desviación estándar; CV, coeficiente de variación dentro del árbol; el marco es el rectángulo dibujado alrededor de cada hoja (lado 1 × lado 2); la distancia se mide al centroide de los árboles. Los árboles sin áreas medidas no contribuyen a las filas de área."))
Tabla 1.Características de los árboles según
su exposición lumínica
ok_t1 <- FALSE
if (HAS_T1) {
rc_stats <- function(x, ...) {
x <- x[is.finite(x)]; n <- length(x)
if (n == 0) return(c("", "n/d" = ""))
c("", "Media (DE)" = paste0(fx(mean(x), 1), " (", if (n > 1) fx(sd(x), 1) else "n/d", ")"),
"Mediana [mín.–máx.]" = paste0(fx(median(x), 1), " [", fx(min(x), 1), "–", fx(max(x), 1), "]"))
}
table1::label(car_df$n_total) <- "Hojas registradas por árbol (n)"
table1::label(car_df$n_medida) <- "Hojas con área medida por árbol (n)"
table1::label(car_df$media) <- "Área foliar media del árbol (cm²)"
table1::label(car_df$cv) <- "CV del área dentro del árbol (%)"
table1::label(car_df$marco_cm2) <- "Área del marco (cm²)"
table1::label(car_df$aspecto) <- "Relación de aspecto del marco (lado mayor/menor)"
table1::label(car_df$dist) <- "Distancia al centroide (m)"
t_car <- tryCatch(table1::table1(~ n_total + n_medida + media + cv + marco_cm2 + aspecto + dist | expo, data = car_df,
overall = "Total", rowlabelhead = "Característica", render.continuous = rc_stats,
render.missing = NULL, topclass = "Rtable1-times"), error = function(e) NULL)
if (!is.null(t_car)) { t1_out(t_car); ok_t1 <- TRUE }
}
```{=html}
Característica
A pleno sol (N=3)
A la sombra (N=3)
Total (N=6)
Hojas registradas por árbol (n)
Media (DE)
10,0 (0,0)
10,0 (0,0)
10,0 (0,0)
Mediana [mín.–máx.]
10,0 [10,0–10,0]
10,0 [10,0–10,0]
10,0 [10,0–10,0]
Hojas con área medida por árbol (n)
Media (DE)
10,0 (0,0)
10,0 (0,0)
10,0 (0,0)
Mediana [mín.–máx.]
10,0 [10,0–10,0]
10,0 [10,0–10,0]
10,0 [10,0–10,0]
Área foliar media del árbol (cm²)
Media (DE)
95,3 (13,9)
117,3 (34,6)
106,3 (26,5)
Mediana [mín.–máx.]
96,1 [81,0–108,7]
123,1 [80,2–148,7]
102,4 [80,2–148,7]
CV del área dentro del árbol (%)
Media (DE)
14,2 (1,8)
17,7 (0,7)
15,9 (2,2)
Mediana [mín.–máx.]
13,3 [13,0–16,2]
17,5 [17,1–18,4]
16,6 [13,0–18,4]
Área del marco (cm²)
Media (DE)
140,4 (21,6)
177,5 (49,8)
158,9 (39,9)
Mediana [mín.–máx.]
139,4 [119,2–162,5]
182,5 [125,5–224,6]
150,9 [119,2–224,6]
Relación de aspecto del marco (lado mayor/menor)
Media (DE)
1,1 (0,0)
1,1 (0,1)
1,1 (0,0)
Mediana [mín.–máx.]
1,1 [1,1–1,1]
1,1 [1,1–1,1]
1,1 [1,1–1,1]
Distancia al centroide (m)
Media (DE)
41,8 (11,3)
76,3 (86,8)
59,0 (58,5)
Mediana [mín.–máx.]
39,4 [31,9–54,1]
43,5 [10,6–174,6]
41,5 [10,6–174,6]
<p class="tnota"><b>Nota.</b> Cada fila resume los árboles de la columna (<i>N</i> = número de árboles); datos como media (DE) y mediana [mín.–máx.]. DE, desviación estándar; CV, coeficiente de variación dentro del árbol; el marco es el rectángulo dibujado alrededor de cada hoja (lado 1 × lado 2); la distancia se mide al centroide de los árboles. Los árboles sin áreas medidas no contribuyen a las filas de área.</p>
``` r
if (!ok_t1) {
tc <- data.frame(Árbol = car_df$arbol, Exposición = as.character(car_df$exposicion), `Hojas registradas` = car_df$n_total, `Hojas medidas` = car_df$n_medida,
`Área media (cm²)` = fx(car_df$media, 1), `CV (%)` = fx(car_df$cv, 1), `Marco (cm²)` = fx(car_df$marco_cm2, 1),
`Aspecto` = fx(car_df$aspecto, 2), `Distancia al centroide (m)` = fx(car_df$dist, 0), check.names = FALSE)
tabla(tc, align = "llrrrrrrr")
}
1.2 Calidad de la base de
datos
Ver la descripción de las variables de la base
vars_tab <- data.frame(
Variable = c("Árbol", "Exposición", "Lado 1 y lado 2", "Área del marco", "Área foliar", "ln(área)", "Cociente área/marco", "Relación de aspecto", "Latitud y longitud", "CCI", "Razón sombra/sol"),
`Columna o cálculo` = c("arbol (T1, T2…)", "exposicion", "lado_1_mm, lado_2_mm", "lado 1 × lado 2 / 100", "area_real_cm2", "log(área foliar)", "área foliar / área del marco", "lado mayor / lado menor", "latitud, longitud", "ANOVA de un factor sobre ln(área)", "exp(β) del modelo mixto o razón de medias geométricas"),
Unidad = c("—", "sol / sombra", "mm", "cm²", "cm²", "ln(cm²)", "0–1", "≥ 1", "grados decimales", "0–1", "sin unidad"),
Descripción = c("Identificador del árbol; es la unidad experimental.", "Condición lumínica del árbol (factor de interés).", "Lados del rectángulo dibujado alrededor de cada hoja.",
"Escala de la fotografía y referencia del tamaño de la hoja.", "Área de la hoja obtenida de la fotografía escalada.", "Variable respuesta de la inferencia (el tamaño es multiplicativo).",
"Fracción del marco que ocupa la hoja.", "Indicador burdo de la forma de la lámina.", "Posición del árbol.", "Fracción de la varianza que ocurre entre árboles.", "Cociente de áreas de sombra respecto de sol; 1 = sin efecto."),
check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("vars", "Variables de la base y su significado", "Las columnas del archivo de datos se normalizan al leerlas (minúsculas, sin tildes)."))
Tabla 2.Variables de la base y su
significado
tabla(vars_tab, align = "llll")
Variable
Columna o cálculo
Unidad
Descripción
Árbol
arbol (T1, T2…)
—
Identificador del árbol; es la unidad experimental.
Exposición
exposicion
sol / sombra
Condición lumínica del árbol (factor de interés).
Lado 1 y lado 2
lado_1_mm, lado_2_mm
mm
Lados del rectángulo dibujado alrededor de cada hoja.
Área del marco
lado 1 × lado 2 / 100
cm²
Escala de la fotografía y referencia del tamaño de la hoja.
Área foliar
area_real_cm2
cm²
Área de la hoja obtenida de la fotografía escalada.
ln(área)
log(área foliar)
ln(cm²)
Variable respuesta de la inferencia (el tamaño es multiplicativo).
Cociente área/marco
área foliar / área del marco
0–1
Fracción del marco que ocupa la hoja.
Relación de aspecto
lado mayor / lado menor
≥ 1
Indicador burdo de la forma de la lámina.
Latitud y longitud
latitud, longitud
grados decimales
Posición del árbol.
CCI
ANOVA de un factor sobre ln(área)
0–1
Fracción de la varianza que ocurre entre árboles.
Razón sombra/sol
exp(β) del modelo mixto o razón de medias geométricas
sin unidad
Cociente de áreas de sombra respecto de sol; 1 = sin efecto.
Nota. Las columnas del archivo de datos se normalizan al leerlas
(minúsculas, sin tildes).
cat(tcap("qc", "Revisión de calidad de la base y decisiones tomadas", "Cada problema se resuelve con una regla explícita y reproducible; la fila original se conserva en la base de trabajo."))
Tabla 3.Revisión de calidad de la base y
decisiones tomadas
tabla(qc_tab, align = "lll")
Verificación
Resultado
Decisión
Estructura de la base
60 filas × 12 columnas; 6 árboles
Se normalizan nombres de columna y tipos
Hojas por árbol
10 (protocolo: 10)
Se conserva el n real de cada árbol
Áreas en blanco (pendientes)
0 de 60 (0,0 %)
Se excluyen del análisis primario; se estiman aparte (sensibilidad)
Árboles sin ninguna área medida
ninguno
Se excluyen del nivel de árbol; se usan en el análisis del marco
Espacios sobrantes en el área
24 celdas
Se eliminan al leer (strip)
Coordenadas con separador de miles
60 filas
Se reconstruye el valor decimal (3.379.480 → 3,379480)
Exposición válida y constante por árbol
0 valores no reconocidos; 0 inconsistencias
Se verifica; los no válidos se excluirían
Área ≤ 0 o mayor que el marco
0 filas (0 corregidas por unidad)
Se corrigen si el cociente /100 es plausible; si no, se excluyen
Archivos de foto repetidos
0
Se eliminan duplicados
Árbol medido dos veces (< umbral de distancia)
0 pares
Se unificarían bajo un solo árbol
Columnas de la plantilla ausentes
grupo, id_arbol, fecha, observaciones
Se advierte; no afecta al análisis
Nota. Cada problema se resuelve con una regla explícita y
reproducible; la fila original se conserva en la base de trabajo.
Áreas completas. Todas las hojas tienen área medida
(Fig. 2).
Fig. 2 | Completitud de la base por hoja y por árbol.a, Mosaico hoja a hoja; los números son el área (cm²)
usada en el análisis. b, Porcentaje de hojas con área
medida por árbol.
1.3 Ubicación de los
árboles: mapa interactivo
Los árboles están separados entre 11 y 230 m; el más alejado del
centroide es T6 (175 m), un detalle relevante porque la posición
espacial puede confundirse con la exposición (véase Forma de la hoja
y contexto espacial). Haz clic en un marcador para ver la
fotografía y los datos del árbol; el control de capas permite cambiar el
mapa base y ocultar una exposición.
presentes <- intersect(niveles_expo, unique(sitios$exposicion))
if (HAS_LEAFLET) {
library(leaflet)
mapa <- leaflet(height = 480) %>%
addProviderTiles(providers$Esri.WorldImagery, group = "Satélite") %>%
addTiles(group = "Calles")
for (e in presentes) {
d <- sitios[sitios$exposicion == e, ]
mapa <- addCircleMarkers(mapa, data = d, lng = ~lon, lat = ~lat, radius = 9, weight = 2,
color = "white", fillColor = col_expo[[e]], fillOpacity = 0.95,
label = ~id_arbol, popup = ~popup,
popupOptions = popupOptions(maxWidth = 260), group = lab_expo[[e]])
}
mapa %>%
addLayersControl(baseGroups = c("Satélite", "Calles"), overlayGroups = unname(lab_expo[presentes]),
options = layersControlOptions(collapsed = FALSE)) %>%
addLegend("bottomright", colors = unname(col_expo[presentes]), labels = unname(lab_expo[presentes]),
title = "Exposición", opacity = 1) %>%
addScaleBar("bottomleft")
} else {
cat("El paquete 'leaflet' no está instalado: se muestra un mapa simple.",
"Para el mapa interactivo ejecuta install.packages('leaflet').\n")
plot(sitios$lon, sitios$lat, pch = 21, cex = 3, bg = col_expo[sitios$exposicion],
asp = 1 / cos(mean(sitios$lat) * pi / 180), xlab = "Longitud (°)", ylab = "Latitud (°)",
main = "Ubicación de los árboles")
text(sitios$lon, sitios$lat, sub(".*_", "", sitios$id_arbol), cex = 0.8)
legend("topright", legend = lab_expo[presentes], pt.bg = col_expo[presentes], pch = 21, bty = "n")
}
Fig. 3 | Mapa interactivo de los árboles muestreados. Cada
círculo es un árbol (color = exposición lumínica). Al pulsarlo se
muestran su fotografía, el número de hojas registradas, el área foliar
media y sus coordenadas (grados decimales).
Fig. 4 | Posición de los árboles en el bosque urbano.a, Plano local (metros respecto del centroide, a partir
de las coordenadas registradas). El tamaño del círculo es proporcional
al área media medida; los círculos vacíos son árboles sin áreas medidas.
b, Distancia entre pares de árboles (m).
1.4 Fotografías de los
árboles
Fotografía de referencia de cada árbol, que documenta su estado, su
entorno y su grado de exposición solar. Haz clic en una imagen para
ampliarla y usa los botones para filtrar por exposición. Se cargaron 6
fotografías.
fig_html <- vapply(seq_len(nrow(sitios)), function(i) {
s <- sitios[i, ]
marco <- if (is.na(s$uri_gal)) paste0('<div class="marco vacio"><span>Foto no disponible<br><code>arbol', s$num, '.jpg</code></span></div>') else
paste0('<div class="marco"><img src="', s$uri_gal, '" alt="Árbol ', s$id_arbol, ' · ', lab_expo[[s$exposicion]], '" loading="lazy"><span class="badge ', s$exposicion, '">', toupper(s$exposicion), '</span></div>')
meta <- paste0(s$hojas, " hojas · ", if (is.na(s$media)) "sin áreas medidas" else paste0("área media ", fx(s$media, 1), " cm²"))
paste0('<figure class="', s$exposicion, '" data-expo="', s$exposicion, '">', marco,
'<figcaption><b>Árbol ', s$id_arbol, '</b> · ', lab_expo[[s$exposicion]], '<br><span class="meta">', meta, '</span></figcaption></figure>')
}, character(1))
js <- paste0("<script>(function(){var lb=document.getElementById('lb'),im=lb.querySelector('img'),cp=lb.querySelector('.lbcap');",
"document.querySelectorAll('.galeria .marco img').forEach(function(el){el.addEventListener('click',function(){im.src=el.src;cp.textContent=el.alt;lb.classList.add('on');});});",
"lb.addEventListener('click',function(){lb.classList.remove('on');});",
"document.addEventListener('keydown',function(e){if(e.key==='Escape'){lb.classList.remove('on');}});",
"var bs=document.querySelectorAll('.galeria-filtros button');bs.forEach(function(b){b.addEventListener('click',function(){bs.forEach(function(x){x.classList.remove('on');});b.classList.add('on');var f=b.getAttribute('data-f');",
"document.querySelectorAll('.galeria figure').forEach(function(fg){fg.classList.toggle('oculto',f!=='todos'&&fg.getAttribute('data-expo')!==f);});});});})();</script>")
# Se devuelve como objeto 'asis' (no con cat): imprimir varios MB de base64 en una sola linea hace que knitr se congele
knitr::asis_output(paste0('\n```{=html}\n',
'<div class="galeria-filtros"><button class="on" data-f="todos">Todos</button><button data-f="sol">A pleno sol</button><button data-f="sombra">A la sombra</button></div>\n',
'<div class="galeria">\n', paste(fig_html, collapse = "\n"), '\n</div>\n',
'<div id="lb" class="lb"><img alt=""><div class="lbcap"></div></div>\n', js, '\n```\n\n'))
SOMBRA
Árbol T1 · A la sombra 10 hojas · área media 80,2 cm²
SOL
Árbol T2 · A pleno sol 10 hojas · área media 108,7 cm²
SOL
Árbol T3 · A pleno sol 10 hojas · área media 81,0 cm²
SOMBRA
Árbol T4 · A la sombra 10 hojas · área media 123,1 cm²
SOL
Árbol T5 · A pleno sol 10 hojas · área media 96,1 cm²
SOMBRA
Árbol T6 · A la sombra 10 hojas · área media 148,7 cm²
Fig. 5 | Fotografías de referencia de los árboles muestreados.
Marco superior: exposición lumínica (naranja, pleno sol; azul, sombra).
Pie: identificador del árbol, número de hojas registradas y área foliar
media.
2 Resultados
2.1 El marco rectangular
como indicador del tamaño de la hoja
Cada hoja se trazó dentro de un marco rectangular cuyos lados se
midieron con regla, de modo que el área del marco (lado
1 × lado 2) existe para las 60 hojas, incluso cuando el área medida por
imagen está pendiente. Entre las 60 hojas con ambas medidas, el área de
la hoja fue en promedio el 66,9 % del área del marco (rango 54–73 %), y
ambas medidas se relacionan de forma muy estrecha (R² = 0,964;
Fig. 6). Al predecir el área de una hoja con su marco,
el error típico es de ≈ 5,3 %. El cociente área/marco difirió entre
árboles (p = 0,006) y sí entre exposiciones (p =
0,009); el marco no es, por tanto, un indicador neutral respecto de la
exposición. Por eso el marco sirve, con cautela, para validar las áreas
medidas, detectar errores de unidad y estimar las áreas pendientes.
Fig. 6 | El área del marco predice el área de la hoja.a, Relación entre el área del marco y el área medida
(escala log–log); línea sólida, ajuste por mínimos cuadrados; línea
discontinua, proporcionalidad con el cociente medio. b,
Cociente área/marco por árbol (puntos: hojas; barras: media ± DE).
2.2 Variación entre y
dentro de árboles
td <- merge(comp[, c("arbol", "exposicion", "n_medida", "n_total")], desc_all[, c("arbol", "media", "mediana", "de", "cv", "li", "ls", "min", "max", "geom")], by = "arbol", all.x = TRUE)
td <- td[order(as.integer(gsub("\\D", "", td$arbol))), ]
td_out <- data.frame(Árbol = td$arbol, Exposición = td$exposicion, `n (medidas/total)` = paste0(td$n_medida, "/", td$n_total),
Media = fx(td$media, 1), Mediana = fx(td$mediana, 1), DE = fx(td$de, 1), `CV (%)` = fx(td$cv, 1),
`IC 95 % de la media` = ifelse(is.na(td$li), "n/d", paste0(fx(td$li, 1), "–", fx(td$ls, 1))),
`Mín.–máx.` = ifelse(is.na(td$min), "n/d", paste0(fx(td$min, 1), "–", fx(td$max, 1))),
`Media geom.` = fx(td$geom, 1), check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("desc", "Estadísticos descriptivos del área foliar (cm²) por árbol",
"Cada columna es un árbol (exposición tras el punto); datos de las hojas con área medida. DE, desviación estándar; CV, coeficiente de variación (DE/media); IC, intervalo de confianza <i>t</i> de Student de la media; n/d, no disponible (sin áreas medidas o una sola hoja)."))
Tabla 4.Estadísticos descriptivos del área
foliar (cm²) por árbol
ok_t1 <- FALSE
if (HAS_T1) {
rc_arbol <- function(x, ...) {
x <- x[is.finite(x)]; n <- length(x)
if (n == 0) return(c("", "n" = "0", "Media (DE)" = "n/d", "Mediana [mín.–máx.]" = "n/d", "CV (%)" = "n/d", "Media geométrica" = "n/d", "IC 95 % de la media" = "n/d"))
m <- mean(x); s <- if (n > 1) sd(x) else NA
ic <- if (n > 1) m + c(-1, 1) * qt(.975, n - 1) * s / sqrt(n) else c(NA, NA)
c("", "n" = as.character(n), "Media (DE)" = paste0(fx(m, 1), " (", fx(s, 1), ")"),
"Mediana [mín.–máx.]" = paste0(fx(median(x), 1), " [", fx(min(x), 1), "–", fx(max(x), 1), "]"),
"CV (%)" = fx(if (n > 1) 100 * s / m else NA, 1), "Media geométrica" = fx(exp(mean(log(x))), 1),
"IC 95 % de la media" = if (n > 1) paste0(fx(ic[1], 1), "–", fx(ic[2], 1)) else "n/d")
}
ld <- lim[, c("area", "arbol")]
ld$arbol_f <- factor(paste0(ld$arbol, " · ", as.character(lim$exposicion)), levels = paste0(comp$arbol, " · ", comp$exposicion))
table1::label(ld$area) <- "Área foliar de la hoja (cm²)"
t_desc <- tryCatch(table1::table1(~ area | arbol_f, data = ld, overall = FALSE, droplevels = FALSE, rowlabelhead = "Variable",
render.continuous = rc_arbol, render.missing = NULL, topclass = "Rtable1-times"), error = function(e) NULL)
if (!is.null(t_desc)) { t1_out(t_desc); ok_t1 <- TRUE }
}
```{=html}
Variable
T1 · sombra (N=10)
T2 · sol (N=10)
T3 · sol (N=10)
T4 · sombra (N=10)
T5 · sol (N=10)
T6 · sombra (N=10)
Área foliar de la hoja (cm²)
n
10
10
10
10
10
10
Media (DE)
80,2 (14,7)
108,7 (14,5)
81,0 (10,5)
123,1 (21,6)
96,1 (15,6)
148,7 (25,4)
Mediana [mín.–máx.]
82,5 [50,8–103,4]
107,3 [92,7–139,0]
76,0 [69,3–97,0]
126,1 [91,1–152,5]
93,8 [73,4–122,4]
142,4 [119,0–191,4]
CV (%)
18,4
13,3
13,0
17,5
16,2
17,1
Media geométrica
78,8
107,9
80,4
121,4
94,9
146,8
IC 95 % de la media
69,7–90,7
98,4–119,1
73,4–88,5
107,7–138,6
84,9–107,2
130,5–166,8
<p class="tnota"><b>Nota.</b> Cada columna es un árbol (exposición tras el punto); datos de las hojas con área medida. DE, desviación estándar; CV, coeficiente de variación (DE/media); IC, intervalo de confianza <i>t</i> de Student de la media; n/d, no disponible (sin áreas medidas o una sola hoja).</p>
``` r
if (!ok_t1) tabla(td_out, align = "llrrrrrrrr")
Las medias de árbol fueron de 80,2 a 148,7 cm² (T1 y T6,
respectivamente), y el CV dentro de árbol de 13,0 a 18,4 %
(Tabla 4, Fig. 7). Las diferencias
entre árboles son comparables o mayores que las que hay entre hojas de
un mismo árbol.
lim$arbol_f2 <- factor(lim$arbol, levels = comp$arbol)
vacios <- which(comp$n_medida == 0)
etq2 <- setNames(comp$exposicion, comp$arbol)
pa <- ggplot(lim, aes(arbol_f2, area, fill = exposicion)) +
geom_boxplot(width = .55, outlier.shape = NA, alpha = .5, colour = "grey25", linewidth = .4) +
geom_jitter(aes(colour = exposicion), width = .13, height = 0, size = 1.7, alpha = .85) +
stat_summary(fun = mean, geom = "point", shape = 23, size = 3, fill = "white", colour = "grey15") +
scale_x_discrete(drop = FALSE, labels = function(x) paste0(x, "\n", etq2[x])) +
scale_fill_manual(values = COL, name = "Exposición") + scale_colour_manual(values = COL, guide = "none") + labs(x = NULL, y = "Área foliar (cm²)")
if (length(vacios)) pa <- pa + annotate("text", x = vacios, y = mean(range(lim$area)), label = "sin áreas\nmedidas", size = 3, colour = "grey40")
pb <- ggplot(desc_all[!is.na(desc_all$de), ], aes(media, de)) + geom_smooth(method = "lm", formula = y ~ x, se = FALSE, colour = "grey40", linewidth = .4, linetype = 2) +
geom_point(aes(fill = exposicion), shape = 21, size = 3.4, colour = "grey15") + geom_text(aes(label = arbol), nudge_y = diff(range(desc_all$de, na.rm = TRUE)) * .1 + .3, size = 3) +
scale_fill_manual(values = COL, guide = "none") + labs(x = "Media del árbol (cm²)", y = "DE dentro del árbol (cm²)")
pc <- ggplot(desc_all[!is.na(desc_all$de_ln), ], aes(media_ln, de_ln)) + geom_smooth(method = "lm", formula = y ~ x, se = FALSE, colour = "grey40", linewidth = .4, linetype = 2) +
geom_point(aes(fill = exposicion), shape = 21, size = 3.4, colour = "grey15") +
scale_fill_manual(values = COL, guide = "none") + labs(x = "Media del área (escala log)", y = "DE del área (escala log)")
dd2 <- desc_all[!is.na(desc_all$de), ]
if (nrow(dd2) >= 3) {
R$r_orig <- cor(dd2$media, dd2$de); R$r_log <- cor(dd2$media_ln, dd2$de_ln)
pb <- pb + annotate("text", x = min(dd2$media), y = max(dd2$de), hjust = 0, size = 3.2, label = paste0("r = ", fx(R$r_orig, 2)))
pc <- pc + annotate("text", x = min(dd2$media_ln), y = max(dd2$de_ln), hjust = 0, size = 3.2, label = paste0("r = ", fx(R$r_log, 2)))
}
pa / (pb | pc) + plot_layout(heights = c(1.25, 1)) + plot_annotation(tag_levels = "a")
Fig. 7 | Distribución del área foliar por árbol y relación
media–dispersión.a, Una caja por árbol
(mediana, rango intercuartílico y bigotes de 1,5 × RIC); puntos, hojas;
rombos blancos, medias. b, c, Desviación estándar
frente a la media de cada árbol en la escala original
(b) y en logaritmos (c); la
transformación logarítmica estabiliza la varianza si desaparece la
dependencia.
Entre árboles, la dispersión de las hojas crece con el tamaño medio
(r = 0,93) y esa relación pasa a r = 0,06 al usar logaritmos (6 árboles;
coeficientes solo descriptivos). Por eso el análisis se hace en escala
logarítmica y los efectos se expresan como razones de tamaño.
2.2.1 Cuánta variación
hay entre árboles
Los árboles sí difieren entre sí en el tamaño de sus hojas (ANOVA,
F(5; 54) = 21,97; p < 0,001). El 68 % de la
variación del tamaño se debe a diferencias entre árboles (coeficiente de
correlación intraclase, CCI = 0,68; IC 95 %: 0,41–0,93)9 y el
resto, a diferencias entre hojas de un mismo árbol (Fig.
8). Es decir, las hojas de un mismo árbol tienden a parecerse
entre sí.
if (!is.null(R$icc)) {
a1 <- R$icc$an; msb <- a1$`Mean Sq`[1]; msw <- a1$`Mean Sq`[2]
v_t_a <- max((msb - msw) / R$icc$n0, 0); v_e_a <- msw
vv <- data.frame(modelo = "Solo árbol\n(ANOVA)", comp = c("Entre árboles", "Entre hojas (dentro del árbol)"), v = c(v_t_a, v_e_a))
if (!is.null(R$mix)) {
Xm <- lme4::getME(R$mix$m, "X"); vf <- var(as.numeric(Xm %*% lme4::fixef(R$mix$m)))
vv <- rbind(vv, data.frame(modelo = "Con exposición\n(mixto)", comp = c("Exposición (fija)", "Entre árboles", "Entre hojas (dentro del árbol)"), v = c(vf, R$mix$v_t, R$mix$v_e)))
}
vv$pct <- ave(vv$v, vv$modelo, FUN = function(z) 100 * z / sum(z))
vv$comp <- factor(vv$comp, levels = c("Exposición (fija)", "Entre árboles", "Entre hojas (dentro del árbol)"))
pa <- ggplot(vv, aes(pct, modelo, fill = comp)) + geom_col(width = .55, colour = "white") +
geom_text(aes(label = ifelse(pct > 6, paste0(fx(pct, 0), " %"), "")), position = position_stack(vjust = .5), size = 3, colour = "white", fontface = "bold") +
scale_fill_manual(values = c("Exposición (fija)" = "#E69F00", "Entre árboles" = "#0072B2", "Entre hojas (dentro del árbol)" = "grey70"), name = "Fuente de variación") +
labs(x = "% de la variación del tamaño de la hoja", y = NULL) + guides(fill = guide_legend(nrow = 2))
pb <- ggplot(data.frame(x = "CCI", e = R$icc$icc, lo = R$icc$li, hi = R$icc$ls), aes(e, x)) +
geom_vline(xintercept = c(0, 1), linetype = 3, colour = "grey60") +
geom_segment(aes(x = lo, xend = hi, y = x, yend = x), linewidth = .8) + geom_point(size = 3.6, shape = 21, fill = "#0072B2") +
scale_x_continuous(limits = c(min(0, R$icc$li) - .05, 1.02)) + labs(x = "Coeficiente de correlación intraclase", y = NULL) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank())
pa + pb + plot_layout(widths = c(1.8, 1)) + plot_annotation(tag_levels = "a")
}
Fig. 8 | Reparto de la variación del tamaño de la hoja.a, Componentes de varianza (porcentaje del total) del
modelo solo con árbol (estimadores de ANOVA) y, si está disponible, del
modelo mixto con la exposición como efecto fijo.10b, Coeficiente de correlación intraclase con su
intervalo de confianza de 95 %.
2.3 Valores atípicos:
¿error de medición u hoja realmente distinta?
Criterio para decidir si una hoja atípica se conserva (dos pasos)
Se aplicó un criterio en dos pasos. Primero, ¿hay
una causa de medición (unidad equivocada, área mayor que el marco, trazo
dudoso, foto borrosa)? Si la hay, se corrige o se excluye, como en la
revisión de calidad (Tabla 3).
Segundo, si no hay causa de medición pero la hoja queda
fuera de la regla de Tukey de su árbol (Q1 − 1,5·RIC, Q3 + 1,5·RIC) o su
z robusto basado en la MAD supera 3,5 en valor absoluto, se
considera una hoja realmente distinta: se conserva y se
mide cuánto cambia el resultado sin ella (análisis de sensibilidad).
Además se examinaron los residuos studentizados y la distancia de Cook
del modelo con árbol.
cat(tcap("atip", "Hojas marcadas por algún criterio de atipicidad", "Se evalúan árboles con al menos 4 hojas medidas. <i>z</i> robusto = 0,6745·(x − mediana)/MAD."))
Tabla 5.Hojas marcadas por algún criterio de
atipicidad
if (nrow(atip_marcadas) > 0) {
ta <- data.frame(Árbol = atip_marcadas$arbol, `Hoja (n.º)` = atip_marcadas$n_hoja, `Área (cm²)` = fx(atip_marcadas$area, 1),
`z robusto` = fx(atip_marcadas$z_robusto, 2), `Fuera de Tukey` = ifelse(atip_marcadas$fuera_tukey, "sí", "no"),
`|z| > 3,5` = ifelse(atip_marcadas$fuera_z, "sí", "no"), `Razón área / mediana del árbol` = fx(atip_marcadas$razon_mediana, 2), check.names = FALSE)
tabla(ta, align = "lrrrccr")
} else cat("<p><i>Ninguna hoja queda fuera de los criterios en los árboles evaluables.</i></p>\n")
Árbol
Hoja (n.º)
Área (cm²)
z robusto
Fuera de Tukey
|z| > 3,5
Razón área / mediana del árbol
T1
5
50,8
-2,55
sí
no
0,62
Nota. Se evalúan árboles con al menos 4 hojas medidas. z
robusto = 0,6745·(x − mediana)/MAD.
R$txt_atip <- paste0("Con los criterios descritos se marcaron ", R$n_atip, " hojas (", tref("atip"), "). Ninguna tiene una causa de medición evidente (su cociente área/marco está dentro del rango observado, ", fx(R$ratio_ok[1], 2), "–", fx(R$ratio_ok[2], 2), "), por lo que se conservan. Según cómo se resuma cada árbol (media, mediana, etc.), la diferencia sombra − sol va de ",
fx(R$sens_rango[1], 1), " a ", fx(R$sens_rango[2], 1), " cm² (", fref("atipicos"), "b)",
if (!is.na(R$sens_rango[1]) && R$sens_rango[1] * R$sens_rango[2] < 0) ": **el signo cambia con el resumen elegido**, así que la conclusión depende de unas pocas hojas." else ": el signo no cambia, así que la conclusión no depende de hojas individuales.")
Con los criterios descritos se marcaron 1 hojas (Tabla
5). Ninguna tiene una causa de medición evidente (su cociente
área/marco está dentro del rango observado, 0,54–0,73), por lo que se
conservan. Según cómo se resuma cada árbol (media, mediana, etc.), la
diferencia sombra − sol va de 22,1 a 24,6 cm² (Fig.
9b): el signo no cambia, así que la conclusión no depende de
hojas individuales.
Fig. 9 | Detección de hojas atípicas y sensibilidad del
resultado.a, z robusto de cada hoja
respecto de la mediana de su árbol; líneas discontinuas, ±3,5.
b, Diferencia sombra − sol entre árboles según el
estadístico con que se resume cada árbol.
2.4 La unidad de análisis
es el árbol
La exposición se asignó al árbol, no a la hoja: las hojas de un mismo
árbol comparten suelo, edad, genotipo y luz. Tratarlas como réplicas de
la exposición multiplica artificialmente el tamaño de
muestra.11 Cuantificamos esa inflación con el efecto
de diseño, DEFF = 1 + (m̄ − 1)·CCI, y con el
tamaño de muestra efectivo, N/DEFF.
R$deff <- NA; R$neff <- NA
if (!is.null(R$icc)) { mbar <- nrow(limA) / nlevels(limA$arbol_f); R$deff <- 1 + (mbar - 1) * max(R$icc$icc, 0); R$neff <- nrow(limA) / R$deff; R$mbar <- mbar }
filas <- list()
if (!is.null(R$pseudo)) filas[[1]] <- c("Hojas como datos independientes (incorrecto)", R$pseudo$n, fx(R$pseudo$razon, 2), fci(R$pseudo$li, R$pseudo$ls), fp(R$pseudo$p))
filas[[length(filas) + 1]] <- c("Un promedio por árbol (correcto)", paste0(R$n_sol, " + ", R$n_som, " = ", R$n_sol + R$n_som), fx(bA$razon, 2), fci(bA$li, bA$ls), fp(bA$p_welch))
tp <- as.data.frame(do.call(rbind, filas), stringsAsFactors = FALSE)
names(tp) <- c("Estrategia de análisis", "Unidades analizadas (n)", "Razón sombra/sol", "IC 95 %", "Valor de p (Welch)")
cat(tcap("pseudo", "Pseudorreplicación: hojas frente a árboles como unidad de análisis", paste0("Prueba de Welch en escala logarítmica (razón de medias geométricas). Efecto de diseño estimado: ", fx(R$deff, 1), "; tamaño de muestra efectivo ≈ ", fx(R$neff, 1), " hojas independientes de ", nrow(limA), ".")))
Tabla 6.Pseudorreplicación: hojas frente a
árboles como unidad de análisis
tabla(tp, align = "lrrrr")
Estrategia de análisis
Unidades analizadas (n)
Razón sombra/sol
IC 95 %
Valor de p (Welch)
Hojas como datos independientes (incorrecto)
60
1,19
[1,04; 1,37]
0,011
Un promedio por árbol (correcto)
3 + 3 = 6
1,19
[0,61; 2,33]
0,448
Nota. Prueba de Welch en escala logarítmica (razón de medias
geométricas). Efecto de diseño estimado: 7,1; tamaño de muestra efectivo
≈ 8,5 hojas independientes de 60.
R$txt_pseudo <- if (!is.null(R$pseudo)) paste0("Si las ", R$pseudo$n, " hojas se trataran como datos independientes, el valor de *p* sería ", fp(R$pseudo$p), " (en lugar de ", fp(bA$p_welch), ") y el intervalo parecería más estrecho (", fci(R$pseudo$li, R$pseudo$ls), " frente a ", fci(bA$li, bA$ls),
"). Esa precisión es ilusoria: como las hojas de un mismo árbol se parecen entre sí (CCI = ", fx(R$icc$icc, 2), "), las ", nrow(limA), " hojas aportan información equivalente a solo unas ", fx(R$neff, 0), " hojas independientes.") else "No hay dos exposiciones con datos suficientes para ilustrar la pseudorreplicación."
Si las 60 hojas se trataran como datos independientes, el valor de
p sería 0,011 (en lugar de 0,448) y el intervalo parecería más
estrecho ([1,04; 1,37] frente a [0,61; 2,33]). Esa precisión es
ilusoria: como las hojas de un mismo árbol se parecen entre sí (CCI =
0,68), las 60 hojas aportan información equivalente a solo unas 8 hojas
independientes.
if (nlevels(limA$exposicion) == 2) {
pa <- ggplot(limA, aes(exposicion, area)) +
geom_violin(aes(fill = exposicion), alpha = .22, colour = NA, scale = "width") +
geom_boxplot(width = .14, outlier.shape = NA, fill = "white", colour = "grey25", linewidth = .4) +
geom_jitter(aes(fill = exposicion, shape = arbol), width = .14, height = 0, size = 2.2, colour = "grey15", stroke = .3, alpha = .85) +
scale_fill_manual(values = COL, guide = "none") + scale_shape_manual(values = shp_f, name = "Árbol") + labs(x = NULL, y = "Área foliar de la hoja (cm²)")
ex_sum <- do.call(rbind, lapply(split(arb, droplevels(arb$exposicion)), function(d) {
n <- nrow(d); m <- mean(d$media); s <- if (n > 1) sd(d$media) else NA; tc <- if (n > 1) qt(.975, n - 1) else NA
data.frame(exposicion = as.character(d$exposicion[1]), n = n, m = m, li = m - tc * s / sqrt(n), ls = m + tc * s / sqrt(n))
}))
ex_sum$exposicion <- factor(ex_sum$exposicion, levels = c("sol", "sombra"))
pb <- ggplot() +
geom_segment(data = ex_sum, aes(x = exposicion, xend = exposicion, y = li, yend = ls), linewidth = 1.1, colour = "grey20", na.rm = TRUE) +
geom_point(data = ex_sum, aes(exposicion, m), shape = 95, size = 14, colour = "grey20") +
geom_point(data = arb, aes(exposicion, media, fill = exposicion, shape = arbol), size = 4, colour = "grey15", stroke = .5, position = position_nudge(x = .18)) +
geom_text(data = arb, aes(exposicion, media, label = arbol), nudge_x = .32, size = 3, colour = "grey25") +
geom_text(data = ex_sum, aes(exposicion, Inf, label = paste0("n = ", n, " árboles")), vjust = 1.6, size = 3.2) +
scale_fill_manual(values = COL, guide = "none") + scale_shape_manual(values = shp_f, guide = "none") + labs(x = NULL, y = "Área foliar media del árbol (cm²)")
pa + pb + plot_layout(widths = c(1.2, 1)) + plot_annotation(tag_levels = "a")
}
Fig. 10 | El contraste sol–sombra: hojas frente a
árboles.a, Hojas (descriptivo): cada símbolo
es un árbol distinto; las hojas del mismo árbol se agrupan, lo que
revela su falta de independencia. b, Unidad de análisis
correcta: un punto por árbol (media aritmética de sus hojas), con la
media de cada exposición y su intervalo de confianza t de 95 %
(barra); n = número de árboles.
2.5 Inferencia sobre la
exposición con el árbol como unidad
Sobre los promedios de árbol se aplicaron seis enfoques
complementarios (Tabla 7), que se resumen en la
Fig. 12.
Ver los seis enfoques y el tamaño del efecto
Los enfoques fueron: la prueba t de Welch,12
sobre la escala original y sobre la escala logarítmica (que da
directamente una razón de medias geométricas); la prueba de Wilcoxon
exacta;13 una prueba de permutación exacta que enumera todos
los repartimientos posibles de las etiquetas sol/sombra entre los
árboles; un bootstrap jerárquico en dos etapas (árboles y luego hojas
dentro de árbol);14 el modelo mixto con el árbol como efecto
aleatorio, con grados de libertad de Satterthwaite;15–17 y el
ANOVA anidado, que prueba la exposición contra la variación entre
árboles. El tamaño del efecto se resume con la g de
Hedges.18,19
fil <- list()
fil[[1]] <- c("Welch con el promedio por árbol (escala log)", paste0("razón = ", fx(bA$razon, 2)), fci(bA$li, bA$ls), paste0("gl = ", fx(bA$df, 1)), fp(bA$p_welch))
fil[[2]] <- c("Welch sobre área media por árbol (cm²)", if (!is.null(bcm)) paste0("dif. = ", fx(bcm$dif, 1), " cm²") else "n/d", if (!is.null(bcm)) fci(bcm$li, bcm$ls, 1) else "n/d", "", if (!is.null(bcm)) fp(bcm$p) else "n/d")
fil[[3]] <- c("Wilcoxon (exacta)", "—", "—", "", fp(bA$p_wilcox))
fil[[4]] <- c("Permutación exacta de etiquetas", "—", "—", paste0(if (!is.null(bA$perm)) bA$perm$n_rep else "n/d", " repartos; p mínimo = ", R$pmin_txt), fp(bA$p_perm))
fil[[5]] <- c("Bootstrap jerárquico (percentil)", if (!is.null(R$boot)) paste0("razón = ", fx(exp(median(R$boot)), 2)) else "n/d", if (!is.null(R$boot)) fci(R$boot_ci[1], R$boot_ci[2]) else "n/d",
if (!is.null(R$boot)) paste0("P(razón > 1) = ", fx(R$boot_prob, 2)) else "", "—")
fil[[6]] <- c("Modelo mixto (árbol aleatorio)", if (!is.null(R$mix)) paste0("razón = ", fx(R$mix$razon, 2)) else "no disponible", if (!is.null(R$mix)) fci(R$mix$li, R$mix$ls) else "—",
if (!is.null(R$mix)) paste0("t = ", fx(R$mix$t, 2), "; gl = ", fx(R$mix$df, 1)) else "", if (!is.null(R$mix)) fp(R$mix$p) else "—")
fil[[7]] <- c("ANOVA anidado (exposición vs. árbol)", "—", "—", if (!is.null(R$nested)) paste0("F(1; ", R$nested$an$Df[2], ") = ", fx(R$nested$Fe, 2)) else "n/d", if (!is.null(R$nested)) fp(R$nested$pe) else "n/d")
fil[[8]] <- c("Tamaño del efecto (g de Hedges, escala log)", paste0("g = ", fx(bA$g, 2)), fci(bA$g_li, bA$g_ls), "", "—")
tb <- as.data.frame(do.call(rbind, fil), stringsAsFactors = FALSE); names(tb) <- c("Método de análisis", "Estimación (sombra respecto de sol)", "IC 95 %", "Estadístico / detalle", "Valor de p")
cat(tcap("bateria", "Comparación sol–sombra con el árbol como unidad (análisis primario: áreas medidas)", paste0("Razones y diferencias son sombra respecto de sol; ", R$n_sol, " árboles de sol y ", R$n_som, " de sombra. El IC del bootstrap es percentil; los demás son <i>t</i> (Welch o Satterthwaite).")))
Tabla 7.Comparación sol–sombra con el árbol
como unidad (análisis primario: áreas medidas)
tabla(tb, align = "lrrrr")
Método de análisis
Estimación (sombra respecto de sol)
IC 95 %
Estadístico / detalle
Valor de p
Welch con el promedio por árbol (escala log)
razón = 1,19
[0,61; 2,33]
gl = 2,8
0,448
Welch sobre área media por árbol (cm²)
dif. = 22,1 cm²
[-52,3; 96,4]
0,390
Wilcoxon (exacta)
—
—
0,700
Permutación exacta de etiquetas
—
—
20 repartos; p mínimo = 0,100
0,500
Bootstrap jerárquico (percentil)
razón = 1,20
[0,85; 1,62]
P(razón > 1) = 0,84
—
Modelo mixto (árbol aleatorio)
razón = 1,19
[0,68; 2,10]
t = 0,88; gl = 4,0
0,429
ANOVA anidado (exposición vs. árbol)
—
—
F(1; 4) = 0,77
0,429
Tamaño del efecto (g de Hedges, escala log)
g = 0,57
[-1,08; 2,22]
—
Nota. Razones y diferencias son sombra respecto de sol; 3 árboles
de sol y 3 de sombra. El IC del bootstrap es percentil; los demás son
t (Welch o Satterthwaite).
bt_txt <- if (!is.null(R$boot)) paste0("El bootstrap jerárquico solo dispone de ", R$boot_nuniq, " combinaciones distintas de árboles, por lo que su intervalo describe la inestabilidad del resultado más que una inferencia fiable.") else ""
R$txt_bat <- if (is.na(bA$p_welch)) "Con los árboles disponibles no es posible estimar un contraste inferencial." else paste0(
"En promedio, las hojas de los árboles de sombra midieron ", fx(R$m_som, 1), " cm² y las de sol, ", fx(R$m_sol, 1), " cm² (diferencia = ", fx(R$dif_cm, 1), " cm²). En razón de tamaños sombra/sol, ", fx(bA$razon, 2), " (IC 95 %: ", fx(bA$li, 2), "–", fx(bA$ls, 2),
"; ", fpp(bA$p_welch), "; tamaño del efecto *g* de Hedges = ", fx(bA$g, 2), "). ", R$frase_h1, " ",
if (R$no_alcanza) paste0("Además, con ", R$n_sol, " y ", R$n_som, " árboles solo hay ", bA$perm$n_rep, " repartos posibles de las etiquetas sol/sombra, de modo que el menor valor de *p* que se podría obtener es ", R$pmin_txt, ": **este diseño no puede alcanzar significación al 5 %, sean cuales sean los datos**. ") else
paste0("La prueba de permutación exacta da ", fpp(bA$p_perm), ". "), bt_txt)
En promedio, las hojas de los árboles de sombra midieron 117,3 cm² y
las de sol, 95,3 cm² (diferencia = 22,1 cm²). En razón de tamaños
sombra/sol, 1,19 (IC 95 %: 0,61–2,33; p = 0,448; tamaño del
efecto g de Hedges = 0,57). La dirección es la de H2 (hojas
algo mayores en sombra), pero el intervalo de confianza incluye la
ausencia de efecto: no hay evidencia suficiente ni a favor de H1 ni a
favor de H2. Además, con 3 y 3 árboles solo hay 20 repartos posibles de
las etiquetas sol/sombra, de modo que el menor valor de p que
se podría obtener es 0,100: este diseño no puede alcanzar
significación al 5 %, sean cuales sean los datos. El bootstrap
jerárquico solo dispone de 100 combinaciones distintas de árboles, por
lo que su intervalo describe la inestabilidad del resultado más que una
inferencia fiable.
Fig. 11 | Distribución de permutación exacta de la razón
sombra/sol. Cada punto es un reparto posible de las etiquetas
sol y sombra entre los árboles analizados; la línea
azul es el reparto observado y la línea punteada, la ausencia de efecto
(razón = 1). Si el factor no importara, todos los repartos serían
igualmente probables.
fr <- data.frame(label = character(), est = numeric(), lo = numeric(), hi = numeric(), tipo = character(), stringsAsFactors = FALSE)
addf <- function(l, e, lo, hi, t) if (!is.null(e) && length(e) == 1 && !is.na(e)) fr <<- rbind(fr, data.frame(label = l, est = e, lo = lo, hi = hi, tipo = t, stringsAsFactors = FALSE))
addf("A · Welch sobre promedios de árbol", bA$razon, bA$li, bA$ls, "correcto")
if (!is.null(R$mix)) addf("A · Modelo mixto (árbol aleatorio)", R$mix$razon, R$mix$li, R$mix$ls, "correcto")
if (!is.null(R$boot)) addf("A · Bootstrap jerárquico", exp(median(R$boot)), R$boot_ci[1], R$boot_ci[2], "correcto")
addf("B · Marco de todas las hojas", bB$razon, bB$li, bB$ls, "correcto")
if (R$n_imp > 0) addf("C · Medidas + completadas", bC$razon, bC$li, bC$ls, "correcto")
if (!is.null(R$pseudo)) addf("Hojas como réplicas (incorrecto)", R$pseudo$razon, R$pseudo$li, R$pseudo$ls, "incorrecto")
if (nrow(fr) > 0) {
fr$label <- factor(fr$label, levels = rev(fr$label))
ggplot(fr, aes(est, label, colour = tipo)) + geom_vline(xintercept = 1, linetype = 2, colour = "grey50") +
geom_segment(aes(x = lo, xend = hi, yend = label), linewidth = 1, na.rm = TRUE) + geom_point(size = 3.4) +
scale_colour_manual(values = c(correcto = "#0072B2", incorrecto = "#D55E00"), guide = "none") +
scale_x_log10(breaks = c(.25, .5, 1, 2, 4, 8)) + labs(x = "Razón de áreas sombra/sol (escala log)", y = NULL)
}
Fig. 12 | La razón sombra/sol según el método y la base de
datos. Puntos: estimaciones; barras: intervalos de confianza de
95 % (escala logarítmica). A, áreas medidas, con el
árbol como unidad; B, área del marco de las hojas;
C (solo si hubo áreas pendientes), áreas medidas más
las pendientes completadas con el modelo del marco. En rojo, el análisis
con hojas como réplicas (incorrecto). Una razón de 1 significa ausencia
de efecto.
2.6 Modelo mixto y ANOVA
anidado
El modelo mixto compara la exposición usando todas las hojas, pero
respetando que cada hoja pertenece a un árbol: el tamaño de la hoja
depende de la exposición (efecto fijo) y de un efecto propio de cada
árbol (efecto aleatorio). Es el equivalente moderno del ANOVA anidado y,
con datos desbalanceados (distinto número de hojas por árbol, como
aquí), es preferible.
if (!is.null(R$mix)) {
mx <- R$mix
t1 <- data.frame(
Medida = c("Razón de áreas sombra/sol", "Variación explicada por la exposición", "Variación debida a diferencias entre árboles", "Variación entre hojas del mismo árbol", "¿Difieren los árboles entre sí?"),
Valor = c(paste0(fx(mx$razon, 2), " ", fci(mx$li, mx$ls), "; ", gsub("\\*", "", fpp(mx$p))),
paste0(fx(100 * mx$r2m, 0), " %"), paste0(fx(100 * (mx$r2c - mx$r2m), 0), " %"), paste0(fx(100 * (1 - mx$r2c), 0), " %"),
gsub("\\*", "", fpp(mx$p_ranef))),
`Qué significa` = c("Cuántas veces es mayor (> 1) o menor (< 1) la hoja de sombra respecto de la de sol; 1 = sin diferencia. Entre corchetes, IC 95 %.",
"Parte de la variación total del tamaño de las hojas que se explica solo por sol o sombra.",
"Parte de la variación total debida a que unos árboles tienen hojas más grandes que otros, además de lo que explica la exposición.",
"Parte de la variación total que corresponde a diferencias entre hojas de un mismo árbol.",
paste0("Prueba de que la variación entre árboles es mayor que cero.", ifelse(mx$singular, " Ajuste singular: la variación entre árboles estimada es ≈ 0.", ""))),
check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("mixto", "Modelo mixto: razón sombra/sol y reparto de la variación del tamaño de la hoja", "Estimado con todas las hojas y el árbol como efecto aleatorio (REML; gl de Satterthwaite). El modelo se ajusta en escala logarítmica, pero aquí la razón se expresa en la escala original. Los tres porcentajes suman 100 % (salvo redondeo)."))
tabla(t1, align = "lll")
} else cat("<p><i>Modelo mixto no disponible (faltan paquetes o árboles).</i></p>")
Tabla 8.Modelo mixto: razón sombra/sol y
reparto de la variación del tamaño de la hoja
Medida
Valor
Qué significa
Razón de áreas sombra/sol
1,19 [0,68; 2,10]; p = 0,429
Cuántas veces es mayor (> 1) o menor (< 1) la hoja de sombra respecto de la de sol; 1 = sin diferencia. Entre corchetes, IC 95 %.
Variación explicada por la exposición
9 %
Parte de la variación total del tamaño de las hojas que se explica solo por sol o sombra.
Variación debida a diferencias entre árboles
63 %
Parte de la variación total debida a que unos árboles tienen hojas más grandes que otros, además de lo que explica la exposición.
Variación entre hojas del mismo árbol
29 %
Parte de la variación total que corresponde a diferencias entre hojas de un mismo árbol.
¿Difieren los árboles entre sí?
p < 0,001
Prueba de que la variación entre árboles es mayor que cero.
Nota. Estimado con todas las hojas y el árbol como efecto
aleatorio (REML; gl de Satterthwaite). El modelo se ajusta en escala
logarítmica, pero aquí la razón se expresa en la escala original. Los
tres porcentajes suman 100 % (salvo redondeo).
if (!is.null(R$nested)) {
an <- R$nested$an
t2 <- data.frame(`Fuente de variación` = c("Exposición", "Árbol (dentro de exposición)", "Hojas (residual)"), `gl` = an$Df, `Suma de cuadrados` = fx(an$`Sum Sq`, 3), `Cuadrado medio` = fx(an$`Mean Sq`, 3),
`Se prueba contra` = c("CM de árbol", "CM de hojas", ""), `F` = c(fx(R$nested$Fe, 2), fx(R$nested$Fa, 2), ""), `Valor de p` = c(fp(R$nested$pe), fp(R$nested$pa), ""), check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("anova", "ANOVA anidado: hojas dentro de árboles dentro de exposición", "Análisis en escala logarítmica. La exposición se prueba contra el cuadrado medio de árbol, que es su error experimental correcto. Con número desigual de hojas por árbol la partición secuencial es aproximada; el modelo mixto es la referencia."))
tabla(t2, align = "lrrrlrr")
R$txt_nested <- paste0("El ANOVA anidado da el mismo mensaje: la exposición ", ifelse(R$nested$pe < 0.05, "tiene un efecto detectable", "no tiene un efecto detectable"), " (*F*(1; ", an$Df[2], ") = ", fx(R$nested$Fe, 2), "; ", fpp(R$nested$pe), ") y los árboles de una misma exposición ",
ifelse(R$nested$pa < 0.05, "sí difieren entre sí", "no difieren de forma detectable"), " (", fpp(R$nested$pa), "). ")
} else { cat("<p><i>ANOVA anidado no disponible (se requieren al menos 3 árboles y las dos exposiciones).</i></p>"); R$txt_nested <- "" }
Tabla 9.ANOVA anidado: hojas dentro de
árboles dentro de exposición
Fuente de variación
gl
Suma de cuadrados
Cuadrado medio
Se prueba contra
F
Valor de p
Exposición
1
0,476
0,476
CM de árbol
0,77
0,429
Árbol (dentro de exposición)
4
2,464
0,616
CM de hojas
23,02
< 0,001
Hojas (residual)
54
1,445
0,027
Nota. Análisis en escala logarítmica. La exposición se prueba
contra el cuadrado medio de árbol, que es su error experimental
correcto. Con número desigual de hojas por árbol la partición secuencial
es aproximada; el modelo mixto es la referencia.
R$txt_mix <- if (!is.null(R$mix)) paste0("El modelo mixto estima una razón sombra/sol de ", fx(R$mix$razon, 2), " (IC 95 %: ", fx(R$mix$li, 2), "–", fx(R$mix$ls, 2), "; ", fpp(R$mix$p),
"). La exposición explica solo el ", fx(100 * R$mix$r2m, 0), " % de la variación del tamaño de las hojas; las diferencias entre árboles, el ", fx(100 * (R$mix$r2c - R$mix$r2m), 0), " %; y el ", fx(100 * (1 - R$mix$r2c), 0), " % restante corresponde a diferencias entre hojas del mismo árbol (", tref("mixto"), "). ") else ""
El modelo mixto estima una razón sombra/sol de 1,19 (IC 95 %:
0,68–2,10; p = 0,429). La exposición explica solo el 9 % de la
variación del tamaño de las hojas; las diferencias entre árboles, el 63
%; y el 29 % restante corresponde a diferencias entre hojas del mismo
árbol (Tabla 8). El ANOVA anidado da el mismo mensaje:
la exposición no tiene un efecto detectable (F(1; 4) = 0,77;
p = 0,429) y los árboles de una misma exposición sí difieren
entre sí (p < 0,001). Como la exposición se asignó a árboles
y no a hojas, el contraste depende del número de árboles; por eso los
intervalos son anchos aunque haya muchas hojas. A continuación se
revisan los supuestos del modelo (Fig. 13).
mm <- NULL
if (!is.null(R$mix)) mm <- R$mix$m else if (exists("m_nest")) mm <- m_nest
if (!is.null(mm)) {
dd3 <- data.frame(e = as.numeric(resid(mm)), f = as.numeric(fitted(mm)), arbol = limA$arbol, expo = limA$exposicion)
p1 <- ggplot(dd3, aes(f, e)) + geom_hline(yintercept = 0, linetype = 2) + geom_point(aes(fill = expo), shape = 21, size = 2.2, colour = "grey20", alpha = .85) +
scale_fill_manual(values = COL, guide = "none") + labs(x = "Valor ajustado", y = "Residuo")
p2 <- ggplot(dd3, aes(sample = e)) + stat_qq_line(colour = "grey40") + stat_qq(size = 1.8, alpha = .8) + labs(x = "Cuantiles teóricos", y = "Cuantiles de los residuos")
p1 + p2 + plot_annotation(tag_levels = "a")
}
Fig. 13 | Diagnóstico del modelo.a,
Residuos frente a valores ajustados: no debería verse ningún patrón.
b, Gráfico cuantil–cuantil de los residuos: los puntos
deberían seguir la línea. Los residuos del modelo mixto son los
condicionales.
En el diagnóstico del modelo (Fig. 13) los residuos
son compatibles con una distribución normal (Shapiro–Wilk, p =
0,408)20 y la variación es similar entre árboles
(Fligner–Killeen, p = 0,814)21. Las pruebas que no
dependen de esos supuestos (ANOVA de Welch y
Kruskal–Wallis)12,22 llevan a la misma conclusión que el
ANOVA (p < 0,001 y p < 0,001, respectivamente).
Con pocas hojas por árbol estas pruebas detectan poco, por eso se
interpreta siempre el gráfico.
2.7 Diferencias entre
árboles: ANOVA y comparaciones múltiples de Tukey
Con 6 árboles hay 15 comparaciones por pares. Hacer tantas pruebas
sueltas al 5 % elevaría la probabilidad de algún falso positivo a ≈ 54
%, por lo que se usó la prueba HSD de Tukey,23 que controla
el error del conjunto, contrastada con pruebas de Welch por pares con
ajuste de Holm.24 Los árboles difieren en 9 de 15 pares
(Tabla 10, Fig. 14), y en 3 de 6 pares
de árboles de la misma exposición. Es decir, dos
árboles con la misma exposición pueden diferir tanto como uno de sol y
uno de sombra: esa variación entre árboles es el ruido frente al cual
debe competir el efecto de la exposición.
if (!is.null(R$tk)) {
tk <- R$tk
t3 <- data.frame(`Comparación (A / B)` = tk$comparacion, `Misma exposición` = ifelse(tk$misma, "sí", "no"), `Razón A/B` = fx(tk$razon, 2), `IC 95 % (Tukey)` = fci(tk$li, tk$ls),
`p ajustado (Tukey)` = fp(tk$p), `p ajustado (Welch + Holm)` = fp(tk$p_welch_holm), `Difieren (5 %)` = ifelse(tk$p < 0.05, "sí", "no"), check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("tukey", "Comparaciones por pares entre árboles", "Escala logarítmica, mostradas como razones de áreas (A respecto de B)."))
tabla(t3, align = "lcrrrrc")
}
Tabla 10.Comparaciones por pares entre
árboles
Comparación (A / B)
Misma exposición
Razón A/B
IC 95 % (Tukey)
p ajustado (Tukey)
p ajustado (Welch + Holm)
Difieren (5 %)
T6 / T1
sí
1,86
[1,50; 2,31]
< 0,001
< 0,001
sí
T6 / T3
no
1,83
[1,47; 2,27]
< 0,001
< 0,001
sí
T6 / T5
no
1,55
[1,25; 1,92]
< 0,001
< 0,001
sí
T4 / T1
sí
1,54
[1,24; 1,91]
< 0,001
< 0,001
sí
T4 / T3
no
1,51
[1,22; 1,87]
< 0,001
< 0,001
sí
T2 / T1
no
1,37
[1,10; 1,70]
0,001
0,006
sí
T6 / T2
no
1,36
[1,10; 1,69]
0,001
0,002
sí
T3 / T2
sí
0,74
[0,60; 0,92]
0,002
< 0,001
sí
T5 / T4
no
0,78
[0,63; 0,97]
0,017
0,037
sí
T6 / T4
sí
1,21
[0,97; 1,50]
0,115
0,129
no
T5 / T1
no
1,20
[0,97; 1,49]
0,131
0,143
no
T5 / T3
sí
1,18
[0,95; 1,47]
0,221
0,127
no
T5 / T2
sí
0,88
[0,71; 1,09]
0,507
0,206
no
T4 / T2
no
1,12
[0,91; 1,40]
0,597
0,228
no
T3 / T1
no
1,02
[0,82; 1,27]
1,000
0,802
no
Nota. Escala logarítmica, mostradas como razones de áreas (A
respecto de B).
Fig. 14 | Razón de áreas entre pares de árboles. Razón
con su intervalo HSD de Tukey (escala log). Si el intervalo cruza 1, no
hay diferencia detectable. Círculos rellenos: árboles de la misma
exposición; círculos vacíos: exposiciones distintas. Rojo: diferencia
detectable al 5 %.
2.8 Robustez frente a la
base de datos y a árboles individuales
Todas las hojas tienen área medida, por lo que no hay nada que
completar. El resultado primario (A) se contrasta con
(B), el análisis del área del marco, que usa solo los
lados medidos con regla y es independiente del script de imagen; y se
repite el contraste omitiendo un árbol a la vez.
mk <- function(lab, b, extra = "") c(lab, paste0(b$n_sol, " / ", b$n_som), fx(b$razon, 2), fci(b$li, b$ls), fp(b$p_welch), fp(b$p_wilcox), fp(b$p_perm))
fs <- list(mk("A · Áreas medidas", bA), mk("B · Marco de todas las hojas", bB))
if (R$n_imp > 0) fs[[3]] <- mk("C · Medidas + completadas", bC)
if (!is.null(R$sim)) fs[[length(fs) + 1]] <- c("C · incertidumbre del completado (mediana y rango 2,5–97,5 %)", "—", fx(R$sim_q[2], 2), fci(R$sim_q[1], R$sim_q[3]), "—", "—", "—")
if (!is.null(R$jk)) fs[[length(fs) + 1]] <- c("A · dejando un árbol fuera (rango)", "—", paste0(fx(R$jk_rango[1], 2), "–", fx(R$jk_rango[2], 2)), "—", "—", "—", "—")
ts <- as.data.frame(do.call(rbind, fs), stringsAsFactors = FALSE)
names(ts) <- c("Base de datos", "n árboles (sol / sombra)", "Razón sombra/sol", "IC 95 %", "p Welch", "p Wilcoxon", "p permutación")
cat(tcap("sens", "Sensibilidad del contraste sol–sombra a la base de datos y a árboles individuales", "Welch, Wilcoxon exacta y permutación exacta sobre promedios de árbol (escala log para las razones)."))
Tabla 11.Sensibilidad del contraste
sol–sombra a la base de datos y a árboles individuales
tabla(ts, align = "lrrrrrr")
Base de datos
n árboles (sol / sombra)
Razón sombra/sol
IC 95 %
p Welch
p Wilcoxon
p permutación
A · Áreas medidas
3 / 3
1,19
[0,61; 2,33]
0,448
0,700
0,500
B · Marco de todas las hojas
3 / 3
1,24
[0,67; 2,27]
0,350
0,400
0,300
A · dejando un árbol fuera (rango)
—
1,04–1,42
—
—
—
—
Nota. Welch, Wilcoxon exacta y permutación exacta sobre promedios
de árbol (escala log para las razones).
dirs <- c(bA$razon, bB$razon, if (R$n_imp > 0) bC$razon); dirs <- dirs[!is.na(dirs)]
R$concord <- length(dirs) >= 2 && (all(dirs > 1) || all(dirs < 1))
R$txt_sens <- paste0("Las bases de datos analizadas ", if (R$concord) paste0("apuntan en la misma dirección (", ifelse(all(dirs > 1), "hojas mayores en sombra", "hojas mayores en sol"), ")") else "**no coinciden** en la dirección del efecto",
". Clasificación: A, ", R$conc_A, "; B, ", R$conc_B, if (R$n_imp > 0) paste0("; C, ", R$conc_C) else "", ". ",
if (!is.null(R$sim)) paste0("Completar las áreas pendientes añade poca incertidumbre (", fx(R$sim_q[1], 2), "–", fx(R$sim_q[3], 2), ") frente a la que impone el número de árboles. ") else "",
if (!is.na(R$jk_rango[1])) paste0("Al quitar un árbol a la vez, la razón varía entre ", fx(R$jk_rango[1], 2), " y ", fx(R$jk_rango[2], 2),
if (R$jk_cruza) paste0(": **el resultado cambia de signo según el árbol que se omita**, es decir, depende de árboles concretos (", fref("jack"), ").") else paste0(": la dirección se mantiene (", fref("jack"), ").")) else "")
Las bases de datos analizadas apuntan en la misma dirección (hojas
mayores en sombra). Clasificación: A, no concluyente (el intervalo
incluye 1); B, no concluyente (el intervalo incluye 1). Al quitar un
árbol a la vez, la razón varía entre 1,04 y 1,42: la dirección se
mantiene (Fig. 16).
if (!is.null(R$sim)) {
ggplot(data.frame(r = exp(R$sim)), aes(r)) + geom_histogram(bins = 40, fill = "grey80", colour = "white") +
geom_vline(xintercept = bC$razon, colour = COL["sombra"], linewidth = 1) + geom_vline(xintercept = bA$razon, colour = "black", linetype = 2) + geom_vline(xintercept = 1, linetype = 3, colour = "grey50") +
labs(x = "Razón sombra/sol", y = "Simulaciones")
} else ggplot() + theme_void() + annotate("text", x = 0, y = 0, label = "No hay áreas pendientes que completar")
Fig. 15 | Incertidumbre propagada del completado de las áreas
pendientes. Distribución de la razón sombra/sol en las
simulaciones que reemplazan cada área pendiente por una predicción del
modelo marco → área más ruido residual. Línea azul: estimación con el
completado determinista (C); línea negra: análisis con solo áreas
medidas (A).
Fig. 16 | Influencia de cada árbol (omisión de un árbol a la
vez). Razón sombra/sol al excluir cada árbol. Línea
discontinua: estimación con todos los árboles; línea punteada: ausencia
de efecto. Un árbol cuya omisión cambia mucho la estimación es un árbol
influyente.
2.9 Potencia y tamaño de
muestra
Con la desviación estándar entre árboles observada (en escala
logarítmica; σ = 0,25, IC 95 %: 0,15–0,71, con solo 4 grados de
libertad), se calculó la razón mínima detectable con 80 % de potencia y
α = 0,05 según el número de árboles por exposición (Fig.
17).
if (!is.null(R$pot)) {
p <- R$pot
lo <- vapply(p$ns, function(n) exp(power.t.test(n = n, power = .8, sd = p$sd_ic[1])$delta), numeric(1))
hi <- vapply(p$ns, function(n) exp(power.t.test(n = n, power = .8, sd = p$sd_ic[2])$delta), numeric(1))
dfp <- data.frame(n = p$ns, mde = p$mde, lo = lo, hi = hi)
ggplot(dfp, aes(n, mde)) + geom_ribbon(aes(ymin = lo, ymax = hi), fill = "grey87") + geom_line(linewidth = .9) +
geom_hline(yintercept = 1, linetype = 3) + geom_hline(yintercept = bA$razon, colour = COL["sombra"], linetype = 2) +
geom_vline(xintercept = min(R$n_sol, R$n_som), colour = "grey40", linetype = 2) +
scale_y_log10(breaks = c(1, 1.25, 1.5, 2, 3, 5)) + coord_cartesian(ylim = c(1, 5)) +
labs(x = "Árboles por exposición", y = "Razón mínima detectable (sombra/sol)")
}
Fig. 17 | Diferencia mínima detectable en función del número de
árboles. Razón sombra/sol detectable con 80 % de potencia
(prueba t de dos muestras sobre promedios de árbol; banda:
incertidumbre de la desviación estándar entre árboles estimada con pocos
grados de libertad). Línea vertical: árboles por exposición en el
análisis A; línea azul discontinua: razón observada.
Con 3 árboles por exposición, la razón mínima detectable es ≈ 2,14,
es decir, solo diferencias muy grandes. Para detectar razones de 1,2;
1,3; 1,5 y 2,0 se necesitarían aproximadamente 31, 16, 7, 4 árboles por
exposición, respectivamente (con la desviación entre árboles aquí
estimada, que es incierta). La conclusión práctica coincide con la de la
partición de varianza: conviene medir más árboles antes
que más hojas por árbol.
Fig. 18 | Relación de aspecto del marco y posición espacial de
los árboles.a, Relación de aspecto (lado
mayor/lado menor del marco) por árbol, como indicador burdo de la forma.
b, Media geométrica del área de cada árbol frente a su
posición norte–sur; un patrón espacial podría confundirse con la
exposición.
La relación de aspecto del marco fue 1,11 en promedio (rango
1,00–1,33), propia de láminas bilobuladas casi tan anchas como largas;
entre exposiciones la razón de aspecto fue 0,96 (IC 95 %: 0,87–1,07;
p = 0,305), sin indicio de cambio de forma. El árbol más
alejado del centroide (T6, a 175 m) hace que la correlación de Spearman
entre la posición norte–sur y el tamaño sea ρ = 0,71 (p =
0,136, n = 6, solo exploratoria). Con tan pocos árboles, la exposición y
la ubicación no pueden separarse.
3 Discusión
Con el árbol como unidad experimental, las hojas de los árboles de
sombra fueron 19 % mayores que las de sol en promedio geométrico (razón
= 1,19; IC 95 %: 0,61–2,33; p = 0,448). La dirección es la de
H2 (hojas algo mayores en sombra), pero el intervalo de confianza
incluye la ausencia de efecto: no hay evidencia suficiente ni a favor de
H1 ni a favor de H2. Más informativo que el contraste es el reparto de
la variación: el 68 % de la variación del tamaño de las hojas está entre
árboles (CCI = 0,68), es decir, el árbol es la fuente de variación
dominante y la exposición, una de varias posibles causas de ella. Con 3
árboles por exposición, el diseño solo habría detectado razones de ≈
2,14 o mayores con 80 % de potencia. Conviene leer estos números con las
cautelas que recomienda la literatura estadística: un intervalo de
confianza que incluye la ausencia de efecto describe
imprecisión, no demuestra que no haya efecto, y la
diferencia entre un resultado «significativo» y otro «no significativo»
no es en sí misma significativa.25–27 Por eso este informe
prioriza las estimaciones con sus intervalos y la coherencia entre
análisis sobre el valor de p de una sola prueba.
3.1 Contraste con la
literatura
La Fig. 19 confronta las predicciones de ambas
hipótesis con lo observado. H1 se apoya en que una mayor radiación
aporta más energía a la fotosíntesis y en que, a escala global, las
hojas grandes predominan en ambientes cálidos, húmedos y
soleados.4 H2 se apoya en la compensación en sombra: con poca
luz las plantas despliegan rasgos que optimizan la captura de luz y
modifican la masa por área y la asignación de superficie
foliar.28,29 A favor de H2 también actúa la limitación
térmica e hídrica a pleno sol: una lámina mayor engrosa la capa límite y
dificulta disipar calor y agua.7,8 Cuál domina depende del
balance entre luz, temperatura y agua en cada micrositio, y por eso la
dirección del efecto sobre el área de una hoja debe contrastarse caso
por caso. Además, el área de una hoja no es una medida de producción: no
se midieron fotosíntesis ni biomasa, y el aprovechamiento de la luz
depende de cómo se organiza todo el follaje.
Fig. 19 | Predicciones de la literatura frente a lo
observado.a, Rutas causales que plantea la
teoría para el área de una hoja individual; los números entre corchetes
remiten a las referencias. b, Razón sombra/sol
observada con tres bases de datos (barras: IC 95 %). La zona ocre es la
región predicha por H1 (hojas mayores a pleno sol); la zona azul, la de
H2 (hojas mayores en sombra).
tl <- data.frame(
Predicción = c("Más radiación y agua suficiente favorecen láminas mayores a pleno sol (H1)", "En sombra, la compensación morfológica favorece láminas mayores (H2)", "El calor excesivo y el déficit hídrico limitan el tamaño a pleno sol", "La luz modifica la masa por área y la asignación foliar", "La variación entre individuos es grande y no puede ignorarse al replicar"),
Fuentes = c(paste0("Ref. ", cn("wright2017")), paste0("Refs. ", cn("valladares2008", "givnish1988", "poorter2019")), paste0("Refs. ", cn("parkhurst1972", "michaletz2015")), paste0("Refs. ", cn("poorter2009", "poorter2019")), paste0("Ref. ", cn("hurlbert1984"))),
`Este estudio` = c(paste0("razón ", fx(bA$razon, 2), " (", fx(bA$li, 2), "–", fx(bA$ls, 2), ")"), paste0("razón ", fx(bA$razon, 2), " (", fx(bA$li, 2), "–", fx(bA$ls, 2), ")"),
"no separable: no se midieron temperatura ni estado hídrico", "no medida (solo área de la lámina)", if (!is.null(R$icc)) paste0("CCI = ", fx(R$icc$icc, 2)) else "n/d"),
Valoración = c(R$val_h1, R$val_alt, "no evaluable con estos datos", "no evaluable con estos datos",
if (!is.null(R$icc)) ifelse(R$icc$icc > 0.3, "consistente: la varianza entre árboles es sustancial", "no evidente en estos datos") else "n/d"),
check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("lit", "Predicciones derivadas de la literatura y su contraste con los datos", "«No evaluable» significa que la variable que distingue la hipótesis no se registró."))
Tabla 12.Predicciones derivadas de la
literatura y su contraste con los datos
tabla(tl, align = "llll")
Predicción
Fuentes
Este estudio
Valoración
Más radiación y agua suficiente favorecen láminas mayores a pleno sol (H1)
Ref. 4
razón 1,19 (0,61–2,33)
no concluyente (el IC incluye 1)
En sombra, la compensación morfológica favorece láminas mayores (H2)
Refs. 5,6,29
razón 1,19 (0,61–2,33)
no concluyente (el IC incluye 1)
El calor excesivo y el déficit hídrico limitan el tamaño a pleno sol
Refs. 7,8
no separable: no se midieron temperatura ni estado hídrico
no evaluable con estos datos
La luz modifica la masa por área y la asignación foliar
Refs. 28,29
no medida (solo área de la lámina)
no evaluable con estos datos
La variación entre individuos es grande y no puede ignorarse al replicar
Ref. 11
CCI = 0,68
consistente: la varianza entre árboles es sustancial
Nota. «No evaluable» significa que la variable que distingue la
hipótesis no se registró.
3.2 Qué es un resultado y
qué es una hipótesis
Siguiendo la distinción que pide la guía, con unos pocos árboles
conviene separar lo que los datos establecen de lo que solo
sugieren:
Resultados (descriptivos, bien sustentados): la
distribución del área por árbol (Tabla 4); la
regularidad del cociente área/marco y su utilidad como control de
calidad (El marco explicó el 96 % de la variación del log-área de las
hojas medidas, lo que permitió un análisis de sensibilidad con las 60
hojas.); y la magnitud de la variación entre árboles frente a la
variación entre hojas.
Hipótesis (requieren más árboles): que la
exposición cambie el área foliar de Bauhinia picta y en qué
sentido. La dirección es la de H2 (hojas algo mayores en sombra), pero
el intervalo de confianza incluye la ausencia de efecto: no hay
evidencia suficiente ni a favor de H1 ni a favor de H2. Esta lectura es
válida únicamente para los 6 árboles analizados.
No evaluable aquí: los mecanismos (luz,
temperatura, agua, suelo pavimentado), porque no se midieron; se
requeriría registrar irradiancia, temperatura foliar o del aire, humedad
del suelo y masa por área.
3.3 Limitaciones
Pocos árboles. La réplica verdadera es el árbol y
hay 3 de sol y 3 de sombra con datos; los grados de libertad del
contraste son los de los árboles y la potencia es baja (véase
Potencia y tamaño de muestra).
Árboles influyentes y confusión espacial. la
exposición y la posición en el bosque urbano no están cruzadas, de modo
que no se pueden separar sus efectos.
Exposición categórica. «Sol» y «sombra» son clases
definidas visualmente (luz directa la mayor parte del día frente a
cobertura de otras copas o luz filtrada), no medidas de irradiancia; el
sombreado varía a lo largo del día y del año, y la sombra por «luz
filtrada» es heterogénea.
Áreas pendientes. Hay 0 áreas pendientes (0,0 %).
Completarlas con el modelo del marco es un artificio útil para evaluar
la sensibilidad, pero no sustituye la medición, y el análisis con el
marco no es una confirmación independiente porque el marco se dibuja a
partir del contorno de la propia hoja.
Elección de los árboles. El único criterio de
selección fue que estuvieran desarrollados y sin daño ni enfermedad
aparente; no se igualaron edad, tamaño ni morfotipo, de modo que parte
de la diferencia atribuida a la exposición puede reflejar esas
diferencias entre individuos.
Una sola especie, un solo sitio y una sola fecha
(no registrada en la base): los resultados no se extrapolan a otras
especies ni a otras épocas.
Medición. La detección del marco y de la figura en
la fotografía, y el dibujo del marco con regla, introducen error de
medida; el error residual del modelo del marco (≈ 5,2 %) es una cota
inferior del error de predicción, no del error del área.
4 Métodos
Sitio y especie. El estudio se realizó en el Bosque
Urbano Multicentro, ubicado en el área forestal protectora del río
Meléndez, comuna 22, Cali (Valle del Cauca, Colombia), a 987 m s. n. m.
(altitud registrada en la base). La especie estudiada fue Bauhinia
picta.
Selección de árboles. Dentro del bosque urbano se
identificaron zonas abiertas y zonas de alta densidad arbórea. Se
consideraron árboles de sol los que reciben luz directa
la mayor parte del día y no están cubiertos por otras copas ni por
edificaciones, y árboles de sombra los que crecen bajo
la cobertura de otros árboles o en zonas con luz filtrada. Se
seleccionaron 6 árboles, 3 de sol y 3 de sombra, para obtener un diseño
balanceado; el único criterio de selección fue que estuvieran
desarrollados y sin daño ni enfermedad aparente. De cada árbol se
registraron las coordenadas y se tomó una fotografía de referencia que
documenta su estado, su entorno y su grado de exposición solar.
Selección de hojas. En cada árbol se muestrearon 10
hojas (60 en total), distribuidas por toda la copa y a diferentes
distancias.
Medición del área foliar. Alrededor del contorno de
cada hoja se dibujó con regla un marco rectangular y se midieron sus dos
lados en milímetros. Se fotografió la hoja con su marco y un script en R
usó el tamaño del marco en cada fotografía como escala para convertir
píxeles a cm² y calcular así el área de la hoja. El área del
marco se calculó como lado 1 × lado 2 (mm²) / 100 (cm²).
Procesamiento y control de calidad. Los datos se
leyeron como texto y se convirtieron a tipos numéricos con reglas
explícitas: eliminación de espacios, coma o punto decimal,
reconstrucción de coordenadas escritas con separador de miles,
normalización de la exposición y de los identificadores. Un área mayor
que su marco es físicamente imposible; si dividida entre 100 resultaba
plausible (cociente entre 0,2 y 1) se interpretó como error de unidad y
se corrigió; en otro caso se excluyó. Las áreas en blanco no se imputan
en el análisis primario. La base analítica primaria (A)
contiene las hojas con área medida válida de los árboles con al menos 3
hojas medidas.
Estadística descriptiva y transformación. Por árbol
se calcularon n, media, mediana, DE, CV, error estándar, IC 95
% (t), mínimo, máximo y media geométrica. La inferencia se hizo
sobre el logaritmo natural del área (ln), porque el tamaño es
multiplicativo y la dispersión crece con la media; las diferencias en ln
se reportan como razones de medias geométricas. En el resto del informe
los resultados se expresan en la escala original (razones de tamaño) y
se omite la mención al logaritmo.
Unidad de análisis y contraste sol–sombra. Para cada
árbol se calculó el promedio de ln(área) y esos promedios se compararon
entre exposiciones con la prueba t de Welch,12 la
prueba de Wilcoxon exacta,13 una prueba de permutación exacta
(diferencia de medias de árbol bajo todos los repartos de las etiquetas)
y un bootstrap jerárquico de dos etapas (5000 réplicas: remuestreo de
árboles dentro de cada exposición y de hojas dentro de cada
árbol).14 Se calculó la g de Hedges con IC
aproximado.18 El efecto de diseño se estimó como 1 +
(m̄ − 1)·CCI.
Modelos. Se ajustó el modelo mixto ln(A) ~
exposición + (1 | árbol) por REML con lme4 y
lmerTest (gl de Satterthwaite), con R² marginal y
condicional (Nakagawa y Schielzeth), y el ANOVA anidado con la
exposición contrastada contra el cuadrado medio de árbol. El CCI se
estimó por ANOVA de un factor con IC de McGraw y Wong, usando el tamaño
medio ponderado n0. Los supuestos se revisaron con
gráficos de residuos y con las pruebas de Shapiro–Wilk y
Fligner–Killeen; como alternativas robustas se usaron el ANOVA de Welch
y Kruskal–Wallis. Las comparaciones por pares entre árboles usaron Tukey
HSD y, como contraste, Welch con ajuste de Holm.
Valores atípicos. Regla de Tukey por árbol
(1,5·RIC), z robusto con la MAD (umbral 3,5), residuos
studentizados (|t| > 3) y distancia de Cook (4/N).
Las hojas sin causa de medición se conservan y se evalúa la sensibilidad
del resultado a distintos resúmenes del árbol (media, mediana, media
recortada, media sin atípicos).
Análisis de sensibilidad. (B) El
contraste se repitió con ln(área del marco) de todas las hojas.
(C) Las áreas pendientes se estimaron con la regresión
ln(área) ~ ln(marco) ajustada a las hojas medidas (con corrección de
retransformación) y se repitió el contraste; su incertidumbre se propagó
con 2000 simulaciones que añaden el error residual y el de estimación
del modelo. También se omitió un árbol a la vez (jackknife por
árbol).
Potencia. Se calculó la razón mínima detectable (80
% de potencia, α = 0,05, prueba t de dos muestras) con la
desviación estándar entre árboles observada dentro de cada exposición y
su IC por χ².
Software y reproducibilidad. Todo el análisis se
ejecuta desde este documento con R version 4.4.2 (2024-10-31 ucrt); los
gráficos usan ggplot2,30 con paleta de Okabe–Ito
apta para daltonismo, y patchwork. Semilla aleatoria:
20261103. Paquetes: ggplot2 4.0.3, patchwork 1.3.2, lme4 2.0.1, lmerTest
3.2.1.31 Si se modifica el archivo de datos, basta volver a
compilar el documento.
Disponibilidad de datos y de código. Los datos
analizados son los de datos.csv. Cambiando el parámetro
guardar_limpios a TRUE se escribe la base
depurada (datos_limpios_area_foliar.csv).
Pérez-Harguindeguy, N. et al. New handbook for standardised
measurement of plant functional traits worldwide. Aust. J. Bot.61, 167–234 (2013).
https://doi.org/10.1071/BT12225
Givnish, T. J. Adaptation to sun and shade: a whole-plant perspective.
Aust. J. Plant Physiol.15, 63–92 (1988).
https://doi.org/10.1071/PP9880063
Parkhurst, D. F. & Loucks, O. L. Optimal leaf size in relation to
environment. J. Ecol.60, 505–537 (1972).
https://doi.org/10.2307/2258359
Michaletz, S. T. et al. Plant thermoregulation: energetics,
trait–environment interactions, and carbon economics. Trends Ecol.
Evol.30, 714–724 (2015).
https://doi.org/10.1016/j.tree.2015.09.006
McGraw, K. O. & Wong, S. P. Forming inferences about some intraclass
correlation coefficients. Psychol. Methods1, 30–46
(1996).
https://doi.org/10.1037/1082-989X.1.1.30
Nakagawa, S. & Schielzeth, H. A general and simple method for
obtaining R2 from generalized linear mixed-effects models.
Methods Ecol. Evol.4, 133–142 (2013).
https://doi.org/10.1111/j.2041-210x.2012.00261.x
Hurlbert, S. H. Pseudoreplication and the design of ecological field
experiments. Ecol. Monogr.54, 187–211 (1984).
https://doi.org/10.2307/1942661
Welch, B. L. The generalization of ‘Student’s’ problem when several
different population variances are involved. Biometrika34, 28–35 (1947).
https://doi.org/10.1093/biomet/34.1-2.28
Bates, D., Mächler, M., Bolker, B. & Walker, S. Fitting linear
mixed-effects models using lme4. J. Stat. Softw.67, 1–48
(2015).
https://doi.org/10.18637/jss.v067.i01
Kuznetsova, A., Brockhoff, P. B. & Christensen, R. H. B. lmerTest
package: tests in linear mixed effects models. J. Stat. Softw.82, 1–26 (2017).
https://doi.org/10.18637/jss.v082.i13
Satterthwaite, F. E. An approximate distribution of estimates of
variance components. Biometrics Bull.2, 110–114 (1946).
https://doi.org/10.2307/3002019
Hedges, L. V. Distribution theory for Glass’s estimator of effect size
and related estimators. J. Educ. Stat.6, 107–128 (1981).
https://doi.org/10.3102/10769986006002107
Lakens, D. Calculating and reporting effect sizes to facilitate
cumulative science: a practical primer for t-tests and ANOVAs. Front.
Psychol.4, 863 (2013).
https://doi.org/10.3389/fpsyg.2013.00863
Gelman, A. & Stern, H. The difference between ‘significant’ and ‘not
significant’ is not itself statistically significant. Am. Stat.60, 328–331 (2006).
https://doi.org/10.1198/000313006X152649
Poorter, H., Niinemets, Ü., Poorter, L., Wright, I. J. & Villar, R.
Causes and consequences of variation in leaf mass per area (LMA): a
meta-analysis. New Phytol.182, 565–588 (2009).
https://doi.org/10.1111/j.1469-8137.2009.02830.x
Poorter, H. et al. A meta-analysis of plant responses to light
intensity for 70 traits ranging from molecules to whole plant
performance. New Phytol.223, 1073–1105 (2019).
https://doi.org/10.1111/nph.15754
R Core Team. R: A Language and Environment for Statistical
Computing (R Foundation for Statistical Computing, Vienna).
https://www.R-project.org/
Información suplementaria
Cumplimiento del protocolo de la guía
ok <- function(x) ifelse(x, "✔ cumple", "✘ no cumple")
n_hoja_arb <- table(datos$arbol)
tpr <- data.frame(
Requisito = c("Al menos 2 árboles a pleno sol y 2 a la sombra", "10 hojas por árbol", "5 árboles por grupo", "Área medida en todas las hojas", "ID con formato G#_T# (p. ej. G3_T2)",
"Columnas de la plantilla (grupo, id_arbol, fecha, observaciones)", "Coordenadas en grados decimales con un mismo separador", "Ningún árbol medido dos veces"),
Estado = c(ok(min(R$n_sol_tot, R$n_som_tot) >= 2), ok(all(n_hoja_arb == 10)), ok(R$n_arb == 5), ok(R$n_falta == 0), ok(all(grepl("^G[0-9]+_T[0-9]+$", datos$arbol_raw))),
ok(length(R$cols_plantilla_faltan) == 0), ok(R$n_coord_miles == 0), ok(nrow(R$dup_arbol) == 0)),
Observación = c(paste0(R$n_sol_tot, " sol / ", R$n_som_tot, " sombra"), paste0(R$hojas_x_arbol[1], "–", R$hojas_x_arbol[2], " hojas"), paste0(R$n_arb, " árboles"),
paste0(R$n_falta, " pendientes"), "los identificadores son T1…T", paste0("faltan: ", ifelse(length(R$cols_plantilla_faltan), paste(R$cols_plantilla_faltan, collapse = ", "), "—")),
paste0(R$n_coord_miles, " filas con separador de miles (reconstruidas)"), paste0(nrow(R$dup_arbol), " pares a menos de ", params$dist_duplicado_m, " m")), stringsAsFactors = FALSE)
tpr$Observación[5] <- paste0("los identificadores son ", paste(head(sort(unique(datos$arbol)), 3), collapse = ", "), "…")
cat(tcap("protocolo", "Cumplimiento de los requisitos de la guía de campo", "Las desviaciones se declaran; no impiden el análisis, pero condicionan su interpretación."))
Tabla 13.Cumplimiento de los requisitos de
la guía de campo
tabla(tpr, align = "lcl")
Requisito
Estado
Observación
Al menos 2 árboles a pleno sol y 2 a la sombra
✔ cumple
3 sol / 3 sombra
10 hojas por árbol
✔ cumple
10–10 hojas
5 árboles por grupo
✘ no cumple
6 árboles
Área medida en todas las hojas
✔ cumple
0 pendientes
ID con formato G#_T# (p. ej. G3_T2)
✘ no cumple
los identificadores son T1, T2, T3…
Columnas de la plantilla (grupo, id_arbol, fecha, observaciones)
✘ no cumple
faltan: grupo, id_arbol, fecha, observaciones
Coordenadas en grados decimales con un mismo separador
✘ no cumple
60 filas con separador de miles (reconstruidas)
Ningún árbol medido dos veces
✔ cumple
0 pares a menos de 5 m
Nota. Las desviaciones se declaran; no impiden el análisis, pero
condicionan su interpretación.
Base de datos hoja a hoja
td2 <- data.frame(Archivo = datos$archivo, Árbol = datos$arbol, Exposición = as.character(datos$exposicion), `Lado 1 (mm)` = fx(datos$lado1, 0), `Lado 2 (mm)` = fx(datos$lado2, 0),
`Marco (cm²)` = fx(datos$marco_cm2, 1), `Área registrada (cm²)` = fx(datos$area_orig, 2), Estado = datos$estado, `Área usada (cm²)` = fx(datos$area_f, 2),
Origen = ifelse(is.na(datos$origen), "—", datos$origen), check.names = FALSE, stringsAsFactors = FALSE)
cat(tcap("datos", "Base de datos depurada (una fila por hoja)", "«Área usada» es la medida o, si estaba pendiente, la estimada con el modelo del marco (solo para el análisis de sensibilidad C)."))
Tabla 14.Base de datos depurada (una fila
por hoja)
Nota. «Área usada» es la medida o, si estaba pendiente, la
estimada con el modelo del marco (solo para el análisis de sensibilidad
C).
Verificación de los DOI con Crossref
norm_t <- function(s) { s <- tolower(iconv(s, to = "ASCII//TRANSLIT")); s <- gsub("[^a-z0-9 ]", " ", s); w <- unique(strsplit(trimws(gsub(" +", " ", s)), " ")[[1]]); w[nchar(w) > 0] }
jacc <- function(a, b) length(intersect(a, b)) / length(union(a, b))
.doi_env <- new.env(); .doi_env$off <- FALSE
verif <- function(k, i) {
r <- REF[[k]]; base <- data.frame(N = i, Referencia = k, DOI = ifelse(is.na(r$doi), "—", r$doi), stringsAsFactors = FALSE)
if (is.na(r$doi)) { base$Estado <- "sin DOI (se enlaza a la URL)"; return(base) }
if (!isTRUE(params$verificar_doi) || !HAS_JSON) { base$Estado <- "verificación desactivada"; return(base) }
if (.doi_env$off) { base$Estado <- "no se pudo consultar (sin conexión)"; return(base) }
res <- tryCatch(jsonlite::fromJSON(paste0("https://api.crossref.org/works/", r$doi)), error = function(e) NULL)
if (is.null(res)) .doi_env$off <- TRUE
if (is.null(res)) { base$Estado <- "no se pudo consultar (sin conexión o DOI no resuelto)"; return(base) }
tt <- res$message$title[1]
an <- tryCatch(as.integer(res$message$issued$`date-parts`[1, 1]), error = function(e) NA_integer_)
sim <- jacc(norm_t(tt), norm_t(r$tit))
base$Estado <- ifelse(sim >= 0.6 && (is.na(an) || abs(an - r$anio) <= 1), "✔ coincide con Crossref", "✘ revisar")
base
}
vt <- do.call(rbind, lapply(seq_along(.cit$orden), function(i) verif(.cit$orden[i], i)))
cat(tcap("doi", "Verificación automática de los DOI citados", "Se consulta la API de Crossref y se compara el título y el año; requiere conexión a internet al compilar."))
Tabla 15.Verificación automática de los DOI
citados
tabla(vt, align = "rllll")
N
Referencia
DOI
Estado
1
ueia2014
—
sin DOI (se enlaza a la URL)
2
violle2007
10.1111/j.0030-1299.2007.15559.x
verificación desactivada
3
perez2013
10.1071/BT12225
verificación desactivada
4
wright2017
10.1126/science.aal4760
verificación desactivada
5
valladares2008
10.1146/annurev.ecolsys.39.110707.173506
verificación desactivada
6
givnish1988
10.1071/PP9880063
verificación desactivada
7
parkhurst1972
10.2307/2258359
verificación desactivada
8
michaletz2015
10.1016/j.tree.2015.09.006
verificación desactivada
9
mcgraw1996
10.1037/1082-989X.1.1.30
verificación desactivada
10
nakagawa2013
10.1111/j.2041-210x.2012.00261.x
verificación desactivada
11
hurlbert1984
10.2307/1942661
verificación desactivada
12
welch1947
10.1093/biomet/34.1-2.28
verificación desactivada
13
wilcoxon1945
10.2307/3001968
verificación desactivada
14
efron1979
10.1214/aos/1176344552
verificación desactivada
15
bates2015
10.18637/jss.v067.i01
verificación desactivada
16
kuznetsova2017
10.18637/jss.v082.i13
verificación desactivada
17
satterthwaite1946
10.2307/3002019
verificación desactivada
18
hedges1981
10.3102/10769986006002107
verificación desactivada
19
lakens2013
10.3389/fpsyg.2013.00863
verificación desactivada
20
shapiro1965
10.1093/biomet/52.3-4.591
verificación desactivada
21
fligner1976
10.1080/01621459.1976.10481517
verificación desactivada
22
kruskal1952
10.1080/01621459.1952.10483441
verificación desactivada
23
tukey1949
10.2307/3001913
verificación desactivada
24
holm1979
—
sin DOI (se enlaza a la URL)
25
gelman2006
10.1198/000313006X152649
verificación desactivada
26
wasserstein2016
10.1080/00031305.2016.1154108
verificación desactivada
27
amrhein2019
10.1038/d41586-019-00857-9
verificación desactivada
28
poorter2009
10.1111/j.1469-8137.2009.02830.x
verificación desactivada
29
poorter2019
10.1111/nph.15754
verificación desactivada
30
wickham2016
10.1007/978-3-319-24277-4
verificación desactivada
31
rcore
—
sin DOI (se enlaza a la URL)
Nota. Se consulta la API de Crossref y se compara el título y el
año; requiere conexión a internet al compilar.