O acesso a medicamentos nas unidades de saúde pública é um dos pilares fundamentais do Sistema Único de Saúde (SUS). No município do Recife, capital de Pernambuco,a rede municipal de saúde atende milhões de cidadãos que dependem exclusivamente do sistema público para obter tratamentos e medicamentosessenciais.
No entanto, a distribuição de medicamentos entre os distritos sanitários e unidades de saúde nem sempre ocorre de forma equitativa. Estoques zerados ou em nível crítico em determinadas unidades podem comprometer tratamentos contínuos, especialmente para pacientes com doenças crônicas, gerando deslocamentos desnecessários, abandono de tratamento e agravamento de quadros clínicos.
O interesse e o impacto dessa questão estendem-se por diferentes esferas da sociedade: permite que gestores de saúde identifiquem distritos e unidades em estado crítico para priorizar o reabastecimento, ao mesmo tempo que possibilita aos cidadãos verificar a disponibilidade de remédios antes de se deslocarem até uma unidade. Além disso, fornece a pesquisadores e formuladores de políticas os subsídios necessários para mapear padrões e propor melhorias na logística de distribuição, promovendo, em última análise, um sistema de saúde pública mais eficiente, transparente e benéfico para toda a sociedade.
Esta análise utiliza o dataset “Medicamentos por Unidade de Saúde”, disponibilizado publicamente pelo portal de Dados Abertos da Prefeitura do Recife. Os dados contêm informações sobre os estoques de medicamentos em cada unidade de saúde municipal, organizados por produto, apresentação, classe terapêutica, bairro e distrito sanitário.
A metodologia empregada segue as seguintes etapas:
A análise foi desenvolvida inteiramente em R,
utilizando o paradigma do tidyverse para manipulação de
dados. Para a visualização, foram combinadas abordagens estáticas
(ggplot2) e interativas (plotly), além de uma
aplicação Shiny que permite a exploração dinâmica dos dados por
diferentes filtros (distrito, bairro, unidade, produto, etc.).
A criação da variável nivel_estoque — categorizada em
Sem Estoque, Crítico, Regular e
Adequado — é central para a análise, pois transforma uma
variável numérica contínua em categorias interpretáveis que facilitam a
identificação de situações de risco.
Os resultados desta análise agregam valor direto a diversos atores da saúde coletiva e do controle social: auxiliam a Secretaria Municipal de Saúde do Recife na identificação de gargalos logísticos e no planejamento de reabastecimentos prioritários, além de permitir que os Coordenadores de Distrito Sanitário monitorem continuamente as condições de abastecimento em suas unidades. Paralelamente, o estudo serve como base científica para pesquisadores de saúde pública investigarem a equidade no acesso a remédios, ao mesmo tempo em que funciona como uma ferramenta essencial para jornalistas e organizações da sociedade civil na fiscalização e promoção da transparência do SUS municipal.
Os pacotes abaixo são necessários para replicar esta análise.
Certifique-se de instalá-los antes de executar o código
(install.packages("nome_do_pacote")).
library(dplyr) # Manipulação e transformação de dados tabulares
library(ggplot2) # Gráficos estáticos baseados na gramática dos gráficos
library(plotly) # Gráficos interativos com hover, zoom e filtros dinâmicos
library(DT) # Tabelas interativas com paginação, busca e filtros por coluna
library(stringr) # Funções para manipulação e limpeza de strings de texto
library(scales) # Formatação de escalas em gráficos (%, moeda, notação, etc.)
library(kableExtra) # Formatação avançada de tabelas estáticas em R Markdown
library(skimr) # Resumos estatísticos detalhados por variável
library(shiny) # Framework para criação de aplicações web interativas em R
library(shinydashboard) # Componentes de layout de dashboard para aplicações Shiny
library(lubridate) # Manipulação e parsing de datas de forma intuitiva
library(tidyr) # Reformulação de dados (pivot_longer, pivot_wider, etc.)
library(RColorBrewer) # Paletas de cores para visualizações
Os dados utilizados nesta análise foram obtidos do portal de Dados Abertos da Prefeitura do Recife, disponível gratuitamente em:
url_dados <- paste0(
"https://dados.recife.pe.gov.br/dataset/",
"8ae2b6b5-51b5-403a-9dea-973a8ed1aca4/resource/",
"1b8142f9-d801-4b54-88ca-5a1df3bd6884/download/",
"medicamentos-por-unidade-de-saude.csv"
)
dados_brutos <- tryCatch({
read.csv(url_dados, encoding = "UTF-8", sep = ";", stringsAsFactors = FALSE)
}, error = function(e) {
warning(paste("Erro ao carregar dados:", e$message))
data.frame()
})
O dataset “Medicamentos por Unidade de Saúde” é mantido e atualizado pela Secretaria de Saúde do Município do Recife com o objetivo de garantir transparência e controle público sobre o estoque de medicamentos da rede municipal.
# Verificando dimensões e estrutura do dataset original
cat("Dimensões do dataset bruto:\n")
## Dimensões do dataset bruto:
cat(" Linhas :", nrow(dados_brutos), "\n")
## Linhas : 40392
cat(" Colunas :", ncol(dados_brutos), "\n\n")
## Colunas : 11
cat("Nomes das variáveis originais:\n")
## Nomes das variáveis originais:
print(names(dados_brutos))
## [1] "distrito" "bairro" "unidade" "classe"
## [5] "apresentacao" "tipo_produto" "codigo_produto" "produto"
## [9] "cadum" "data_carga" "quantidade"
Características identificadas no dataset original:
quantidade utiliza vírgula como separador
decimal, padrão brasileiro que precisa ser convertido para ponto antes
de qualquer operação numérica.produto e bairro apresentam mistura de
maiúsculas e minúsculas (ex.: "AMOXICILINA" vs
"Amoxicilina"), o que geraria duplicatas em agrupamentos
diretos.unidade
contém espaços iniciais, finais e duplos internos que precisam ser
removidos."") nas variáveis categóricas e NA após a
conversão numérica de quantidade.quantidade.# Verificando valores ausentes e strings vazias no dataset bruto
ausentes <- data.frame(
Variavel = names(dados_brutos),
NAs = sapply(dados_brutos, function(x) sum(is.na(x))),
Strings_Vazias = sapply(dados_brutos, function(x) sum(x == "", na.rm = TRUE))
)
ausentes %>%
kableExtra::kable(
caption = "Tabela 1: Diagnóstico de Valores Ausentes e Strings Vazias",
col.names = c("Variável", "Alertas de NAs", "Strings Vazias"),
align = c("l", "c", "c"),
row.names = FALSE
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = FALSE,
position = "center"
) %>%
# Formatação condicional exclusiva para a coluna de NAs (Coluna 2)
kableExtra::column_spec(2,
color = ifelse(ausentes$NAs > 0, "#D9534F", "#999999"),
bold = ifelse(ausentes$NAs > 0, TRUE, FALSE)
) %>%
# Formatação condicional exclusiva para Strings Vazias (Coluna 3)
kableExtra::column_spec(3,
color = ifelse(ausentes$Strings_Vazias > 0, "#D9534F", "#999999"),
bold = ifelse(ausentes$Strings_Vazias > 0, TRUE, FALSE)
)
| Variável | Alertas de NAs | Strings Vazias |
|---|---|---|
| distrito | 4 | 0 |
| bairro | 0 | 306 |
| unidade | 0 | 0 |
| classe | 0 | 14268 |
| apresentacao | 0 | 0 |
| tipo_produto | 0 | 0 |
| codigo_produto | 0 | 0 |
| produto | 0 | 0 |
| cadum | 1756 | 0 |
| data_carga | 0 | 0 |
| quantidade | 0 | 0 |
As etapas de limpeza seguem um processo lógico: primeiro corrigimos os tipos de dados, depois padronizamos o texto, criamos variáveis derivadas e por fim removemos registros inválidos.
dados_limpos <- dados_brutos %>%
mutate(
# ETAPA 1: CONVERSÃO DE TIPOS
# Como usamos read.csv2, a quantidade já é numérica.
# Mantemos a conversão de data:
data_carga = as.Date(data_carga),
# ETAPA 2: PADRONIZAÇÃO DE TEXTO
produto = str_to_title(produto),
bairro = str_to_title(bairro),
classe = str_to_title(classe),
tipo_produto = str_to_title(tipo_produto),
apresentacao = str_to_upper(apresentacao),
unidade = str_squish(unidade),
# ETAPA 3: REFORMATAR VARIÁVEL
distrito = paste0("Distrito ", str_pad(distrito, 2, pad = "0")),
# ETAPA 4: CRIAÇÃO DE VARIÁVEL DERIVADA
nivel_estoque = case_when(
quantidade == 0 ~ "Sem Estoque",
quantidade < 50 ~ "Crítico",
quantidade < 200 ~ "Regular",
TRUE ~ "Adequado"
)
) %>%
# ETAPA 5: REMOÇÃO DE REGISTROS INVÁLIDOS
filter(
!is.na(quantidade),
!is.na(unidade) & unidade != "",
!is.na(produto) & produto != "",
!is.na(apresentacao) & apresentacao != "",
!is.na(tipo_produto) & tipo_produto != "",
!is.na(distrito) & distrito != "",
distrito != "Distrito NA"
)
Após a limpeza, as 10 primeiras linhas do dataset possuem a seguinte estrutura:
# 1. Separamos a amostra para facilitar a formatação condicional das colunas
amostra <- dados_limpos %>%
head(10) %>%
select(distrito, bairro, unidade, produto,
apresentacao, quantidade, nivel_estoque, data_carga)
# 2. Geramos a tabela estilizada
amostra %>%
kableExtra::kable(
caption = "Tabela 2: Amostra do Dataset Final (10 primeiras linhas)",
col.names = c("Distrito", "Bairro", "Unidade de Saúde", "Medicamento",
"Apres.", "Qtd", "Nível de Estoque", "Data Carga"),
align = c("c", "l", "l", "l", "c", "r", "c", "c"),
row.names = FALSE,
format.args = list(big.mark = ".", decimal.mark = ",")
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE
) %>%
# Formatação condicional para a coluna "Nível de Estoque" (Coluna 7)
kableExtra::column_spec(7,
bold = TRUE,
color = case_when(
amostra$nivel_estoque %in% c("Sem Estoque", "Crítico") ~ "#D9534F",
amostra$nivel_estoque == "Regular" ~ "#F0AD4E",
TRUE ~ "#5CB85C"
)
) %>%
kableExtra::column_spec(6, bold = TRUE) %>%
kableExtra::scroll_box(width = "100%")
| Distrito | Bairro | Unidade de Saúde | Medicamento | Apres. | Qtd | Nível de Estoque | Data Carga |
|---|---|---|---|---|---|---|---|
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Bicarbonato De Sodio 10% Solucao Injetavel - 10ml | AMP | 0,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Alendronato De Sodio 70mg | COMPR | 76,0 | Adequado | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Alopurinol 300mg | COMPR | 370,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Cetoprofeno 50mg/Ml Solucao Injetavel - 2ml | AMP | 34,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Acido Acetilsalicilico 100mg | COMPR | 2580,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Dipirona 500mg/Ml Solucao Injetavel - 2ml | AMP | 29,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Dipirona 500mg | COMPR | 6630,0 | Adequado | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Ibuprofeno 600mg | COMPR | 1840,0 | Crítico | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Paracetamol 500mg | COMPR | 910,0 | Adequado | 2024-10-10 |
| Distrito 01 | Boa Vista | Us 131 Distrito Sanitario I Recife | Dipirona 500mg/Ml Solucao Oral - 10ml | FRASCO | 88,0 | Adequado | 2024-10-10 |
# Resumo das variáveis categóricas
resumo_categorico <- data.frame(
Variavel = c(
"distrito", "bairro", "unidade", "produto",
"apresentacao", "classe", "tipo_produto", "nivel_estoque"
),
Tipo = c(
"Categórica", "Categórica", "Categórica", "Categórica",
"Categórica", "Categórica", "Categórica", "Categórica (derivada)"
),
Categorias_Unicas = c(
n_distinct(dados_limpos$distrito),
n_distinct(dados_limpos$bairro),
n_distinct(dados_limpos$unidade),
n_distinct(dados_limpos$produto),
n_distinct(dados_limpos$apresentacao),
n_distinct(dados_limpos$classe),
n_distinct(dados_limpos$tipo_produto),
n_distinct(dados_limpos$nivel_estoque)
),
Exemplos = c(
paste(head(sort(unique(dados_limpos$distrito)), 3), collapse = ", "),
paste(head(sort(unique(dados_limpos$bairro)), 3), collapse = ", "),
paste(head(sort(unique(dados_limpos$unidade)), 2), collapse = ", "),
paste(head(sort(unique(dados_limpos$produto)), 3), collapse = ", "),
paste(head(sort(unique(dados_limpos$apresentacao)), 3), collapse = ", "),
paste(head(sort(unique(dados_limpos$classe)), 3), collapse = ", "),
paste(unique(dados_limpos$tipo_produto), collapse = ", "),
paste(sort(unique(dados_limpos$nivel_estoque)), collapse = ", ")
)
)
resumo_categorico %>%
kableExtra::kable(
caption = "Tabela 3: Resumo Geral das Variáveis Categóricas",
col.names = c("Variável", "Tipo de Dado", "Categorias Únicas", "Exemplos de Registros"),
align = c("l", "l", "c", "l"),
row.names = FALSE
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE
) %>%
kableExtra::column_spec(3, bold = TRUE, color = "#2C3E50")
| Variável | Tipo de Dado | Categorias Únicas | Exemplos de Registros |
|---|---|---|---|
| distrito | Categórica | 8 | Distrito 01, Distrito 02, Distrito 03 |
| bairro | Categórica | 71 | , Af0gados, Afogados |
| unidade | Categórica | 184 | HOSPITAL AGAMENON MAGALHAES, Us 101 Policlinica Prof Waldemar de Oliveira |
| produto | Categórica | 1020 | Acebrofilina Sol. Oral 50mg / 5ml, Acetato De Medroxiprogesterona 5mg, *Acetato De Prednisolona 1% Colirio - 5ml |
| apresentacao | Categórica | 24 | ADESIVO, AMP, BISN. |
| classe | Categórica | 123 | , Agente Alcalinizante, Agente Antiressortivo |
| tipo_produto | Categórica | 2 | Medicamentos, Medicamentos P/ Pacientes Especiais |
| nivel_estoque | Categórica (derivada) | 2 | Adequado, Crítico |
#Garantir tipo numérico
dados_limpos <- dados_limpos %>%
mutate(
quantidade = quantidade %>%
stringr::str_replace_all("\\.", "") %>%
stringr::str_replace(",", ".") %>%
as.numeric()
)
# Resumo estatístico da variável numérica principal
resumo_numerico <- dados_limpos %>%
summarise(
Minimo = min(quantidade, na.rm = TRUE),
Q1 = quantile(quantidade, 0.25, na.rm = TRUE),
Mediana = median(quantidade, na.rm = TRUE),
Media = round(mean(quantidade, na.rm = TRUE), 2),
Q3 = quantile(quantidade, 0.75, na.rm = TRUE),
Maximo = max(quantidade, na.rm = TRUE),
Desvio_Pad = round(sd(quantidade, na.rm = TRUE), 2),
Total = sum(quantidade, na.rm = TRUE)
)
# Tabela Formatada
resumo_numerico %>%
kableExtra::kable(
caption = "Tabela 4: Resumo Estatístico da Variável Quantidade",
col.names = c("Mínimo", "1º Quartil (Q1)", "Mediana", "Média",
"3º Quartil (Q3)", "Máximo", "Desvio Padrão", "Total Geral"),
align = "r",
row.names = FALSE,
format.args = list(big.mark = ".", decimal.mark = ",")
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE
) %>%
kableExtra::column_spec(c(3, 4), bold = TRUE, color = "#2C3E50") %>%
kableExtra::column_spec(8, bold = TRUE, color = "#337AB7")
| Mínimo | 1º Quartil (Q1) | Mediana | Média | 3º Quartil (Q3) | Máximo | Desvio Padrão | Total Geral |
|---|---|---|---|---|---|---|---|
| -431 | 0 | 0 | 701,83 | 70 | 462.040 | 5.825,77 | 28.345.681 |
O dataset final contém 40388 registros e 12 variáveis, cobrindo 184 unidades de saúde distribuídas em 8 distritos sanitários do Recife. Ao todo, estão catalogados 1020medicamentos distintos. A quantidade média por registro é de 701.8 unidades,com mediana de 0,indicando uma distribuição fortemente assimétrica à direita, ou seja,a maioria dos registros tem quantidades baixas, mas alguns poucos medicamentos concentram estoques muito elevados.
# Distribuição geral dos níveis de estoque em toda a rede municipal
dist_nivel <- dados_limpos %>%
count(nivel_estoque) %>%
mutate(
pct = n / sum(n) * 100,
nivel_estoque = factor(nivel_estoque,
levels = c("Sem Estoque", "Crítico","Regular", "Adequado"))
) %>%
arrange(nivel_estoque)
dist_nivel %>%
kableExtra::kable(
caption = "Tabela 5: Distribuição dos registros por nível de estoque",
col.names = c("Nível de Estoque", "Registros", "Proporção (%)"),
digits = 1,
row.names = FALSE,
format.args = list(big.mark = ".")
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover")
) %>%
kableExtra::row_spec(
which(dist_nivel$nivel_estoque %in% c("Sem Estoque", "Crítico")),
color = "white",
background = "#d73027"
) %>%
kableExtra::row_spec(
which(dist_nivel$nivel_estoque == "Adequado"),
background = "#d4edda"
)
| Nível de Estoque | Registros | Proporção (%) |
|---|---|---|
| Crítico | 34.936 | 86.5 |
| Adequado | 5.452 | 13.5 |
Insight: Do total de registros, 86.5% estão em situação crítica ou sem estoque, um sinal de alerta expressivo para os gestores de saúde do Recife, indicando que uma parcela relevante dos medicamentos cadastrados não está disponível para a população no momento da coleta dos dados.
# Identifica as 15 classes com maior proporção de registros com estoque zerado
# Filtramos classes com pelo menos 10 registros para garantir representatividade
classes_criticas <- dados_limpos %>%
group_by(classe) %>%
summarise(
total = n(),
sem_estoque = sum(nivel_estoque == "Sem Estoque"),
pct_sem = sem_estoque / total * 100,
.groups = "drop"
) %>%
filter(total >= 10) %>%
arrange(desc(pct_sem)) %>%
slice(1:15)
p_classes <- ggplot(
classes_criticas,
aes(x = reorder(classe, pct_sem),
y = pct_sem,
fill = pct_sem,
text = paste0(classe,
"\nSem estoque: ", round(pct_sem, 1), "%",
"\nTotal registros: ", total))
) +
geom_col(show.legend = FALSE) +
geom_text(aes(label = paste0(round(pct_sem, 1), "%")),
hjust = -0.1, size = 3) +
scale_fill_gradient(low = "#fee08b", high = "#d73027") +
scale_y_continuous(
limits = c(0, 105),
labels = scales::percent_format(scale = 1)
) +
coord_flip() +
labs(
title = "Gráfico 1: Top 15 Classes com Maior % de Estoque Zero",
x = "Classe Terapêutica",
y = "% de Registros com Estoque Zero",
caption = "Fonte: Dados Abertos — Prefeitura do Recife"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(size = 12, face = "plain")
)
ggplotly(p_classes, tooltip = "text") %>%
layout(margin = list(t = 60))
Insight: Algumas classes terapêuticas apresentam taxas alarmantes de estoque zero. Isso é especialmente preocupante quando se trata de medicamentos para condições crônicas, onde a interrupção do tratamento pode gerar complicações graves e internações evitáveis.
# Top 10 medicamentos com maior quantidade total em estoque
top10_maior <- dados_limpos %>%
group_by(produto) %>%
summarise(total = sum(quantidade, na.rm = TRUE), .groups = "drop") %>%
arrange(desc(total)) %>%
slice(1:10)
# Top 10 medicamentos com mais registros de quantidade zerada
top10_escasso <- dados_limpos %>%
filter(quantidade == 0) %>%
count(produto, name = "total") %>%
arrange(desc(total)) %>%
slice(1:10)
# Gráfico dos mais estocados
p_maior <- plot_ly(
top10_maior,
x = ~total, y = ~reorder(produto, total),
type = "bar",
orientation = "h",
marker = list(color = "#1a9850"),
hovertemplate = "<b>%{y}</b><br>Total em Estoque: %{x:,.0f}<extra></extra>"
) %>%
layout(
xaxis = list(title = "Quantidade Total"),
yaxis = list(title = "")
)
# Gráfico dos mais escassos
p_escasso <- plot_ly(
top10_escasso,
x = ~total, y = ~reorder(produto, total),
type = "bar",
orientation = "h",
marker = list(color = "#d73027"),
hovertemplate = "<b>%{y}</b><br>Registros Zerados: %{x:,.0f}<extra></extra>"
) %>%
layout(
xaxis = list(title = "Nº de Registros com Estoque Zero"),
yaxis = list(title = "")
)
# Combina os dois gráficos
subplot(p_maior, p_escasso, nrows = 2, shareX = FALSE, titleY = TRUE, margin = 0.08) %>%
layout(
title = list(text = "Gráfico 2: Medicamentos Mais Estocados vs. Mais Escassos", font = list(size = 14)),
showlegend = FALSE,
margin = list(l = 400, t = 80, b = 60),
annotations = list(
list(
text = "Fonte: Dados Abertos — Prefeitura do Recife",
showarrow = FALSE, x = 1, y = -0.15,
xref = "paper", yref = "paper",
font = list(size = 9)
),
list(
text = "<b>Top 10 — Mais Estocados</b>",
showarrow = FALSE, x = 0.7, y = 1.05,
xref = "paper", yref = "paper",
font = list(size = 12)
),
list(
text = "<b>Top 10 — Mais Escassos</b>",
showarrow = FALSE, x = 0.7, y = 0.46,
xref = "paper", yref = "paper",
font = list(size = 12)
)
)
)
Insight: A comparação evidencia um descompasso na gestão de inventário. Enquanto alguns medicamentos acumulam estoques elevados, outros aparecem zerados em diversas unidades simultaneamente, sugerindo falhas na previsão de demanda ou na cadeia de suprimentos municipal.
# Compara o total de medicamentos catalogados com os efetivamente disponíveis
diversidade <- dados_limpos %>%
group_by(distrito) %>%
summarise(
total_medicamentos = n_distinct(produto),
medicamentos_disponiveis = n_distinct(produto[quantidade > 0]),
pct_disponivel = round(medicamentos_disponiveis /
total_medicamentos * 100, 1),
total_unidades = n_distinct(unidade),
qtd_total = sum(quantidade, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(pct_disponivel))
diversidade %>%
kableExtra::kable(
caption = "Tabela 6: Diversidade e disponibilidade por distrito",
col.names = c("Distrito", "Total Medicamentos",
"Medicamentos Disponíveis", "% Disponível",
"Unidades de Saúde", "Qtd. Total em Estoque"),
row.names = FALSE,
format.args = list(big.mark = ".", decimal.mark = ",")
) %>%
kableExtra::kable_styling(
bootstrap_options = c("striped", "hover")
) %>%
kableExtra::column_spec(4,
color = "white",
background = ifelse(diversidade$pct_disponivel >= 70, "#1a9850",
ifelse(diversidade$pct_disponivel >= 50, "#fc8d59",
"#d73027"))
)
| Distrito | Total Medicamentos | Medicamentos Disponíveis | % Disponível | Unidades de Saúde | Qtd. Total em Estoque |
|---|---|---|---|---|---|
| Distrito 08 | 549 | 300 | 54,6 | 29 | 2.962.167 |
| Distrito 05 | 617 | 328 | 53,2 | 27 | 6.872.712 |
| Distrito 03 | 650 | 333 | 51,2 | 18 | 1.500.092 |
| Distrito 02 | 618 | 314 | 50,8 | 22 | 2.704.322 |
| Distrito 01 | 622 | 300 | 48,2 | 22 | 1.924.346 |
| Distrito 07 | 525 | 244 | 46,5 | 23 | 2.266.236 |
| Distrito 06 | 563 | 258 | 45,8 | 19 | 5.767.543 |
| Distrito 04 | 633 | 285 | 45,0 | 24 | 4.348.263 |
Insight: Nem todos os distritos têm acesso à mesma diversidade de medicamentos. Distritos com menor percentual disponível podem estar atendendo populações vulneráveis com um portfólio terapêutico reduzido, o que compromete a integralidade do cuidado em saúde.
# Agrupa os 12 tipos de apresentação mais frequentes
dados_apres <- dados_limpos %>%
count(apresentacao, sort = TRUE) %>%
mutate(pct = n / sum(n) * 100) %>%
slice(1:12)
plot_ly(
dados_apres,
labels = ~apresentacao,
values = ~n,
type = "pie",
textinfo = "label+percent",
hovertemplate = paste0(
"<b>%{label}</b><br>",
"Registros: %{value:,.0f}<br>",
"Proporção: %{percent}<extra></extra>"
),
marker = list(
colors = RColorBrewer::brewer.pal(
min(nrow(dados_apres), 12), "Set3"
)
)
) %>%
layout(
title = list(
text = "Gráfico 3: Proporção de Registros por Tipo de Apresentação",
font = list(size = 14)
),
legend = list(orientation = "v"),
annotations = list(
list(
text = "Fonte: Dados Abertos Recife",
showarrow = FALSE, x = 1.1, y = -0.1,
xref = "paper", yref = "paper",
font = list(size = 9)
)
)
)
Insight: O domínio de determinadas apresentações farmacêuticas (como comprimidos) sobre outras (como soluções injetáveis ou pomadas) reflete o perfil epidemiológico da população atendida e os protocolos terapêuticos adotados pela rede municipal de saúde.