💡 Atualmente, estou desenvolvendo um projeto voltado para o mapeamento de congestionamentos urbanos, analisando seus padrões de origem e propagação. Para isso, levo em consideração tanto os elementos da rede viária quanto aspectos do ambiente construído, buscando compreender os fatores que influenciam a formação e dispersão do tráfego intenso.
🔍 Com isso pretendo elaborar uma análise multidimensional através da união de estrutura (grafos), complexidade (fractais) e contexto (ambiente construído) para modelagem da estrutura urbana de mobilidade.
Com esses três aspectos posso implementar camadas de contexto urbano e integrar dados do ambiente construído, como:
✨ Como muitos congestionamentos têm origem nas interseções, pretendo avaliá-los por meio de métricas da teoria dos grafos, identificando padrões estruturais que podem impactar diretamente a fluidez do trânsito e a mobilidade urbana
🔹 Por que usar grafos para entender congestionamentos?
📌 Interseções como vértices: As interseções rodoviárias funcionam como
nós da rede, sendo pontos cruciais na propagação do
congestionamento.
📌 Ruas como arestas: As conexões entre interseções formam as arestas,
determinando como o fluxo de tráfego se desloca.
📌 Centralidade de intermediação (betweenness): Identifica nós
estratégicos que atuam como gargalos—pontos onde o congestionamento
tende a se formar.
📌 Centralidade de proximidade (closeness): Mostra quais interseções
estão mais acessíveis, podendo afetar a dispersão do tráfego.
📌 Centralidade de grau (degree): Avalia o número de conexões de uma
interseção, indicando se ela tem muitas entradas e saídas e como isso
pode impactar a fluidez.
📌 Propagação do congestionamento: Usando propriedades do grafo, é
possível analisar como os padrões de trânsito evoluem e prever zonas
críticas antes que se tornem problemáticas.
🔹 Vantagens da abordagem com grafos
✅ Permite uma visualização estruturada da rede viária e dos padrões de
tráfego.
✅ Quantifica impactos de cruzamentos críticos no fluxo geral.
✅ Ajuda no planejamento urbano, permitindo ajustes estratégicos para
reduzir congestionamentos.
✅ Pode ser combinado com dados de ambiente construído, como largura das
ruas e presença de semáforos, para análises mais precisas.
🔹 Por que usar fractais para entender congestionamentos urbanos?
📌 Auto-semelhança urbana:
Cidades crescem de forma desigual, mas com padrões que se repetem em
várias escalas — bairros, ruas e cruzamentos muitas vezes refletem
estruturas maiores. Fractais ajudam a captar essa auto-organização
espacial.
📌 Complexidade da malha viária:
Redes de tráfego apresentam ramificações, aglomerações e zonas
periféricas que não são bem descritas por geometria tradicional. Já a
geometria fractal abraça essa complexidade.
📌 Medição da rugosidade e dispersão:
A dimensão fractal permite quantificar a irregularidade e fragmentação
da malha viária, o que afeta diretamente como o tráfego se espalha e
onde ele tende a se acumular.
📌 Previsibilidade da propagação:
Sistemas com estrutura fractal costumam ter zonas críticas recorrentes.
Ao entender a estrutura fractal, é possível prever como um
congestionamento pode se espalhar de forma não-linear.
📌 Escalas múltiplas de análise:
Fractais funcionam bem desde o nível macro (zonas inteiras de uma
cidade) até o micro (interseções locais), permitindo integrar diferentes
camadas de análise — inclusive o ambiente construído.
✅ Vantagens da abordagem fractal
- Mensuração objetiva da complexidade urbana
- Integração com modelos dinâmicos de propagação (como SIR, percolação
ou CA)
- Complementaridade com as métricas de centralidade do grafo
- Aplicável a dados espaciais vetoriais ou raster
- Base para simulações de cenários urbanos com alta fidelidad
Criar um grafo que incorpore dados da rede viária permitindo que análises de grafos e fractais possam ser realizadas sobre a rede viária em nós de interesse.
Na figura abaixo podemos ver que o objeto no mapa e o grafo compartilham um mesmo valor de atributo que se chama osm_id, esse atributo é a ID do link fornecida pelo Open Street Maps (OSM).
Resultado esperado: Grafo com arestas de mesmo ID das Ruas do arquivo shape
library(sf)
library(igraph)
library(visNetwork)
library(dplyr)
library(mapview)
ruas <- st_read("C:/Users/fagne/OneDrive/SIG/sul-latest-free.shp/OSM_POA/OSM_PoA/OSM_PoA.shp")
## Reading layer `OSM_PoA' from data source
## `C:\Users\fagne\OneDrive\SIG\sul-latest-free.shp\OSM_POA\OSM_PoA\OSM_PoA.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 42439 features and 10 fields
## Geometry type: MULTILINESTRING
## Dimension: XY
## Bounding box: xmin: -51.29933 ymin: -30.26926 xmax: -51.01163 ymax: -29.94017
## Geodetic CRS: WGS 84
ruas <- ruas[ruas$highway %in% c("primary", "primary_link", "secondary", "secondary_link"), ]
ruas <- st_transform(ruas, 4326)
Aqui criamos um bounding box para definir uma área específica para análise dentro da rede de arteriais que carregamos.
bbox <- st_bbox(c(xmin = -51.13754, ymin = -30.03429, xmax = -51.12969, ymax = -30.02931),
crs = st_crs(4326))
# plinio
bbox <- st_bbox(c(xmin = -51.186075, ymin = -30.022909, xmax = -51.183189, ymax = -30.020670), crs = st_crs(4326))
bbox <- st_bbox(c(xmin = -51.23577, ymin = -30.05178, xmax = -51.15562, ymax = -30.01504),
crs = st_crs(4326)) # WGS 84
# Converter para um objeto sf (polígono)
bbox_sf <- st_as_sfc(bbox)
# Visualizar com mapview
mapview(bbox_sf, col.regions = "red", alpha = 0.3)
Aqui já é possível visualizar a rede compreendida no bounding box.
ruas <- st_crop(ruas, bbox)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
mapview(ruas)
ruas_segmentadas <- ruas %>%
st_cast("LINESTRING") %>%
group_by(osm_id) %>%
summarise(geometry = st_union(geometry), .groups = "drop") %>%
mutate(osm_id = as.character(osm_id), edge_id = row_number()) # Criar um ID único para cada segmento
coords <- st_coordinates(ruas_segmentadas)
nodes <- data.frame(
X = coords[, "X"],
Y = coords[, "Y"]
) %>%
distinct() %>%
mutate(id = row_number()) # Atribuir um ID único para cada nó
coords <- st_coordinates(ruas_segmentadas) # Extrair coordenadas corretamente
edges_temp <- data.frame(
osm_id = rep(ruas_segmentadas$osm_id, sapply(st_geometry(ruas_segmentadas), function(g) nrow(st_coordinates(g)))),
X = coords[, "X"],
Y = coords[, "Y"]
)
edges <- edges_temp %>%
group_by(osm_id) %>%
summarise(from.X = first(X), from.Y = first(Y),
to.X = last(X), to.Y = last(Y)) %>%
left_join(nodes, by = c("from.X" = "X", "from.Y" = "Y")) %>%
rename(from = id) %>%
left_join(nodes, by = c("to.X" = "X", "to.Y" = "Y")) %>%
rename(to = id) %>%
left_join(ruas_segmentadas %>% select(osm_id, edge_id, geometry), by = "osm_id") %>%
mutate(original_id = osm_id) # Agora `osm_id` será corretamente preservado
edges <- edges %>%
dplyr::select(from, to, original_id, edge_id)
nodes <- nodes %>%
filter(id %in% c(edges$from, edges$to))
print(nrow(ruas_segmentadas)) # Deve ser igual ao número de edges
## [1] 1419
print(nrow(edges)) # Deve ser igual ao número de ruas
## [1] 1419
edges_sf <- edges_temp %>%
st_as_sf(coords = c("X", "Y"), crs = 4326) # Converter para spatial dataframe
mapview(edges_sf, zcol="osm_id") + mapview(ruas, zcol="osm_id")
grafo <- graph_from_data_frame(edges, directed = TRUE)
plot(grafo, vertex.label = NA, main = "Grafo da Rede Viaria")
Os vértices representam os nós da rede—no seu caso, podem ser
interseções de ruas ou pontos específicos no mapa.
- Vértices altos: Indica uma rede viária complexa, com muitas
interseções.
- Vértices baixos: Pode representar caminhos mais diretos, com menos
pontos de decisão.
print(vcount(grafo))
## [1] 1281
As arestas representam conexões entre os vértices—ou seja, as ruas ou
caminhos entre interseções.
- Arestas altas: Indica uma rede viária bem interligada, com múltiplas
rotas possíveis.
- Arestas baixas: Pode significar poucas alternativas, o que pode afetar
o fluxo de tráfego.
print(ecount(grafo))
## [1] 1419
Mede quão conectada está a rede.
- Densidade alta: Muitas conexões entre nós, indicando um centro urbano
compacto.
- Densidade baixa: Rede mais espalhada, típica de áreas suburbanas.
print(edge_density(grafo))
## [1] 0.0008654128
O grau de um nó é o número de conexões que ele possui.
- Nó de alto grau: Muito conectado, pode ser um ponto central na rede
viária.
- Nó de baixo grau: Poucas conexões, pode ser um cul-de-sac ou um
cruzamento menos utilizado.
Essa métrica indica quantos vizinhos imediatos um nó possui.
- Nó com alto grau: Muito conectado, pode ser um ponto de grande fluxo
na rede viária.
- Nó com baixo grau: Poucas conexões, pode representar um beco sem saída
ou um cruzamento menos movimentado.
graus <- degree(grafo) # vetor com os graus de cada nó
head(graus, 25) # mostra os 25 primeiros
## 1 8 11 13 15 17 19 21 29 36 39 45 47 63 69 72 77 81 84 86
## 2 3 2 4 2 4 2 3 4 3 3 2 3 2 4 2 3 4 3 3
## 91 112 118 120 122
## 3 2 2 2 3
Mede quantas vezes um nó é usado como “ponte” entre outros.
- Nó com alta betweenness: Crucial para conectar diferentes partes da
rede.
- Nó com baixa betweenness: Menos importante para a conectividade
global.
graus <- betweenness(grafo) # vetor com os betweenness de cada nó
head(graus, 25) # mostra os 25 primeiros
## 1 8 11 13 15 17 19 21
## 24493.33 15332.33 37038.67 106193.33 5045.00 112300.17 3036.00 5316.00
## 29 36 39 45 47 63 69 72
## 28026.00 1960.00 17396.50 3045.00 5045.00 1249.00 114473.17 55005.00
## 77 81 84 86 91 112 118 120
## 55656.67 62704.67 40597.33 31672.83 32934.00 14602.00 4040.00 390.00
## 122
## 77854.67
A centralidade de proximidade (closeness) mede o quão rapidamente um
nó pode alcançar todos os outros na rede. Ela ajuda a identificar pontos
estratégicos para navegação e mobilidade. 🚀
- Um nó com alta proximidade pode chegar rapidamente a todos os outros
pontos da rede.
- Um nó com baixa proximidade está mais isolado, levando mais tempo para
alcançar os demais.
Isso é útil, por exemplo, para planejamento urbano, indicando
interseções centrais que facilitam o tráfego.
Fórmula matemática
A proximidade de um nó ( u ) é calculada como:
\[C(u) = \frac{1}{\sum d(u,
v)}\]
onde ( d(u, v) ) representa a distância mais curta entre o nó ( u ) e
todos os outros ( v ).
Quanto menor a soma das distâncias, maior a proximidade!
graus <- closeness(grafo) # vetor com os closeness de cada nó
head(graus, 25) # mostra os 25 primeiros
## 1 8 11 13 15 17
## 1.717859e-05 2.183072e-05 2.483176e-05 2.183311e-05 2.178364e-05 2.524870e-05
## 19 21 29 36 39 45
## 2.031529e-05 2.050273e-05 2.011020e-05 3.333333e-01 2.014383e-05 2.060072e-05
## 47 63 69 72 77 81
## 1.555887e-05 1.503714e-05 2.465058e-05 2.088686e-05 1.925335e-05 2.219854e-05
## 84 86 91 112 118 120
## 1.882211e-05 2.221679e-05 2.597403e-03 9.523810e-03 1.531816e-05 1.098901e-02
## 122
## 1.680108e-05
Representa a maior distância entre dois nós da rede.
- Diâmetro grande: Cidade extensa, onde os extremos estão longe.
- Diâmetro pequeno: Cidade compacta, tudo está perto.
print(diameter(grafo))
## [1] 122
# comunidades <- cluster_louvain(grafo)
# V(grafo)$comunidade <- membership(comunidades)
nodes_vis <- data.frame(
id = nodes$id,
label = nodes$id,
title = paste("ID:", nodes$id) # Exibir ID ao passar o mouse
)
edges_vis <- edges %>%
mutate(
title = paste("Rua OSM ID:", original_id), # Exibir ao passar o mouse
# osm = original_id, # Exibir ao passar o mouse
label = original_id # Exibir diretamente no grafo
) %>%
dplyr::select(from, to, title, label) # Removido erro de texto extra
#edges_vis$title <- as.character(edges_vis$original_id) # Converter para texto legível
nodes_vis <- nodes_vis %>%
filter(id %in% c(edges_vis$from, edges_vis$to))
visNetwork(nodes_vis, edges_vis) %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
visLegend(position = "right")
edges_vis <- edges_vis %>%
mutate(
comprimento_km = 1,#as.numeric(st_length(geometry)) / 1000, # exemplo com comprimento da rua
peso_congestionamento = 2,#1 / (faixas + 1) + as.numeric(tem_semaforo) + densidade_edif,
info_tooltip = paste("Comprimento",comprimento_km, "<br>Peso:", peso_congestionamento,"<br>Faixas:", NA, "<br>Semáforo:", NA, "<br>Densidade:", NA)
)
edges_vis$title <- edges_vis$info_tooltip
edges_vis$label <- paste0("ID: ", edges_vis$label)
visNetwork(nodes_vis, edges_vis)
nodes_vis <- data.frame(
id = nodes$id,
label = nodes$id,
title = paste("ID:", nodes$id), # Exibir ID ao passar o mouse
group = nodes$id # Atribuir o grupo baseado na comunidade
#group = V(grafo)$comunidade # Atribuir o grupo baseado na comunidade
)
nodes_vis$color <- rainbow(length(unique(nodes_vis$group)))[nodes_vis$group]
edges_vis <- edges %>%
mutate(title = paste("Rua OSM ID:", original_id), label = original_id) %>%
dplyr::select(from, to, original_id)
visNetwork(nodes_vis, edges_vis) %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
visGroups(groupname = unique(nodes_vis$group)) %>%
visLegend(position = "right")
Ah, os fractais… uma beleza caótica que ainda está no forno! 🔥
A análise fractal pode revelar padrões ocultos na estrutura da sua rede viária e ajudar a entender sua complexidade. Aqui estão alguns passos para transformar sua rede em um fractal e realizar a análise:
1️⃣ Converter a Rede em um Fractal Método de Box-Counting: Uma abordagem comum para medir a dimensão fractal de redes espaciais. Você pode dividir sua rede em uma grade de diferentes tamanhos e contar quantas células contêm partes da rede.
Método de Similaridade: Algumas redes viárias apresentam padrões de auto-semelhança, onde segmentos menores se parecem com a estrutura maior. Você pode testar isso aplicando subdivisões iterativas.
2️⃣ Calcular a Dimensão Fractal Use a função fractaldim() do pacote fractal no R para calcular a dimensão fractal da rede.
Outra opção é usar boxcount() do pacote pracma, que implementa o método de contagem de caixas.
3️⃣ Analisar Propriedades Fractais Distribuição de Grau: Redes fractais muitas vezes seguem distribuições de potência. Você pode verificar isso com fit_power_law() do pacote igraph.
Centralidade e Caminhos: A análise de betweenness e closeness pode revelar padrões fractais na conectividade da rede.
4️⃣ Visualização Fractal Você pode usar ggplot2 para criar gráficos que mostram a estrutura fractal da rede.
1️⃣ Cálculo da Dimensão Fractal com Box-Counting Este método divide a rede em uma grade e conta quantas células contêm partes da rede.
🧠 O que é a Dimensão Fractal? - É uma medida da complexidade espacial de um objeto irregular — como uma rede de ruas ou o contorno de uma cidade. - A dimensão fractal indica o grau em que o padrão “enche” o espaço: quanto mais fragmentado ou ramificado, maior a dimensão (embora nunca exceda o valor inteiro do espaço: em 2D, nunca passa de 2).
📦 Box-Counting: Como funciona a técnica? A ideia do método é: - Cobrir o conjunto de pontos com uma malha de quadrados de tamanho size - Contar quantos quadrados contêm pelo menos um ponto - Repetir com diferentes tamanhos de quadrado - Plotar o resultado em escala log-log para estimar a dimensão fractal com uma regressão
📊 Interpretação - Uma rede viária mais orgânica, como em centros históricos, tende a ter dimensão fractal mais alta - Redes muito regulares ou planejadas (como malhas retangulares) têm dimensões mais próximas de 1
library(pracma)
# Função para calcular a dimensão fractal usando Box-Counting
box_counting <- function(points, sizes) {
counts <- sapply(sizes, function(size) {
grid_x <- seq(min(points$X), max(points$X), by = size)
grid_y <- seq(min(points$Y), max(points$Y), by = size)
count <- sum(sapply(grid_x, function(x) {
sum(sapply(grid_y, function(y) {
any(points$X >= x & points$X < x + size & points$Y >= y & points$Y < y + size)
}))
}))
return(count)
})
return(data.frame(size = sizes, count = counts))
}
# Aplicação sobre os nós da rede
library(sf)
# Transformar em objeto sf
nodes_sf <- st_as_sf(nodes, coords = c("X", "Y"), crs = 4326)
# Projetar para metros (exemplo: UTM SIRGAS zone 22S)
nodes_proj <- st_transform(nodes_sf, crs = 31983)
# Extrair coordenadas metrificadas
coords <- st_coordinates(nodes_proj)
nodes_metros <- data.frame(X = coords[,1], Y = coords[,2])
#- Varia o tamanho das caixas de 0.001 a 0.01 (em unidades do espaço — pode ser km, graus, etc.)
sizes <- seq(50, 1000, by = 25) # caixas de 100m a 1000m
result <- box_counting(nodes_metros, sizes)
# Ajuste log-log para estimar a dimensão fractal
#plot(log(result$size), log(result$count), type = "b", main = "Dimensão Fractal da Rede Viária")
plot(log(result$size), log(result$count), type = "b",
xlab = "Log(Tamanho da caixa)", ylab = "Log(Contagem)",
main = "Dimensão Fractal da Rede Viária")
modelo <- lm(log(count) ~ log(size), data = result)
summary(modelo)
##
## Call:
## lm(formula = log(count) ~ log(size), data = result)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.55697 -0.09418 0.04604 0.13608 0.19164
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 11.7280 0.2224 52.73 <2e-16 ***
## log(size) -1.1487 0.0365 -31.48 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.171 on 37 degrees of freedom
## Multiple R-squared: 0.964, Adjusted R-squared: 0.963
## F-statistic: 990.7 on 1 and 37 DF, p-value: < 2.2e-16
area_m2 <- result$size^2 # em metros quadrados
area_km2 <- (result$size / 1000)^2 # em quilômetros quadrados
result$area_km2 <- (result$size / 1000)^2
result
## size count area_km2
## 1 50 794 0.002500
## 2 75 674 0.005625
## 3 100 545 0.010000
## 4 125 474 0.015625
## 5 150 424 0.022500
## 6 175 370 0.030625
## 7 200 331 0.040000
## 8 225 298 0.050625
## 9 250 260 0.062500
## 10 275 228 0.075625
## 11 300 212 0.090000
## 12 325 193 0.105625
## 13 350 174 0.122500
## 14 375 163 0.140625
## 15 400 154 0.160000
## 16 425 141 0.180625
## 17 450 123 0.202500
## 18 475 115 0.225625
## 19 500 109 0.250000
## 20 525 103 0.275625
## 21 550 94 0.302500
## 22 575 90 0.330625
## 23 600 86 0.360000
## 24 625 77 0.390625
## 25 650 74 0.422500
## 26 675 72 0.455625
## 27 700 70 0.490000
## 28 725 61 0.525625
## 29 750 57 0.562500
## 30 775 57 0.600625
## 31 800 53 0.640000
## 32 825 52 0.680625
## 33 850 48 0.722500
## 34 875 43 0.765625
## 35 900 39 0.810000
## 36 925 38 0.855625
## 37 950 40 0.902500
## 38 975 37 0.950625
## 39 1000 36 1.000000
🧠 Por que count diminui quando size aumenta?
O método de box-counting funciona assim: - Você cobre o espaço com
caixas de tamanho fixo.
- Para cada tamanho, conta quantas caixas contêm pelo menos um
ponto.
- Quando a caixa é pequena, há mais chance de ela conter apenas um ponto
ou poucos, então o número total de caixas com conteúdo é maior.
- Conforme a caixa aumenta, várias pequenas áreas com pontos são
englobadas por uma única caixa — ou seja, menos caixas contêm pontos, o
que faz count diminuir.
library(ggplot2)
library(dplyr)
# Suponha que nodes_metros tenha as colunas X e Y em metros
# Defina tamanho da caixa (ex: 200 metros)
box_size <- 200
# Gerar limites da grade
x_breaks <- seq(min(nodes_metros$X), max(nodes_metros$X), by = box_size)
y_breaks <- seq(min(nodes_metros$Y), max(nodes_metros$Y), by = box_size)
# Criar todas as caixas como data frame
caixas <- expand.grid(x = x_breaks, y = y_breaks) %>%
mutate(xend = x + box_size, yend = y + box_size)
# Plotar pontos + caixas
ggplot() +
geom_point(data = nodes_metros, aes(x = X, y = Y), color = "blue", size = 0.8, alpha = 0.6) +
geom_rect(data = caixas, aes(xmin = x, xmax = xend, ymin = y, ymax = yend),
fill = NA, color = "red", linewidth = 0.3) +
labs(title = "Rede Viária com Box-Counting", x = "X (metros)", y = "Y (metros)") +
theme_minimal()
2️⃣ Distribuição de Grau e Ajuste de Lei de Potência Redes fractais frequentemente seguem distribuições de potência.
library(igraph)
# Ajuste de Lei de Potência
fit <- fit_power_law(degree(grafo))
print(fit)
## $continuous
## [1] FALSE
##
## $alpha
## [1] 14.63404
##
## $xmin
## [1] 4
##
## $logLik
## [1] -16.8932
##
## $KS.stat
## [1] 0.002578868
3️⃣ Visualização Fractal Podemos visualizar padrões fractais na rede.
library(ggplot2)
ggplot(nodes, aes(x = X, y = Y)) +
geom_point(color = "blue", alpha = 0.5) +
theme_minimal() +
ggtitle("Visualização Fractal da Rede Viária")
library(igraph)
# Criar o grafo a partir das arestas
grafo <- graph_from_data_frame(edges, directed = FALSE)
# Calcular betweenness centrality
betweenness_values <- betweenness(grafo, normalized = TRUE)
head(betweenness_values)
## 1 8 11 13 15 17
## 0.015485973 0.017866128 0.003923302 0.144635180 0.007458219 0.024276856
# Calcular closeness centrality
closeness_values <- closeness(grafo, normalized = TRUE)
head(closeness_values)
## 1 8 11 13 15 17
## 0.02396122 0.03363327 0.03427357 0.03397534 0.03219876 0.03017772
# Adicionar os valores aos nós
nodes$betweenness <- betweenness_values[nodes$id]
nodes$closeness <- closeness_values[nodes$id]
# Visualizar os resultados
print(summary(nodes$betweenness))
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.0000 0.0030 0.0100 0.0238 0.0269 0.2431 692
print(summary(nodes$closeness))
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## 0.0181 0.0257 0.0294 0.0550 0.0332 1.0000 692
# Visualizar graficamente
library(ggplot2)
ggplot(nodes, aes(x = betweenness)) +
geom_histogram(bins = 30, fill = "blue", alpha = 0.7) +
theme_minimal() +
ggtitle("Distribuição da Centralidade Betweenness")
## Warning: Removed 692 rows containing non-finite outside the scale range
## (`stat_bin()`).
ggplot(nodes, aes(x = closeness)) +
geom_histogram(bins = 30, fill = "red", alpha = 0.7) +
theme_minimal() +
ggtitle("Distribuição da Centralidade Closeness")
## Warning: Removed 692 rows containing non-finite outside the scale range
## (`stat_bin()`).
1️⃣ Dimensão de Hausdorff Este método mede a complexidade da rede considerando sua auto-semelhança.
Uma dimensão alta como essa pode indicar que o conjunto ocupa muito espaço (ou grau de liberdade) dentro do espaço de origem.
Em análise fractal: seria um objeto extremamente intricado em múltiplas escalas.
A dimensão de Hausdorff, nesse contexto, quantifica como o número de vizinhos acessíveis cresce com a escala.
Em redes rodoviárias, ela pode indicar densidade de conexões e redundância geográfica (por exemplo, número de caminhos alternativos entre regiões).
Uma dimensão alta, como 31.7, sugere que o grafo é extremamente ramificado, com muitas possibilidades de movimento, rotas e interconexões — talvez até que os dados estejam em um espaço de atributos muito rico (tempo, fluxo, tipo de via, etc.).
library(geometry)
##
## Attaching package: 'geometry'
## The following objects are masked from 'package:pracma':
##
## cart2pol, cart2sph, dot, pol2cart, polyarea, sph2cart
# Função para calcular a dimensão de Hausdorff
hausdorff_dim <- function(points) {
dist_matrix <- dist(points)
return(max(dist_matrix) / min(dist_matrix))
}
# Aplicação sobre os nós da rede
hausdorff_value <- hausdorff_dim(nodes[, c("X", "Y")])
print(paste("Dimensão de Hausdorff:", hausdorff_value))
## [1] "Dimensão de Hausdorff: 17446.8981030362"
2️⃣ Análise de Percolação Estuda a conectividade da rede e como ela se fragmenta.
🔬 O que é análise de percolação?
- É um estudo da resiliência de uma rede à perda de ligações.
- Muito usado em redes viárias, elétricas, sociais, etc.
- Mostra se a rede mantém conectividade ou se se divide em vários
pedaços (componentes).
library(igraph)
components <- components(grafo)
print(paste("Número de componentes antes da remoção:", components$no))
## [1] "Número de componentes antes da remoção: 23"
# Remover aleatoriamente 10% das arestas e verificar conectividade
grafo_removido <- delete_edges(grafo, sample(E(grafo), length(E(grafo)) * 0.1))
components <- components(grafo_removido)
print(paste("Número de componentes após remoção:", components$no))
## [1] "Número de componentes após remoção: 89"
3️⃣ Distribuição de Lei de Potência Verifica se a rede segue uma distribuição fractal.
📊 O que é uma Lei de Potência?
- Uma variável segue lei de potência se:
P(k) k^{-}
onde:
- k é o grau do vértice (número de conexões)
- é o expoente de decaimento
- Redes que seguem essa distribuição têm poucos hubs altamente
conectados e muitos vértices com poucas conexões
- É comum em redes “naturais”, não totalmente planejadas, como a rede
viária orgânica de cidades antigas
🔍 Interpretação
- Se o ajuste for bom (verifique o p-valor ou KS-test), significa que
sua rede:
- É possivelmente scale-free
- Tem estrutura fractal
- Pode ter alta resiliência a falhas aleatórias, mas sensibilidade a
ataques dirigidos
library(igraph)
# Ajuste de Lei de Potência
fit <- fit_power_law(degree(grafo))
print(fit)
## $continuous
## [1] FALSE
##
## $alpha
## [1] 14.63404
##
## $xmin
## [1] 4
##
## $logLik
## [1] -16.8932
##
## $KS.stat
## [1] 0.002578868
4️⃣ Dimensão Fractal da Fronteira Mede a irregularidade das bordas da rede.
É uma medida de complexidade geométrica das bordas da rede, e não
da rede inteira.
Fronteiras retas e simples têm dimensões próximas de 1.
Fronteiras recortadas, ramificadas ou com muitos “dedos” têm
dimensões entre 1 e 2.
Isso é útil para estudar urbanização, dispersão de bairros, ou áreas limítrofes com morfologia orgânica.
result$r: tamanho das caixas
result$Nr: número de caixas que contêm pelo menos um ponto
Ao usar log(1 / r), você está traçando a escala inversa, que é
comum em análises fractais
A inclinação da reta nesse gráfico é a dimensão fractal estimada da borda
~1.0 → borda simples, curva suave
~1.2 a 1.5 → bordas ramificadas, urbanismo orgânico
1.5 → fronteiras altamente fragmentadas (ex: favelas, área ribeirinha, ocupações irregulares)
#devtools::install_github ("mariodosreis/fractal")
#https://github.com/mariodosreis/fractal
library(fractal)
library(Rdimtools)
## ** ------------------------------------------------------- **
## ** Rdimtools || Dimension Reduction and Estimation Toolbox
## **
## ** Version : 1.1.2 (2025)
## ** Maintainer : Kisung You (kisungyou@outlook.com)
## ** Website : https://kisungyou.com/Rdimtools/
## **
## ** Please see 'citation('Rdimtools)' to cite the package.
## ** ------------------------------------------------------- **
# Aplicação do método de Box-Counting na fronteira
border_points <- nodes[nodes$id %in% c(edges$from, edges$to), ]
# Definir um número adequado de níveis para a análise fractal
nlevel_value <- 50 # Ajuste conforme necessário
# Executar a análise de Box-Counting
result <- est.boxcount(as.matrix(border_points[, c("X", "Y")]), nlevel = nlevel_value)
# Visualizar os resultados
plot(log(1 / result$r), log(result$Nr), type = "b",
main = "Dimensão Fractal da Fronteira",
xlab = "Log(1/Escala)", ylab = "Log(Número de caixas)")
5️⃣ Análise de Auto-Similaridade
Verifica padrões de auto-semelhança na rede.
Auto-similaridade é quando subestruturas de uma rede se parecem com a
estrutura maior, como em fractais. Em redes urbanas, isso pode
indicar:
- Bairros que repetem um padrão viário similar
- Comunidades que têm distribuição de grau semelhante
- Recorrência de sub-redes modulares com morfologias parecidas
# Carregar pacotes
library(tibble)
##
## Attaching package: 'tibble'
## The following object is masked from 'package:igraph':
##
## as_data_frame
library(knitr)
# Criar tabela com algoritmos
algoritmos <- tibble::tibble(
Algoritmo = c("Louvain", "Fast Greedy", "Walktrap", "Edge Betweenness", "Infomap"),
Função_igraph = c("cluster_louvain()", "cluster_fast_greedy()", "cluster_walktrap()",
"cluster_edge_betweenness()", "cluster_infomap()"),
Tipo_de_Abordagem = c(
"Modularidade otimizada",
"Hierarquia aglomerativa",
"Passeios aleatórios",
"Centralidade das arestas",
"Compressão da informação"
),
Características = c(
"Eficiente, detecta grandes comunidades",
"Bom para redes pequenas ou médias",
"Captura bem subestruturas locais",
"Mais lento, útil para redes com estrutura clara",
"Detecta comunidades compactas com alta coerência"
)
)
# Exibir tabela formatada
knitr::kable(algoritmos, caption = "Principais Algoritmos de Comunidades no igraph", align = "c")
Algoritmo | Função_igraph | Tipo_de_Abordagem | Características |
---|---|---|---|
Louvain | cluster_louvain() | Modularidade otimizada | Eficiente, detecta grandes comunidades |
Fast Greedy | cluster_fast_greedy() | Hierarquia aglomerativa | Bom para redes pequenas ou médias |
Walktrap | cluster_walktrap() | Passeios aleatórios | Captura bem subestruturas locais |
Edge Betweenness | cluster_edge_betweenness() | Centralidade das arestas | Mais lento, útil para redes com estrutura clara |
Infomap | cluster_infomap() | Compressão da informação | Detecta comunidades compactas com alta coerência |
library(igraph)
library(Rdimtools)
library(ggplot2)
# Criar o grafo
grafo <- graph_from_data_frame(edges, directed = FALSE)
# **1. Corrigir erro na extração de comunidades**
comunidades <- cluster_louvain(grafo)
membership_df <- data.frame(id = as.numeric(names(membership(comunidades))),
comunidade = as.numeric(membership(comunidades)))
Geramos o grafo de comunidades
visNetwork(nodes_vis, edges_vis) %>%
visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
visGroups(groupname = unique(nodes_vis$comunidade)) %>%
visLegend(position = "right")
# **5. Corrigir a análise fractal**
nlevel_value <- 50
result <- est.boxcount(as.matrix(nodes[, c("X", "Y")]), nlevel = nlevel_value)
# **6. Ajustar gráfico para evitar NA values**
ggplot(na.omit(nodes), aes(x = betweenness)) +
geom_histogram(bins = 30, fill = "blue", alpha = 0.7) +
theme_minimal() +
ggtitle("Distribuição da Centralidade Betweenness")