Objetivo

💡 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:

Grafos

✨ 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.

Fractais

🔹 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

Objetivo específico

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

Resultado esperado: Grafo com arestas de mesmo ID das Ruas do arquivo shape

Pipeline

Carregar bibliotecas

library(sf)
library(igraph)
library(visNetwork)
library(dplyr)
library(mapview)

🏙 1. Importar e preparar a rede viária

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

Nesse caso estou trabalhando apenas com vias arteriais

ruas <- ruas[ruas$highway %in% c("primary", "primary_link", "secondary", "secondary_link"), ]
ruas <- st_transform(ruas, 4326)

Recortar para uma área específica

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)

Visualizar o subset

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)

🌍 2. Garantir que cada rua seja um único segmento e preservar osm_id

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

📌 3. Extrair coordenadas corretamente

coords <- st_coordinates(ruas_segmentadas)

🔗 4. Criar lista única de nós com base nas coordenadas

nodes <- data.frame(
  X = coords[, "X"], 
  Y = coords[, "Y"]
) %>%
  distinct() %>%
  mutate(id = row_number())  # Atribuir um ID único para cada nó

🔗 5. Criar arestas e manter correspondência correta com osm_id

coords <- st_coordinates(ruas_segmentadas)  # Extrair coordenadas corretamente

Criar edges

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"]
)

Ajustar edges corretamente

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))

🔎 6. Verificar correspondência entre edges e ruas

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

🗺 7. Visualizar edges_temp no mapview

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")

🏗 8. Criar grafo com igraph

grafo <- graph_from_data_frame(edges, directed = TRUE)
plot(grafo, vertex.label = NA, main = "Grafo da Rede Viaria")

📊 9. Obter métricas do grafo

Número de vértices

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

Número de arestas

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

Densidade do grafo ou Densidade da rede

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

Grau dos nós ou Centralidade de Grau

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

Centralidade de intermediação

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

Centralidade de proximidade

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

Diâmetro do grafo

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

Atribuir comunidades aos nós

# comunidades <- cluster_louvain(grafo)
# V(grafo)$comunidade <- membership(comunidades)  

🌐 10. Criar visualização interativa com visNetwork

Primeiro criamos o identificador de ID dos vértices

nodes_vis <- data.frame(
  id = nodes$id, 
  label = nodes$id, 
  title = paste("ID:", nodes$id)  # Exibir ID ao passar o mouse
)

Depois o identificador de ID das arestas

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

Por fim, mantemos apenas vértices ligados efetivamente Às arestas

nodes_vis <- nodes_vis %>%
  filter(id %in% c(edges_vis$from, edges_vis$to))

Então, exibimos a rede

 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) 

Grupamento de vértices por comunidades

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
)

Customizamos as cores de exibição das comunidades

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)

Geramos o grafo de comunidades

visNetwork(nodes_vis, edges_vis) %>%
  visOptions(highlightNearest = TRUE, nodesIdSelection = TRUE) %>%
  visGroups(groupname = unique(nodes_vis$group)) %>%
  visLegend(position = "right")

Fractais

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.

O pacote tidygraph pode ajudar a visualizar padrões de auto-semelhança.

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")

Box-couting no Modelo de Regressão

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")
Principais Algoritmos de Comunidades no igraph
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")