Este documento trata-se de procedimento para escolha das variáveis ambientais. Devido os processamentos levarem horas para completar, os códigos foram mantidos na forma de texto e não automatizados. O usuário replicar as análises ao usar este código e executar em seu próprio equipamento.
library(vegan)
## Carregando pacotes exigidos: permute
library(readxl)
library(dplyr)
##
## Anexando pacote: 'dplyr'
## Os seguintes objetos são mascarados por 'package:stats':
##
## filter, lag
## Os seguintes objetos são mascarados por 'package:base':
##
## intersect, setdiff, setequal, union
# 1. Carregar a matriz de comunidade (plantas) salva previamente
matrix_run <- readRDS("matrix_run.rds")
# 2. Carregar o agrupamento dos Domínios Florísticos (k-means)
my_data_group <- readRDS("my_data_group.rds")
# 3. Ler o arquivo .xlsx com as variáveis ambientais brutas
raw_data_env <- read_excel("env_variables.xlsx")
Anotações: O arquivo Excel deve ser formatado previamente antes de ser carregado no R.
# Função que evita que as variáveis quantitativas virem NA.
intel_conversor <- function(coluna) {
if (is.numeric(coluna)) { return(coluna) }
try_num <- suppressWarnings(as.numeric(gsub(",", ".", coluna)))
if (all(is.na(try_num)) && !all(is.na(coluna))) {
return(coluna) # Se virou tudo NA, é texto de verdade (ex: "Latossolo").
} else {
return(try_num) # Se funcionou, retorna o número corrigido.
}
}
# Tratamento de dados e conversão
clean_data_env <- raw_data_env %>%
mutate(across(-locality, intel_conversor))
# Alinhamento Mestre com os códigos das localidades da 'matrix_run'
# Filtramos apenas os códigos presentes na matrix_run e ordenamos EXATAMENTE igual
filter_data_env <- clean_data_env %>%
filter(locality %in% rownames(matrix_run)) %>%
arrange(match(locality, rownames(matrix_run)))
# Configurar para o formato exigido pela CCA (dados como rownames)
# O pacote vegan exige um data.frame clássico para definir rownames
final_data_env <- as.data.frame(filter_data_env)
rownames(final_data_env) <- final_data_env$locality
# Remover a coluna de código de localidades e outras colunas textuais
# Deixamos apenas as variáveis preditoras para a análise
final_data_env <- final_data_env %>%
select(-locality)
# Definir variáveis categóricas (como Salinidade) como fatores
final_data_env$SG_sal <- as.factor(final_data_env$SG_sal)
final_data_env$FAO_Dom_Soil <- as.factor(final_data_env$FAO_Dom_Soil)
final_data_env$FAO_Dom_Soil_Simb <- as.factor(final_data_env$FAO_Dom_Soil_Simb)
final_data_env$FAO_Sub_Soil <- as.factor(final_data_env$FAO_Sub_Soil)
# LIMPEZA DE DADOS AUSENTES (NAs) E VALIDAÇÃO
# Identificar quais linhas têm algum NA na matriz ambiental
rows_with_na <- which(!complete.cases(final_data_env))
# Se houver NAs, removemos essas localidades de AMBAS as matrizes
if(length(rows_with_na) > 0) {
ids_problematics <- rownames(final_data_env)[rows_with_na]
final_data_env <- final_data_env[!(rownames(final_data_env) %in% ids_problematics), ]
matrix_run <- matrix_run[!(rownames(matrix_run) %in% ids_problematics), ]
cat("Foram removidas", length(ids_problematics), "localidades devido a NAs ambientais.\n")
} else {
cat("Nenhum NA encontrado! Suas matrizes estão limpas.\n")
}
## Nenhum NA encontrado! Suas matrizes estão limpas.
# VALIDAÇÃO FINAL (Obrigatório retornar TRUE para as matrizes estarem pareadas)
cat("O pareamento das matrizes está correto? ->", all(rownames(matrix_run) == rownames(final_data_env)), "\n")
## O pareamento das matrizes está correto? -> TRUE
Anotações: Nesta etapa, a matriz fica alinhada e limpa com as variáveis categóricas e numéricas, as localidades sem informações são eliminadas para que a análise posterior possa rodar tranquilamente.
# ANÁLISE DE CORRESPONDÊNCIA CANÔNICA (CCA) COM SELEÇÃO FORWARD
# O Modelo Nulo (Apenas a matriz de plantas)
model_null <- cca(matrix_run ~ 1, data = final_data_env)
# O Modelo Completo (Escopo máximo SEM as variáveis redundantes/aliasing Df=0)
model_full <- cca(matrix_run ~ FAO_Sub_Soil + SG_sal +
WC_bio_1 + WC_bio_2 + WC_bio_3 + WC_bio_4 + WC_bio_8 +
WC_bio_9 + WC_bio_10 + WC_bio_11 + WC_bio_12 + WC_bio_13 +
WC_bio_14 + WC_bio_15 + WC_bio_16 + WC_bio_17 + WC_bio_18 +
WC_bio_19 + SRTM_alt + TC_aet + TC_soil + TC_vpd +
TC_tmin + TC_ppt + TC_tmax + TC_def + PHIHOX_M_sl4 +
BDRICM_M + CLYPPT_M_sl4 + OCDENS_M_sl4,
data = final_data_env)
# ====================================================================
# ESTRATÉGIA DE CARREGAMENTO INTELIGENTE (Ignora horas de processamento)
# ====================================================================
arquivo_modelo <- "modelo_cca_selecionado.rds"
arquivo_anova <- "anova_marginal_cca.rds"
# Verifica se AMBOS os arquivos já existem na sua pasta
if (file.exists(arquivo_modelo) && file.exists(arquivo_anova)) {
model_select <- readRDS(arquivo_modelo)
final_model_test <- readRDS(arquivo_anova)
cat("SUCESSO: Modelo carregado! Pulando a matemática pesada...\n")
} else {
# O SEU ALERTA DE PÂNICO AQUI:
stop("ERRO: Os arquivos .rds não foram encontrados na pasta! O Knit vai parar agora para não demorar horas.")
# Executar a Seleção Forward (ordiR2step)
cat("Iniciando a seleção forward de variáveis. Aguarde...\n")
model_select <- ordiR2step(model_null, scope = formula(model_full),
direction = "forward", permutations = 999, trace = FALSE)
saveRDS(model_select, file = arquivo_modelo)
# O teste marginal final com as variáveis que sobreviveram
cat("Executando o teste marginal final das variáveis retidas...\n")
final_model_test <- anova(model_select, by = "margin", permutations = 999, parallel = 4)
saveRDS(final_model_test, file = arquivo_anova)
}
## SUCESSO: Modelo carregado! Pulando a matemática pesada...
# ====================================================================
# RESULTADOS E GRÁFICOS DO MODELO VENCEDOR
# Visualizar a Inércia e a Fórmula Final selecionada
print(model_select)
##
## Call: cca(formula = matrix_run ~ FAO_Sub_Soil + WC_bio_13 + WC_bio_4 +
## TC_def + WC_bio_12 + WC_bio_11 + TC_vpd + WC_bio_8 + CLYPPT_M_sl4 +
## WC_bio_10 + WC_bio_15 + TC_soil + TC_ppt + WC_bio_17 + WC_bio_9 + WC_bio_3
## + WC_bio_14 + WC_bio_2 + TC_aet + WC_bio_19 + WC_bio_18 + WC_bio_16, data =
## final_data_env)
##
## Inertia Proportion Rank
## Total 18.8872 1.0000
## Constrained 7.4618 0.3951 61
## Unconstrained 11.4254 0.6049 230
##
## Inertia is scaled Chi-square
##
## Eigenvalues for constrained axes:
## CCA1 CCA2 CCA3 CCA4 CCA5 CCA6 CCA7 CCA8 CCA9 CCA10 CCA11
## 0.8149 0.4936 0.4568 0.3428 0.2784 0.2461 0.2325 0.2151 0.2001 0.1879 0.1781
## CCA12 CCA13 CCA14 CCA15 CCA16 CCA17 CCA18 CCA19 CCA20 CCA21 CCA22
## 0.1659 0.1625 0.1470 0.1369 0.1328 0.1263 0.1216 0.1164 0.1127 0.1081 0.1052
## CCA23 CCA24 CCA25 CCA26 CCA27 CCA28 CCA29 CCA30 CCA31 CCA32 CCA33
## 0.1015 0.0990 0.0971 0.0946 0.0936 0.0908 0.0854 0.0816 0.0800 0.0787 0.0744
## CCA34 CCA35 CCA36 CCA37 CCA38 CCA39 CCA40 CCA41 CCA42 CCA43 CCA44
## 0.0742 0.0730 0.0700 0.0681 0.0671 0.0654 0.0643 0.0636 0.0617 0.0602 0.0587
## CCA45 CCA46 CCA47 CCA48 CCA49 CCA50 CCA51 CCA52 CCA53 CCA54 CCA55
## 0.0566 0.0557 0.0541 0.0521 0.0498 0.0488 0.0454 0.0441 0.0427 0.0397 0.0391
## CCA56 CCA57 CCA58 CCA59 CCA60 CCA61
## 0.0363 0.0317 0.0302 0.0301 0.0165 0.0045
##
## Eigenvalues for unconstrained axes:
## CA1 CA2 CA3 CA4 CA5 CA6 CA7 CA8
## 0.31619 0.22911 0.21641 0.19315 0.18633 0.17280 0.16691 0.16543
## (Showing 8 of 230 unconstrained eigenvalues)
# Visualizar o resultado do teste de permutações
print(final_model_test)
## Permutation test for cca under reduced model
## Marginal effects of terms
## Permutation: free
## Number of permutations: 999
##
## Model: cca(formula = matrix_run ~ FAO_Sub_Soil + WC_bio_13 + WC_bio_4 + TC_def + WC_bio_12 + WC_bio_11 + TC_vpd + WC_bio_8 + CLYPPT_M_sl4 + WC_bio_10 + WC_bio_15 + TC_soil + TC_ppt + WC_bio_17 + WC_bio_9 + WC_bio_3 + WC_bio_14 + WC_bio_2 + TC_aet + WC_bio_19 + WC_bio_18 + WC_bio_16, data = final_data_env)
## Df ChiSquare F Pr(>F)
## FAO_Sub_Soil 40 3.4795 1.7511 0.001 ***
## WC_bio_13 1 0.0771 1.5520 0.006 **
## WC_bio_4 1 0.0862 1.7358 0.001 ***
## TC_def 1 0.0908 1.8272 0.001 ***
## WC_bio_12 1 0.0828 1.6673 0.001 ***
## WC_bio_11 1 0.0830 1.6717 0.002 **
## TC_vpd 1 0.1023 2.0596 0.001 ***
## WC_bio_8 1 0.0849 1.7084 0.002 **
## CLYPPT_M_sl4 1 0.0861 1.7326 0.001 ***
## WC_bio_10 1 0.0833 1.6778 0.003 **
## WC_bio_15 1 0.0795 1.6001 0.003 **
## TC_soil 1 0.0974 1.9611 0.001 ***
## TC_ppt 1 0.0832 1.6747 0.001 ***
## WC_bio_17 1 0.0961 1.9339 0.001 ***
## WC_bio_9 1 0.0934 1.8795 0.002 **
## WC_bio_3 1 0.0924 1.8602 0.001 ***
## WC_bio_14 1 0.0999 2.0117 0.001 ***
## WC_bio_2 1 0.0870 1.7520 0.001 ***
## TC_aet 1 0.0826 1.6637 0.003 **
## WC_bio_19 1 0.0731 1.4721 0.016 *
## WC_bio_18 1 0.0758 1.5265 0.011 *
## WC_bio_16 1 0.0732 1.4733 0.006 **
## Residual 230 11.4254
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Gráfico Biplot Limpo com o Modelo Final
plot(model_select, scaling = 2, main = "Biplot Canônico (CCA) - Modelo Parcimonioso")
Call: cca(formula = matrix_run ~ FAO_Sub_Soil + WC_bio_13 + WC_bio_4 + TC_def + WC_bio_12 + WC_bio_11 + TC_vpd + WC_bio_8 + CLYPPT_M_sl4 + WC_bio_10 + WC_bio_15 + TC_soil + TC_ppt + WC_bio_17 + WC_bio_9 + WC_bio_3 + WC_bio_14 + WC_bio_2 + TC_aet + WC_bio_19 + WC_bio_18 + WC_bio_16, data = final_data_env)
Inertia Proportion Rank
Total 18.8872 1.0000
Constrained 7.4618 0.3951 61 Unconstrained 11.4254 0.6049 230
Inertia is scaled Chi-square
Eigenvalues for constrained axes: CCA1 CCA2 CCA3 CCA4 CCA5 CCA6 CCA7 CCA8 CCA9 CCA10 CCA11 CCA12 CCA13 CCA14 CCA15 0.8149 0.4936 0.4568 0.3428 0.2784 0.2461 0.2325 0.2151 0.2001 0.1879 0.1781 0.1659 0.1625 0.1470 0.1369 CCA16 CCA17 CCA18 CCA19 CCA20 CCA21 CCA22 CCA23 CCA24 CCA25 CCA26 CCA27 CCA28 CCA29 CCA30 0.1328 0.1263 0.1216 0.1164 0.1127 0.1081 0.1052 0.1015 0.0990 0.0971 0.0946 0.0936 0.0908 0.0854 0.0816 CCA31 CCA32 CCA33 CCA34 CCA35 CCA36 CCA37 CCA38 CCA39 CCA40 CCA41 CCA42 CCA43 CCA44 CCA45 0.0800 0.0787 0.0744 0.0742 0.0730 0.0700 0.0681 0.0671 0.0654 0.0643 0.0636 0.0617 0.0602 0.0587 0.0566 CCA46 CCA47 CCA48 CCA49 CCA50 CCA51 CCA52 CCA53 CCA54 CCA55 CCA56 CCA57 CCA58 CCA59 CCA60 0.0557 0.0541 0.0521 0.0498 0.0488 0.0454 0.0441 0.0427 0.0397 0.0391 0.0363 0.0317 0.0302 0.0301 0.0165 CCA61 0.0045
Eigenvalues for unconstrained axes: CA1 CA2 CA3 CA4 CA5 CA6 CA7 CA8 0.31619 0.22911 0.21641 0.19315 0.18633 0.17280 0.16691 0.16543 (Showing 8 of 230 unconstrained eigenvalues)
Permutation test for cca under reduced model Marginal effects of terms Permutation: free Number of permutations: 999
Model: cca(formula = matrix_run ~ FAO_Sub_Soil + WC_bio_13 + WC_bio_4
+ TC_def + WC_bio_12 + WC_bio_11 + TC_vpd + WC_bio_8 + CLYPPT_M_sl4 +
WC_bio_10 + WC_bio_15 + TC_soil + TC_ppt + WC_bio_17 + WC_bio_9 +
WC_bio_3 + WC_bio_14 + WC_bio_2 + TC_aet + WC_bio_19 + WC_bio_18 +
WC_bio_16, data = final_data_env) Df ChiSquare F Pr(>F)
FAO_Sub_Soil 40 3.4795 1.7511 0.001 WC_bio_13 1 0.0771
1.5520 0.006 WC_bio_4 1 0.0862 1.7358 0.001
TC_def 1 0.0908 1.8272 0.001 WC_bio_12 1 0.0828 1.6673
0.004 WC_bio_11 1 0.0830 1.6717 0.002 TC_vpd 1 0.1023
2.0596 0.001 WC_bio_8 1 0.0849 1.7084 0.001
CLYPPT_M_sl4 1 0.0861 1.7326 0.001 WC_bio_10 1 0.0833
1.6778 0.001 WC_bio_15 1 0.0795 1.6001 0.002
TC_soil 1 0.0974 1.9611 0.002 TC_ppt 1 0.0832 1.6747 0.003
WC_bio_17 1 0.0961 1.9339 0.001 WC_bio_9 1
0.0934 1.8795 0.001 WC_bio_3 1 0.0924 1.8602 0.001
WC_bio_14 1 0.0999 2.0117 0.001 WC_bio_2 1
0.0870 1.7520 0.002 TC_aet 1 0.0826 1.6637 0.001
WC_bio_19 1 0.0731 1.4721 0.011 *
WC_bio_18 1 0.0758 1.5265 0.008 WC_bio_16 1 0.0732 1.4733
0.009 ** Residual 230 11.4254
— Signif. codes: 0 ‘’ 0.001 ‘’ 0.01 ‘’ 0.05
‘.’ 0.1 ‘ ’ 1
Anotações: Aqui foram inseridas variáveis categóricas e numéricas. Total Inertia (Inércia Total): É a variabilidade total da comunidade vegetal. Constrained Inertia (Inércia Constrangida): É a porção da variabilidade que é explicada diretamente pelo seu conjunto de variáveis ambientais (clima + solo + salinidade). Proportion: Divida a inércia constrangida pela total para obter a porcentagem de explicação do seu modelo (ex: 0.124 significa que o ambiente explica 12,4% da distribuição das plantas). Nota: Em matrizes grandes com milhares de pontos, valores entre 5% e 15% são perfeitamente normais e altamente significativos. Para provar que a relação encontrada não foi por acaso, rodamos testes de permutação Monte Carlo. No gráfico gerado: Setas/Vetores: Indicam a direção de maior aumento das variáveis numéricas (ex: maior chuva ou acidez). Pontos de Fatores: Os nomes dos solos e os níveis de salinidade aparecerão como pontos centrais (centroides). Localidades próximas a esses pontos possuem maior afinidade por aquela característica edáfica. Na tabela de significância foi possível avaliar quais variáveis poderiam estar com problemas (Exemplo: Df=0, F=Inf/NaN). Isso se chama Aliasing (ou multicolinearidade perfeita). Significa que o R detectou que essas variáveis são 100% redundantes.
# Transformar a saída do teste marginal em um data frame manipulável
anova_table <- as.data.frame(final_model_test)
# Extrair os nomes das variáveis cujo valor de Pr(>F) é menor ou igual a 0.001 (***)
# O uso de which() já exclui automaticamente a linha "Residual" (que possui NA)
all_sig_var <- rownames(anova_table)[which(anova_table$`Pr(>F)` <= 0.001)]
# Isolar a variável categórica (usada para gerar os centroides no gráfico)
# e reter estritamente as variáveis contínuas para as setas (vetores)
categ_var <- "FAO_Sub_Soil"
top_sig_var <- all_sig_var[all_sig_var != categ_var]
cat("Foram retidas automaticamente", length(top_sig_var), "variáveis contínuas com significância máxima.\n")
## Foram retidas automaticamente 11 variáveis contínuas com significância máxima.
print(top_sig_var)
## [1] "WC_bio_4" "TC_def" "WC_bio_12" "TC_vpd" "CLYPPT_M_sl4"
## [6] "TC_soil" "TC_ppt" "WC_bio_17" "WC_bio_3" "WC_bio_14"
## [11] "WC_bio_2"
Anotações: A escolha pela função ordiR2step usa o critério do R² ajustado (Adjusted R-squared) e testes de permutação em cada passo, garantindo que o modelo final seja robusto, parcimonioso e livre de redundâncias. Para aplicar a ordiR2step corretamente com base no resultado preliminar, há uma regra: o modelo de escopo máximo não pode conter as variáveis que retornaram Df = 0 (Aliasing). Se você as deixar no escopo, a função de seleção pode falhar ao calcular o R². Portanto, removeremos FAO_Dom_Soil, FAO_Dom_Soil_Simb, WC_bio_5, WC_bio_6 e WC_bio_7 da equação inicial. As variáveis não significativas (como a salinidade e o pH) podem ficar; o próprio algoritmo vai testá-las e descartá-las automaticamente se não ajudarem. Para evitar problemas de colinearidade e construir um modelo parcimonioso capaz de explicar a variação das espécies botânicas avaliadas, aplicou-se uma seleção de variáveis do tipo forward-selection utilizando a função ordiR2step do pacote vegan. O procedimento iterativo incluiu variáveis preditoras no modelo de Análise de Correspondência Canônica (CCA) apenas se apresentassem contribuição estatisticamente significativa (p < 0,05) baseada em 999 permutações de Monte Carlo, e se a inclusão da variável aumentasse o R² ajustado geral do modelo (Blanchet et al., 2008). Variáveis perfeitamente colineares foram removidas a priori do modelo completo. Blanchet, F. G., Legendre, P., & Borcard, D. (2008). Forward selection of explanatory variables. Ecology, 89(9), 2623-2632. A seleção progressiva (forward selection) identificou um subconjunto parcimonioso de 22 variáveis ambientais que estruturam significativamente a composição da comunidade lenhosa. A Análise de Correspondência Canônica (CCA) global revelou que este conjunto de preditores edafoclimáticos e topográficos explicou 39,48% da inércia total da comunidade (Inércia Constrangida = 7,45; Inércia Total = 18,88). Os dois primeiros eixos canônicos (CCA1 e CCA2) apresentaram autovalores de 0,81 e 0,49, respectivamente, capturando os principais gradientes de substituição florística (turnover) nas áreas de estudo. A alta proporção de variância não explicada (60,52%) é esperada em amostragens de comunidades em larga escala, refletindo a inerente estocasticidade demográfica, dinâmicas espaço-temporais não medidas e fatores bióticos não incluídos no modelo. Dada a alta sensibilidade do valor de p em amostragens de grande escala (N > 14.000), a importância relativa das variáveis ambientais retidas no modelo não foi avaliada exclusivamente pela significância estatística, mas sim pela magnitude do tamanho do efeito (Effect Size). Para a interpretação dos gradientes principais e construção dos biplots de ordenação, aplicou-se um limiar de relevância, destacando-se apenas os preditores que apresentaram os maiores valores de estatística F no teste de efeitos marginais, garantindo uma representação parcimoniosa dos filtros ambientais dominantes na estruturação da comunidade.
# Extração de scores (coordenadas) do modelo selecionado
cca_scores <- scores(model_select, display = c("sites", "species", "bp", "cn"), scaling = 2)
site_df <- as.data.frame(cca_scores$sites)
species_df <- as.data.frame(cca_scores$species)
env_df <- as.data.frame(cca_scores$biplot)
centroid_df <- as.data.frame(cca_scores$centroids)
# Limpeza dos nomes das categorias de solo (remover prefixo da coluna)
rownames(centroid_df) <- gsub("FAO_Sub_Soil", "", rownames(centroid_df))
centroid_df$soil_name <- rownames(centroid_df)
# Alinhamento seguro e nomeação dos Domínios Florísticos (k-means)
raw_groups <- as.factor(my_data_group[rownames(site_df)])
levels(raw_groups) <- c("Floristic Domain A", "Floristic Domain B")
site_df$domain <- raw_groups
# Definição das cores hexadecimais para a plotagem
domain_colors <- c("Floristic Domain A" = "#d95f02",
"Floristic Domain B" = "#1b9e77")
# Cálculo de Escala Automática Inteligente (Mantém a proporção em 90%)
max_point_limit <- max(abs(site_df$CCA1), abs(site_df$CCA2),
abs(species_df$CCA1), abs(species_df$CCA2))
max_arrow_limit <- max(abs(env_df$CCA1), abs(env_df$CCA2))
auto_scale_factor <- (max_point_limit / max_arrow_limit) * 0.9
env_df$CCA1 <- env_df$CCA1 * auto_scale_factor
env_df$CCA2 <- env_df$CCA2 * auto_scale_factor
# DICIONÁRIO MESTRE: Automação Total de Nomes e Categorias
# Este dicionário contém todas as variáveis contínuas do 'model_full'.
# O script aplicará o nome elegante automaticamente a qualquer variável que a ANOVA selecionar.
master_labels <- c(
WC_bio_1 = "Temp. Média Anual", WC_bio_2 = "Amp. Térmica Diária",
WC_bio_3 = "Isotermalidade", WC_bio_4 = "Sazon. da Temp.",
WC_bio_8 = "Temp. (Trim. Úmido)", WC_bio_9 = "Temp. (Trim. Seco)",
WC_bio_10 = "Temp. (Trim. Quente)", WC_bio_11 = "Temp. (Trim. Frio)",
WC_bio_12 = "Prec. Anual", WC_bio_13 = "Prec. (Mês Úmido)",
WC_bio_14 = "Prec. (Mês Seco)", WC_bio_15 = "Sazon. da Prec.",
WC_bio_16 = "Prec. (Trim. Úmido)", WC_bio_17 = "Prec. (Trim. Seco)",
WC_bio_18 = "Prec. (Trim. Quente)", WC_bio_19 = "Prec. (Trim. Frio)",
TC_aet = "Evapotranspiração Real", TC_soil = "Umidade do Solo",
TC_vpd = "Déficit de Pressão de Vapor", TC_tmin = "Temp. Mínima",
TC_ppt = "Precipitação (TC)", TC_tmax = "Temp. Máxima",
TC_def = "Déficit Hídrico", SRTM_alt = "Altitude",
PHIHOX_M_sl4 = "pH do Solo", BDRICM_M = "Prof. da Rocha",
CLYPPT_M_sl4 = "Teor de Argila", OCDENS_M_sl4 = "Densidade de Carbono"
)
# Aplica os nomes apenas às variáveis que sobreviveram na tabela
env_df$clean_labels <- master_labels[rownames(env_df)]
env_top_df <- env_df[rownames(env_df) %in% top_sig_var, , drop = FALSE]
# FILTRAGEM TEMÁTICA DINÂMICA (Sem Hardcoding)
# Define quais variáveis pertencem a qual grupo biológico/físico
master_soil_topo <- c("SRTM_alt", "PHIHOX_M_sl4", "BDRICM_M", "CLYPPT_M_sl4", "OCDENS_M_sl4")
master_water <- c("WC_bio_12", "WC_bio_13", "WC_bio_14", "WC_bio_15", "WC_bio_16",
"WC_bio_17", "WC_bio_18", "WC_bio_19", "TC_aet", "TC_soil",
"TC_vpd", "TC_ppt", "TC_def")
master_temp <- c("WC_bio_1", "WC_bio_2", "WC_bio_3", "WC_bio_4", "WC_bio_8",
"WC_bio_9", "WC_bio_10", "WC_bio_11", "TC_tmin", "TC_tmax")
# A função intersect() garante que apenas as variáveis que são simultaneamente
# ALTAMENTE SIGNIFICATIVAS (top_sig_var) e daquela CATEGORIA vão para o gráfico respectivo.
# O argumento 'drop = FALSE' impede que o R quebre o formato caso apenas 1 variável seja retida.
soil_cont_arrows <- env_top_df[rownames(env_top_df) %in% intersect(top_sig_var, master_soil_topo), , drop = FALSE]
water_arrows <- env_top_df[rownames(env_top_df) %in% intersect(top_sig_var, master_water), , drop = FALSE]
temp_arrows <- env_top_df[rownames(env_top_df) %in% intersect(top_sig_var, master_temp), , drop = FALSE]
Anotações: Nesta etapa, extraímos as coordenadas geradas pela CCA. Para garantir total reprodutibilidade com diferentes conjuntos de dados, o agrupamento temático das setas contínuas (Solo, Hídrico, Térmico) e a aplicação dos rótulos são feitos de forma totalmente automatizada cruzando as variáveis significativas com um Dicionário Mestre.
Nesta seção, definimos a função customizada no ggplot2
adaptada para os novos objetos em inglês. Ela ajusta as legendas
laterais dinamicamente e enquadra as imagens de forma independente,
utilizando apenas o conjunto filtrado de preditores altamente
significativos.
library(ggplot2)
library(ggrepel)
create_individual_plot <- function(arrow_data = NULL, plot_title, include_centroids = FALSE) {
# Gráfico base contendo as camadas de Espécies e Localidades
p <- ggplot() +
geom_hline(yintercept = 0, linetype = "dashed", color = "gray80") +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray80") +
# 1. Espécies (Mapeado para o formato de cruz "Sinal de mais" na legenda)
geom_point(data = species_df, aes(x = CCA1, y = CCA2, shape = "Espécies (Sinal de mais)"),
color = "gray70", alpha = 0.5, size = 1) +
# 2. Localidades (Mapeado para círculo, preenchido pelas cores dos Domínios)
geom_point(data = site_df, aes(x = CCA1, y = CCA2, fill = domain, shape = "Localidades (Círculos)"),
color = "black", size = 2.5, alpha = 0.8) +
# Aplicação da paleta manual com as cores hexadecimais dos Domínios Florísticos
scale_fill_manual(values = domain_colors, name = "Domínios Fitogeográficos")
# CONTROLE DINÂMICO DA LEGENDA DE SÍMBOLOS (Evita erros de dimensões e corrige as cores)
if(include_centroids) {
# 3. Centroides (Exibidos apenas quando include_centroids = TRUE)
p <- p +
geom_point(data = centroid_df, aes(x = CCA1, y = CCA2, shape = "Solos (Quadrados cinzas)"),
fill = "gray60", color = "black", size = 3.5, stroke = 1) +
geom_text_repel(data = centroid_df, aes(x = CCA1, y = CCA2, label = soil_name),
color = "gray20", fontface = "bold.italic", size = 3,
max.overlaps = 50, box.padding = 0.4)
# Vetor de formas contendo 3 elementos (Espécies, Localidades e Solos)
used_shapes <- c("Espécies (Sinal de mais)" = 3,
"Localidades (Círculos)" = 21,
"Solos (Quadrados cinzas)" = 22)
shape_guide <- guide_legend(override.aes = list(
shape = c(3, 21, 22),
color = c("gray50", "black", "black"),
fill = c(NA, "black", "gray60"),
size = 4))
} else {
# Vetor de formas contendo apenas 2 elementos quando não houver solo categórico
used_shapes <- c("Espécies (Sinal de mais)" = 3,
"Localidades (Círculos)" = 21)
shape_guide <- guide_legend(override.aes = list(
shape = c(3, 21),
color = c("gray50", "black"),
fill = c(NA, "black"),
size = 4))
}
# 4. Projeção das Setas Contínuas (Vetores ambientais)
if(!is.null(arrow_data) && nrow(arrow_data) > 0) {
p <- p +
geom_segment(data = arrow_data, aes(x = 0, y = 0, xend = CCA1, yend = CCA2),
arrow = arrow(length = unit(0.25, "cm")), color = "black", linewidth = 0.8) +
geom_text_repel(data = arrow_data, aes(x = CCA1, y = CCA2, label = clean_labels),
color = "black", fontface = "bold", size = 3.5,
box.padding = 0.5, point.padding = 0.3)
}
# 5. Configurações Estéticas Finais e Fixação da Proporção do Zoom (1:1)
p <- p +
scale_shape_manual(name = "Elementos do Gráfico", values = used_shapes) +
theme_classic() +
coord_fixed(ratio = 1,
xlim = c(-max_point_limit, max_point_limit),
ylim = c(-max_point_limit, max_point_limit)) +
labs(title = plot_title, x = "Eixo Canônico 1 (CCA1)", y = "Eixo Canônico 2 (CCA2)") +
theme(plot.title = element_text(face = "bold", size = 11),
axis.title = element_text(face = "bold", size = 10),
legend.position = "right",
legend.box = "vertical",
legend.title = element_text(face = "bold", size = 10),
legend.text = element_text(size = 9)) +
# Força a legenda do fill a respeitar o círculo oco (21) para exibir as cores corretas
guides(shape = shape_guide,
fill = guide_legend(override.aes = list(shape = 21, size = 4, color = "black")))
return(p)
}
# 1. Plotagem da Variável Categórica (Apenas os centroides e quadrados cinzas de solo)
soil_cat_plot <- create_individual_plot(arrow_data = NULL,
plot_title = "Variável Categórica: Classificação Pedológica (FAO)",
include_centroids = TRUE)
# 2. Plotagem da Variável Contínua Edafíca (Apenas a seta de textura/argila)
soil_cont_plot <- create_individual_plot(arrow_data = soil_cont_arrows,
plot_title = "Variável Contínua Edáfica: Teor de Argila",
include_centroids = FALSE)
# 3. Plotagem do Filtro Hidrológico (Setas de estresse hídrico e seca)
water_plot <- create_individual_plot(arrow_data = water_arrows,
plot_title = "Filtro Hídrico: Estresse Atmosférico e Seca Sazonal",
include_centroids = FALSE)
# 4. Plotagem do Filtro Térmico (Setas dos regimes de temperatura)
temp_plot <- create_individual_plot(arrow_data = temp_arrows,
plot_title = "Filtro Térmico: Regime de Temperaturas",
include_centroids = FALSE)
# Comandos que forçam os gráficos a aparecerem no corpo do documento R Markdown
print(soil_cat_plot)
print(soil_cont_plot)
print(water_plot)
print(temp_plot)
# Salvamento automatizado dos arquivos individuais no diretório ativo a 300 DPI
ggsave("CCA_Fig1_SolosCat.png", plot = soil_cat_plot, width = 10, height = 7, dpi = 300)
ggsave("CCA_Fig2_SolosCont.png", plot = soil_cont_plot, width = 10, height = 7, dpi = 300)
ggsave("CCA_Fig3_FiltroHidrico.png", plot = water_plot, width = 10, height = 7, dpi = 300)
ggsave("CCA_Fig4_FiltroTermico.png", plot = temp_plot, width = 10, height = 7, dpi = 300)