Visão Geral

Row

INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA - IFSULDEMINAS

Polícia Militar de Minas Gerais
BPTran

Relatório: Roubos e Furtos de Veículos
Período: 2023 a 2025

Discente: Marcelo José Gomes da Silva
Nº Polícia: 129.894-2
Email: marcelo.gomes@alunos.ifsuldeminas.edu.br

Total de Roubos

13.606

Total de Furtos

73.387

Row

Tabela Interativa (2023–2025)

Gráficos Estatísticos

Row

Evolução Mensal (Linha)

Comparativo Geral (Barras)

Row

Top 10 municipios (Ranking)

Sazonalidade (Acumulado por Mês)

Mapa Temático

Row

Mapa por municipio (MG) — total de registros (2023–2025)

---
title: "Painel Criminalidade - Veículos MG (BPTran)"
output:
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: scroll
    theme: cosmo
    self_contained: true
    source_code: embed
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)

library(tidyverse)
library(DT)
library(janitor)
library(sf)
library(geobr)
library(viridis)
library(htmltools)
library(stringi)

# 1) Verificar arquivos
arq_roubos <- "veiculos_roubados.csv"
arq_furtos <- "veiculos_furtados.csv"

if (!file.exists(arq_roubos) || !file.exists(arq_furtos)) {
  stop("ERRO: Coloque 'veiculos_roubados.csv' e 'veiculos_furtados.csv' na mesma pasta do .Rmd.")
}

# 2) Ler CSV com separador ;  (ponto-e-vírgula)
ler_csv_pv <- function(arquivo) {
  readr::read_delim(
    file = arquivo,
    delim = ";",
    locale = locale(encoding = "Latin1"),
    show_col_types = FALSE,
    trim_ws = TRUE
  )
}

roubos <- ler_csv_pv(arq_roubos) %>% mutate(Natureza = "Roubo")
furtos <- ler_csv_pv(arq_furtos) %>% mutate(Natureza = "Furto")

dados <- bind_rows(roubos, furtos) %>%
  janitor::clean_names() %>%
  mutate(
    registros = suppressWarnings(as.numeric(registros)),
    mes = suppressWarnings(as.integer(mes)),
    ano_fato = suppressWarnings(as.integer(ano_fato)),

    # cod_ibge: limpa tudo, garante 7 dígitos (padrão municipio ibge)
    cod_ibge = stringr::str_replace_all(as.character(cod_ibge), "[^0-9]", ""),
    cod_ibge = stringr::str_pad(cod_ibge, width = 7, side = "left", pad = "0")
  )

# 3) Checar colunas mínimas
campos_obrig <- c("registros", "municipio", "cod_ibge", "mes", "ano_fato", "natureza")
faltando <- setdiff(campos_obrig, names(dados))
if (length(faltando) > 0) {
  stop(paste("ERRO: faltam colunas no CSV:", paste(faltando, collapse = ", ")))
}

# 4) Filtrar período
dados_recentes <- dados %>%
  filter(ano_fato >= 2023) %>%
  mutate(data_base = as.Date(paste(ano_fato, mes, "01", sep = "-")))

# 5) Totalizadores
total_roubo <- dados_recentes %>%
  filter(natureza == "Roubo") %>%
  summarise(t = sum(registros, na.rm = TRUE)) %>%
  pull(t)

total_furto <- dados_recentes %>%
  filter(natureza == "Furto") %>%
  summarise(t = sum(registros, na.rm = TRUE)) %>%
  pull(t)

# 6) DataTables PT-BR (sem depender de internet/CDN)
dt_lang_ptbr <- list(
  sEmptyTable = "Nenhum dado disponível na tabela",
  sInfo = "Mostrando _START_ até _END_ de _TOTAL_ registros",
  sInfoEmpty = "Mostrando 0 até 0 de 0 registros",
  sInfoFiltered = "(filtrado de _MAX_ registros no total)",
  sLengthMenu = "Mostrar _MENU_ registros",
  sLoadingRecords = "Carregando...",
  sProcessing = "Processando...",
  sSearch = "Pesquisar:",
  sZeroRecords = "Nenhum registro encontrado",
  oPaginate = list(sNext = "Próximo", sPrevious = "Anterior", sFirst = "Primeiro", sLast = "Último")
)

# 7) Mapa de MG por municipio (join pelo cod_ibge)
mapa_mg <- geobr::read_municipality(code_muni = "all", year = 2020, showProgress = FALSE) %>%
  dplyr::filter(code_state == 31) %>%
  dplyr::mutate(code_muni = stringr::str_pad(as.character(code_muni), width = 7, side = "left", pad = "0"))


# --- 1) Criar chave de municipio no MAPA (sem acento / caixa alta) ---
lookup_municipios <- mapa_mg %>%
  sf::st_drop_geometry() %>%
  transmute(
    code_muni = stringr::str_pad(as.character(code_muni), width = 7, side = "left", pad = "0"),
    municipio_mapa = name_muni,
    chave_muni = stringr::str_squish(
      stringi::stri_trans_general(toupper(name_muni), "Latin-ASCII")
    )
  ) %>%
  distinct(chave_muni, .keep_all = TRUE)

# --- 2) Criar chave de municipio nos DADOS (sem acento / caixa alta) ---
dados_recentes <- dados_recentes %>%
  mutate(
    chave_muni = stringr::str_squish(
      stringi::stri_trans_general(toupper(municipio), "Latin-ASCII")
    )
  )

# --- 3) Colar o code_muni no seu dado pelo nome do municipio ---
dados_com_codigo <- dados_recentes %>%
  left_join(lookup_municipios %>% select(code_muni, chave_muni), by = "chave_muni")

# --- 4) Agregar e juntar ao mapa ---
dados_mapa <- dados_com_codigo %>%
  group_by(code_muni) %>%
  summarise(total = sum(registros, na.rm = TRUE), .groups = "drop")

mapa_final <- mapa_mg %>%
  mutate(code_muni = stringr::str_pad(as.character(code_muni), width = 7, side = "left", pad = "0")) %>%
  left_join(dados_mapa, by = "code_muni")
```

Visão Geral {data-icon="fa-tachometer"}
=======================================================================
Row {data-height=230}
-----------------------------------------------------------------------

### INSTITUTO FEDERAL DE EDUCAÇÃO, CIÊNCIA E TECNOLOGIA - IFSULDEMINAS

```{r results='asis'}
HTML('
<div style="background-color:#f5f5f5; padding:15px; border-radius:8px;">
  <div style="display:flex; justify-content:space-between; align-items:flex-start;">
    <div>
      <strong>Polícia Militar de Minas Gerais</strong><br>
      <strong>BPTran</strong><br><br>
      <strong>Relatório:</strong> Roubos e Furtos de Veículos<br>
      <strong>Período:</strong> 2023 a 2025<br><br>
      <strong>Discente:</strong> Marcelo José Gomes da Silva<br>
      <strong>Nº Polícia:</strong> 129.894-2<br>
      <strong>Email:</strong> marcelo.gomes@alunos.ifsuldeminas.edu.br<br>
    </div>
    <div style="text-align:right;">
      <img src="logo.png" style="height:110px;">
    </div>
  </div>
</div>
')

```

### Total de Roubos

```{r}
flexdashboard::valueBox(format(total_roubo, big.mark="."), icon = "fa-exclamation-triangle", color = "danger")
```

### Total de Furtos

```{r}
flexdashboard::valueBox(format(total_furto, big.mark="."), icon = "fa-car", color = "warning")
```

Row {data-height=520}
-----------------------------------------------------------------------

### Tabela Interativa (2023–2025)

```{r}
tabela_exibicao <- dados_recentes %>%
  select(municipio, ano_fato, mes, natureza, registros, risp, rmbh) %>%
  arrange(desc(ano_fato), desc(mes))

DT::datatable(
  tabela_exibicao,
  colnames = c("municipio", "Ano", "Mês", "Natureza", "Registros", "RISP", "RMBH"),
  options = list(pageLength = 10, scrollX = TRUE, language = dt_lang_ptbr)
)
```

Gráficos Estatísticos {data-icon="fa-chart-bar"}
=======================================================================

Row {data-height=520}
-----------------------------------------------------------------------

### Evolução Mensal (Linha)

```{r}
evolucao <- dados_recentes %>%
  group_by(data_base, natureza) %>%
  summarise(total = sum(registros, na.rm = TRUE), .groups = "drop")

ggplot(evolucao, aes(x = data_base, y = total, color = natureza)) +
  geom_line(linewidth = 1.1) +
  geom_point() +
  labs(
    title = "Evolução mensal de ocorrências",
    x = "Data",
    y = "Total de ocorrências",
    color = "Natureza"
  ) +
  theme_minimal()
```

### Comparativo Geral (Barras)

```{r}
comparativo <- dados_recentes %>%
  group_by(natureza) %>%
  summarise(total = sum(registros, na.rm = TRUE), .groups = "drop")

ggplot(comparativo, aes(x = natureza, y = total, fill = natureza)) +
  geom_col() +
  labs(
    title = "Total acumulado (2023–2025)",
    x = "Natureza",
    y = "Total"
  ) +
  theme_minimal() +
  theme(legend.position = "none")
```

Row {data-height=520}
-----------------------------------------------------------------------

### Top 10 municipios (Ranking)

```{r}
top10 <- dados_recentes %>%
  group_by(municipio) %>%
  summarise(total = sum(registros, na.rm = TRUE), .groups = "drop") %>%
  slice_max(order_by = total, n = 10)

ggplot(top10, aes(x = reorder(municipio, total), y = total)) +
  geom_col() +
  coord_flip() +
  labs(
    title = "10 municipios com mais registros (2023–2025)",
    x = "",
    y = "Ocorrências"
  ) +
  theme_minimal()
```

### Sazonalidade (Acumulado por Mês)

```{r}
sazonal <- dados_recentes %>%
  group_by(mes) %>%
  summarise(total = sum(registros, na.rm = TRUE), .groups = "drop") %>%
  arrange(mes)

ggplot(sazonal, aes(x = factor(mes), y = total)) +
  geom_col() +
  labs(
    title = "Ocorrências por mês (acumulado 2023–2025)",
    x = "Mês (1=Jan ... 12=Dez)",
    y = "Total"
  ) +
  theme_minimal()
```

Mapa Temático {data-icon="fa-map"}
=======================================================================

Row {data-height=900}
-----------------------------------------------------------------------

### Mapa por municipio (MG) — total de registros (2023–2025)

```{r}
ggplot(mapa_final) +
  geom_sf(aes(fill = total), color = NA) +
  scale_fill_viridis_c(
    option = "magma",
    direction = -1,
    name = "Total",
    na.value = "grey90"
  ) +
  labs(
    title = "Distribuição espacial — Minas Gerais (2023–2025)",
    subtitle = "Total de registros por municipio"
  ) +
  theme_void()
```