R/pitplot.R

Defines functions pitplot

Documented in pitplot

#' @title Plot pit stop results
#' @description Plot pit stop results (MUST BE in tibble format)
#' @format Tibble
#' @importFrom dplyr mutate case_when arrange group_by summarise first %>%
#' @importFrom stats sd reorder
#' @import ggplot2
#' @param pits_data Tibble data generated by the pits() function
#' @param type Plot type: individual pit stop by driver (1), grouped by team (2), grouped by driver (3, by default)
#' @param title_text Text for the plot title, in quotes (" ") (if is omitted, a default text will be used).
#' @return A ggplot object
#' @examples
#' \donttest{
#' pitplot(pits(10, 2025), 1, "Title: Hello world!")
#' }
#' @export
pitplot <- function(pits_data, type=3, title_text=NULL) {

  if (!tibble::is_tibble(pits_data)) {
    stop("pits_data object MUST BE tibble...")
  }

  if (missing(type)) {
    message("No type argument provided. Defaulting to type = 3 (pits grouped by driver)")
  }

  if (! type %in% c(1,2,3)) {
    stop("type must be 1 (all pits), 2 (pits grouped by team), or 3 (pits grouped by driver)")
  }
  message("Processing...")
  message("  O    _________    O\n/|\\>  _\\=..o..=/_  </|\\ \n / \\ |_|-// \\\\-|_| / \\ ")

  # colour drivers by team

  pits_data2 <- pits_data %>%
    mutate(Color = case_when(
      Team == "Mercedes"  ~ "#02FAC0",
      Team == "Ferrari" ~ "red",
      Team == "Red Bull"  ~ "#A303FF",
      Team == "McLaren" ~ "orange",
      Team == "Renault" ~ "yellow",
      Team == "Racing Point" ~ "#FA028A",
      Team == "Toro Rosso" ~ "blue",
      Team == "Aston Martin"  ~ "forestgreen",
      Team == "Racing Bulls"  ~ "white",
      Team == "RB"  ~ "white",
      Team == "AlphaTauri"  ~ "#87A8E0",
      Team == "Alpine"  ~ "#FA028A",
      Team == "Williams"  ~ "#03A3FF",
      Team == "Sauber"  ~ "green",
      Team == "Alfa Romeo"  ~ "brown",
      Team == "Audi"  ~ "brown",
      Team == "Haas"  ~ "grey",
      Team == "Cadillac"  ~ "#B9975B",
      TRUE ~ "grey25"  # color por defecto
    ))

  # Gráfico por piloto
  if(type == 1){
    if (is.null(title_text)) {
      title_text <- "Pit stops by driver"
    }
    pits_data3 <- pits_data2 %>%
      mutate(Abbreviation = toupper(substr(Driver, 1, 3))) %>%
      mutate(ID = paste0("l.",Lap," ",Abbreviation)) %>%
      arrange(`Time (sec)`)

    p <- ggplot(pits_data3, aes(x = reorder(ID, `Time (sec)`),
                                          y = `Time (sec)`,
                                fill = I(Color))) +
      geom_col() +
      geom_text(aes(label = formatC(`Time (sec)`, format = "f", digits = 2)),
                         vjust = 0, hjust=-0.0685, color = "white", angle=65) +
      coord_cartesian(ylim = c(0, round(max(pits_data3$`Time (sec)`)+1.5))) + scale_y_continuous(breaks = c(1,2,3,5,10,15,20)) +
      labs(
        title=paste0(title_text),
        subtitle = paste0("Pit stops data (Total: ", nrow(pits_data3),")\n","Best pit stop: ",pits_data3$Team[1],", ",pits_data3$`Time (sec)`[1], " s, lap ",pits_data3$Lap[1], ", round ", pits_data3$Round[1], ", year ", pits_data3$Year[1]),
        x = "Driver and lap (l.)",
        y = "Pit Stop time (s)"
      ) +
      theme(
        plot.margin = margin(7, 7, 7, 7, "pt"),
        text = element_text(color="white"),
        plot.title = element_text(size = 18, face = "bold",color = "yellow"),
        panel.background = element_rect(fill = "grey10", color = NA),  # fondo del panel
        plot.background = element_rect(fill = "grey10", color = NA),
        axis.title = element_text(),
        axis.line = element_line(color = "white"),
        axis.ticks = element_line(color = "white"),
        axis.ticks.y=element_blank(),
        axis.text.x = element_text(angle = 45, hjust = 1,color="grey40"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(margin = margin(t = 3)),
        axis.title.y = element_text(margin = margin(r = 8)),
        panel.grid = element_line(color="grey28"),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.y = element_line(
          color = "grey35",
          linewidth = 0.25, linetype = "solid"
        ),
        legend.position = "none"
      )
    return(p)
  }

  # Gráfico por equipo
  if(type == 2){
    if (is.null(title_text)) {
      title_text <- "Pit stops by team"
    }

    pits_data2b <- pits_data2 %>%
    arrange(`Time (sec)`)

    pits_data3 <- pits_data2b %>%
      mutate(Team = ifelse(Team == "Racing Bulls", "RB", Team)) %>%
      mutate(Abbreviation = toupper(substr(Driver, 1, 3))) %>%
      mutate(ID = paste0("l.",Lap, " ",Abbreviation)) %>% group_by(Team) %>%
      summarise(mean_time = mean(`Time (sec)`, na.rm = TRUE),
                sd= sd(`Time (sec)`, na.rm=TRUE),Color = first(Color))

    p <- ggplot(pits_data3, aes(
      x = reorder(Team, mean_time),
      y = mean_time,fill = I(Color))) +
      geom_col() +
      geom_text(aes(label = paste(formatC(mean_time, format = "f", digits = 2),"\n\u00B1",formatC(sd, format = "f", digits = 1))), # ,y = pmin(duration + 0.05, 24) limitar a posicion los valores altos geom_text
                vjust = -0.25, hjust=0.5, color = "white", lineheight = 0.8, angle=0) +
      coord_cartesian(ylim = c(0, round(max(pits_data3$mean_time)+1.5))) + scale_y_continuous(breaks = c(1,2,3,5,10,15,20)) +
      labs(
        title = paste0(title_text),
        subtitle = paste0("Average pit stop by team (Total: ",nrow(pits_data2b),")\n","Best pit stop: ",pits_data2b$Driver[1]," - ",pits_data2b$Team[1],", ",pits_data2b$`Time (sec)`[1], " s, lap ",pits_data2b$Lap[1], ", round ", pits_data2b$Round[1], ", year ", pits_data2b$Year[1]),
        x = "Team",
        y = "Pit Stop time (s, mean \u00B1 sd)"
      ) +
      theme(
        plot.margin = margin(7, 7, 7, 7, "pt"),
        text = element_text(color="white"),
        plot.title = element_text(size = 18, face = "bold",color = "yellow"),
        panel.background = element_rect(fill = "grey10", color = NA),  # fondo del panel
        plot.background = element_rect(fill = "grey10", color = NA),
        axis.title = element_text(),
        axis.line = element_line(color = "white"),
        axis.ticks = element_line(color = "white"),
        axis.ticks.y=element_blank(),
        axis.text.x = element_text(angle = 45, hjust = 1,color="grey40"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(margin = margin(t = 3)),
        axis.title.y = element_text(margin = margin(r = 8)),
        panel.grid = element_line(color="grey28"),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.y = element_line(
          color = "grey35",
          linewidth = 0.25, linetype = "solid"
        ),
        legend.position = "none"
      )

    return(p)
  }

  # Resumen por piloto
  if(type == 3){

    if (is.null(title_text)) {
      title_text <- "Pit stops grouped by driver"
    }

    pits_data2b <- pits_data2 %>%
      arrange(`Time (sec)`)

    pits_data3 <- pits_data2b %>%
      mutate(Abbreviation = toupper(substr(Driver, 1, 3))) %>%
      group_by(Abbreviation) %>%
      summarise(mean_time = mean(`Time (sec)`, na.rm = TRUE), sd= sd(`Time (sec)`, na.rm=TRUE),Color = first(Color))

    p <- ggplot(pits_data3, aes(
      x = reorder(Abbreviation, mean_time),
      y = mean_time,fill = I(Color))) +
      geom_col() +
      geom_text(aes(label = paste(formatC(mean_time, format = "f", digits = 2),"\n\u00B1",formatC(sd, format = "f", digits = 1))), # ,y = pmin(duration + 0.05, 24) limitar a posicion los valores altos geom_text
                vjust = -0.25, hjust=0.5, color = "white",lineheight = 0.8, angle=0) +
      coord_cartesian(ylim = c(0, round(max(pits_data3$mean_time)+1.5))) + scale_y_continuous(breaks = c(1,2,3,5,10,15,20)) +
      labs(
        title = paste0(title_text),
        subtitle = paste0("Pit stops data (Total: ",nrow(pits_data2b),")\n","Best pit stop: ",pits_data2b$Driver[1]," - ", pits_data2b$Team[1],", ",pits_data2b$`Time (sec)`[1], " s, lap ",pits_data2b$Lap[1], ", round ", pits_data2b$Round[1], ", year ", pits_data2b$Year[1]),
        x = "Driver",
        y = "Pit Stop time (s, mean \u00B1 sd)"
      ) +
      theme(
        plot.margin = margin(7, 7, 7, 7, "pt"),
        text = element_text(color="white"),
        plot.title = element_text(size = 18, face = "bold",color = "yellow"),
        panel.background = element_rect(fill = "grey10", color = NA),  # fondo del panel
        plot.background = element_rect(fill = "grey10", color = NA),
        axis.title = element_text(),
        axis.line = element_line(color = "white"),
        axis.ticks = element_line(color = "white"),
        axis.ticks.y=element_blank(),
        axis.text.x = element_text(angle = 45, hjust = 1,color="grey40"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(margin = margin(t = 3)),
        axis.title.y = element_text(margin = margin(r = 8)),
        panel.grid = element_line(color="grey28"),
        panel.grid.minor.y = element_blank(),
        panel.grid.major.y = element_line(
          color = "grey35",
          linewidth = 0.25, linetype = "solid"
        ),
        legend.position = "none"
      )
    return(p)
  }

}

Try the f1pits package in your browser

Any scripts or data that you put into this service are public.

f1pits documentation built on May 20, 2026, 5:07 p.m.