Este é um documento anexo que pertence ao artigo intitulado “Spatial structuring of woody biodiversity in the South-Central South America”, de autoria de Ângela Lúcia Bagnatori Sartori, Geraldo Alves Damasceno Junior, Emerson Pereira da Silva, Giovana Amaral Umar, Isabela Oliveira Ferreira, Mateus César Araújo Pestana, Maxwell da Rosa Oliveira, Thomaz Ricardo Favreto Sinani e Flávio Macedo Alves
Estas análises são baseadas em 112 referencias bibliográficas e base de dados dos autores realizados em remanescentes de Chaco e ecorregiões adjacentes. Nós compilamos dados de ocorrência de 1.623 táxons da flora em 307 localidades, que podem ser acessados no Material Suplementar “matrix_original.xlsx” e as análises podem ser replicadas seguindo este roteiro.
Nesta etapa, são carregados os pacotes necessários para a manipulação de dados, análises espaciais e ordenação multivariada. A semente aleatória (set.seed) é definida para garantir a reprodutibilidade das análises que envolvem permutações.
library(readxl)
library(tidyverse)
library(vegan)
library(betapart)
library(venn)
library(ggrepel)
library(dendextend)
library(geosphere)
library(indicspecies)
library(rgbif)
library(sf)
library(terra)
library(circlize)
library(ggalluvial)
library(pheatmap)
library(writexl)
library(ape)
library(ggnewscale)
library(svglite)
set.seed(123)
Anotações: A correta execução desta etapa permite o fluxo ininterrupto das análises ecológicas, carregando todas as funções necessárias na memória do R. Se houver erro, os pacotes devem ser previamente instalados.
Definição das localidades alvo (áreas de interesse primário) que guiarão as análises e a identificação do domínio florístico correspondente.
# Inserir no vetor as áreas que gostaria de obter a caracterização
local_target <- c("CHA_PANT_01",
"CHA_PANT_02",
"CHA_PANT_03",
"CHA_PANT_04",
"CHA_PANT_07",
"CHA_PANT_08",
"CHA_PANT_09",
"CHA_PANT_10")
Anotações: Estas áreas servirão como marcadores nas ordenações futuras, permitindo rastrear a qual agrupamento estatístico elas pertencem e com quais regiões elas se assemelham.
Definição das coordenadas geográficas (Bounding Box) que delimitam a área de estudo.
# Inserir coordenadas de abrangência dos dados (Bounding Box)
# c(Long_Min, Long_Max, Lat_Min, Lat_Max)
boundary_area <- c(-67.720090, -41.072987, -41.011410, -4.714250)
Anotações: Este recorte espacial atua como um filtro de segurança para garantir que a busca de dados em bases abertas (como o GBIF) retorne apenas registros georreferenciados dentro da região continental de interesse.
Importação e estruturação da matriz de dados de presença/ausência. Aplica-se uma filtragem iterativa matemática para remover locais com menos de 5 espécies e espécies que ocorrem em apenas um local (singletons).
# 2.1. Importar a planilha original
input_matrix <- read_excel("matrix_original.xlsx", col_types = "text")
# 2.2. Processar e pivotar os dados
pivot_matrix <- input_matrix %>%
select(locality, taxa) %>%
distinct(locality, taxa) %>%
mutate(presence = 1) %>%
pivot_wider(names_from = taxa, values_from = presence, values_fill = 0)
# 2.3. Ajustar os nomes das linhas (rownames) e converter para matriz numérica
matriz_df <- as.data.frame(pivot_matrix)
rownames(matriz_df) <- matriz_df$locality
matriz_df <- matriz_df %>% select(-locality)
matrix_PA <- as.matrix(matriz_df)
# 2.4 Limpeza Recursiva da Matriz (manter localidades >= 5 e espécies > 1)
matrix_PA_clean <- matrix_PA
initial_row <- nrow(matrix_PA_clean)
initial_col <- ncol(matrix_PA_clean)
iteration <- 0
while(any(rowSums(matrix_PA_clean) < 5) | any(colSums(matrix_PA_clean) <= 1)) {
iteration <- iteration + 1
valid_rows <- rowSums(matrix_PA_clean) >= 5
matrix_PA_clean <- matrix_PA_clean[valid_rows, , drop = FALSE]
valid_cols <- colSums(matrix_PA_clean) > 1
matrix_PA_clean <- matrix_PA_clean[, valid_cols, drop = FALSE]
if(nrow(matrix_PA_clean) == 0 | ncol(matrix_PA_clean) == 0) stop("Filtro muito rigoroso. Matriz vazia!")
}
cat("--- RELATÓRIO DE ESTABILIZAÇÃO DA MATRIZ ---\n")
## --- RELATÓRIO DE ESTABILIZAÇÃO DA MATRIZ ---
cat("O R atingiu a estabilidade perfeita em", iteration, "ciclos de limpeza.\n\n")
## O R atingiu a estabilidade perfeita em 2 ciclos de limpeza.
cat("LOCALIDADES (Linhas):\n - Originais:", initial_row, "\n - Mantidas: ", nrow(matrix_PA_clean), "\n - Removidas:", initial_row - nrow(matrix_PA_clean), "\n\n")
## LOCALIDADES (Linhas):
## - Originais: 308
## - Mantidas: 305
## - Removidas: 3
cat("ESPÉCIES (Colunas):\n - Originais:", initial_col, "\n - Mantidas: ", ncol(matrix_PA_clean), "\n - Removidas:", initial_col - ncol(matrix_PA_clean), "\n")
## ESPÉCIES (Colunas):
## - Originais: 1587
## - Mantidas: 1061
## - Removidas: 526
Anotações: A filtragem iterativa estabilizou a matriz de dados, removendo vieses causados por subamostragem e espécies raras pontuais. O resultado é uma matriz ecologicamente robusta para as análises multivariadas.
Importação da planilha contendo os metadados abióticos e as variáveis edafoclimáticas.
raw_data_env <- read_excel("env_variables.xlsx")
Anotações: Estes dados ambientais ficam armazenados na memória para subsidiar etapas futuras de ordenação restrita (como RDA ou CCA).
Visualização do esforço amostral bruto (pré-curadoria) plotado sobre as ecorregiões originais. A técnica de alpha blending (transparência cumulativa) é aplicada para evidenciar as coordenadas com alta densidade de amostragem sem a necessidade de clusterização numérica.
cat("\nPreparando dados espaciais originais e carregando ecorregiões...\n")
##
## Preparando dados espaciais originais e carregando ecorregiões...
df_pontos_originais <- input_matrix %>%
select(locality, longitud, latitud) %>%
distinct() %>%
mutate(long = as.numeric(gsub(",", ".", longitud)), lat = as.numeric(gsub(",", ".", latitud)))
ecorregioes_originais <- input_matrix %>%
select(Ecorregiao_Olson = TNC_Ecoregion_Olson) %>% filter(!is.na(Ecorregiao_Olson)) %>% distinct() %>% pull()
url_wwf <- "[https://c402277.ssl.cf1.rackcdn.com/publications/15/files/original/official_teow.zip](https://c402277.ssl.cf1.rackcdn.com/publications/15/files/original/official_teow.zip)"
zip_dest <- "wwf_teow.zip"
dir_dest <- "wwf_teow_extracted"
if(!dir.exists(dir_dest)) {
download.file(url_wwf, destfile = zip_dest, mode = "wb")
unzip(zip_dest, exdir = dir_dest)
}
caminho_shp <- list.files(dir_dest, pattern = "\\.shp$", recursive = TRUE, full.names = TRUE)
sf::sf_use_s2(FALSE)
shape_olson <- st_read(caminho_shp[1], quiet = TRUE) %>% st_transform(4326)
shape_eco_originais <- shape_olson %>%
filter(ECO_NAME %in% ecorregioes_originais) %>%
group_by(ECO_NAME) %>% summarise(geometry = st_union(geometry))
sf::sf_use_s2(TRUE)
# --- PADRONIZAÇÃO ESTÉTICA DO MAPA 1 (Baseado no MST) ---
cores_atuais <- c("#35978f", "#bf812d", "#8c510a", "#dfc27d", "#f6e8c3", "#f5f5f5", "#80cdc1", "#01665e", "#c7eae5")
ecos_alfabetica <- sort(unique(shape_eco_originais$ECO_NAME))
names(cores_atuais) <- ecos_alfabetica[1:length(cores_atuais)]
ordem_legenda_brbg <- names(cores_atuais)[c(3, 2, 4, 5, 6, 9, 7, 1, 8)]
mapa_amostras_iniciais <- ggplot() +
# Ecorregiões sem borda (color = NA) e com transparência (alpha = 0.7)
geom_sf(data = shape_eco_originais, aes(fill = ECO_NAME), alpha = 0.7, color = NA) +
# Pontos estruturados com borda branca (shape = 21) para melhor contraste
geom_point(data = df_pontos_originais, aes(x = long, y = lat), size = 2.5, shape = 21, fill = "black", color = "white", stroke = 0.4, alpha = 0.6) +
scale_fill_manual(values = cores_atuais, breaks = ordem_legenda_brbg) +
coord_sf(xlim = boundary_area[1:2], ylim = boundary_area[3:4], expand = FALSE) +
theme_minimal() +
labs(title = "Distribuição Espacial das Localidades Amostradas", subtitle = "Esforço amostral bruto", fill = "Ecorregião (Olson):", x = "Longitude", y = "Latitude") +
theme(legend.position = "right", plot.title = element_text(face = "bold", size = 14), panel.grid.minor = element_blank())
print(mapa_amostras_iniciais)
Cálculo da frequência de ocorrência das espécies para visualizar a distribuição e a dominância de táxons comuns e raros na região de estudo.
frequency_sp <- colSums(matrix_PA_clean)
frequency_order <- sort(frequency_sp, decreasing = TRUE)
percent_ocur <- (frequency_order / nrow(matrix_PA_clean)) * 100
plot(percent_ocur, type = "l", lwd = 2, col = "blue", main = "Curva de Frequencia-Ordem das Angiospermas", xlab = "Ordenacao das Especies", ylab = "Frequencia de Ocorrencia (%)")
abline(h = 5, col = "red", lty = 2)
cat("A espécie mais comum ocorre em", round(percent_ocur[1], 1), "% das áreas.\n")
## A espécie mais comum ocorre em 36.1 % das áreas.
cat("Número de espécies hiper-raras (<5% de ocorrência):", sum(percent_ocur < 5), "\n")
## Número de espécies hiper-raras (<5% de ocorrência): 792
Anotações: O gráfico em forma de “J invertido” é típico de comunidades biológicas regionais. A enorme proporção de espécies raras (abaixo da linha vermelha de 5%) sugere um alto número de especialistas locais e uma forte substituição de táxons (turnover) na América do Sul.
Visualização da matriz de presença/ausência da flora através de um mapa de calor (Heatmap).
matrix_image <- as.matrix(matrix_PA_clean)
matrix_image <- t(matrix_image)[, nrow(matrix_image):1]
image(x = 1:ncol(matrix_PA_clean), y = 1:nrow(matrix_PA_clean), z = matrix_image, col = c("white", "#cb181d"), main = "Mapa de Calor da Matriz", xlab = "Espécies", ylab = "Localidades")
# 1. Calcular as distâncias florísticas (Jaccard)
dist_loc <- vegdist(matrix_PA_clean, method = "jaccard")
dist_sp <- vegdist(t(matrix_PA_clean), method = "jaccard")
tree_loc <- hclust(dist_loc, method = "ward.D2")
tree_sp <- hclust(dist_sp, method = "ward.D2")
pheatmap(as.matrix(matrix_PA_clean), color = c("#f7f7f7", "#cb181d"), cluster_rows = tree_loc, cluster_cols = tree_sp, show_rownames = FALSE, show_colnames = FALSE, border_color = NA, legend_breaks = c(0, 1), legend_labels = c("Ausência", "Presença"), main = "Heatmap Florístico Clusterizado")
Anotações: O Heatmap permite
uma visualização rápida da estrutura bruta dos dados, evidenciando
lacunas e agrupamentos prévios de localidades antes mesmo da aplicação
de testes estatísticos avançados. Os pontos vermelhos no heatmap
representam presença (1) e a parte branca representa ausência (0); é
possível detectar agrupamentos prévios das espécies nas
localidades.
Curva de acumulação de espécies calculada por meio de permutações aleatórias das localidades amostradas baseadas em incidência.
regional_rare <- specaccum(matrix_PA_clean, method = "random", permutations = 100)
plot(regional_rare, ci.type = "poly", col = "darkgreen", lwd = 2, ci.lty = 0, ci.col = "lightgreen", main = "Curva de Acumulacao Regional", xlab = "Esforco Amostral", ylab = "Riqueza Acumulada")
grid()
Anotações: A estabilização
(achatamento) da curva confirma que o esforço amostral bibliográfico
compilado neste estudo foi suficiente para capturar e representar com
segurança a diversidade florística regional.
Criação de um diagrama de conjuntos baseado nas classificações de biomas atribuídas originalmente às áreas na literatura base.
df_locality <- tibble(locality = rownames(matrix_PA_clean))
df_biome_align <- df_locality %>% left_join(input_matrix %>% select(locality, domain_biome) %>% distinct(), by = "locality")
biome_vec <- df_biome_align$domain_biome
biome_uniq <- unique(na.omit(biome_vec))
nomes_biomas_puros <- biome_uniq
list_venn_dinamic <- lapply(biome_uniq, function(biome_actual) {
row_biome <- matrix_PA_clean[biome_vec == biome_actual, , drop = FALSE]
present_sp <- colnames(row_biome)[colSums(row_biome) > 0]
return(present_sp)
})
names(list_venn_dinamic) <- biome_uniq
lista_limpa_venn <- list_venn_dinamic
biome_name <- names(list_venn_dinamic)
biome_rich <- sapply(list_venn_dinamic, length)
names(list_venn_dinamic) <- paste0(biome_name, "\n(", biome_rich, " spp.)")
# AQUI ESTÁ A CORREÇÃO: Inserção do ilabels = "counts"
venn(list_venn_dinamic, zcolor = "style", opacity = 0.4, ilabels = "counts", ilcs = 0.5, sncs = 0.8, box = FALSE, borders = FALSE)
todas_spp <- unique(unlist(lista_limpa_venn))
df_sp_venn <- data.frame(Especie = todas_spp)
for (b in nomes_biomas_puros) { df_sp_venn[[b]] <- df_sp_venn$Especie %in% lista_limpa_venn[[b]] }
df_combinacoes <- df_sp_venn %>% select(-Especie) %>% group_by(across(everything())) %>% summarise(Numero_Especies = n(), .groups = "drop")
nomear_categoria <- function(linha) {
biomas_presentes <- nomes_biomas_puros[as.logical(linha)]
n_pres <- length(biomas_presentes)
n_tot <- length(nomes_biomas_puros)
if(n_pres == 1) return(paste("Exclusiva:", biomas_presentes))
else if (n_pres == n_tot) return("Intersecção: TODOS os Biomas")
else return(paste("Intersecção:", paste(biomas_presentes, collapse = " + ")))
}
df_combinacoes$Categoria <- apply(df_combinacoes[, nomes_biomas_puros], 1, nomear_categoria)
df_tabela_venn <- df_combinacoes %>% arrange(desc(Numero_Especies)) %>% select(Categoria, Numero_Especies, everything())
cat("\n")
knitr::kable(df_tabela_venn, caption = "Tabela Resumo: Compartilhamento e Exclusividade.")
| Categoria | Numero_Especies | Cerrado | Pantanal | Chaco | Mata Atlântica | Chiquitano |
|---|---|---|---|---|---|---|
| Exclusiva: Chaco | 230 | FALSE | FALSE | TRUE | FALSE | FALSE |
| Intersecção: Cerrado + Pantanal | 193 | TRUE | TRUE | FALSE | FALSE | FALSE |
| Exclusiva: Cerrado | 116 | TRUE | FALSE | FALSE | FALSE | FALSE |
| Intersecção: Cerrado + Pantanal + Mata Atlântica | 82 | TRUE | TRUE | FALSE | TRUE | FALSE |
| Exclusiva: Pantanal | 79 | FALSE | TRUE | FALSE | FALSE | FALSE |
| Intersecção: Pantanal + Chaco | 79 | FALSE | TRUE | TRUE | FALSE | FALSE |
| Intersecção: Cerrado + Pantanal + Chaco + Mata Atlântica | 74 | TRUE | TRUE | TRUE | TRUE | FALSE |
| Intersecção: Cerrado + Mata Atlântica | 40 | TRUE | FALSE | FALSE | TRUE | FALSE |
| Intersecção: Cerrado + Pantanal + Chaco | 34 | TRUE | TRUE | TRUE | FALSE | FALSE |
| Intersecção: Pantanal + Chaco + Mata Atlântica | 18 | FALSE | TRUE | TRUE | TRUE | FALSE |
| Intersecção: Cerrado + Chaco | 17 | TRUE | FALSE | TRUE | FALSE | FALSE |
| Intersecção: Cerrado + Chaco + Mata Atlântica | 16 | TRUE | FALSE | TRUE | TRUE | FALSE |
| Intersecção: TODOS os Biomas | 15 | TRUE | TRUE | TRUE | TRUE | TRUE |
| Intersecção: Chaco + Mata Atlântica | 14 | FALSE | FALSE | TRUE | TRUE | FALSE |
| Intersecção: Pantanal + Mata Atlântica | 12 | FALSE | TRUE | FALSE | TRUE | FALSE |
| Intersecção: Pantanal + Chaco + Chiquitano | 8 | FALSE | TRUE | TRUE | FALSE | TRUE |
| Intersecção: Chaco + Chiquitano | 7 | FALSE | FALSE | TRUE | FALSE | TRUE |
| Intersecção: Cerrado + Pantanal + Mata Atlântica + Chiquitano | 7 | TRUE | TRUE | FALSE | TRUE | TRUE |
| Intersecção: Cerrado + Pantanal + Chaco + Chiquitano | 6 | TRUE | TRUE | TRUE | FALSE | TRUE |
| Exclusiva: Mata Atlântica | 5 | FALSE | FALSE | FALSE | TRUE | FALSE |
| Intersecção: Cerrado + Chaco + Mata Atlântica + Chiquitano | 3 | TRUE | FALSE | TRUE | TRUE | TRUE |
| Intersecção: Cerrado + Chiquitano | 2 | TRUE | FALSE | FALSE | FALSE | TRUE |
| Intersecção: Cerrado + Pantanal + Chiquitano | 2 | TRUE | TRUE | FALSE | FALSE | TRUE |
| Intersecção: Pantanal + Chaco + Mata Atlântica + Chiquitano | 1 | FALSE | TRUE | TRUE | TRUE | TRUE |
| Intersecção: Cerrado + Mata Atlântica + Chiquitano | 1 | TRUE | FALSE | FALSE | TRUE | TRUE |
Anotações: O diagrama ilustra o número de espécies consideradas exclusivas de cada bioma e dimensiona o elevado volume de táxons compartilhados nas zonas de transição (ecótonos).
Cálculo do Z-Score para identificar localidades com desvio multivariado extremo perante a comunidade regional, seguindo os critérios de McCune & Grace.
square_matrix_raw <- as.matrix(dist_loc)
distm_raw <- rowMeans(square_matrix_raw)
z_scores_raw <- (distm_raw - mean(distm_raw)) / sd(distm_raw)
raw_rich <- rowSums(matrix_PA_clean)
df_diagnostic <- data.frame(Localidade = rownames(matrix_PA_clean), Riqueza = raw_rich, Z_Score = z_scores_raw)
df_diagnostic <- df_diagnostic %>% mutate(Status = ifelse(Z_Score > 2.0 | Riqueza < 5, "Excluída", "Mantida"))
ggplot(df_diagnostic, aes(x = Riqueza, y = Z_Score, color = Status)) +
geom_point(alpha = 0.7, size = 2.5) +
geom_hline(yintercept = 2.0, linetype = "dashed", linewidth = 1, color = "darkred") +
annotate("text", x = max(df_diagnostic$Riqueza) * 0.5, y = 2.25, label = "Corte Multivariado (Z > 2.0)", color = "darkred", fontface = "bold") +
geom_vline(xintercept = 4.5, linetype = "dotted", linewidth = 1, color = "blue") +
theme_bw() + labs(title = "Diagnostico de Curadoria da Matriz", x = "Riqueza Floristica", y = "Z-Score") +
scale_color_manual(values = c("Excluída" = "red", "Mantida" = "grey40")) + theme(legend.position = "bottom")
Anotações: O gráfico cruza a
riqueza de espécies com o distanciamento florístico (Z-score).
Localidades pontuadas acima da linha de corte vermelha (\(Z > 2.0\)) são anômalas à tendência
central dos dados e precisam ser tratadas.
Remoção matemática das localidades identificadas como outliers estatísticos com base nas suas distâncias médias de Jaccard.
outliers_multi <- which(z_scores_raw > 2.0)
if(length(outliers_multi) > 0) {
info_outliers <- data.frame(Localidade = names(outliers_multi), Z_Score = round(z_scores_raw[outliers_multi], 2))
print(knitr::kable(info_outliers[order(-info_outliers$Z_Score), ]))
}
##
##
## | |Localidade | Z_Score|
## |:-------------|:-------------|-------:|
## |CHA_SEC_11 |CHA_SEC_11 | 2.65|
## |CERDAO_CER_33 |CERDAO_CER_33 | 2.47|
## |CHA_SEC_15 |CHA_SEC_15 | 2.18|
## |CERDAO_CER_35 |CERDAO_CER_35 | 2.14|
## |CERDAO_CER_26 |CERDAO_CER_26 | 2.12|
## |CHA_HYGRO_03 |CHA_HYGRO_03 | 2.08|
## |CILIAR_CER_17 |CILIAR_CER_17 | 2.02|
matrix_PA_clean_inter <- matrix_PA_clean[z_scores_raw <= 2.0, ]
Anotações: A remoção destas localidades atípicas é fundamental para estabilizar os dados, garantindo que o estresse do NMDS seja aceitável e que as ordenações ecológicas não sofram distorções de escala.
Nova rodada iterativa de limpeza biológica para garantir que a remoção dos outliers não tenha gerado novos “singletons” secundários na matriz de dados.
cat("Limpeza Biológica Recursiva (Riqueza < 5 e Frequência <= 1) ---\n")
## Limpeza Biológica Recursiva (Riqueza < 5 e Frequência <= 1) ---
iteration_bio <- 1
continue_clean_bio <- TRUE
matrix_PA_clean_recur <- matrix_PA_clean_inter
while(continue_clean_bio) {
cat("[Rodada", iteration_bio, "] ")
curren_rich <- rowSums(matrix_PA_clean_recur)
curren_freq <- colSums(matrix_PA_clean_recur)
loc_remove <- which(curren_rich < 5)
spp_remove <- which(curren_freq <= 1)
if(length(loc_remove) == 0 && length(spp_remove) == 0) {
cat("A matriz estabilizou! Nenhuma localidade < 5 spp ou espécie única detectada.\n")
continue_clean_bio <- FALSE
} else {
cat("Removendo", length(loc_remove), "localidades e", length(spp_remove), "espécies...\n")
matrix_PA_clean_recur <- matrix_PA_clean_recur[curren_rich >= 5, curren_freq > 1]
cat(" -> Novo tamanho parcial:", nrow(matrix_PA_clean_recur), "localidades e", ncol(matrix_PA_clean_recur), "espécies.\n")
iteration_bio <- iteration_bio + 1
if(iteration_bio > 4) {
cat("\n[!] ALERTA: Limite de segurança atingido. Parando.\n")
continue_clean_bio <- FALSE
}
}
}
## [Rodada 1 ] Removendo 0 localidades e 16 espécies...
## -> Novo tamanho parcial: 298 localidades e 1045 espécies.
## [Rodada 2 ] A matriz estabilizou! Nenhuma localidade < 5 spp ou espécie única detectada.
matrix_run <- matrix_PA_clean_recur
cat("\n=== RESUMO DA CURADORIA DE DADOS ===\n")
##
## === RESUMO DA CURADORIA DE DADOS ===
cat("Matriz Definitiva: ", nrow(matrix_run), "localidades e", ncol(matrix_run), "espécies.\n")
## Matriz Definitiva: 298 localidades e 1045 espécies.
Anotações: Esta etapa de controle de qualidade garante uma matriz definitiva padronizada, totalmente livre de artefatos amostrais que poderiam interferir nos agrupamentos ecológicos das próximas seções.
Partição da diversidade beta utilizando o índice de Jaccard, separando a dissimilaridade florística em componentes de substituição (Turnover) e aninhamento (Nestedness).
part_beta <- beta.multi(matrix_run, index.family = "jaccard")
cat("Dissimilaridade Jaccard Total (Regiao):", round(part_beta$beta.JAC, 3), "\n")
## Dissimilaridade Jaccard Total (Regiao): 0.996
cat("Fracao por Turnover (Substituicao):", round(part_beta$beta.JTU, 3), "\n")
## Fracao por Turnover (Substituicao): 0.994
cat("Fracao por Aninhamento (Perda de especies):", round(part_beta$beta.JNE, 3), "\n")
## Fracao por Aninhamento (Perda de especies): 0.002
Anotações: Os resultados indicam que quase a totalidade da diversidade beta regional é explicada pela substituição de espécies (Turnover), evidenciando fortes descontinuidades florísticas, refutando a hipótese de que a diversidade local é apenas um subconjunto empobrecido de uma flora dominante (Nestedness).
Ordenação não supervisionada das localidades (NMDS) e agrupamento hierárquico (Ward.D2) com base exclusivamente na dissimilaridade florística de Jaccard, ignorando classificações a priori.
dissimilarity_matrix <- vegdist(matrix_run, method = "jaccard")
tree_biome <- hclust(dissimilarity_matrix, method = "ward.D2")
k_excell <- 2
my_data_group <- cutree(tree_biome, k = k_excell)
my_data_group <- factor(my_data_group, levels = c(1, 2), labels = c("Floristic Domain A", "Floristic Domain B"))
dendro_obj <- as.dendrogram(tree_biome)
grupos_na_ordem_do_plot <- my_data_group[tree_biome$order]
left_branc <- as.character(grupos_na_ordem_do_plot[1])
cores_ramos <- if (left_branc == "Floristic Domain A") c("#d95f02", "#1b9e77") else c("#1b9e77", "#d95f02")
dendro_colorido <- color_branches(dendro_obj, k = k_excell, col = cores_ramos)
dendro_colorido <- dendrapply(dendro_colorido, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) {
if (length(rotulos_no) > 0 && rotulos_no %in% local_target) {
np <- attr(node, "nodePar")
if (is.null(np)) attr(node, "nodePar") <- list(pch = "|", col = "black", cex = 1.5) else { np$pch <- "|"; np$col <- "black"; np$cex <- 1.5; attr(node, "nodePar") <- np }
}
attr(node, "label") <- ""
}
return(node)
})
par(mar = c(2, 4, 3, 1))
plot(dendro_colorido, main = "Dendrograma Floristico: Separacao dos Dominios (k=2)", ylab = "Distancia de Ward", xlab = "Localidades")
legend("topright", legend = c("Floristic Domain A", "Floristic Domain B", "Target Areas"), fill = c("#d95f02", "#1b9e77", "white"), border = c("black", "black", "white"), pch = c(NA, NA, "|"), col = c(NA, NA, "black"), pt.cex = 1.2, bty = "n", inset = c(0.02, 0.02))
nmds_result <- metaMDS(dissimilarity_matrix, k = 2, trymax = 100, trace = FALSE)
df_nmds_blind <- data.frame(Locality = rownames(matrix_run), NMDS1 = nmds_result$points[, 1], NMDS2 = nmds_result$points[, 2], Floristic_Group = my_data_group)
val_calc <- df_nmds_blind %>% group_by(Floristic_Group) %>% summarise(Outliers_NMDS1 = list(boxplot.stats(NMDS1)$out), .groups = "drop")
nmds_outliers_id <- df_nmds_blind %>% filter(NMDS1 %in% unlist(val_calc$Outliers_NMDS1))
df_nmds_blind <- df_nmds_blind %>% mutate(Is_Outlier = ifelse(Locality %in% nmds_outliers_id$Locality, "Sim", "Não"), Point_Color = ifelse(Locality %in% local_target, "Target Areas", as.character(Floristic_Group)))
# Centroides NMDS
centroides_nmds <- df_nmds_blind %>% group_by(Floristic_Group) %>% summarise(Centro_X = mean(NMDS1), Centro_Y = mean(NMDS2))
df_spider <- df_nmds_blind %>% left_join(centroides_nmds, by = "Floristic_Group")
# Scatter NMDS
ggplot(df_spider, aes(x = NMDS1, y = NMDS2)) +
geom_segment(aes(xend = Centro_X, yend = Centro_Y, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) +
geom_point(aes(color = Point_Color, alpha = Is_Outlier), size = 3) +
scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") +
geom_point(data = centroides_nmds, aes(x = Centro_X, y = Centro_Y, fill = Floristic_Group), size = 4.5, shape = 23, color = "black", stroke = 0.8) +
geom_text_repel(data = subset(df_spider, Is_Outlier == "Sim"), aes(label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6) +
theme_bw() + labs(title = "NMDS: Dispersão Florística", x = "NMDS 1", y = "NMDS 2") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
# Boxplot NMDS
ggplot(df_nmds_blind, aes(x = Floristic_Group, y = NMDS1, fill = Floristic_Group)) + geom_boxplot(alpha = 0.8) + theme_bw() + scale_fill_manual(values = c("#d95f02", "#1b9e77")) + theme(legend.position = "none")
Anotações: O dendrograma
sugere a quebra dos dados em dois grandes domínios florísticos centrais
(\(k=2\)). O NMDS confirma visualmente
essa forte separação no espaço bidimensional, atrelado a um nível de
estresse estatisticamente interpretável (< 0.20).
Análise de Coordenadas Principais (PCoA) aplicada como método de ordenação métrico complementar ao NMDS, de modo a preservar as distâncias lineares originais da matriz.
pcoa_result <- cmdscale(dissimilarity_matrix, k = 2, eig = TRUE)
percent_axis1 <- round(pcoa_result$eig[1] / sum(pcoa_result$eig) * 100, 1)
percent_axis2 <- round(pcoa_result$eig[2] / sum(pcoa_result$eig) * 100, 1)
df_pcoa_blind <- data.frame(Locality = rownames(matrix_run), PCoA1 = pcoa_result$points[, 1], PCoA2 = pcoa_result$points[, 2], Floristic_Group = my_data_group)
centroides_pcoa <- df_pcoa_blind %>% group_by(Floristic_Group) %>% summarise(Centro_X = mean(PCoA1), Centro_Y = mean(PCoA2))
val_calc_pcoa <- df_pcoa_blind %>% group_by(Floristic_Group) %>% summarise(Outliers_PCoA1 = list(boxplot.stats(PCoA1)$out), .groups = "drop")
pcoa_outliers_id <- df_pcoa_blind %>% filter(PCoA1 %in% unlist(val_calc_pcoa$Outliers_PCoA1))
df_pcoa_spider <- df_pcoa_blind %>% left_join(centroides_pcoa, by = "Floristic_Group") %>% mutate(Is_Outlier = ifelse(Locality %in% pcoa_outliers_id$Locality, "Sim", "Não"), Point_Color = ifelse(Locality %in% local_target, "Target Areas", as.character(Floristic_Group)))
ggplot(df_pcoa_spider, aes(x = PCoA1, y = PCoA2)) + geom_segment(aes(xend = Centro_X, yend = Centro_Y, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) + geom_point(aes(color = Point_Color, alpha = Is_Outlier), size = 3) + scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") + geom_point(data = centroides_pcoa, aes(x = Centro_X, y = Centro_Y, fill = Floristic_Group), size = 4, shape = 23, color = "black", stroke = 0.5) + geom_text_repel(data = subset(df_pcoa_spider, Is_Outlier == "Sim"), aes(label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6, point.padding = 0.3, max.overlaps = Inf) + theme_bw() + labs(title = "PCoA: Dispersão Florística a partir do Núcleo", x = paste0("PCoA 1 (", percent_axis1, "%)"), y = paste0("PCoA 2 (", percent_axis2, "%)")) + scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) + scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
ggplot(df_pcoa_blind, aes(x = Floristic_Group, y = PCoA1, fill = Floristic_Group)) + geom_boxplot(alpha = 0.8, outlier.shape = 16, outlier.size = 2, outlier.color = "red") + theme_bw() + labs(title = "Separacao Floristica ao Longo do Gradiente", x = "Dominio", y = "PCoA1") + scale_fill_manual(values = c("#d95f02", "#1b9e77")) + theme(legend.position = "none")
Anotações: A PCoA corrobora
perfeitamente a dicotomia observada no NMDS. A quantificação da
variância retida nos Eixos 1 e 2 confirma a existência de um gradiente
ambiental e florístico dominante moldando esta província
intertropical.
Aplicação do teste não paramétrico PERMANOVA para validar estatisticamente a diferença florística entre os agrupamentos derivados do dendrograma.
df_permanova_blind <- data.frame(Floristic_Group = my_data_group)
permanova_test <- adonis2(dissimilarity_matrix ~ Floristic_Group, data = df_permanova_blind, permutations = 999)
print(permanova_test)
## Permutation test for adonis under reduced model
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = dissimilarity_matrix ~ Floristic_Group, data = df_permanova_blind, permutations = 999)
## Df SumOfSqs R2 F Pr(>F)
## Model 1 13.777 0.10437 34.492 0.001 ***
## Residual 296 118.229 0.89563
## Total 297 132.006 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
dispers_grupos <- betadisper(dissimilarity_matrix, df_permanova_blind$Floristic_Group)
df_perm_scatter <- data.frame(Locality = rownames(matrix_run), PCoA1 = dispers_grupos$vectors[, 1], PCoA2 = dispers_grupos$vectors[, 2], Floristic_Group = df_permanova_blind$Floristic_Group, Centroid_Distance = dispers_grupos$distances)
df_centroids <- data.frame(Floristic_Group = rownames(dispers_grupos$centroids), Centroid1 = dispers_grupos$centroids[, 1], Centroid2 = dispers_grupos$centroids[, 2])
val_calc_perm <- df_perm_scatter %>% group_by(Floristic_Group) %>% summarise(Outliers_Dist = list(boxplot.stats(Centroid_Distance)$out), .groups = "drop")
perm_outliers_id <- df_perm_scatter %>% filter(Centroid_Distance %in% unlist(val_calc_perm$Outliers_Dist))
df_perm_scatter <- df_perm_scatter %>% left_join(df_centroids, by = "Floristic_Group") %>% mutate(Is_Outlier = ifelse(Locality %in% perm_outliers_id$Locality, "Sim", "Não"), Point_Color = ifelse(Locality %in% local_target, "Target Areas", as.character(Floristic_Group)))
ggplot(df_perm_scatter) + geom_segment(aes(x = Centroid1, y = Centroid2, xend = PCoA1, yend = PCoA2, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) + geom_point(aes(x = PCoA1, y = PCoA2, color = Point_Color, alpha = Is_Outlier), size = 3) + scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") + geom_point(aes(x = Centroid1, y = Centroid2, fill = Floristic_Group), size = 4, shape = 23, color = "black", stroke = 0.5) + geom_text_repel(data = subset(df_perm_scatter, Is_Outlier == "Sim"), aes(x = PCoA1, y = PCoA2, label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6, point.padding = 0.3, max.overlaps = Inf) + theme_bw() + labs(title = "Dispersão da PERMANOVA", x = "Eixo 1", y = "Eixo 2") + scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) + scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
df_permanova_blind$Centroid_Distance <- dispers_grupos$distances
ggplot(df_permanova_blind, aes(x = Floristic_Group, y = Centroid_Distance, fill = Floristic_Group)) + geom_boxplot(alpha = 0.8, outlier.shape = 16, outlier.size = 2, outlier.color = "red") + theme_bw() + labs(title = "Variância Interna dos Grupos", x = "Domínio", y = "Distância Florística") + scale_fill_manual(values = c("#d95f02", "#1b9e77")) + theme(legend.position = "none")
Anotações: O teste PERMANOVA
confirma que a divisão nos Domínios A e B possui significância
estatística robusta (\(p \leq 0.05\)).
O gráfico de Teia (Spider Plot) ilustra a distância e o confinamento de
cada localidade em relação ao centro do seu próprio grupo
ecológico.
Teste de Mantel para avaliar o efeito prático do Isolamento por Distância (IBD), correlacionando a matriz de dissimilaridade florística com a matriz de distância geográfica real (em km).
df_coords_align <- df_locality %>% left_join(input_matrix %>% select(locality, longitud, latitud) %>% distinct(), by = "locality") %>% mutate(longitud = as.numeric(gsub(",", ".", longitud)), latitud = as.numeric(gsub(",", ".", latitud)))
surv_locality <- rownames(matrix_run)
df_coords_clean <- df_coords_align[match(surv_locality, df_coords_align$locality), ]
coords_numeric <- df_coords_clean %>% select(longitud, latitud)
coords_matrix <- as.matrix(coords_numeric)
geo_dist_matrix_km <- distm(coords_matrix, fun = distHaversine) / 1000
geo_distance_clean <- as.dist(geo_dist_matrix_km)
# Usa a dissimilarity_matrix original do 5.2
mantel_test <- mantel(dissimilarity_matrix, geo_distance_clean, method = "spearman", permutations = 999)
print(mantel_test)
##
## Mantel statistic based on Spearman's rank correlation rho
##
## Call:
## mantel(xdis = dissimilarity_matrix, ydis = geo_distance_clean, method = "spearman", permutations = 999)
##
## Mantel statistic r: 0.459
## Significance: 0.001
##
## Upper quantiles of permutations (null model):
## 90% 95% 97.5% 99%
## 0.0225 0.0304 0.0368 0.0425
## Permutation: free
## Number of permutations: 999
df_mantel_visual <- data.frame(Dist_Geo = as.vector(geo_distance_clean), Dist_Flor = as.vector(dissimilarity_matrix))
ggplot(df_mantel_visual, aes(x = Dist_Geo, y = Dist_Flor)) + geom_point(alpha = 0.08, color = "#2c3e50", size = 0.4) + geom_smooth(method = "lm", formula = y ~ x, color = "red", linetype = "dashed", linewidth = 1, se = FALSE) + theme_bw() + labs(title = "Isolamento por Distancia", x = "Distancia Geografica Real (km)", y = "Dissimilaridade Floristica")
Anotações: A correlação
linear positiva e significativa suporta o princípio do Isolamento por
Distância: as diferenças na composição de espécies entre duas áreas
estudadas se acentuam fortemente à medida que a distância geográfica
geodésica entre elas aumenta.
Projeção de uma rede de ligação mínima (MST) baseada nas distâncias florísticas de Jaccard, colapsadas em nível de ecorregiões para revelar as principais rotas de similaridade biogeográfica.
# ==============================================================================
# 1. COLAPSAR A MATRIZ FLORÍSTICA PARA O NÍVEL DE ECORREGIÃO
# ==============================================================================
df_ecorregioes <- input_matrix %>% select(locality, Ecorregiao_Olson = TNC_Ecoregion_Olson) %>% distinct()
df_matriz <- as.data.frame(matrix_run)
df_matriz$locality <- rownames(df_matriz)
df_matriz_eco <- df_matriz %>% left_join(df_ecorregioes, by = "locality") %>% filter(!is.na(Ecorregiao_Olson))
matriz_eco_agrupada <- df_matriz_eco %>% select(-locality) %>% group_by(Ecorregiao_Olson) %>% summarise(across(everything(), sum)) %>% as.data.frame()
rownames(matriz_eco_agrupada) <- matriz_eco_agrupada$Ecorregiao_Olson
matriz_eco_agrupada <- matriz_eco_agrupada[, -1]
matriz_eco_binaria <- ifelse(matriz_eco_agrupada > 0, 1, 0)
# CÁLCULO DA RIQUEZA: Soma das ocorrências na matriz binária
riqueza_por_eco <- rowSums(matriz_eco_binaria)
dist_eco <- vegdist(matriz_eco_binaria, method = "jaccard")
arvore_espacial <- spantree(dist_eco)
# ==============================================================================
# 2. PREPARAÇÃO ESPACIAL, CENTROIDES E UNIÃO COM NMDS (k=2)
# ==============================================================================
cat("\nUnificando polígonos das ecorregiões a partir do shapefile base...\n")
##
## Unificando polígonos das ecorregiões a partir do shapefile base...
ecorregioes_presentes <- rownames(matriz_eco_binaria)
sf::sf_use_s2(FALSE)
## Spherical geometry (s2) switched off
# Reutiliza o shape_olson carregado no chunk map_originais (3.1)
shape_eco_unificado <- shape_olson %>%
filter(ECO_NAME %in% ecorregioes_presentes) %>%
group_by(ECO_NAME) %>%
summarise(geometry = st_union(geometry))
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
## although coordinates are longitude/latitude, st_union assumes that they are
## planar
centroides <- st_centroid(shape_eco_unificado)
coords_centroides <- st_coordinates(centroides)
df_centroides <- data.frame(Ecorregiao = shape_eco_unificado$ECO_NAME, X = coords_centroides[, 1], Y = coords_centroides[, 2])
df_centroides <- df_centroides[match(rownames(matriz_eco_binaria), df_centroides$Ecorregiao), ]
# Adiciona a Riqueza
df_centroides$Riqueza <- riqueza_por_eco[df_centroides$Ecorregiao]
# --- A MÁGICA DOS DATAFRAMES PARA PUXAR A COR DO NMDS ---
# 1. Pega o grupo (A ou B) que foi definido no NMDS para cada localidade
df_grupos_loc <- df_nmds_blind %>% select(locality = Locality, Floristic_Group)
# 2. Cruza isso com a informação de qual ecorregião cada localidade pertence
df_eco_grupos <- df_grupos_loc %>%
left_join(df_ecorregioes, by = "locality") %>%
filter(!is.na(Ecorregiao_Olson))
# 3. Calcula qual é o domínio predominante dentro da ecorregião
df_grupos_nmds <- df_eco_grupos %>%
group_by(Ecorregiao_Olson) %>%
summarise(Grupo_k2 = names(which.max(table(Floristic_Group)))) %>%
rename(Ecorregiao = Ecorregiao_Olson)
# 4. Junta essa informação aos centroides do mapa
df_centroides <- df_centroides %>% left_join(df_grupos_nmds, by = "Ecorregiao")
# --------------------------------------------------------
sf::sf_use_s2(TRUE)
## Spherical geometry (s2) switched on
# ==============================================================================
# 3. CRIAR OS "RAMOS ESPACIAIS" DO MST E PREPARAR CORES BrBG
# ==============================================================================
df_ramos <- data.frame(
X_Origem = df_centroides$X[2:nrow(df_centroides)],
Y_Origem = df_centroides$Y[2:nrow(df_centroides)],
X_Destino = df_centroides$X[arvore_espacial$kid],
Y_Destino = df_centroides$Y[arvore_espacial$kid],
Similaridade_Jaccard = 1 - arvore_espacial$dist
)
df_ramos$X_Mid <- (df_ramos$X_Origem + df_ramos$X_Destino) / 2
df_ramos$Y_Mid <- (df_ramos$Y_Origem + df_ramos$Y_Destino) / 2
df_ramos$Jaccard_Rotulo <- sprintf("%.2f", df_ramos$Similaridade_Jaccard)
# Configuração da Paleta BrBG (preservando cores no mapa, alterando legenda)
cores_atuais <- c("#35978f", "#bf812d", "#8c510a", "#dfc27d", "#f6e8c3", "#f5f5f5", "#80cdc1", "#01665e", "#c7eae5")
ecos_alfabetica <- sort(unique(shape_eco_unificado$ECO_NAME))
names(cores_atuais) <- ecos_alfabetica
ordem_legenda_brbg <- names(cores_atuais)[c(3, 2, 4, 5, 6, 9, 7, 1, 8)]
# ==============================================================================
# 4. PLOTAGEM DO MAPA DE REDE (COM ggnewscale)
# ==============================================================================
mapa_ramos_colapsados <- ggplot() +
# A. Polígonos das Ecorregiões (color = NA para tirar a linha branca)
geom_sf(data = shape_eco_unificado, aes(fill = ECO_NAME), alpha = 0.7, color = NA) +
scale_fill_manual(values = cores_atuais, breaks = ordem_legenda_brbg) +
# B. Ramos da MST (Espessura dinâmica baseada na similaridade)
geom_segment(
data = df_ramos,
aes(x = X_Origem, y = Y_Origem, xend = X_Destino, yend = Y_Destino, linewidth = Similaridade_Jaccard),
color = "gray15", alpha = 0.85
) +
# C. Rótulos numéricos da Similaridade nos Ramos
geom_label(
data = df_ramos,
aes(x = X_Mid, y = Y_Mid, label = Jaccard_Rotulo),
size = 2.8, fill = "white", color = "black", fontface = "bold", label.padding = unit(0.15, "lines"), label.size = 0.2
) +
# --- HABILITANDO A SEGUNDA ESCALA DE CORES PARA OS PONTOS ---
new_scale_fill() +
# D. Nós/Centroides (Tamanho pela Riqueza, Cor pelo NMDS k=2)
geom_point(
data = df_centroides,
aes(x = X, y = Y, size = Riqueza, fill = Grupo_k2),
shape = 21,
color = "black",
stroke = 1.3
) +
# E. Escalas dos Centroides e Ramos
scale_fill_manual(
values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"),
name = "Complexo Fitogeográfico (NMDS)",
na.value = "red",
guide = guide_legend(override.aes = list(size = 6))
) +
scale_size_continuous(range = c(3.5, 9.5), name = "Riqueza de Espécies") +
scale_linewidth_continuous(range = c(0.7, 2.2), guide = "none") + # Retirada da legenda do Jaccard
# F. Tema e Títulos
theme_minimal() +
labs(
title = "Rede de Conexões Florísticas Inter-Ecorregiões",
subtitle = "Ramos: Similaridade de Jaccard | Nós: Riqueza e Domínio (NMDS)",
fill = "Ecorregião (Olson):",
x = "Longitude",
y = "Latitude"
) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 14),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "#f0f0f0", linewidth = 0.3)
)
print(mapa_ramos_colapsados)
Execução da DCA (Detrended Correspondence Analysis) para aferir o comprimento do gradiente florístico e determinar se o modelo de resposta das plantas é predominantemente linear ou unimodal.
dca_model <- decorana(matrix_run)
print(dca_model)
##
## Call:
## decorana(veg = matrix_run)
##
## Detrended correspondence analysis with 26 segments.
## Rescaling of axes with 4 iterations.
## Total inertia (scaled Chi-square): 19.1239
##
## DCA1 DCA2 DCA3 DCA4
## Eigenvalues 0.8076 0.4328 0.3257 0.2722
## Additive Eigenvalues 0.8076 0.4129 0.2933 0.2647
## Decorana values 0.8380 0.4078 0.3697 0.2478
## Axis lengths 7.5949 4.1883 4.7307 3.2118
df_dca <- as.data.frame(scores(dca_model, display = "sites"))
df_dca$Locality <- rownames(matrix_run)
df_dca$Floristic_Group <- my_data_group
df_dca <- df_dca %>% mutate(Point_Color = ifelse(Locality %in% local_target, "Target Areas", as.character(Floristic_Group)))
ggplot(df_dca, aes(x = DCA1, y = DCA2)) + stat_ellipse(aes(color = Floristic_Group, fill = Floristic_Group), geom = "polygon", alpha = 0.15, linetype = "solid", linewidth = 0.8) + geom_point(aes(color = Point_Color), size = 3, alpha = 0.7) + theme_bw() + labs(title = "Detrended Correspondence Analysis (DCA)", x = "Eixo DCA 1", y = "Eixo DCA 2") + scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) + scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom", plot.title = element_text(face = "bold"))
Anotações: O comprimento
calculado do Eixo 1 (DCA1) dita o método de ordenação ambiental
subsequente (Fluxograma). Valores acentuados (ex: > 4.0 SD)
justificam análises constrangidas unimodais, como a CCA, para avaliar as
condicionantes edafoclimáticas. Verificar o fluxograma abaixo para a
tomada de decisão em qual análise utilizar para avaliação da influência
de um conjunto de variáveis independentes sobre múltiplos resultados. [
Matriz de Espécies ] | v [ Executar DCA (Função: decorana) ] | v [
Avaliar Comprimento do Eixo 1 (DCA1) ] | +——————–+——————–+ | | | v v v [
< 3.0 SD ] [ 3.0 a 4.0 SD ] [ > 4.0 SD ] | | | v v v [ Resposta
Linear ] [ Gradiente Intermediário ] [ Resposta Unimodal ] (Baixo
Turnover) (Zona de Transição) (Alto Turnover) | | | v v v [ tb-RDA ] [
tb-RDA ] [ CCA ]
SE (DCA1 < 3.0) ENTÃO: Hipótese: As plantas respondem de forma linear ao solo/clima. Ação prévia: Transformar matrix_run com o método de Hellinger. Análise Final: RDA (Análise de Redundância).
SE (DCA1 >= 3.0 E DCA1 <= 4.0) ENTÃO: Hipótese: Gradiente moderado. Ambas as respostas existem. Decisão: Escolher tb-RDA (preferência atual da literatura por robustez estatística).
SE (DCA1 > 4.0) ENTÃO: Hipótese: As plantas têm uma resposta em forma de sino (unimodal). Ocorrem substituições completas de espécies nos extremos do ambiente. Ação prévia: Nenhuma transformação necessária na matriz. Análise Final: CCA (Análise Canônica de Correspondências).
Criação de um gráfico aluvial (Sankey) e de tabelas de contingência cruzando a classificação de biomas originais da literatura com os domínios fitogeográficos estatísticos obtidos (Data-Driven).
df_lista_grupos <- data.frame(Localidade = names(my_data_group), Dominio_Floristico = as.character(my_data_group))
df_lado_a_lado <- df_lista_grupos %>% group_by(Dominio_Floristico) %>% mutate(Linha = row_number()) %>% pivot_wider(names_from = Dominio_Floristico, values_from = Localidade) %>% select(-Linha)
df_lado_a_lado[is.na(df_lado_a_lado)] <- ""
knitr::kable(df_lado_a_lado, caption = "Divisao das localidades entre dominios.")
| Floristic Domain A | Floristic Domain B |
|---|---|
| CERDAO_CER_01 | CHA_UM_CHA_01 |
| CER.S.ST_CER_01 | CHA_UM_CHA_02 |
| CERDAO_CER_02 | CHA_UM_CHA_03 |
| CERDAO_CER_03 | CHA_SEC_01 |
| CERDAO_CER_04 | CHA_SEC_02 |
| CERDAO_CER_05 | CHA_SEC_03 |
| CERDAO_CER_06 | CHA_SEC_04 |
| CERDAO_CER_07 | CHA_SEC_05 |
| CERDAO_CER_08 | CHA_SEC_06 |
| CERDAO_CER_09 | CHA_SEC_07 |
| CERDAO_CER_10 | CHA_ARID_01 |
| CERDAO_CER_11 | CHA_SERRA_01 |
| CERDAO_CER_23 | CHA_BOL_01 |
| CERDAO_CER_24 | CHA_PAMPA_01 |
| CER.S.ST_PANT_01 | CHA_PANT_01 |
| CERDAO_CER_12 | CHA_PANT_02 |
| CERDAO_CER_13 | CHA_PANT_03 |
| CILIAR_CER_01 | CHA_PANT_04 |
| CILIAR_CER_02 | CHA_UM_CHA_04 |
| CILIAR_CER_03 | CHA_UM_CHA_05 |
| CILIAR_CER_04 | CHA_UM_CHA_06 |
| CILIAR_CER_05 | CHA_PANT_06 |
| CAMP.MUR_CER_01 | CHA_UM_CHA_07 |
| CAMP.MUR_CER_02 | CHA_BOL_02 |
| CERDAO_CER_14 | CHA_SEM_SAL_01 |
| CER.RUPES_CER_01 | CHA_SEM_ARID_01 |
| CILIAR_CER_06 | CHA_SERRA_02 |
| CER.S.ST_CER_02 | CHA_PANT_07 |
| CILIAR_CER_07 | CHA_PANT_08 |
| CILIAR_CER_08 | CHA_PANT_09 |
| CILIAR_CER_09 | CHA_SEM_ARID_02 |
| CERDAO_CER_15 | CHA_SEM_ARID_03 |
| CERDAO_CER_25 | CHA_SEM_ARID_04 |
| CERDAO_CER_27 | CHA_SEM_ARID_05 |
| FES_PANT_17 | CHA_SEM_ARID_06 |
| CILIAR_CER_10 | CHA_SEM_ARID_07 |
| CILIAR_CER_11 | CHA_SEM_ARID_08 |
| CERDAO_CER_28 | CHA_PANT_10 |
| CERDAO_CER_29 | CHA_AREN_01 |
| CERDAO_CER_30 | CHA_AREN_02 |
| CERDAO_CER_31 | CHA_ENC_AREN_02 |
| CILIAR_CER_12 | CHA_INTERDUN_01 |
| CERDAO_CER_16 | CHA_INTERDUN_02 |
| CERDAO_CER_17 | CHA_INTERDUN_03 |
| CERDAO_CER_18 | CHA_LEQ_ALU_01 |
| TRANS_CER_01 | CHA_LEQ_ALU_02 |
| FED_PANT_01 | CHA_LEQ_ALU_03 |
| FED_CER_01 | CHA_LEQ_ALU_04 |
| FED_PANT_02 | CHA_LEQ_ALU_05 |
| FED_PANT_03 | CHA_LEQ_ALU_06 |
| CILIAR_CER_13 | CHA_LEQ_ALU_07 |
| CILIAR_MA_01 | CHA_LEQ_ALU_08 |
| CILIAR_CER_14 | CHA_LEQ_ALU_09 |
| FES_CER_01 | CHA_LEQ_ALU_10 |
| FES_CER_02 | CHA_LEQ_ALU_11 |
| FES_CER_03 | CHA_LEQ_ALU_12 |
| FES_MA_01 | CHA_LEQ_ALU_13 |
| FES_MA_02 | CHA_LEQ_ALU_14 |
| FES_MA_03 | CHA_LEQ_ALU_15 |
| FES_MA_04 | CHA_LEQ_ALU_16 |
| FES_PANT_01 | CHA_LEQ_ALU_17 |
| FES_CHI_01 | CHA_LEQ_ALU_18 |
| CILIAR_MA_02 | CHA_LEQ_ALU_19 |
| FES_CER_04 | CHA_CHIQ_01 |
| FES_CER_05 | CHA_CHIQ_02 |
| FES_CER_06 | CHA_CHIQ_03 |
| FES_CER_07 | CHA_CHIQ_04 |
| FES_PANT_02 | CHA_CHIQ_05 |
| FES_PANT_03 | CHA_CHIQ_06 |
| FES_PANT_04 | CHA_CHIQ_07 |
| FES_PANT_05 | CHA_CHIQ_08 |
| FES_PANT_06 | CHA_CHIQ_09 |
| FES_CER_08 | CHA_CHIQ_10 |
| FES_CER_09 | CHA_CHIQ_11 |
| FES_CER_10 | CHA_CHIQ_12 |
| FES_CER_11 | CHA_CHIQ_13 |
| FES_MA_05 | CHA_EASTERN_01 |
| FES_MA_06 | CHA_EASTERN_02 |
| FES_MA_07 | CHA_EASTERN_03 |
| FES_MA_08 | CHA_EASTERN_04 |
| FED_PANT_04 | CHA_LEQ_ALU_20 |
| PARAT_PANT_03 | CHA_LEQ_ALU_21 |
| CERDAO_PANT_01 | CHA_LEQ_ALU_22 |
| CERDAO_PANT_02 | CHA_LEQ_ALU_23 |
| CERDAO_PANT_03 | CHA_LEQ_ALU_24 |
| CILIAR_PANT_01 | CHA_LEQ_ALU_25 |
| TRANS_CER_02 | CHA_LEQ_ALU_26 |
| CAPAO_PANT_13 | CHA_LEQ_ALU_27 |
| CERDAO_PANT_23 | CHA_LEQ_ALU_28 |
| CAPAO_PANT_07 | CHA_SEM_AR_LEQ_ALU_01 |
| CAPAO_PANT_06 | CHA_EASTERN_05 |
| CILIAR_PANT_02 | CHA_EASTERN_06 |
| CILIAR_PANT_03 | CHA_EASTERN_07 |
| CILIAR_PANT_04 | CHA_HYGRO_01 |
| CILIAR_PANT_05 | CHA_HYGRO_02 |
| CILIAR_PANT_06 | CHA_SEC_08 |
| CAMP.CERR_PANT_05 | CHA_UM_CHA_08 |
| FES_PANT_18 | CHA_SEC_09 |
| FED_PANT_05 | CHA_SEC_10 |
| CAPAO_PANT_01 | CHA_ESPI_01 |
| CAPAO_PANT_08 | CHA_UM_CHA_09 |
| CERDAO_PANT_04 | CHA_UM_CHA_10 |
| CERDAO_PANT_05 | CHA_SEC_12 |
| CERDAO_PANT_06 | CHA_SEC_13 |
| CERDAO_PANT_07 | CHA_SEC_14 |
| CERDAO_PANT_08 | CHA_UM_CHA_11 |
| CERDAO_PANT_09 | CHA_SEC_16 |
| CERDAO_PANT_10 | CHA_BOL_05 |
| CERDAO_PANT_11 | |
| CAPAO_PANT_02 | |
| CERDAO_PANT_20 | |
| CAPAO_PANT_03 | |
| CAMP.CERR_PANT_01 | |
| CERDAO_PANT_12 | |
| CILIAR_PANT_07 | |
| CERDAO_PANT_19 | |
| CERDAO_PANT_21 | |
| FED_PANT_07 | |
| FED_PANT_08 | |
| FED_PANT_09 | |
| FED_PANT_10 | |
| CAMP.CERR_PANT_02 | |
| CAPAO_PANT_14 | |
| PARAT_PANT_02 | |
| CAMP.MUR_PANT_01 | |
| CAPAO_PANT_12 | |
| CAPAO_PANT_09 | |
| CAMP.MUR_PANT_02 | |
| CERDAO_PANT_13 | |
| CAPAO_PANT_04 | |
| CAPAO_PANT_05 | |
| FES_PANT_07 | |
| CAMP.CERR_PANT_03 | |
| CERDAO_PANT_14 | |
| CAPAO_PANT_11 | |
| CILIAR_PANT_08 | |
| FES_PANT_08 | |
| CILIAR_PANT_09 | |
| CILIAR_PANT_10 | |
| CILIAR_PANT_11 | |
| CERDAO_PANT_22 | |
| MAT_ACURI_PANT_01 | |
| CAPAO_PANT_10 | |
| CAMB_PANT_01 | |
| CAPAO_PANT_15 | |
| CERDAO_PANT_15 | |
| CERDAO_CER_19 | |
| CILIAR_PANT_12 | |
| CERDAO_PANT_16 | |
| FES_PANT_09 | |
| FES_PANT_10 | |
| CILIAR_PANT_13 | |
| CILIAR_PANT_14 | |
| FESM_PANT_01 | |
| CILIAR_PANT_15 | |
| FES_PANT_11 | |
| CAMP.CERR_PANT_04 | |
| FES_PANT_12 | |
| CAMP.CERR_CER_01 | |
| CAMP.MUR_CER_03 | |
| CER.S.ST_CER_03 | |
| CERDAO_CER_20 | |
| BABA_CER_01 | |
| CAPAO_CER_01 | |
| CILIAR_CER_18 | |
| CILIAR_MA_03 | |
| CERDAO_CER_21 | |
| FED_PANT_06 | |
| CERDAO_CER_22 | |
| CERDAO_PANT_17 | |
| CERDAO_PANT_18 | |
| FES_PANT_13 | |
| FES_PANT_14 | |
| CER.S.ST_PANT_02 | |
| FES_PANT_15 | |
| FES_PANT_16 | |
| CAMB_PANT_02 | |
| CAMP.MUR_PANT_03 | |
| CHA_CHIQ_14 | |
| CHA_CHIQ_15 | |
| CHA_CHIQ_16 | |
| CHA_CHIQ_17 | |
| CHA_CHIQ_18 | |
| CHA_CHIQ_19 | |
| CERDAO_CER_32 | |
| CERDAO_CER_34 | |
| CERDAO_CER_36 | |
| CER.S.ST_CER_04 | |
| CHA_BOL_03 | |
| CHA_BOL_04 |
locs_finais <- rownames(matrix_run)
df_biome_filtrado <- df_biome_align %>% filter(locality %in% locs_finais) %>% arrange(match(locality, locs_finais))
df_flow <- data.frame(Locality = locs_finais, Dominio_Original = df_biome_filtrado$domain_biome, Dominio_Cluster = as.character(my_data_group)) %>% mutate(Flow_Color = ifelse(Locality %in% local_target, "Target Areas", as.character(Dominio_Cluster)))
ggplot(df_flow, aes(axis1 = Dominio_Original, axis2 = Dominio_Cluster)) + geom_alluvium(aes(fill = Flow_Color), width = 1/8, alpha = 0.7, knot.pos = 0.4) + geom_stratum(width = 1/4, fill = "grey80", color = "black") + geom_text_repel(stat = "stratum", aes(label = str_wrap(after_stat(stratum), width = 18)), size = 3.5, direction = "y", nudge_x = 0) + scale_x_discrete(limits = c("Bioma Original", "Grupo Floristico (k=2)"), expand = c(.05, .05)) + scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) + theme_minimal() + labs(title = "Fluxo de Reclassificacao Floristica", y = "Numero de Localidades") + theme(legend.position = "bottom")
matriz_A <- matrix_run[my_data_group == "Floristic Domain A", ]
matriz_B <- matrix_run[my_data_group == "Floristic Domain B", ]
lista_venn_dominios <- list("Domain A" = colnames(matriz_A)[colSums(matriz_A) > 0], "Domain B" = colnames(matriz_B)[colSums(matriz_B) > 0])
names(lista_venn_dominios) <- paste0(names(lista_venn_dominios), "\n(", sapply(lista_venn_dominios, length), " spp.)")
# AQUI ESTÁ A CORREÇÃO: Inserção do ilabels = "counts"
venn(lista_venn_dominios, zcolor = c("#d95f02", "#1b9e77"), opacity = 0.5, ilabels = "counts", ilcs = 1.5, sncs = 1.2, box = FALSE)
title("Compartilhamento de Especies entre Dominios")
beta_A <- beta.multi(matriz_A, index.family = "jaccard")
beta_B <- beta.multi(matriz_B, index.family = "jaccard")
df_beta_longo <- data.frame(Dominio = c("Floristic Domain A", "Floristic Domain B"), Turnover = c(beta_A$beta.JTU, beta_B$beta.JTU), Nestedness = c(beta_A$beta.JNE, beta_B$beta.JNE)) %>% pivot_longer(cols = c(Turnover, Nestedness), names_to = "Componente", values_to = "Valor_Beta") %>% group_by(Dominio) %>% mutate(Total = sum(Valor_Beta), Proporcao = Valor_Beta / Total * 100, Label = paste0(round(Proporcao, 1), "%")) %>% ungroup()
ggplot(df_beta_longo, aes(x = Dominio, y = Valor_Beta, fill = Componente)) + geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7, color = "black") + geom_text(aes(label = Label), position = position_dodge(width = 0.8), vjust = -0.5, fontface = "bold", size = 4.5) + theme_bw() + labs(title = "Componentes da Diversidade Beta por Dominio", y = "Valor da Dissimilaridade") + scale_y_continuous(expand = expansion(mult = c(0, 0.15))) + scale_fill_manual(values = c("Turnover" = "#2c3e50", "Nestedness" = "#bdc3c7")) + theme(legend.position = "bottom")
Anotações: O fluxo aluvial
revela a correspondência ou o espalhamento de transição dos biomas ao
serem submetidos a algoritmos de clusterização imparciais.
Adicionalmente, o particionamento Beta confirma a invariabilidade da
predominância do Turnover dentro de cada um dos novos
domínios.
Identificação estatística das espécies indicadoras de cada Domínio através do método IndVal e subsequente validação espacial utilizando pontos de ocorrência georreferenciada resgatados do GBIF.
resultados_indval <- multipatt(matrix_run, my_data_group, func = "IndVal.g", duleg = TRUE, control = how(nperm = 999))
res_tabela <- resultados_indval$sign
res_tabela$especie <- rownames(res_tabela)
col_grupo_A <- grep("s.Floristic.Domain.A", colnames(res_tabela), value = TRUE)
col_grupo_B <- grep("s.Floristic.Domain.B", colnames(res_tabela), value = TRUE)
res_sig <- res_tabela %>% filter(p.value <= 0.05)
res_sig$dominio <- NA_character_
res_sig$dominio[res_sig[, col_grupo_A] == 1] <- "Floristic Domain A"
res_sig$dominio[res_sig[, col_grupo_B] == 1] <- "Floristic Domain B"
res_sig <- res_sig %>% filter(!is.na(dominio))
top_indicadoras <- res_sig %>%
group_by(dominio) %>%
slice_max(stat, n = 10) %>%
arrange(dominio, desc(stat)) %>%
mutate(especie_clean = stringr::word(gsub("_", " ", especie), 1, 2))
ggplot(top_indicadoras, aes(x = stat, y = reorder(especie_clean, stat), color = dominio)) +
geom_segment(aes(x = 0, xend = stat, y = reorder(especie_clean, stat), yend = reorder(especie_clean, stat)), color = "grey60", linetype = "dashed") +
geom_point(aes(shape = dominio), size = 4) + # <-- Adicionado mapeamento de shape
facet_wrap(~dominio, scales = "free_y", ncol = 1) +
theme_bw() +
labs(title = "Top 10 Especies Indicadoras", x = "Valor de Indicação (stat)", y = "") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) +
scale_shape_manual(values = c("Floristic Domain A" = 16, "Floristic Domain B" = 17)) + # <-- 16 (Círculo), 17 (Triângulo)
theme(legend.position = "none", axis.text.y = element_text(face = "italic"), strip.background = element_rect(fill = "#f0f0f0"), strip.text = element_text(face = "bold"))
df_indicadoras <- top_indicadoras %>% select(especie = especie_clean, dominio)
cat("\nBuscando ocorrencias no GBIF para as especies indicadoras...\n")
##
## Buscando ocorrencias no GBIF para as especies indicadoras...
ocorrencias_list <- lapply(df_indicadoras$especie, function(sp) {
dados_gbif <- occ_data(scientificName = sp, limit = 300, hasCoordinate = TRUE, hasGeospatialIssue = FALSE)$data
if(!is.null(dados_gbif) && is.data.frame(dados_gbif) && nrow(dados_gbif) > 0 && "decimalLongitude" %in% colnames(dados_gbif)) {
dados_filtrados <- dados_gbif %>% select(decimalLongitude, decimalLatitude) %>% mutate(especie = sp)
return(dados_filtrados)
} else { return(NULL) }
})
df_ocorrencias <- bind_rows(ocorrencias_list)
if(nrow(df_ocorrencias) > 0 && "decimalLongitude" %in% colnames(df_ocorrencias)) {
df_ocorrencias <- df_ocorrencias %>% filter(decimalLongitude >= boundary_area[1] & decimalLongitude <= boundary_area[2], decimalLatitude >= boundary_area[3] & decimalLatitude <= boundary_area[4])
if(nrow(df_ocorrencias) == 0) stop("GBIF encontrou dados, mas NENHUM PONTO caiu dentro do 'boundary_area'.")
df_ocorrencias <- df_ocorrencias %>% left_join(df_indicadoras, by = "especie")
points_sf <- st_as_sf(df_ocorrencias, coords = c("decimalLongitude", "decimalLatitude"), crs = 4326)
shape_biomas <- st_read("mapa_pontos.gpkg", quiet = TRUE) %>% st_transform(4326)
mapa_validacao <- ggplot() +
geom_sf(data = shape_biomas, fill = "grey90", color = "grey50", linewidth = 0.5) +
# 1. Adicionado shape = dominio no aes()
geom_sf(data = points_sf, aes(color = dominio, shape = dominio), size = 1.5, alpha = 0.8) +
coord_sf(xlim = boundary_area[1:2], ylim = boundary_area[3:4], expand = FALSE) +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) +
# 2. Adicionado scale_shape_manual para garantir os círculos e triângulos
scale_shape_manual(values = c("Floristic Domain A" = 16, "Floristic Domain B" = 17)) +
theme_minimal() +
# 3. Adicionado shape = "Dominio:" para mesclar as legendas de cor e formato
labs(title = "Validacao Espacial das Indicadoras", color = "Dominio:", shape = "Dominio:") +
theme(legend.position = "right")
print(mapa_validacao)
} else { stop("Nenhuma especie indicadora retornou ocorrencias do GBIF.") }
Anotações: O Dot Plot destaca
os táxons mais fiéis a cada agrupamento. O mapa final cruza esses
resultados teóricos com a realidade, demonstrando inequivocamente que a
distribuição natural das espécies indicadoras acompanha as projeções
geográficas dos domínios estatísticos.
Isolamento computacional do Domínio Fitogeográfico específico que englobou as áreas-alvo brasileiras de estudo, desvinculando-o dos atritos florísticos externos à sua ecorregião.
df_conferencia <- data.frame(Localidade = names(my_data_group), Dominio_Estatistico = as.character(my_data_group))
resultado_alvos <- df_conferencia %>% filter(Localidade %in% local_target)
dominio_alvo <- names(which.max(table(resultado_alvos$Dominio_Estatistico)))
cat("\n[!] O domínio que engloba as suas áreas de interesse é o:", dominio_alvo, "\n")
##
## [!] O domínio que engloba as suas áreas de interesse é o: Floristic Domain B
matrix_dominio_foco <- matrix_run[my_data_group == dominio_alvo, ]
spp_presentes <- colSums(matrix_dominio_foco) > 0
matrix_alvo_limpa <- matrix_dominio_foco[, spp_presentes]
dissimilarity_alvo <- vegdist(matrix_alvo_limpa, method = "jaccard")
tree_alvo <- hclust(dissimilarity_alvo, method = "ward.D2")
dend_alvo <- as.dendrogram(tree_alvo)
cor_dominio <- ifelse(dominio_alvo == "Floristic Domain A", "#d95f02", "#1b9e77")
dend_alvo <- color_branches(dend_alvo, k = 1, col = cor_dominio)
dend_alvo <- dendrapply(dend_alvo, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) {
if (length(rotulos_no) > 0 && rotulos_no %in% local_target) {
np <- attr(node, "nodePar")
if (is.null(np)) attr(node, "nodePar") <- list(pch = "|", col = "black", cex = 1.5) else { np$pch <- "|"; np$col <- "black"; np$cex <- 1.5; attr(node, "nodePar") <- np }
}
attr(node, "label") <- ""
}
return(node)
})
par(mar = c(2, 4, 3, 1))
plot(dend_alvo, main = paste("Estrutura Interna -", dominio_alvo), ylab = "Distância de Ward", xlab = "Localidades")
title(xlab = "Localidades", line = 0.5, font.lab = 2)
legend("topright", legend = c(paste("Domínio:", dominio_alvo), "Target Areas"), fill = c(cor_dominio, "white"), border = c("black", "white"), pch = c(NA, "|"), col = c(NA, "black"), pt.cex = 1.2, bty = "n", cex = 0.9, inset = c(0.02, 0.02))
Anotações: Ao reconstruir o
dendrograma utilizando apenas a matriz do Domínio Alvo, a topologia se
refina e ganha precisão analítica. Isso foca o estudo estritamente na
homogeneidade de escala restrita e no ecótono adjacente ao Chaco
Brasileiro.
Varredura automatizada em busca do número ideal de subgrupos biológicos (\(k\)) dentro do domínio alvo, baseando-se no maior acúmulo de espécies indicadoras significativas (IndVal).
cat("Busca automatica de subgrupos para o", dominio_alvo, "...\n")
## Busca automatica de subgrupos para o Floristic Domain B ...
k_atual <- 2
quedas_consecutivas <- 0
limite_quedas <- 3
max_spp_registrado <- 0
limite_seguranca <- 20
df_resultados_sub <- data.frame(K = integer(), Spp_Significativas = integer(), Soma_IndVal = numeric())
set.seed(123)
while(quedas_consecutivas < limite_quedas && k_atual <= limite_seguranca) {
grupos_temp <- cutree(tree_alvo, k = k_atual)
indval_temp <- multipatt(matrix_alvo_limpa, grupos_temp, func = "IndVal.g", duleg = TRUE, control = how(nperm = 999))
res <- indval_temp$sign
spp_sig <- res[!is.na(res$p.value) & res$p.value <= 0.05, ]
qtd_spp <- nrow(spp_sig)
df_resultados_sub <- rbind(df_resultados_sub, data.frame(K = k_atual, Spp_Significativas = qtd_spp, Soma_IndVal = sum(spp_sig$stat, na.rm = TRUE)))
if(qtd_spp >= max_spp_registrado) { max_spp_registrado <- qtd_spp; quedas_consecutivas <- 0 } else { quedas_consecutivas <- quedas_consecutivas + 1 }
k_atual <- k_atual + 1
}
pico_sub_k <- df_resultados_sub$K[which.max(df_resultados_sub$Spp_Significativas)]
df_plot_sub <- df_resultados_sub %>% pivot_longer(cols = c(Spp_Significativas, Soma_IndVal), names_to = "Metrica", values_to = "Valor")
df_plot_sub$Metrica <- factor(df_plot_sub$Metrica, levels = c("Spp_Significativas", "Soma_IndVal"), labels = c("Total Espécies", "Soma IndVal"))
grafico_otimizacao_sub <- ggplot(df_plot_sub, aes(x = K, y = Valor)) + geom_line(color = "#2980b9", linewidth = 1.2) + geom_point(size = 3, color = "#2c3e50") + geom_vline(xintercept = pico_sub_k, linetype = "dashed", color = "#c0392b", linewidth = 1) + facet_wrap(~Metrica, scales = "free_y", ncol = 1) + scale_x_continuous(breaks = min(df_resultados_sub$K):max(df_resultados_sub$K)) + theme_bw() + labs(title = paste("Otimizacao de K em", dominio_alvo), subtitle = paste("Pico biológico em k =", pico_sub_k))
print(grafico_otimizacao_sub)
k_sub <- pico_sub_k
paleta_sub <- c("#d1ece1", "#a3d8c6", "#75c5ac", "#48b191", "#147659", "#0d4f3b")[1:k_sub]
dend_base <- as.dendrogram(tree_alvo)
grupos_sub <- cutree(dend_base, k = k_sub, order_clusters_as_data = FALSE)
dend_base_colorido <- color_branches(dend_base, k = k_sub, col = paleta_sub)
dend_alvo_circ <- dendrapply(dend_base_colorido, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) attr(node, "label") <- ""
return(node)
})
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_alvo_circ, labels = FALSE, main = paste("Subdivisões", dominio_alvo)))
legend("center", legend = paste("Agrupamento", 1:k_sub), fill = paleta_sub, border = rep("black", k_sub), bty = "n", cex = 0.75, title = "Subgrupos")
for (i in 1:k_sub) {
locs_grupo <- names(grupos_sub[grupos_sub == i])
locs_remover <- labels(dend_base_colorido)[!labels(dend_base_colorido) %in% locs_grupo]
dend_individual <- prune(dend_base_colorido, locs_remover)
dend_individual <- set(dend_individual, "labels_cex", 0.5)
dend_individual <- set(dend_individual, "branches_lwd", 2)
dend_individual <- dendrapply(dend_individual, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) {
rotulo <- attr(node, "label")
if (length(rotulo) > 0 && rotulo %in% local_target) {
np <- attr(node, "nodePar")
if (is.null(np)) attr(node, "nodePar") <- list(lab.col = "black", lab.font = 2) else { np$lab.col <- "black"; np$lab.font <- 2; attr(node, "nodePar") <- np }
}
}
return(node)
})
par(mar = c(5, 2, 4, 15))
plot(dend_individual, horiz = TRUE, main = paste("Agrupamento", i, ":", dominio_alvo), xlab = "Distância de Ward")
}
Anotações: O modelo de parada
estocástica (Early Stopping) identificou o pico biológico paramétrico da
meta-comunidade antes de fragmentá-la irrealisticamente. O dendrograma
circular expõe com elegância estas ramificações florísticas menores em
formato de árvore filogenética.
Identificação e ranqueamento das espécies indicadoras (IndVal) que sustentam biologicamente a divisão dos subgrupos encontrados na meta-comunidade do domínio alvo.
indval_sub <- multipatt(matrix_alvo_limpa, grupos_sub, func = "IndVal.g", duleg = TRUE, control = how(nperm = 999))
res_sub <- indval_sub$sign
res_sub$especie <- rownames(res_sub)
res_sub_sig <- res_sub %>% filter(!is.na(p.value) & p.value <= 0.05)
res_sub_sig$Subgrupo <- NA_character_
for (i in 1:k_sub) {
coluna_grupo <- paste0("s.", i)
if (coluna_grupo %in% colnames(res_sub_sig)) res_sub_sig$Subgrupo[res_sub_sig[[coluna_grupo]] == 1] <- paste("Agrupamento", i)
}
res_sub_sig <- res_sub_sig %>% filter(!is.na(Subgrupo))
top_indicadoras_sub <- res_sub_sig %>% group_by(Subgrupo) %>% slice_max(stat, n = 10) %>% arrange(Subgrupo, desc(stat))
print(knitr::kable(top_indicadoras_sub %>% select(Subgrupo, especie, stat, p.value), digits = 3, caption = paste("Top 10 Indicadoras", dominio_alvo)))
##
##
## Table: Top 10 Indicadoras Floristic Domain B
##
## |Subgrupo |especie | stat| p.value|
## |:-------------|:------------------------------------------------------------|-----:|-------:|
## |Agrupamento 1 |Neltuma_x_vinalillo_(Stuck.)_C.E.Hughes_&_G.P.Lewis | 0.606| 0.001|
## |Agrupamento 1 |Neltuma_nigra_(Griseb.)_C.E.Hughes_&_G.P.Lewis | 0.540| 0.007|
## |Agrupamento 1 |Harrisia_pomanensis_(F.A.C.Weber_ex_K.Schum.)_Britton_&_Rose | 0.535| 0.002|
## |Agrupamento 1 |Parkinsonia_praecox_(Ruiz_&_Pav.)_Hawkins | 0.522| 0.014|
## |Agrupamento 1 |Neltuma_ruscifolia_(Griseb.)_C.E.Hughes_&_G.P.Lewis | 0.482| 0.024|
## |Agrupamento 1 |Annona_nutans_(R.E.Fr.)_R.E.Fr. | 0.474| 0.002|
## |Agrupamento 1 |Mimosa_hexandra_Micheli | 0.452| 0.007|
## |Agrupamento 1 |Jodina_rhombifolia_(Hook._&_Arn.)_Hook._&_Arn._ex_Reissek | 0.434| 0.030|
## |Agrupamento 1 |Chloroleucon_tenuiflorum_(Benth.)_Barneby_&_J.W.Grimes | 0.429| 0.015|
## |Agrupamento 1 |Ruprechtia_exploratricis_Sandwith | 0.404| 0.011|
## |Agrupamento 1 |Neltuma_rubriflora_(Hassl.)_C.E.Hughes_&_G.P.Lewis | 0.404| 0.006|
## |Agrupamento 1 |Mimosa_glutinosa_Malme | 0.404| 0.014|
## |Agrupamento 2 |Ptilochaeta_nudipes_Griseb. | 0.757| 0.001|
## |Agrupamento 2 |Cereus_hildmannianus_K.Schum. | 0.708| 0.001|
## |Agrupamento 2 |Quiabentia_verticillata_(Vaupel)_Vaupel_ex_A.Berger | 0.664| 0.001|
## |Agrupamento 2 |Senegalia_emilioana_(Fortunato_&_Ciald.)_Seigler_&_Ebinger | 0.645| 0.001|
## |Agrupamento 2 |Cereus_stenogonus_K.Schum. | 0.643| 0.002|
## |Agrupamento 2 |Coccoloba_argentinensis_Speg. | 0.639| 0.001|
## |Agrupamento 2 |Ceiba_insignis_(Kunth)_P.E.Gibbs_&_Semir | 0.631| 0.001|
## |Agrupamento 2 |Argythamnia_breviramea_Müll.Arg. | 0.621| 0.001|
## |Agrupamento 2 |Chloroleucon_chacoense_(Burkart)_Barneby_&_J.W.Grimes | 0.612| 0.002|
## |Agrupamento 2 |Mimosa_castanoclada_Barneby_&_Fortunato | 0.597| 0.001|
## |Agrupamento 3 |Phyllostylon_rhamnoides_(J.Poiss.)_Taub. | 0.628| 0.001|
## |Agrupamento 3 |Harrisia_bonplandii_(Parm._ex_Pfeiff.)_Britton_&_Rose | 0.598| 0.001|
## |Agrupamento 3 |Bulnesia_sarmientoi_Lorentz_ex_Griseb. | 0.589| 0.003|
## |Agrupamento 3 |Salta_triflora_(Griseb.)_Adr.Sanchez | 0.581| 0.006|
## |Agrupamento 3 |Morisonia_tweedieana_(Eichler)_Christenh._&_Byng | 0.577| 0.004|
## |Agrupamento 3 |Trithrinax_schizophylla_Drude | 0.517| 0.002|
## |Agrupamento 3 |Opuntia_discolor_Britton_&_Rose | 0.487| 0.011|
## |Agrupamento 3 |Adelia_membranifolia_(Müll.Arg.)_Chodat_&_Hassl. | 0.427| 0.017|
## |Agrupamento 3 |Acanthocalycium_rhodotrichum_(K.Schum.)_Schlumpb. | 0.404| 0.017|
## |Agrupamento 3 |Allophylus_pauciflorus_Radlk. | 0.394| 0.046|
## |Agrupamento 4 |Neltuma_alba_(Griseb.)_C.E.Hughes_&_G.P.Lewis | 0.641| 0.001|
## |Agrupamento 4 |Celtis_iguanaea_(Jacq.)_Sarg. | 0.579| 0.002|
## |Agrupamento 4 |Salix_humboldtiana_Willd. | 0.573| 0.001|
## |Agrupamento 4 |Aloysia_gratissima_(Gillies_&_Hook.)_Tronc. | 0.548| 0.006|
## |Agrupamento 4 |Ceiba_chodatii_(Hassl.)_Ravenna | 0.531| 0.003|
## |Agrupamento 4 |Cestrum_parqui_(Lam.)_L'Hér. | 0.531| 0.002|
## |Agrupamento 4 |Sapium_haematospermum_Müll.Arg. | 0.514| 0.010|
## |Agrupamento 4 |Geoffroea_decorticans_(Gillies_ex_Hook._&_Arn.)_Burkart | 0.495| 0.017|
## |Agrupamento 4 |Syagrus_romanzoffiana_(Cham.)_Glassman | 0.488| 0.003|
## |Agrupamento 4 |Muehlenbeckia_sagittifolia_(Ortega)_Meisn. | 0.488| 0.002|
if(nrow(top_indicadoras_sub) > 0) {
# Vetor de formas geométricas para manter o padrão visual do mapa
formas_dinamicas <- c(21, 24, 22, 23, 25, 21)[1:k_sub]
grafico_indval_sub <- ggplot(top_indicadoras_sub, aes(x = stat, y = reorder(especie, stat))) +
geom_segment(aes(x = 0, xend = stat, y = reorder(especie, stat), yend = reorder(especie, stat)), color = "grey60", linetype = "dashed") +
# Mapeando o preenchimento (fill) e formato (shape) por subgrupo, com borda preta
geom_point(aes(fill = Subgrupo, shape = Subgrupo), size = 4, color = "black") +
facet_wrap(~Subgrupo, scales = "free_y", ncol = 2) +
theme_bw() +
labs(title = "Espécies Indicadoras", x = "IndVal", y = "") +
# Aplicando as escalas idênticas às dos mapas
scale_fill_manual(values = paleta_sub) +
scale_shape_manual(values = formas_dinamicas) +
theme(legend.position = "none", axis.text.y = element_text(face = "italic"), strip.background = element_rect(fill = "#f0f0f0"), strip.text = element_text(face = "bold"))
print(grafico_indval_sub)
}
Projeção geográfica dos subgrupos delimitados no dendrograma do Domínio Alvo. O mapa utiliza a caixa delimitadora (Bounding Box) exclusiva das coordenadas amostrais, acrescida de 10% de margem, sobrepondo os subgrupos à paleta de cores original das ecorregiões de fundo.
cat("\nPreparando dados espaciais dos subgrupos e sobrepondo às ecorregiões originais...\n")
##
## Preparando dados espaciais dos subgrupos e sobrepondo às ecorregiões originais...
# 1. Extrair os subgrupos do dendrograma e juntar com as coordenadas
df_subgrupos <- data.frame(locality = names(grupos_sub), Subgrupo = paste("Agrupamento", grupos_sub))
df_sub_coords <- df_subgrupos %>%
left_join(input_matrix %>% select(locality, longitud, latitud) %>% distinct(), by = "locality") %>%
mutate(long = as.numeric(gsub(",", ".", longitud)), lat = as.numeric(gsub(",", ".", latitud)))
# Transformar em objeto espacial
points_sub_sf <- st_as_sf(df_sub_coords, coords = c("long", "lat"), crs = 4326)
# Capturar os limites geográficos EXCLUSIVOS dos pontos dos subgrupos
bbox_pontos <- st_bbox(points_sub_sf)
# Criar uma margem de segurança (10%) para os pontos não tocarem na borda da figura
margem_x <- (bbox_pontos["xmax"] - bbox_pontos["xmin"]) * 0.1
margem_y <- (bbox_pontos["ymax"] - bbox_pontos["ymin"]) * 0.1
limites_x <- c(bbox_pontos["xmin"] - margem_x, bbox_pontos["xmax"] + margem_x)
limites_y <- c(bbox_pontos["ymin"] - margem_y, bbox_pontos["ymax"] + margem_y)
# Vetor de formas geométricas dinâmicas
formas_dinamicas <- c(21, 24, 22, 23, 25, 21)[1:k_sub]
# Resgata a configuração original de cores das Ecorregiões (Paleta BrBG)
cores_atuais <- c("#35978f", "#bf812d", "#8c510a", "#dfc27d", "#f6e8c3", "#f5f5f5", "#80cdc1", "#01665e", "#c7eae5")
ecos_alfabetica <- sort(unique(shape_eco_originais$ECO_NAME))
names(cores_atuais) <- ecos_alfabetica[1:length(cores_atuais)]
ordem_legenda_brbg <- names(cores_atuais)[c(3, 2, 4, 5, 6, 9, 7, 1, 8)]
# 3. Plotagem do Mapa com enquadramento cirúrgico e múltiplas escalas
mapa_subgrupos <- ggplot() +
# --- CAMADA 1: FUNDO DAS ECORREGIÕES ---
geom_sf(data = shape_eco_originais, aes(fill = ECO_NAME), alpha = 0.7, color = NA) +
scale_fill_manual(values = cores_atuais, breaks = ordem_legenda_brbg, name = "Ecorregião (Olson):") +
# Habilita a segunda escala de cores para os pontos não "brigarem" com o fundo
new_scale_fill() +
# --- CAMADA 2: PONTOS DOS SUBGRUPOS ---
geom_sf(data = points_sub_sf, aes(fill = Subgrupo, shape = Subgrupo), color = "black", stroke = 0.4, size = 2.5, alpha = 0.9) +
scale_fill_manual(values = paleta_sub) +
scale_shape_manual(values = formas_dinamicas) +
# Aplica o zoom cravado nas coordenadas dos pontos com a margem calculada
coord_sf(xlim = limites_x, ylim = limites_y, expand = FALSE) +
theme_minimal() +
labs(
title = paste("Estruturação Espacial -", dominio_alvo),
subtitle = paste("Projeção focada na nuvem de dispersão dos", k_sub, "subgrupos florísticos"),
fill = "Subgrupo:",
shape = "Subgrupo:"
) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 14),
panel.grid.minor = element_blank()
)
print(mapa_subgrupos)
Projeção de uma rede de ligação mínima (Minimum Spanning Tree) baseada nas distâncias florísticas de Jaccard entre os subgrupos. Os centróides geográficos foram calculados a partir da média espacial das coordenadas amostrais de cada unidade florística.
cat("\nColapsando matriz florística e calculando centróides geográficos dos subgrupos...\n")
##
## Colapsando matriz florística e calculando centróides geográficos dos subgrupos...
# ==============================================================================
# 1. COLAPSAR A MATRIZ PARA O NÍVEL DE SUBGRUPO
# ==============================================================================
df_matriz_alvo <- as.data.frame(matrix_alvo_limpa)
df_matriz_alvo$locality <- rownames(df_matriz_alvo)
df_grupos_match <- data.frame(locality = names(grupos_sub), Subgrupo = paste("Agrupamento", grupos_sub))
matriz_sub_agrupada <- df_matriz_alvo %>%
left_join(df_grupos_match, by = "locality") %>%
select(-locality) %>%
group_by(Subgrupo) %>%
summarise(across(everything(), sum)) %>%
as.data.frame()
rownames(matriz_sub_agrupada) <- matriz_sub_agrupada$Subgrupo
matriz_sub_agrupada <- matriz_sub_agrupada[, -1]
# Matriz binária de presença/ausência (1 ou 0) para o subgrupo
matriz_sub_binaria <- ifelse(matriz_sub_agrupada > 0, 1, 0)
riqueza_sub <- rowSums(matriz_sub_binaria)
# Calcular similaridade de Jaccard e a Rede (MST)
dist_sub <- vegdist(matriz_sub_binaria, method = "jaccard")
arvore_sub <- spantree(dist_sub)
# ==============================================================================
# 2. CALCULAR CENTRÓIDES GEOGRÁFICOS
# ==============================================================================
# O centróide é a média das latitudes e longitudes de todos os pontos do agrupamento
df_centroides_sub <- df_sub_coords %>%
group_by(Subgrupo) %>%
summarise(X = mean(long), Y = mean(lat), .groups = 'drop') %>%
mutate(Riqueza = riqueza_sub[Subgrupo])
# Garantir a mesma ordem da árvore MST
df_centroides_sub <- df_centroides_sub[match(rownames(matriz_sub_binaria), df_centroides_sub$Subgrupo), ]
# ==============================================================================
# 3. CRIAR OS RAMOS (LINHAS) DA MST
# ==============================================================================
df_ramos_sub <- data.frame(
X_Origem = df_centroides_sub$X[2:nrow(df_centroides_sub)],
Y_Origem = df_centroides_sub$Y[2:nrow(df_centroides_sub)],
X_Destino = df_centroides_sub$X[arvore_sub$kid],
Y_Destino = df_centroides_sub$Y[arvore_sub$kid],
Similaridade_Jaccard = 1 - arvore_sub$dist
)
# Ponto central da linha para colocar o rótulo de texto
df_ramos_sub$X_Mid <- (df_ramos_sub$X_Origem + df_ramos_sub$X_Destino) / 2
df_ramos_sub$Y_Mid <- (df_ramos_sub$Y_Origem + df_ramos_sub$Y_Destino) / 2
df_ramos_sub$Jaccard_Rotulo <- sprintf("%.2f", df_ramos_sub$Similaridade_Jaccard)
# ==============================================================================
# 4. PLOTAGEM DO MAPA (COM ZOOM E MÚLTIPLAS ESCALAS)
# ==============================================================================
mapa_mst_sub <- ggplot() +
# A. Camada de Fundo: Ecorregiões originais (mais opacas para não poluir)
geom_sf(data = shape_eco_originais, aes(fill = ECO_NAME), alpha = 0.5, color = NA) +
scale_fill_manual(values = cores_atuais, breaks = ordem_legenda_brbg, name = "Ecorregião (Olson):") +
new_scale_fill() +
# B. Pontos reais das localidades (pequenos e no fundo)
geom_sf(data = points_sub_sf, aes(color = Subgrupo), size = 1.2, alpha = 0.4, show.legend = FALSE) +
scale_color_manual(values = paleta_sub) +
# C. Ramos (Linhas do MST) conectando os centróides
geom_segment(data = df_ramos_sub, aes(x = X_Origem, y = Y_Origem, xend = X_Destino, yend = Y_Destino, linewidth = Similaridade_Jaccard), color = "gray15", alpha = 0.85) +
geom_label(data = df_ramos_sub, aes(x = X_Mid, y = Y_Mid, label = Jaccard_Rotulo), size = 3, fill = "white", color = "black", fontface = "bold", label.padding = unit(0.15, "lines")) +
# D. Centróides (Nós da rede)
geom_point(data = df_centroides_sub, aes(x = X, y = Y, size = Riqueza, fill = Subgrupo), shape = 21, color = "black", stroke = 1.2) +
scale_fill_manual(values = paleta_sub, name = "Centróide Florístico:") +
scale_size_continuous(range = c(5, 12), name = "Riqueza de Espécies") +
scale_linewidth_continuous(range = c(0.8, 2.5), guide = "none") +
# E. Zoom Geográfico (Mantém a Bounding Box do Chunk 6.4.3)
coord_sf(xlim = limites_x, ylim = limites_y, expand = FALSE) +
theme_minimal() +
labs(
title = paste("Conectividade Espacial (MST) -", dominio_alvo),
subtitle = "Rede de similaridade florística conectando os centróides geográficos dos subgrupos",
x = "Longitude", y = "Latitude"
) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 14),
panel.grid.minor = element_blank()
)
print(mapa_mst_sub)
Reavaliação das subdivisões florísticas internas do Domínio B impondo manualmente a quebra em 3 subgrupos (\(k=3\)), espelhando a estruturação esperada ou discutida em literaturas correlatas.
dominio_B_name <- "Floristic Domain B"
matrix_dominio_B <- matrix_run[my_data_group == dominio_B_name, ]
matrix_B_limpa <- matrix_dominio_B[, colSums(matrix_dominio_B) > 0]
dissimilarity_B <- vegdist(matrix_B_limpa, method = "jaccard")
tree_B <- hclust(dissimilarity_B, method = "ward.D2")
k_sub_B <- 3
paleta_sub_B <- c("#00468B", "#ED0000", "#0099B4", "#925E9F", "#FDAF91", "#AD002A")[1:k_sub_B]
dend_base_B <- as.dendrogram(tree_B)
grupos_sub_B <- cutree(dend_base_B, k = k_sub_B, order_clusters_as_data = FALSE)
dend_base_colorido_B <- color_branches(dend_base_B, k = k_sub_B, col = paleta_sub_B)
dend_B_circ <- dendrapply(dend_base_colorido_B, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) attr(node, "label") <- ""
return(node)
})
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_B_circ, labels = FALSE, main = paste("Subdivisões", dominio_B_name)))
legend("center", legend = paste("Agrupamento", 1:k_sub_B), fill = paleta_sub_B, border = rep("black", k_sub_B), bty = "n", cex = 0.75, title = "Subgrupos")
for (i in 1:k_sub_B) {
locs_grupo <- names(grupos_sub_B[grupos_sub_B == i])
locs_remover <- labels(dend_base_colorido_B)[!labels(dend_base_colorido_B) %in% locs_grupo]
dend_individual <- prune(dend_base_colorido_B, locs_remover)
dend_individual <- set(dend_individual, "labels_cex", 0.5)
dend_individual <- set(dend_individual, "branches_lwd", 2)
dend_individual <- dendrapply(dend_individual, function(node) {
rotulos_no <- labels(node)
if (length(rotulos_no) > 0 && all(rotulos_no %in% local_target)) {
ep <- attr(node, "edgePar")
if (is.null(ep)) attr(node, "edgePar") <- list(lwd = 3) else { ep$lwd <- 3; attr(node, "edgePar") <- ep }
}
if (is.leaf(node)) {
rotulo <- attr(node, "label")
if (length(rotulo) > 0 && rotulo %in% local_target) {
np <- attr(node, "nodePar")
if (is.null(np)) attr(node, "nodePar") <- list(lab.col = "black", lab.font = 2) else { np$lab.col <- "black"; np$lab.font <- 2; attr(node, "nodePar") <- np }
}
}
return(node)
})
par(mar = c(5, 2, 4, 15))
plot(dend_individual, horiz = TRUE, main = paste("Agrupamento", i, ":", dominio_B_name), xlab = "Distância de Ward")
}
Anotações: O detalhamento em
“lupas horizontais” isola os ramos do dendrograma em destaque,
permitindo que se avalie visualmente e com extrema precisão como as
unidades amostrais da região do Chaco se distribuem nestes três estratos
florísticos convergentes.
Exportação consolidada do Material Suplementar. Reúne tabelas de interesse e salva painéis gráficos gerados em dataframes do Excel e imagens em formato PNG com alta resolução de publicação (300 DPI).
# ==============================================================================
# 7.1. PREPARAÇÃO DO DIRETÓRIO DE EXPORTAÇÃO E PACOTES
# ==============================================================================
if(!dir.exists("Resultados_Exportados")) {
dir.create("Resultados_Exportados")
}
if(!require(writexl)) install.packages("writexl")
if(!require(svglite)) install.packages("svglite") # O melhor renderizador de vetores editáveis do R
library(writexl)
library(svglite)
# ==============================================================================
# 7.2. CATEGORIA I: TABELAS E DADOS SUPLEMENTARES
# ==============================================================================
cat("Consolidando dataframes em planilhas multi-abas...\n")
## Consolidando dataframes em planilhas multi-abas...
df_gbif_texto <- if(exists("df_ocorrencias")) df_ocorrencias else data.frame(Aviso="Rodar item 6.2")
if(inherits(df_gbif_texto, "sf")) df_gbif_texto <- st_drop_geometry(df_gbif_texto)
df_indicadoras_completas_k2 <- if(exists("res_sig")) { res_sig %>% select(dominio, especie, stat, p.value) %>% arrange(dominio, desc(stat)) } else data.frame()
df_indicadoras_completas_sub <- if(exists("res_sub_sig")) { res_sub_sig %>% select(Subgrupo, especie, stat, p.value) %>% arrange(Subgrupo, desc(stat)) } else data.frame()
lista_tabelas <- list(
"1_Matriz_Curada" = if(exists("matrix_run")) data.frame(Localidade = rownames(matrix_run), matrix_run, row.names = NULL) else data.frame(),
"2_Outliers" = if(exists("info_outliers")) info_outliers else data.frame(Aviso="Sem outliers"),
"3_Dados_Venn" = if(exists("df_tabela_venn")) df_tabela_venn else data.frame(Aviso="Sem dados"),
"4_Dominios" = if(exists("df_lista_grupos")) df_lista_grupos else data.frame(),
"5_Indicadoras_Gerais_k2" = df_indicadoras_completas_k2,
"6_Otimizacao_K" = if(exists("df_resultados_sub")) df_resultados_sub else data.frame(),
"7_Indicadoras_Subgrupos" = df_indicadoras_completas_sub,
"8_Validacao_GBIF" = df_gbif_texto
)
write_xlsx(lista_tabelas, path = "Resultados_Exportados/Material_Suplementar_Tabelas.xlsx")
cat("✓ Tabelas consolidadas com sucesso.\n")
## ✓ Tabelas consolidadas com sucesso.
# ==============================================================================
# 7.3. CATEGORIA II: MAPAS ESPACIAIS E BIOGEOGRÁFICOS
# ==============================================================================
cat("\nRenderizando gráficos e mapas em PNG (Alta Res) e SVG (Editável)...\n")
##
## Renderizando gráficos e mapas em PNG (Alta Res) e SVG (Editável)...
if(exists("mapa_amostras_iniciais")) {
ggsave("Resultados_Exportados/00_Mapa_Esforco_Amostral.png", plot = mapa_amostras_iniciais, width = 12, height = 8, dpi = 300, bg = "white")
ggsave("Resultados_Exportados/00_Mapa_Esforco_Amostral.svg", plot = mapa_amostras_iniciais, width = 12, height = 8, bg = "white")
}
if(exists("mapa_ramos_colapsados")) {
ggsave("Resultados_Exportados/15_MST_Ecorregioes.png", plot = mapa_ramos_colapsados, width = 12, height = 8, dpi = 300, bg="white")
ggsave("Resultados_Exportados/15_MST_Ecorregioes.svg", plot = mapa_ramos_colapsados, width = 12, height = 8, bg="white")
}
if(exists("mapa_validacao")) {
ggsave("Resultados_Exportados/20_Mapa_GBIF.png", plot = mapa_validacao, width = 12, height = 8, dpi = 300, bg="white")
# Adicionado o svglite para o mapa também
ggsave("Resultados_Exportados/20_Mapa_GBIF.svg", plot = mapa_validacao, width = 12, height = 8, bg="white", device = svglite::svglite)
}
# Novos Mapas Espaciais dos Subgrupos (Domínio Alvo)
if(exists("mapa_subgrupos")) {
ggsave("Resultados_Exportados/22b_Mapa_Subgrupos.png", plot = mapa_subgrupos, width = 12, height = 8, dpi = 300, bg="white")
ggsave("Resultados_Exportados/22b_Mapa_Subgrupos.svg", plot = mapa_subgrupos, width = 12, height = 8, bg="white")
}
if(exists("mapa_mst_sub")) {
ggsave("Resultados_Exportados/22c_MST_Subgrupos.png", plot = mapa_mst_sub, width = 12, height = 8, dpi = 300, bg="white")
ggsave("Resultados_Exportados/22c_MST_Subgrupos.svg", plot = mapa_mst_sub, width = 12, height = 8, bg="white")
}
# ==============================================================================
# 7.4. CATEGORIA III: ORDENAÇÕES MULTIVARIADAS
# ==============================================================================
if(exists("df_spider") && exists("centroides_nmds") && exists("df_nmds_blind")) {
p_nmds_scat <- ggplot(df_spider, aes(x = NMDS1, y = NMDS2)) +
geom_segment(aes(xend = Centro_X, yend = Centro_Y, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) +
geom_point(aes(color = Point_Color, alpha = Is_Outlier), size = 3) +
scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") +
geom_point(data = centroides_nmds, aes(x = Centro_X, y = Centro_Y, fill = Floristic_Group), size = 4.5, shape = 23, color = "black", stroke = 0.8) +
geom_text_repel(data = subset(df_spider, Is_Outlier == "Sim"), aes(label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6, point.padding = 0.3, max.overlaps = Inf) +
theme_bw() + labs(title = "NMDS: Dispersão Florística a partir do Núcleo", subtitle = "Associação ao complexo fitogeográfico correspondente", x = "Eixo NMDS 1", y = "Eixo NMDS 2", color = "Legenda") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/07_NMDS_Scatter.png", plot = p_nmds_scat, width = 10, height = 7, dpi = 300, bg="white")
ggsave("Resultados_Exportados/07_NMDS_Scatter.svg", plot = p_nmds_scat, width = 10, height = 7, bg="white")
p_nmds_box <- ggplot(df_nmds_blind, aes(x = Floristic_Group, y = NMDS1, fill = Floristic_Group)) +
geom_boxplot(alpha = 0.8, outlier.shape = 16, outlier.size = 2, outlier.color = "red") +
theme_bw() + labs(title = "Separacao Floristica ao Longo do Gradiente", x = "Dominio Fitogeografico (k=2)", y = "Eixo 1 (NMDS1)") +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) + theme(legend.position = "none", plot.title = element_text(face = "bold"))
ggsave("Resultados_Exportados/08_NMDS_Boxplot.png", plot = p_nmds_box, width = 8, height = 6, dpi = 300, bg="white")
ggsave("Resultados_Exportados/08_NMDS_Boxplot.svg", plot = p_nmds_box, width = 8, height = 6, bg="white")
}
if(exists("df_pcoa_spider") && exists("df_pcoa_blind") && exists("centroides_pcoa")) {
p_pcoa_scat <- ggplot(df_pcoa_spider, aes(x = PCoA1, y = PCoA2)) +
geom_segment(aes(xend = Centro_X, yend = Centro_Y, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) +
geom_point(aes(color = Point_Color, alpha = Is_Outlier), size = 3) + scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") +
geom_point(data = centroides_pcoa, aes(x = Centro_X, y = Centro_Y, fill = Floristic_Group), size = 4, shape = 23, color = "black", stroke = 0.5) +
geom_text_repel(data = subset(df_pcoa_spider, Is_Outlier == "Sim"), aes(label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6, point.padding = 0.3, max.overlaps = Inf) +
theme_bw() + labs(title = "PCoA: Dispersão Florística a partir do Núcleo", subtitle = "Ordenação métrica preservando distâncias originais", x = "PCoA 1", y = "PCoA 2", color = "Legenda") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/09_PCoA_Scatter.png", plot = p_pcoa_scat, width = 10, height = 7, dpi = 300, bg="white")
ggsave("Resultados_Exportados/09_PCoA_Scatter.svg", plot = p_pcoa_scat, width = 10, height = 7, bg="white")
p_pcoa_box <- ggplot(df_pcoa_blind, aes(x = Floristic_Group, y = PCoA1, fill = Floristic_Group)) +
geom_boxplot(alpha = 0.8, outlier.shape = 16, outlier.size = 2, outlier.color = "red") +
theme_bw() + labs(title = "Separacao Floristica ao Longo do Gradiente", x = "Dominio Fitogeografico (k=2)", y = "Eixo 1 (PCoA1)") +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) + theme(legend.position = "none", plot.title = element_text(face = "bold"))
ggsave("Resultados_Exportados/10_PCoA_Boxplot.png", plot = p_pcoa_box, width = 8, height = 6, dpi = 300, bg="white")
ggsave("Resultados_Exportados/10_PCoA_Boxplot.svg", plot = p_pcoa_box, width = 8, height = 6, bg="white")
}
if(exists("df_perm_scatter") && exists("df_permanova_blind")) {
p_perm_spider <- ggplot(df_perm_scatter) +
geom_segment(aes(x = Centroid1, y = Centroid2, xend = PCoA1, yend = PCoA2, color = Floristic_Group), alpha = 0.2, linewidth = 0.3) +
geom_point(aes(x = PCoA1, y = PCoA2, color = Point_Color, alpha = Is_Outlier), size = 3) +
scale_alpha_manual(values = c("Sim" = 1, "Não" = 0.4), guide = "none") +
geom_point(aes(x = Centroid1, y = Centroid2, fill = Floristic_Group), size = 4, shape = 23, color = "black", stroke = 0.5) +
geom_text_repel(data = subset(df_perm_scatter, Is_Outlier == "Sim"), aes(x = PCoA1, y = PCoA2, label = Locality), size = 3.5, fontface = "bold", box.padding = 0.6, point.padding = 0.3, max.overlaps = Inf) +
theme_bw() + labs(title = "Dispersão da PERMANOVA", subtitle = "Associação baseada na variância multivariada", x = "Eixo 1", y = "Eixo 2", color = "Legenda") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/11_PERMANOVA_Spider.png", plot = p_perm_spider, width = 10, height = 7, dpi = 300, bg="white")
ggsave("Resultados_Exportados/11_PERMANOVA_Spider.svg", plot = p_perm_spider, width = 10, height = 7, bg="white")
p_perm_box <- ggplot(df_permanova_blind, aes(x = Floristic_Group, y = Centroid_Distance, fill = Floristic_Group)) +
geom_boxplot(alpha = 0.8, outlier.shape = 16, outlier.size = 2, outlier.color = "red") +
theme_bw() + labs(title = "Variância Interna dos Grupos (PERMANOVA)", x = "Domínio Fitogeográfico (k=2)", y = "Distância Florística") +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) + theme(legend.position = "none", plot.title = element_text(face = "bold"))
ggsave("Resultados_Exportados/12_PERMANOVA_Boxplot.png", plot = p_perm_box, width = 8, height = 6, dpi = 300, bg="white")
ggsave("Resultados_Exportados/12_PERMANOVA_Boxplot.svg", plot = p_perm_box, width = 8, height = 6, bg="white")
}
if(exists("df_mantel_visual")) {
p_mantel <- ggplot(df_mantel_visual, aes(x = Dist_Geo, y = Dist_Flor)) +
geom_point(alpha = 0.08, color = "#2c3e50", size = 0.4) +
geom_smooth(method = "lm", formula = y ~ x, color = "red", linetype = "dashed", linewidth = 1, se = FALSE) +
theme_bw() + labs(title = "Isolamento por Distancia", x = "Distancia Geografica Real (km)", y = "Dissimilaridade Floristica (Jaccard)")
ggsave("Resultados_Exportados/13_Mantel_Scatter.png", plot = p_mantel, width = 8, height = 6, dpi = 300, bg="white")
ggsave("Resultados_Exportados/13_Mantel_Scatter.svg", plot = p_mantel, width = 8, height = 6, bg="white")
}
if(exists("df_dca")) {
p_dca <- ggplot(df_dca, aes(x = DCA1, y = DCA2)) +
stat_ellipse(aes(color = Floristic_Group, fill = Floristic_Group), geom = "polygon", alpha = 0.15, linetype = "solid", linewidth = 0.8) +
geom_point(aes(color = Point_Color), size = 3, alpha = 0.7) +
theme_bw() + labs(title = "Detrended Correspondence Analysis (DCA)", subtitle = "Ordenacao das localidades para avaliacao do gradiente ambiental", x = "Eixo DCA 1", y = "Eixo DCA 2") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77"), guide = "none") + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/14_DCA_Scatter.png", plot = p_dca, width = 10, height = 7, dpi = 300, bg="white")
ggsave("Resultados_Exportados/14_DCA_Scatter.svg", plot = p_dca, width = 10, height = 7, bg="white")
}
# ==============================================================================
# 7.5. CATEGORIA IV: GRÁFICOS EXPLORATÓRIOS E DE COMPOSIÇÃO
# ==============================================================================
if(exists("percent_ocur")) {
png("Resultados_Exportados/01_Rank_Frequency.png", width=2400, height=1800, res=300)
plot(percent_ocur, type = "l", lwd = 2, col = "blue", main = "Curva de Frequencia-Ordem das Angiospermas", xlab = "Ordenacao das Especies (da mais comum a mais rara)", ylab = "Frequencia de Ocorrencia (%)")
abline(h = 5, col = "red", lty = 2)
dev.off()
svglite("Resultados_Exportados/01_Rank_Frequency.svg", width=8, height=6)
plot(percent_ocur, type = "l", lwd = 2, col = "blue", main = "Curva de Frequencia-Ordem das Angiospermas", xlab = "Ordenacao das Especies (da mais comum a mais rara)", ylab = "Frequencia de Ocorrencia (%)")
abline(h = 5, col = "red", lty = 2)
dev.off()
}
## png
## 2
if(exists("matrix_PA_clean")) {
matrix_image <- t(as.matrix(matrix_PA_clean))[, nrow(matrix_PA_clean):1]
png("Resultados_Exportados/02_Heatmap.png", width=3000, height=2400, res=300)
image(x = 1:ncol(matrix_PA_clean), y = 1:nrow(matrix_PA_clean), z = matrix_image, col = c("white", "#cb181d"), main = "Mapa de Calor da Matriz de Presença/Ausência", xlab = "Espécies", ylab = "Localidades")
dev.off()
svglite("Resultados_Exportados/02_Heatmap.svg", width=10, height=8)
image(x = 1:ncol(matrix_PA_clean), y = 1:nrow(matrix_PA_clean), z = matrix_image, col = c("white", "#cb181d"), main = "Mapa de Calor da Matriz de Presença/Ausência", xlab = "Espécies", ylab = "Localidades")
dev.off()
}
## png
## 2
if(exists("matrix_PA_clean") && exists("tree_loc")) {
pheatmap(as.matrix(matrix_PA_clean), filename = "Resultados_Exportados/02b_Heatmap_Clusterizado.png", width = 12, height = 10, color = c("#f7f7f7", "#cb181d"), cluster_rows = tree_loc, cluster_cols = tree_sp, show_rownames = FALSE, show_colnames = FALSE, border_color = NA, legend_breaks = c(0, 1), legend_labels = c("Ausência", "Presença"), main = "Heatmap Florístico Clusterizado (Localidades vs Espécies)")
svglite("Resultados_Exportados/02b_Heatmap_Clusterizado.svg", width = 12, height = 10)
pheatmap(as.matrix(matrix_PA_clean), color = c("#f7f7f7", "#cb181d"), cluster_rows = tree_loc, cluster_cols = tree_sp, show_rownames = FALSE, show_colnames = FALSE, border_color = NA, legend_breaks = c(0, 1), legend_labels = c("Ausência", "Presença"), main = "Heatmap Florístico Clusterizado (Localidades vs Espécies)")
dev.off()
}
## pdf
## 3
if(exists("regional_rare")) {
png("Resultados_Exportados/03_Rarefaction.png", width=2400, height=1800, res=300)
plot(regional_rare, ci.type = "poly", col = "darkgreen", lwd = 2, ci.lty = 0, ci.col = "lightgreen", main = "Curva de Acumulacao Regional de Especies", xlab = "Esforco Amostral", ylab = "Riqueza Acumulada de Especies")
grid()
dev.off()
svglite("Resultados_Exportados/03_Rarefaction.svg", width=8, height=6)
plot(regional_rare, ci.type = "poly", col = "darkgreen", lwd = 2, ci.lty = 0, ci.col = "lightgreen", main = "Curva de Acumulacao Regional de Especies", xlab = "Esforco Amostral", ylab = "Riqueza Acumulada de Especies")
grid()
dev.off()
}
## pdf
## 3
if(exists("list_venn_dinamic")) {
png("Resultados_Exportados/04_Venn_Biomas.png", width=2400, height=2400, res=300)
venn(list_venn_dinamic, zcolor = "style", opacity = 0.4, ilabels = "counts", ilcs = 0.5, sncs = 0.8, box = FALSE, borders = FALSE)
dev.off()
svglite("Resultados_Exportados/04_Venn_Biomas.svg", width=8, height=8)
venn(list_venn_dinamic, zcolor = "style", opacity = 0.4, ilabels = "counts", ilcs = 0.5, sncs = 0.8, box = FALSE, borders = FALSE)
dev.off()
}
## pdf
## 3
if(exists("df_diagnostic")) {
p_zscore <- ggplot(df_diagnostic, aes(x = Riqueza, y = Z_Score, color = Status)) +
geom_point(alpha = 0.7, size = 2.5) +
geom_hline(yintercept = 2.0, linetype = "dashed", linewidth = 1, color = "darkred") +
annotate("text", x = max(df_diagnostic$Riqueza) * 0.5, y = 2.25, label = "Corte Multivariado (Z > 2.0)", color = "darkred", fontface = "bold") +
geom_vline(xintercept = 4.5, linetype = "dotted", linewidth = 1, color = "blue") +
annotate("text", x = 1.5, y = max(df_diagnostic$Z_Score) * 0.85, label = "Corte Biologico (< 5 spp)", color = "blue", fontface = "bold", angle = 90, hjust = 1) +
theme_bw() + labs(title = "Diagnostico de Curadoria da Matriz Floristica", subtitle = "Identificacao de localidades com desvio multivariado extremo ou subamostragem", x = "Riqueza Floristica", y = "Distancia Media Multivariada (Z-Score)") +
scale_color_manual(values = c("Excluída (Outlier/Subamostrada)" = "red", "Mantida (Matriz Final)" = "grey40")) +
theme(legend.position = "bottom", plot.title = element_text(face = "bold"))
ggsave("Resultados_Exportados/05_Diagnostico_ZScore.png", plot = p_zscore, width = 10, height = 7, dpi = 300, bg="white")
ggsave("Resultados_Exportados/05_Diagnostico_ZScore.svg", plot = p_zscore, width = 10, height = 7, bg="white")
}
if(exists("df_flow")) {
p_alluvial <- ggplot(df_flow, aes(axis1 = Dominio_Original, axis2 = Dominio_Cluster)) +
geom_alluvium(aes(fill = Flow_Color), width = 1/8, alpha = 0.7, knot.pos = 0.4) +
geom_stratum(width = 1/4, fill = "grey80", color = "black") +
geom_text_repel(stat = "stratum", aes(label = str_wrap(after_stat(stratum), width = 18)), size = 3.5, direction = "y", nudge_x = 0) +
scale_x_discrete(limits = c("Bioma Original", "Grupo Floristico (k=2)"), expand = c(.05, .05)) +
scale_fill_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77", "Target Areas" = "black")) +
theme_minimal() + labs(title = "Fluxo de Reclassificacao Floristica", y = "Numero de Localidades") + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/16_Alluvial_Flux.png", plot = p_alluvial, width = 10, height = 8, dpi = 300, bg="white")
ggsave("Resultados_Exportados/16_Alluvial_Flux.svg", plot = p_alluvial, width = 10, height = 8, bg="white")
}
# (ATUALIZADO: Segundo Diagrama de Venn com os valores de intersecção)
if(exists("lista_venn_dominios")) {
png("Resultados_Exportados/17_Venn_Dominios_k2.png", width=2400, height=2400, res=300)
venn(lista_venn_dominios, zcolor = c("#d95f02", "#1b9e77"), opacity = 0.5, ilabels = "counts", ilcs = 1.5, sncs = 1.2, box = FALSE)
title("Compartilhamento de Especies entre Dominios")
dev.off()
svglite("Resultados_Exportados/17_Venn_Dominios_k2.svg", width=8, height=8)
venn(lista_venn_dominios, zcolor = c("#d95f02", "#1b9e77"), opacity = 0.5, ilabels = "counts", ilcs = 1.5, sncs = 1.2, box = FALSE)
title("Compartilhamento de Especies entre Dominios")
dev.off()
}
## pdf
## 3
if(exists("df_beta_longo")) {
p_beta <- ggplot(df_beta_longo, aes(x = Dominio, y = Valor_Beta, fill = Componente)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7, color = "black") +
geom_text(aes(label = Label), position = position_dodge(width = 0.8), vjust = -0.5, fontface = "bold", size = 4.5) +
theme_bw() + labs(title = "Componentes da Diversidade Beta por Dominio", y = "Valor da Dissimilaridade") +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
scale_fill_manual(values = c("Turnover" = "#2c3e50", "Nestedness" = "#bdc3c7")) + theme(legend.position = "bottom")
ggsave("Resultados_Exportados/18_Beta_Diversity.png", plot = p_beta, width = 8, height = 6, dpi = 300, bg="white")
ggsave("Resultados_Exportados/18_Beta_Diversity.svg", plot = p_beta, width = 8, height = 6, bg="white")
}
if(exists("top_indicadoras")) {
# Atualizado: usa 'especie_clean', shape = dominio e scale_shape_manual
p_indval <- ggplot(top_indicadoras, aes(x = stat, y = reorder(especie_clean, stat), color = dominio)) +
geom_segment(aes(x = 0, xend = stat, y = reorder(especie_clean, stat), yend = reorder(especie_clean, stat)), color = "grey60", linetype = "dashed") +
geom_point(aes(shape = dominio), size = 4) +
facet_wrap(~dominio, scales = "free_y", ncol = 1) +
theme_bw() +
labs(title = "Top 10 Especies Indicadoras", x = "Valor de Indicação (stat)", y = "") +
scale_color_manual(values = c("Floristic Domain A" = "#d95f02", "Floristic Domain B" = "#1b9e77")) +
scale_shape_manual(values = c("Floristic Domain A" = 16, "Floristic Domain B" = 17)) +
theme(legend.position = "none", axis.text.y = element_text(face = "italic"), strip.background = element_rect(fill = "#f0f0f0"), strip.text = element_text(face = "bold"))
ggsave("Resultados_Exportados/19_IndVal_Dotplot.png", plot = p_indval, width = 8, height = 10, dpi = 300, bg="white")
# Adicionado o svglite para preservar o texto, caso o sistema permita
ggsave("Resultados_Exportados/19_IndVal_Dotplot.svg", plot = p_indval, width = 8, height = 10, bg="white", device = svglite::svglite)
}
if(exists("grafico_otimizacao_sub")) {
ggsave("Resultados_Exportados/22_Otimizacao_K.png", plot = grafico_otimizacao_sub, width = 8, height = 10, dpi = 300, bg="white")
ggsave("Resultados_Exportados/22_Otimizacao_K.svg", plot = grafico_otimizacao_sub, width = 8, height = 10, bg="white")
}
# (ATUALIZADO: Exporta o novo gráfico de indicadoras com formas e cores dos subgrupos)
if(exists("grafico_indval_sub")) {
ggsave("Resultados_Exportados/25_IndVal_Subgrupos.png", plot = grafico_indval_sub, width = 14, height = 8, dpi = 300, bg="white")
ggsave("Resultados_Exportados/25_IndVal_Subgrupos.svg", plot = grafico_indval_sub, width = 14, height = 8, bg="white")
}
# ==============================================================================
# 7.6. CATEGORIA VI: DENDROGRAMAS E ESTRUTURAS HIERÁRQUICAS
# ==============================================================================
if(exists("dendro_colorido")) {
png("Resultados_Exportados/06_Dendrograma_k2.png", width=3600, height=1800, res=300)
par(mar = c(2, 4, 3, 1))
plot(dendro_colorido, main = "Dendrograma Floristico: Separacao dos Dominios (k=2)", ylab = "Distancia de Ward", xlab = "Localidades")
title(xlab = "Localidades", line = 0.5, font.lab = 2)
legend("topright", legend = c("Floristic Domain A", "Floristic Domain B", "Target Areas"), fill = c("#d95f02", "#1b9e77", "white"), border = c("black", "black", "white"), pch = c(NA, NA, "|"), col = c(NA, NA, "black"), pt.cex = 1.2, bty = "n", cex = 0.9, inset = c(0.02, 0.02))
dev.off()
svglite("Resultados_Exportados/06_Dendrograma_k2.svg", width=12, height=6)
par(mar = c(2, 4, 3, 1))
plot(dendro_colorido, main = "Dendrograma Floristico: Separacao dos Dominios (k=2)", ylab = "Distancia de Ward", xlab = "Localidades")
title(xlab = "Localidades", line = 0.5, font.lab = 2)
legend("topright", legend = c("Floristic Domain A", "Floristic Domain B", "Target Areas"), fill = c("#d95f02", "#1b9e77", "white"), border = c("black", "black", "white"), pch = c(NA, NA, "|"), col = c(NA, NA, "black"), pt.cex = 1.2, bty = "n", cex = 0.9, inset = c(0.02, 0.02))
dev.off()
}
## pdf
## 3
if(exists("dend_alvo") && exists("dominio_alvo") && exists("cor_dominio")) {
png("Resultados_Exportados/21_Dendrograma_Alvo.png", width=3600, height=1800, res=300)
par(mar = c(2, 4, 3, 1))
plot(dend_alvo, main = paste("Estrutura Interna -", dominio_alvo), ylab = "Distância de Ward", xlab = "Localidades")
title(xlab = "Localidades", line = 0.5, font.lab = 2)
legend("topright", legend = c(paste("Domínio:", dominio_alvo), "Target Areas"), fill = c(cor_dominio, "white"), border = c("black", "white"), pch = c(NA, "|"), col = c(NA, "black"), pt.cex = 1.2, bty = "n", cex = 0.9, inset = c(0.02, 0.02))
dev.off()
svglite("Resultados_Exportados/21_Dendrograma_Alvo.svg", width=12, height=6)
par(mar = c(2, 4, 3, 1))
plot(dend_alvo, main = paste("Estrutura Interna -", dominio_alvo), ylab = "Distância de Ward", xlab = "Localidades")
title(xlab = "Localidades", line = 0.5, font.lab = 2)
legend("topright", legend = c(paste("Domínio:", dominio_alvo), "Target Areas"), fill = c(cor_dominio, "white"), border = c("black", "white"), pch = c(NA, "|"), col = c(NA, "black"), pt.cex = 1.2, bty = "n", cex = 0.9, inset = c(0.02, 0.02))
dev.off()
}
## pdf
## 3
if(exists("dend_alvo_circ") && exists("paleta_sub")) {
png("Resultados_Exportados/23_Dendro_Circular_k_Optimo.png", width=3000, height=3000, res=300)
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_alvo_circ, labels = FALSE, main = paste("Subdivisões", dominio_alvo)))
legend("center", legend = paste("Agrupamento", 1:k_sub), fill = paleta_sub, border = rep("black", k_sub), bty = "n", cex = 0.75, title = "Subgrupos")
dev.off()
svglite("Resultados_Exportados/23_Dendro_Circular_k_Optimo.svg", width=10, height=10)
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_alvo_circ, labels = FALSE, main = paste("Subdivisões", dominio_alvo)))
legend("center", legend = paste("Agrupamento", 1:k_sub), fill = paleta_sub, border = rep("black", k_sub), bty = "n", cex = 0.75, title = "Subgrupos")
dev.off()
}
## pdf
## 3
if(exists("dend_B_circ") && exists("paleta_sub_B")) {
png("Resultados_Exportados/24_Dendro_Circular_k3.png", width=3000, height=3000, res=300)
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_B_circ, labels = FALSE, main = paste("Subdivisões Florísticas do", dominio_B_name)))
legend("center", legend = paste("Agrupamento", 1:k_sub_B), fill = paleta_sub_B, border = rep("black", k_sub_B), bty = "n", cex = 0.75, title = "Subgrupos")
dev.off()
svglite("Resultados_Exportados/24_Dendro_Circular_k3.svg", width=10, height=10)
par(mar = c(2, 2, 2, 8))
suppressWarnings(circlize_dendrogram(dend_B_circ, labels = FALSE, main = paste("Subdivisões Florísticas do", dominio_B_name)))
legend("center", legend = paste("Agrupamento", 1:k_sub_B), fill = paleta_sub_B, border = rep("black", k_sub_B), bty = "n", cex = 0.75, title = "Subgrupos")
dev.off()
}
## pdf
## 3
if(exists("tree_biome")) {
write.tree(as.phylo(tree_biome), file = "Resultados_Exportados/26_dendrograma.nwk")
}
cat("\n✓ Exportação finalizada com sucesso! Todas as imagens foram exportadas em duplas (PNG e SVG editável).\n")
##
## ✓ Exportação finalizada com sucesso! Todas as imagens foram exportadas em duplas (PNG e SVG editável).
Anotações: A automatização desta última etapa consolida as diretrizes de dados abertos (Open Science). A padronização da saída assegura que as matrizes de confusão, índices biológicos e scatterplots espaciais estejam diretamente aptos e adequados para anexação no periódico acadêmico.