title: “📊 Relatório de Análise de Crimes de Veículos” author: “PMMG — 3º SGT CLEIDSON DANIEL PEREIRA” output: flexdashboard::flex_dashboard: orientation: columns vertical_layout: fill theme: yeti navbar: - title: “PMMG” href: “https://www.policiamilitar.mg.gov.br/” align: right logo: “https://upload.wikimedia.org/wikipedia/commons/d/d4/Bras%C3%A3o_da_Pol%C3%ADcia_Militar_de_Minas_Gerais.svg

# Pacotes essenciais
library(flexdashboard)
library(readr)
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
library(lubridate)
## 
## Anexando pacote: 'lubridate'
## Os seguintes objetos são mascarados por 'package:base':
## 
##     date, intersect, setdiff, union
library(stringi)
library(janitor)
## 
## Anexando pacote: 'janitor'
## Os seguintes objetos são mascarados por 'package:stats':
## 
##     chisq.test, fisher.test
library(DT)
library(plotly)
## Carregando pacotes exigidos: ggplot2
## 
## Anexando pacote: 'plotly'
## O seguinte objeto é mascarado por 'package:ggplot2':
## 
##     last_plot
## O seguinte objeto é mascarado por 'package:stats':
## 
##     filter
## O seguinte objeto é mascarado por 'package:graphics':
## 
##     layout
library(ggplot2)
library(leaflet)
library(geobr)
## Carregando namespace exigido: sf
library(scales)
## 
## Anexando pacote: 'scales'
## O seguinte objeto é mascarado por 'package:readr':
## 
##     col_factor
library(sf)
## Linking to GEOS 3.13.1, GDAL 3.11.4, PROJ 9.7.0; sf_use_s2() is TRUE
library(tidyr) 

# Opções gerais para o R
options(scipen = 999) # Desabilita notação científica
# Carregar dados
furto <- read_delim(
  "data/Veiculos - Furto - Jan 2015 a Out 2025.csv",
  delim = ";",
  locale = locale(encoding = "UTF-8"),
  show_col_types = FALSE
)

roubo <- read_delim(
  "data/Veiculos - Roubo - Jan 2015 a Out 2025.csv",
  delim = ";",
  locale = locale(encoding = "UTF-8"),
  show_col_types = FALSE
)

# Renomear para nomes limpos (snake_case)
furto <- furto %>% clean_names()
roubo <- roubo %>% clean_names()

# Tratamento de codificação (mantido por segurança)
furto <- furto %>% mutate(across(where(is.character), ~stri_encode(., from = "UTF-8", to = "UTF-8")))
roubo <- roubo %>% mutate(across(where(is.character), ~stri_encode(., from = "UTF-8", to = "UTF-8")))

# Nome correto da coluna de mês após clean_names()
nome_mes <- "mes_numerico_fato"

# Ajuste FURTO
furto <- furto %>%
  mutate(
    ano = as.integer(ano_fato),
    mes = as.integer(.data[[nome_mes]]),
    data = if_else(
      !is.na(data_fato),
      as.Date(data_fato),
      make_date(ano, mes, 1)
    ),
    tipo = "Furto",
    qtde_veiculos = as.numeric(qtde_veiculos)
  )

# Ajuste ROUBO
roubo <- roubo %>%
  mutate(
    ano = as.integer(ano_fato),
    mes = as.integer(.data[[nome_mes]]),
    data = if_else(
      !is.na(data_fato),
      as.Date(data_fato),
      make_date(ano, mes, 1)
    ),
    tipo = "Roubo",
    qtde_veiculos = as.numeric(qtde_veiculos)
  )

# Unir tudo
dados <- bind_rows(furto, roubo) %>% arrange(data)

# Sumarização para KPIs
total_furto <- sum(furto$qtde_veiculos, na.rm = TRUE)
total_roubo <- sum(roubo$qtde_veiculos, na.rm = TRUE)
total_geral <- total_furto + total_roubo

# Sumarização para Tabela Regional (RPM)
dados_rpm <- dados %>%
  group_by(risp) %>%
  summarise(
    Total_Geral = sum(qtde_veiculos, na.rm = TRUE),
    Furto = sum(qtde_veiculos[tipo == "Furto"], na.rm = TRUE),
    Roubo = sum(qtde_veiculos[tipo == "Roubo"], na.rm = TRUE)
  ) %>%
  mutate(
    Proporcao_Roubo = Roubo / Total_Geral,
    Proporcao_Furto = Furto / Total_Geral
  ) %>%
  arrange(desc(Total_Geral))

# Sumarização para o gráfico de Série Temporal Mensal
dados_ts <- dados %>%
  mutate(data_mes = lubridate::make_date(year = ano_fato, month = mes, day = 1)) %>%
  count(data_mes, tipo)

# Sumarização para os gráficos de Tipo de Veículo
furto_tipo <- furto %>% 
    group_by(tipo_veiculo) %>% 
    summarise(n = sum(qtde_veiculos, na.rm = TRUE)) %>% 
    arrange(desc(n)) %>% 
    head(10)
    
roubo_tipo <- roubo %>% 
    group_by(tipo_veiculo) %>% 
    summarise(n = sum(qtde_veiculos, na.rm = TRUE)) %>% 
    arrange(desc(n)) %>% 
    head(10)

# Sumarização para o gráfico de Série Anual
dados_comb_plot <- dados %>% count(ano_fato, tipo)

Visão Geral e Tendências {data-icon=“fa-chart-line”}

Indicadores Chave (KPIs) {data-width=300}

Total Geral de Ocorrências

valueBox(
  format(total_geral, big.mark = ".", decimal.mark = ","),
  icon = "fa-chart-pie",
  color = "primary"
)
410.907

Total de Furtos

valueBox(
  format(total_furto, big.mark = ".", decimal.mark = ","),
  icon = "fa-mask",
  color = "warning"
)
284.020

Total de Roubos

valueBox(
  format(total_roubo, big.mark = ".", decimal.mark = ","),
  icon = "fa-car-crash",
  color = "danger"
)
126.887

Série Temporal e Comparação Anual {data-width=700}

Comparação Furto x Roubo por Ano (Gráfico 1)

p_ano <- ggplot(dados_comb_plot, aes(x = ano_fato, y = n, color = tipo)) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Comparação Furto x Roubo (2015-2025)",
    x = "Ano",
    y = "Quantidade",
    color = "Tipo de Crime"
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

# Torna o gráfico interativo
ggplotly(p_ano, tooltip = c("x", "y", "color"))

Série Temporal Mensal (Gráfico 2)

p_ts <- ggplot(dados_ts, aes(x = data_mes, y = n, color = tipo)) +
  geom_line(linewidth = 0.8) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Série Temporal Mensal por Tipo de Crime",
    x = "Data",
    y = "Quantidade",
    color = "Tipo"
  ) +
  theme_minimal()

# Torna o gráfico interativo
ggplotly(p_ts, tooltip = c("x", "y", "color"))

Análise Regional e Detalhada {data-icon=“fa-map-marked-alt”}

Regional: Tabela e Sumarização Interativa {data-width=400}

Tabela Interativa de Ocorrências por RISP/RPM

# Tabela interativa usando DT
datatable(
dados_rpm,
 caption = 'Total e Proporção de Crimes por RPM',
 options = list(
  dom = 'ltipr',
  pageLength = 10,
  language = list(url = '//cdn.datatables.net/plug-ins/1.10.11/i18n/Portuguese-Brasil.json')
 ),
 rownames = FALSE,
 filter = 'top'
) %>%
 formatCurrency(
  c('Total_Geral', 'Furto', 'Roubo'),
 currency = "",
 digits = 0,
  mark = "."
 ) %>%
 formatPercentage(
  c('Proporcao_Roubo', 'Proporcao_Furto'),
  digits = 1,
 mark = ","
 )

Top 10 RPMs e Proporção de Roubo (Gráfico 3)

# Top 10 RPMs por Total Geral
top_10_rpm <- dados_rpm %>% 
  head(10) %>%
  mutate(risp = as.factor(risp))

p_sum <- ggplot(top_10_rpm, aes(x = reorder(risp, Total_Geral), y = Total_Geral, fill = Proporcao_Roubo)) +
  geom_col() +
  geom_text(aes(label = format(Total_Geral, big.mark = ".", scientific = FALSE)), hjust = -0.1, size = 3) +
  scale_y_continuous(labels = scales::comma, limits = c(0, max(top_10_rpm$Total_Geral) * 1.1)) +
  labs(
    title = "Top 10 RISP/RPMs por Volume de Ocorrências",
    x = "Região (RISP/RPM)",
    y = "Total de Ocorrências",
    fill = "Proporção de Roubo"
  ) +
  coord_flip() +
  theme_minimal() +
  scale_fill_gradient(low = "lightblue", high = "red", labels = scales::percent)

# Torna o gráfico interativo
ggplotly(p_sum, tooltip = c("x", "y", "fill")) %>%
  config(displayModeBar = FALSE)
## Warning in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L, :
## 'big.mark' e 'decimal.mark' são ambos '.', o que pode ser confuso

Tipologia de Veículos {data-width=600}

Furtos por Tipo de Veículo (Top 10) (Gráfico 4)

p_furto_tipo <- ggplot(furto_tipo, aes(x = reorder(tipo_veiculo, n), y = n)) +
  geom_col(fill = "#56B4E9", alpha = 0.8) +
  coord_flip() +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Top 10 Furtos por Tipo de Veículo",
    x = "Tipo de Veículo",
    y = "Quantidade"
  ) +
  theme_minimal()

ggplotly(p_furto_tipo) %>%
  config(displayModeBar = FALSE)

Roubos por Tipo de Veículo (Top 10) (Gráfico 5)

p_roubo_tipo <- ggplot(roubo_tipo, aes(x = reorder(tipo_veiculo, n), y = n)) +
  geom_col(fill = "#D55E00", alpha = 0.8) +
  coord_flip() +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Top 10 Roubos por Tipo de Veículo",
    x = "Tipo de Veículo",
    y = "Quantidade"
  ) +
  theme_minimal()


ggplotly(p_roubo_tipo) %>%
  config(displayModeBar = FALSE)

Análise de Oportunidade (Heatmaps) {data-icon=“fa-calendar-alt”}

Heatmap de Furtos (Ano × Mês) (Gráfico 6)

# Gera a sumarização e o Heatmap de Furtos
furto_heat <- furto %>%
  count(ano_fato, mes) %>%
  mutate(mes = factor(mes, levels = 1:12, labels = month.abb))

ggplot(furto_heat, aes(x = ano_fato, y = mes, fill = n)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "#e5f5e0", high = "#31a354", labels = scales::comma) +
  labs(
    title = "Ocorrências de Furto por Mês e Ano",
    x = "Ano",
    y = "Mês",
    fill = "Qtd"
  ) +
  theme_minimal() +
  theme(panel.grid = element_blank())

Heatmap de Roubos (Ano × Mês) (Gráfico 7)

# Gera a sumarização e o Heatmap de Roubos
roubo_heat <- roubo %>%
  count(ano_fato, mes) %>%
  mutate(mes = factor(mes, levels = 1:12, labels = month.abb))

ggplot(roubo_heat, aes(x = ano_fato, y = mes, fill = n)) +
  geom_tile(color = "white") +
  scale_fill_gradient(low = "#fee5d9", high = "#de2d26", labels = scales::comma) +
  labs(
    title = "Ocorrências de Roubo por Mês e Ano",
    x = "Ano",
    y = "Mês",
    fill = "Qtd"
  ) +
  theme_minimal() +
  theme(panel.grid = element_blank())