Problema

Se requiere crear un gráfico mensual que compare la suma total de horas extras con el presupuesto asignado para horas extras. En aquellos meses en los que el total de horas extras supere el presupuesto, la barra correspondiente debe resaltarse en rojo para alertar a la gerencia sobre el exceso registrado en ese periodo.

library(openxlsx)
library(tidyverse)

Abrir el DATASET con el que vamos a realizar el ejemplo

# Datos de Presupuesto y num de horas trabajadas de Cumbaya en Enero 2025
data1 <- read.xlsx("C:\\Users\\cristhian.sumba\\Documentos\\DATOS1.xlsx",
                  detectDates = T) # para detectar campos de fecha
head(data1,10)
##    BUDGETMODELID STORE PPTO_NHE_X_DIA_Columna       DATE Recargo_Total
## 1         MODELO   N01               104.7948 2025-01-01        194.60
## 2         MODELO   N01               104.7948 2025-01-02        466.28
## 3         MODELO   N01               104.7948 2025-01-03        637.35
## 4         MODELO   N01               104.7948 2025-01-04        109.76
## 5         MODELO   N01               104.7948 2025-01-05         87.20
## 6         MODELO   N01               104.7948 2025-01-06          2.26
## 7         MODELO   N01               104.7948 2025-01-07          1.57
## 8         MODELO   N01               104.7948 2025-01-08         29.31
## 9         MODELO   N01               104.7948 2025-01-09         53.30
## 10        MODELO   N01               104.7948 2025-01-10         68.13

El DATASET contiene información de presupuesto (para horas extras) y el recargo total (total de horas extras) que realizan los trabajadores en dicha empresa para cierto local N01 desde el 1 de enero al 31 de marzo del 2025.

## InFO DE LA DATA
glimpse(data1)
## Rows: 88
## Columns: 5
## $ BUDGETMODELID          <chr> "MODELO", "MODELO", "MODELO", "MODELO", "MODELO…
## $ STORE                  <chr> "N01", "N01", "N01", "N01", "N01", "N01", "N01"…
## $ PPTO_NHE_X_DIA_Columna <dbl> 104.7948, 104.7948, 104.7948, 104.7948, 104.794…
## $ DATE                   <date> 2025-01-01, 2025-01-02, 2025-01-03, 2025-01-04…
## $ Recargo_Total          <dbl> 194.60, 466.28, 637.35, 109.76, 87.20, 2.26, 1.…

Obtener el Nombre de mes

# Crear el nombre del Mes
data1$nombre_mes<- format(data1$DATE, "%B")
# Frecuencia del mes
table(data1$nombre_mes)
## 
##   enero febrero   marzo 
##      31      28      29

Renombrar columnas = NUEVAS//ANTIGUAS

dataset <- data1 %>%
  rename(
    recargo_total = Recargo_Total,
    presupuesto = PPTO_NHE_X_DIA_Columna
  )

Recodificar o Etiquetar Meses

meses <- c("enero", "febrero", "marzo","abril", "mayo","junio","julio", "agosto","septiembre","octubre","noviembre","diciembre")

dataset <- dataset %>%
  mutate(
    num_mes = match(tolower(nombre_mes), meses),
    nombre_mes = factor(nombre_mes, levels = meses, ordered = TRUE)
  )
head(dataset,5)
##   BUDGETMODELID STORE presupuesto       DATE recargo_total nombre_mes num_mes
## 1        MODELO   N01    104.7948 2025-01-01        194.60      enero       1
## 2        MODELO   N01    104.7948 2025-01-02        466.28      enero       1
## 3        MODELO   N01    104.7948 2025-01-03        637.35      enero       1
## 4        MODELO   N01    104.7948 2025-01-04        109.76      enero       1
## 5        MODELO   N01    104.7948 2025-01-05         87.20      enero       1

Pasar de formato ancho a formato largo

data_pivot <- pivot_longer(
  dataset,
  cols = c(presupuesto, recargo_total),
  names_to = "tipo", # se crea una columna con los valores de presupuesto y recargo
  values_to = "valor" # contiene los valores la columna creada (tipo) 
)

Seleccionar, Agrupar datos por mes y sumar la columna = valor (presupuesto y recargo)

tabla_resumen <- data_pivot %>% select(nombre_mes,tipo,valor) %>% 
  group_by(nombre_mes, tipo) %>% 
  summarise(suma = sum(valor))
## `summarise()` has grouped output by 'nombre_mes'. You can override using the
## `.groups` argument.
tabla_resumen
## # A tibble: 6 × 3
## # Groups:   nombre_mes [3]
##   nombre_mes tipo           suma
##   <ord>      <chr>         <dbl>
## 1 enero      presupuesto   3249.
## 2 enero      recargo_total 2854.
## 3 febrero    presupuesto   3249.
## 4 febrero    recargo_total 1889.
## 5 marzo      presupuesto   3132.
## 6 marzo      recargo_total 3857.

Crear la condicion si Recargo > Presupuesto = recargo_total.mayor

  • Compara suma cuando en tipo sea igual a “recargo_total” por mes y esto – sea mayor que – suma cuando en tipo sea igual a “presupuesto”.
  • Si la condición se cumple se tiene el valor de “mayor” caso contrario “normal” y guarda este resultado en una columna llamada condicion.
  • Crear la columna fill_var en donde se concatene las columnas tipo y condicion
tabla_resumen <- tabla_resumen %>%
  mutate(
    condicion = ifelse(tipo == "recargo_total" & 
                         suma > tabla_resumen$suma[tabla_resumen$tipo == "presupuesto"][
                           match(nombre_mes, tabla_resumen$nombre_mes[tabla_resumen$tipo == "presupuesto"])],
                       "mayor", "normal"),
    fill_var = interaction(tipo, condicion) %>% 
      factor(levels = c("presupuesto.normal", "recargo_total.normal", "recargo_total.mayor"))
  )
tabla_resumen
## # A tibble: 6 × 5
## # Groups:   nombre_mes [3]
##   nombre_mes tipo           suma condicion fill_var            
##   <ord>      <chr>         <dbl> <chr>     <fct>               
## 1 enero      presupuesto   3249. normal    presupuesto.normal  
## 2 enero      recargo_total 2854. normal    recargo_total.normal
## 3 febrero    presupuesto   3249. normal    presupuesto.normal  
## 4 febrero    recargo_total 1889. normal    recargo_total.normal
## 5 marzo      presupuesto   3132. normal    presupuesto.normal  
## 6 marzo      recargo_total 3857. mayor     recargo_total.mayor

Crear el gráfico de barras apiladas en donde los grupos a colorear sea igual a fill_var

plot1 <- ggplot(tabla_resumen, aes(x = nombre_mes, y = suma, 
                                   fill = fill_var)
  ) +
  # Barras apiladas
  geom_bar(position = 'stack', stat = 'identity') +
  # Condicion de colores
  scale_fill_manual(
    values = c(
      "presupuesto.normal" = "#2D386D",
      "recargo_total.normal" = "#59A33A",
      "recargo_total.mayor" = "#D20103"
    ),
    ## Etiquetas en la leyenda
    labels = c(
      "presupuesto.normal" = "PPTO NHE",
      "recargo_total.normal" = "Recargo Total",
      "recargo_total.mayor" = "Riesgo Ope"
    ),
    na.translate = FALSE #elimina los NA de la leyenda
  )

Etiquetas en el grafico

plot1 +
  # Etiquetas en el eje x
  labs(fill = NULL,
       x = NULL,
       y = NULL) +
  # Etiquetas de datos en las barras
  geom_text(aes(label = paste("$", format(round(suma), big.mark = ".", decimal.mark = ","))), 
            position = position_stack(vjust = 0.5),
            color = "white", size = 4) +
  # Tamaño de etiquetas en el eje X
  theme(
    # Aumentar tamaño de etiquetas del eje X y negrita
    axis.text.x = element_text(size = 12, face = "bold")
    )