Results

Fighters by Major Fight Events

Blue vs Red Corner

Win and Loss Streaks

Finish Times

Method Of Victory

UFC Events

Journey to Title

Fighter Reach

R Code

# To do -------------------------------------------------------------------

# Change strikes above average definition to above the median. 


# Summary -----------------------------------------------------------------

# Setup -------------------------------------------------------------------

library(tidyr)
library(dplyr)
library(reshape2)
library(ggplot2)
library(openxlsx)
library(tibble)
library(formattable)
library(reactable)
library(stringr)
library(binom)
library(ggrepel)
library(showtext)
library(sysfonts)
library(treemap)
library(treemapify)
library(ggimage)
library(rsvg)
library(png)
library(magick)

# font_add_google("Margarine", "Margarine")
# showtext_auto()
# theme_set(theme_gray(base_family = "Margarine"))
# 
# theme_set(theme_gray(base_family = "Margarine"))
# update_geom_defaults("text", list(family = "Margarine"))
# update_geom_defaults("text_repel", list(family = "Margarine"))


font_add_google("Audiowide", "Audiowide")
showtext_auto()
theme_set(theme_gray(base_family = "Audiowide"))

theme_set(theme_gray(base_family = "Audiowide"))
update_geom_defaults("text", list(family = "Audiowide"))
update_geom_defaults("text_repel", list(family = "Audiowide"))

# Data --------------------------------------------------------------------

data.events <- read.csv("Events.csv")
data.fighters.stats <- read.csv("Fighters Stats.csv")
data.fighters.profile <- read.csv("Fighters.csv")
data.fight.outcomes <- read.csv("Fights.csv")


# Lookups -----------------------------------------------------------------

expected.fighters <- tibble(
  Fighter = c(
    "Max Holloway",
    "Justin Gaethje",
    "Michael Chandler",
    "Johnny Walker",
    "Derrick Lewis",
    "Ronda Rousey",
    "Amanda Nunes",
    "Tony Ferguson",
    "Mike Perry"),
  ID = 1:9
)

actual.fighters <- tibble(
  Fighter = c(
    "Jim Miller",
    "Matt Hughes",
    "Joe Stevenson",
    "Matt Brown",
    "Nate Diaz",
    "Dustin Poirer",
    "TJ Waldburger",
    "David Mitchell",
    "Jon Fitch",
    "Chris Lytle",
    "Joe Doerksen",
    "Dustin Poirier",
    "Shannon Gugerty"
  ),
  ID = 1:13
)


# Icons and Images ------------------------------------------------------------------



# Rough work ------------------------------------------------------------------


# Clean  ----------------------------------------------------------------

#Total fight time in seconds

# Logic to convert Round and Fight_Time to total seconds:

  # If Fight_Time > 5:00, ignore rounds and only use Fight_Time (old rule set with no rounds)
  # If Fight_Time = 5:00, ignore Fight_Time and only use Rounds with no subtraction (round is complete and covered by round number)
  # In all other cases where Fight_TIme < 5:00
      # Rounds minus 1, times 300. (1 is the current round which will be counted separately from Fight_Time)
      # Parse min:secs and then minutes times 60
      # Add together round calc + minute calc + seconds

data.fight.outcomes.clean <-
  data.fight.outcomes%>%
  separate(
    Fight_Time,
    c("minutes","seconds"),
    sep = ":"
  )%>%
  mutate(
    round.time.seconds = 
      (as.numeric(minutes) * 60) + as.numeric(seconds),
    total.time.seconds = 
      case_when(
        round.time.seconds > 300 ~ round.time.seconds, # Fights over 5mins are non standard format and 1 rounders
        round.time.seconds == 300 ~ Round * 300, # If round time == 5mins; take round count x 5mins
        round.time.seconds < 300 ~ ((Round - 1) * 300) + (round.time.seconds) #if round is <5mins, take rounds and subtract 1 + round time. Subtract 1 because current round is incomplete and added based on round time. 
      ),
    method.simplified =
      case_when(
        str_detect(Method, "SUB ") ~ "Submission", 
        str_detect(Method, "KO/TKO") ~ "K0/TKO", 
        str_detect(Method, "-DEC") ~ "Decision",
        TRUE ~ "Other"
      )
  )%>%
  left_join(
    data.events%>%
      select(
        Event_Id,
        Date
      ),
    by = "Event_Id"
  )
  





# Major fight events per fighter ----------------------------------------------------------

# A crude and subjective measure of "action" in a fighter by awarding one point for each: 
# Sub attempt
# KD
# Significant strikes > weight class average (This would be more fair if done by round but not in the data.)
# Non-decision win

# Data shows a typical funnel shape when the rate is plotted against increasing sample size on the x axis. 
# As the sample size increases for any given point (in this case that being the total number of fights in the UFC for a given fighter) the average rate (action per fight) moves towards the overall mean. Fighters with smaller number of fights have a larger spread in the rate as chance alone of outcomes can play a big role on the final rate.
# For example: The highest rate is seen for James Wilks with ~ 6 action.per.fight. However, this is only based on 4 fights in the UFC. And one of these with Matt Brown had 3 sub attempts each, a KD and a TKO giving at least 8 points. Should James wIlks had had a longer UFC career, the impact of this fight would have been watered down, loweriing his average significantly. 

# I have filter out fighters with less that 4 fights due to this issue.

# It goes without saying that the biggest caveat with this analysis is that 'action' is a fight is both subjective (takedowns i did not include because although they can be exciting and lmportant parts of a good fight, they can also be a precusor to a lul in action for ground control) and difficult to define with simple metrics. E.g of the chosen metrics, sub attempts can be brief and fleeting exchanges or dramatic and drawn out moments. Strikes are by far the most difficult to integrate in part because the previous metrics general occur in small numbers - a couple times at most ina  given fight. Strikes however dwarf these in numbers. So in an attempt to intregrate them I have reduced them down to whether the number of significant strikes is higher than average. This is adjusted by weight class which have a naturally large variation in the number of significant strikes). 

# This somewhat brings striking to a more comparable metric for action. Though I think ideally a per round sig nificant strike count would allow for a contribution of more than 1 and perhaps fairer, given they are the cornerstone of an entertaining fighter. 

# I might go back and readjust the above average strike calculation give perhaps 1 point for <2 rounds and 2 for >2 rounds. This will reward longer fights with high sig strikes with less bias intrudced by awarding lots for points with only some rounds pulling up the sig strike average.

# I should investigate the mean, median and st.dev for sig strikes within weight classes. Perhaps average is not fair.

# The upper and lower lines indicate upper and lower bounds. These narrow as the number of fights increase and are calculated by looking at the variance* accross the entire set of data, and assuming a poisson distrubution* , give us a range that we would expect the value for a given number of total fights to fall between, with repeated occurences 95% and 99.8% (blue and orange, respectively) of the time. I.e only 5 out 100 fighters who fought 30 times we would expect to have a action per fight score of ~3.0. (Matt Brown managed to keep a action.per.fight rate of 3.8 - well above this)


table.fight.outcomes <- 
  data.fight.outcomes.clean%>%
  left_join( # join table with significant strikes per min by weight class
    data.fight.outcomes.clean%>%
              group_by(Weight_Class)%>%
              summarise(
                sig.str.ave.weightclass = sum(STR_1 + STR_2)/sum(total.time.seconds/60)
              ),
    by = "Weight_Class"
  )%>%
  mutate(
    sig.str.above.ave = # Column scoring fights with significant strikes above average 
      case_when(
        sum(STR_1 + STR_2)/sum(total.time.seconds/60) > median(sig.str.ave.weightclass) #check if fight sig.strikes is higher than weight class
        ~ 1 * (case_when(total.time.seconds > 600 ~ 1, TRUE ~ 1)), #if yes, check if rounds > 2, and give 2 points if so,
        TRUE ~ 0),
    KD.total = KD_1 + KD_2,
    finish = 
      case_when(
        str_detect(Method, "SUB ") | str_detect(Method, "KO/TKO ") ~ 1, TRUE ~ 0),
    action.total = 
      KD_1 + KD_2 + SUB_1 + SUB_2 + finish + sig.str.above.ave
  )

# Paste all fighters in single column with corresponding KDs



table.fight.outcomes <-
  bind_rows(
    table.fight.outcomes%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, action.total, total.time.seconds
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1"
      ),
    table.fight.outcomes%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, action.total, total.time.seconds
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2"
      ),
  )%>%
  mutate(
    counter = 1
  )%>%
  group_by(Fighter_Id, Fighter)%>%
  summarise(
    action.total = sum(action.total),
    fight.time = sum(total.time.seconds),
    total.fights = sum(counter),
    .groups = "drop"
  )%>%
  mutate(
    action.per.min = action.total/(fight.time/60),
    action.per.fight = action.total/total.fights
  )%>%
  filter(
    total.fights > 4 
  )%>%
  left_join(
    expected.fighters,
    by = "Fighter"
  )%>%
  left_join(
    actual.fighters,
    by = "Fighter"
  )%>%
  mutate(
    overall.action.per.fight = sum(action.total)/sum(total.fights),
    se = sqrt(overall.action.per.fight / total.fights),
    upper95 = overall.action.per.fight + 1.96 * sqrt(overall.action.per.fight / total.fights),
    lower95 = pmax(0, overall.action.per.fight - 1.96 * sqrt(overall.action.per.fight / total.fights)),
    upper99.8 = overall.action.per.fight + 3 * sqrt(overall.action.per.fight / total.fights),
    lower99.8 = pmax(0, overall.action.per.fight - 3 * sqrt(overall.action.per.fight / total.fights))
  )%>%
  left_join(
    data.fighters.stats%>%
      select(
        Fighter_Id, Gender, Stance, Fighting.Style, Weight_Class),
    by = c("Fighter_Id")
  )%>%
  mutate(
    significant = case_when(
      action.per.fight > upper99.8
      ~ "Higher",
      TRUE ~ "Lower"
    )
  )




# scatter with actual and expected outliers

table.fight.outcomes <- table.fight.outcomes %>%
  mutate(
    point_type = case_when(
      significant == "Higher" ~ "Fighters with significantly high action",
      !is.na(ID.x) ~ "Other noteable fighters",
      TRUE ~ NA_character_
    )
  )

plot.1 <- ggplot(
  data = table.fight.outcomes,
  aes(
    x = total.fights,
    y = action.per.fight,
    label = Fighter
  )
)+
  geom_point(
    size = 5,
    alpha = 0.2,
    colour = "#C678DD"
  ) +
  geom_line(aes(y = upper95), linetype = "dashed", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = lower95), linetype = "dashed", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = upper99.8), linetype = "dotted", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = lower99.8), linetype = "dotted", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = overall.action.per.fight), linetype = "solid", linewidth = .8, colour = "white", show.legend = F
  ) +
  # Points with legend
  geom_point(
    aes(color = point_type),
    size = 5,
    na.rm = TRUE
  ) +
  scale_color_manual(
    name = "Legend",
    values = c(
      "Fighters with significantly high action" = "#22C55E",
      
      "Other noteable fighters" = "#F59E0B"
    ),
    na.translate = FALSE
  ) +
  labs(
    x = "Total UFC Fights",
    y = "Action-points per Fight",
    title = "UFC Fighters by 'Action-points' per Fight and Total Number of Fights, 1994 to 2025",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )+
  theme(
    legend.position = c(0.95, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "top"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA)
  )+
  geom_text_repel(
    data = table.fight.outcomes %>%
      filter(significant == "Higher"),
    aes(label = Fighter),
    colour = "white",
    size = 3,
    fontface = "bold",
    nudge_x = 0.3,
    direction = "y",
    hjust = 0,
    box.padding = 0.3,
    point.padding = 0.2,
    segment.color = "grey70"
  )+
  geom_text_repel(
    data = table.fight.outcomes%>%
      filter(
        !is.na(ID.x)
      ),
    aes(label = Fighter),
    colour = "white",
    size = 3,
    fontface = "bold",
    nudge_x = 0.3,
    direction = "y",
    hjust = 0,
    box.padding = 0.3,
    point.padding = 0.2,
    segment.color = "grey70"
  )
  


# Scatter by sex

plot.2 <- ggplot(
  data = table.fight.outcomes,
  aes(
    x = total.fights,
    y = action.per.fight
  )
)+
  geom_point(
    data = table.fight.outcomes,
    aes(
      colour = Gender
    ),
    size = 5,
    alpha = 0.5,
    show.legend = TRUE
  )+
  geom_point(
    data = table.fight.outcomes%>%
    filter(
      Gender == "Female"
    ),
    colour = "#F59E0B",
    size = 5,
    alpha = 0.25
  )+
  scale_color_manual(
    name = "Legend",
    values = c(
      "Male" = "#C678DD",
      
      "Female" = "#F59E0B"
    ),
    na.translate = FALSE
  ) +
  geom_line(aes(y = upper95), linetype = "dashed", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = lower95), linetype = "dashed", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = upper99.8), linetype = "dotted", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = lower99.8), linetype = "dotted", linewidth = .8, colour = "white", show.legend = F
  ) +
  geom_line(aes(y = overall.action.per.fight), linetype = "dashed", linewidth = .8, colour = "white", show.legend = F
  )+
  labs(
    x = "Total UFC Fights",
    y = "Action-points per Fight",
    title = "UFC Fighters by 'Action-points' per Fight and Total Number of Fights, 1994 to 2025",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )+
  theme(
    legend.position = c(0.95, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "top"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA)
  )




# Referee -----------------------------------------------------------------

# Is referee statistically more likely to have a fight go to decision?


table.refs <-
  data.fight.outcomes%>%
  mutate(
    count = 1,
    decision = 
      case_when(str_detect(Method, "-DEC") ~ 1, TRUE ~ 0),
    finish = 
      case_when(
        str_detect(Method, "SUB ") | str_detect(Method, "KO/TKO ") ~ 1, TRUE ~ 0)
  )%>%
  group_by(Referee)%>%
  summarise(
    count = sum(count),
    decision = sum(decision),
    finish = sum(finish),
    .groups = "drop"
  )%>%
  mutate(
    finish.rate = finish/count
  )%>%
  bind_cols(
    binom.confint(.$finish,
                  .$count,
                  methods = "wilson")[,c("lower","upper")]
    )
  

ggplot(
  data = 
    table.refs%>%
    filter(count >100),
  aes(
    y = finish.rate,
    x = reorder(Referee, finish.rate)
  )
) + 
  geom_col(
    colour = "#C678DD",
    fill = "#C678DD"
  ) +
  geom_hline(
    data = table.refs%>%
      filter(count >100)%>%
      summarise(average = sum(finish)/sum(count)),
    aes(yintercept = average
    ),
    linewidth = 1.5,
    colour = "white"
  )+
  theme(
    legend.position = c(0.95, 0.25),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "top"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(angle = -45, vjust = -2)  # rotate 45 degrees
  )+
  labs(
    x = "Referee (with 100+ fights)",
    y = "Finish rate per fight refereed",
    title = "UFC Referees by Finish Rate of Refereed Fights",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )+
  geom_errorbar(
    aes(
      ymin = lower,
      ymax = upper,
      linetype = "95% CI"
      ),
    linewidth = .2,
    colour = "white") +
  scale_linetype_manual(
    name = "Legend",
    values = c("95% CI" = "dashed")
  )
  




# Blue vs Red -------------------------------------------------------------


# Compare wins and losses by Red vs Blue

# Compare method of victory by Red vs Blue



table.red.v.blue <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, Result_1, method.simplified
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "Result" = "Result_1"
      )%>%
      mutate(
        side = "Red"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, Result_2, method.simplified
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "Result" = "Result_2"
      )%>%
      mutate(
        side = "Blue"
      )
  )%>%
  mutate(
    counter = case_when(
      Result == "W" ~ 1,
      TRUE ~ 0
    )
  )


table.red.v.blue.2 <- 
  table.red.v.blue%>%
  group_by(side, method.simplified)%>%
  summarise(
    count = sum(counter), .groups = "drop"
  )%>%
  group_by(side)%>%
  mutate(
    percentage = round((count / sum(count)) *100,1)
  )

plot.3 <- ggplot(
  data = table.red.v.blue.2,
  aes(
    x = method.simplified,
    y = percentage,
    fill = side
  )
) +
  geom_col(
    position = "dodge"
  )+
  theme(
    legend.position = c(0.95, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "top"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(angle = -45, vjust = -2)  # rotate 45 degrees
  )+
  labs(
    x = "Method of Victory",
    y = "Percentage of Fights (%)",
    title = "Method of Victory by Blue or Red Corner",
    fill = "Corner",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  ) +
  geom_text(
    aes(label = percentage),
    vjust = -0.5,
    position = position_dodge(0.9),
    colour = "white"
  )+
  scale_fill_manual(
    name = "Corner",
    values = c(
      "Red" = "#F8766D",
      
      "Blue" = "#00B8e7"
    ),
    na.translate = FALSE
  )
  


# Win/Loss Streak Probabilities -------------------------------------------


# Create 5 tables with subsets of: All fights, 1 loss, 2 loss, 3 loss, 4+ losses
# Bind together and calculate % wins based on unique column ID

table.loss.snowball <- # All fighters in single column with outcome and date
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, Event_Id, Result_1
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "Result" = "Result_1"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, Event_Id, Result_2
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "Result" = "Result_2"
      )
  )%>%
  left_join(
    data.events%>%
      select(
        Event_Id,
        Date
      ),
    by = "Event_Id"
  )%>%
  mutate(
    win.count = case_when(Result == "W" ~ 1, TRUE ~ 0),
    fight.count = 1,
    Date = as.Date(Date)
  )


table.loss.snowball.2 <-
  table.loss.snowball%>%
  group_by(Fighter)%>%
  arrange(Date, .by_group = TRUE)%>% # essential for lag and lead function
  mutate(
    loss.start = #checks for a loss and previous result of a win/draw/nc/NA
      Result == "L" & 
      (lag(Result) != "L" | is.na(lag(Result))), 
    after.loss = # marks the fight immediately after the loss.start as
      lag(loss.start) == TRUE,  
    second.loss.start = #checks for loss & 2nd prior loss & 3rd prior win/draw/nc/NA
      Result == "L" & 
      lag(Result) == "L" & 
      (lag(Result, n = 2) != "L" | is.na(lag(Result, n =2))),
    after.second.loss = 
      lag(second.loss.start) == TRUE,
    third.loss.start =
      Result == "L" & 
      lag(Result) == "L" & 
      lag(Result, n = 2) == "L" & 
      (lag(Result, n = 3) != "L" | is.na(lag(Result, n =3))),
    after.third.loss =
      lag(third.loss.start) == TRUE,
    fourplus.loss.start =
      Result == "L" & 
      lag(Result) == "L" & 
      lag(Result, n = 2) == "L" & # third loss
      lag(Result, n = 3) == "L"& # fourth loss
      ( # keep checking for up to 7 losses or win/draw/nc/NA
            (lag(Result, n = 4) == "L") | #fifth loss
            (lag(Result, n = 4) == "L" & lag(Result, n = 5) == "L") |#fifth and sixth
            (lag(Result, n = 4) == "L" & lag(Result, n = 5) == "L" & lag(Result, n = 6) == "L") | #5-7
            (lag(Result, n = 4) == "L" & lag(Result, n = 5) == "L" & lag(Result, n = 6) == "L" & lag(Result, n = 7) == "L")|
            (lag(Result, n = 4) != "L") | # 
            (is.na(lag(Result, n =4)))
            ),
    after.fourplus.loss =
      lag(fourplus.loss.start) == TRUE
    )

table.loss.snowball.3 <-
  tibble(
    Type = "Loss streak",
    streak = c("0 (all fights)",
               "1",
               "2",
               "3",
               "4+"),
    win.rate = c(
      with(table.loss.snowball.2,
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.loss.snowball.2, after.loss),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.loss.snowball.2, after.second.loss),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.loss.snowball.2, after.third.loss),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.loss.snowball.2, after.fourplus.loss),
           sum(win.count) / sum(fight.count))
    )
  )


# Win Streaks

table.win.snowball.2 <-
  table.loss.snowball%>%
  group_by(Fighter)%>%
  arrange(Date, .by_group = TRUE)%>% # essential for lag and lead function
  mutate(
    win.start = #checks for a win and previous result of a win/draw/nc/NA
      Result == "W" & 
      (lag(Result) != "W" | is.na(lag(Result))), 
    after.win = # marks the fight immediately after the win.start as
      lag(win.start) == TRUE,  
    second.win.start = #checks for win & 2nd prior win & 3rd prior win/draw/nc/NA
      Result == "W" & 
      lag(Result) == "W" & 
      (lag(Result, n = 2) != "W" | is.na(lag(Result, n =2))),
    after.second.win = 
      lag(second.win.start) == TRUE,
    third.win.start =
      Result == "W" & 
      lag(Result) == "W" & 
      lag(Result, n = 2) == "W" & 
      (lag(Result, n = 3) != "W" | is.na(lag(Result, n =3))),
    after.third.win =
      lag(third.win.start) == TRUE,
    fourplus.win.start =
      Result == "W" & 
      lag(Result) == "W" & 
      lag(Result, n = 2) == "W" & # third win
      lag(Result, n = 3) == "W"& # fourth win
      ( # keep checking for up to 7 wines or win/draw/nc/NA
        (lag(Result, n = 4) == "W") | #fifth win
          (lag(Result, n = 4) == "W" & lag(Result, n = 5) == "W") |#fifth and sixth
          (lag(Result, n = 4) == "W" & lag(Result, n = 5) == "W" & lag(Result, n = 6) == "W") | #5-7
          (lag(Result, n = 4) == "W" & lag(Result, n = 5) == "W" & lag(Result, n = 6) == "W" & lag(Result, n = 7) == "W")|
          (lag(Result, n = 4) != "W") | # 
          (is.na(lag(Result, n =4)))
      ),
    after.fourplus.win =
      lag(fourplus.win.start) == TRUE
  )

table.win.snowball.3 <-
  tibble(
    Type = "Win streak",
    streak = c("0 (all fights)",
               "1",
               "2",
               "3",
               "4+"),
    win.rate = c(
      with(table.win.snowball.2,
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.win.snowball.2, after.win),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.win.snowball.2, after.second.win),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.win.snowball.2, after.third.win),
           sum(win.count) / sum(fight.count)),
      
      with(subset(table.win.snowball.2, after.fourplus.win),
           sum(win.count) / sum(fight.count))
    )
  )


table.win.loss.streaks <-
  rbind(
    table.loss.snowball.3,
    table.win.snowball.3
  )%>%
  mutate(
    win.rate = round(win.rate*100,1) 
  )

plot.4 <- ggplot(
  data = 
    table.win.loss.streaks%>%
    filter(
      streak != "0 (all fights)"
    ),
  aes(
    x = streak,
    y = win.rate,
    fill = Type
  )
)+
  geom_col(
    position = "dodge"
  )+
  geom_hline(
    yintercept = 
      table.win.loss.streaks%>%
      filter(
        Type == "Win streak",
        streak == "0 (all fights)"
      )%>%
      pull(win.rate),
    linetype = "dashed",
    linewidth = 1,
    colour = "white"
  )+
  theme(
    legend.position = c(0.95, 0.05),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 13)
  )+
  labs(
    x = "Win/Loss Streak",
    y = "Percentage of Fights (%)",
    title = "Win Outcomes by Win/Loss Streak, 1994 - 2025",
    fill = "Streak Type",
    caption = "Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  ) +
  geom_text(
    aes(label = win.rate),
    vjust = -0.5,
    position = position_dodge(0.9),
    colour = "white"
  )

# Finish Time -------------------------------------------------------------

# To look at all fights ending before scheduled time regardless of reason (includes DQs and overturned)
# filter to finishes
# label time in seconds to 30 second blocks
# summarise to count finishes in each time block


lookup.30seconds <- 
    tibble(
      total.time.seconds = 1:1500,
      time.block = rep(1:50, each = 30),
      round.name = 
        rep(
          c("Round 1", 
            "Round 2", 
            "Round 3", 
            "Round 4", 
            "Round 5"),
          each = 300),
      label = 
        rep(
          c(
            "00:00-00:30",
            "00:31-01:00",
            "01:01-01:30",
            "01:31-02:00",
            "02:01-02:30",
            "02:31-03:00",
            "03:01-03:30",
            "03:31-04:00",
            "04:01-04:30",
            "04:31-05:00"),
          each = 30,
          times = 5
        )
    )


table.finish.time <-
  data.fight.outcomes.clean%>%
  filter(
    Time.Format == "3 Rnd (5-5-5)" & total.time.seconds < 900| 
      Time.Format == "5 Rnd (5-5-5-5-5)" & total.time.seconds < 1500
  )%>%
  left_join(
    lookup.30seconds,
    by = "total.time.seconds"
  )%>%
  group_by(
    Time.Format, time.block, round.name, label
  )%>%
  mutate(
    count = n()
  )%>%
  summarise(
    mean(count)
  )


# label angle tables


table.finish.time.3rnd.labels <- 
  table.finish.time%>%
  filter( # angles must be calculated separately for 3 and 5 round due to chart shape changes
    Time.Format == "3 Rnd (5-5-5)"
  )

number_of_bar <- nrow(table.finish.time.3rnd.labels)
angle <-  90 - 360 * (table.finish.time.3rnd.labels$time.block-0.5) /number_of_bar     # substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)
    
table.finish.time.3rnd.labels <- 
  table.finish.time.3rnd.labels%>%
  ungroup()%>%
  mutate(
    hjust = ifelse(angle < -90, 1, 0),
    angle = ifelse(angle < -90, angle+180, angle)
  )


plot5 <- ggplot(
  data = 
    table.finish.time%>%
    filter(Time.Format == "3 Rnd (5-5-5)"),
  aes(
    x = time.block,
    y = `mean(count)`,
    fill = round.name
  )
) + 
  ylim(-100,300)+
  geom_bar(
    stat = "identity"
    )+
  coord_polar(start = 0)+
  geom_text(
    data=table.finish.time.3rnd.labels, 
    aes(
      x=time.block, y=`mean(count)`+10, 
      label=label, 
      hjust=hjust
      ), 
    color="white", 
    fontface="bold",
    alpha=1, 
    size=3, 
    angle= table.finish.time.3rnd.labels$angle, 
    inherit.aes = FALSE )+
  theme(
    legend.position = c(0.95, 0.10),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    axis.text = element_blank(),
    axis.title = element_blank(),
    panel.grid = element_blank(),
    plot.margin = unit(rep(-2,4), "cm"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    plot.caption = element_text(colour = "white", size = 10, hjust = 1)
  )+
  labs(
    fill = "Round",
    caption  = "Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )



# 5nd labels



table.finish.time.5rnd.labels <- 
  table.finish.time%>%
  filter( # angles must be calculated separately for 3 and 5 round due to chart shape changes
    Time.Format == "5 Rnd (5-5-5-5-5)"
  )

number_of_bar2 <- nrow(table.finish.time.5rnd.labels)
angle2 <-  90 - 360 * (table.finish.time.5rnd.labels$time.block-0.5) /number_of_bar2     # substract 0.5 because the letter must have the angle of the center of the bars. Not extreme right(1) or extreme left (0)

table.finish.time.5rnd.labels <- 
  table.finish.time.5rnd.labels%>%
  ungroup()%>%
  mutate(
    hjust = ifelse(angle2 < -90, 1, 0),
    angle = ifelse(angle2 < -90, angle2+180, angle2)
  )

plot.6 <- ggplot(
  data = 
    table.finish.time%>%
    filter(Time.Format == "5 Rnd (5-5-5-5-5)"),
  aes(
    x = time.block,
    y = `mean(count)`,
    fill = round.name
  )
)+ 
  ylim(-13, 25)+
  geom_bar(stat = "identity")+
  coord_polar(start = 0)+
  geom_text(
    data=table.finish.time.5rnd.labels, 
    aes(
      x=time.block, y=`mean(count)`+2, 
      label=label, 
      hjust=hjust
    ), 
    color="white", 
    fontface="bold",
    alpha=1, 
    size=3, 
    angle= table.finish.time.5rnd.labels$angle, 
    inherit.aes = FALSE )+
  theme(
    legend.position = c(0.97, 0.08),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    axis.text = element_blank(),
    axis.title = element_blank(),
    panel.grid = element_blank(),
    plot.margin = unit(rep(-2,4), "cm"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    plot.caption = element_text(colour = "white", size = 10, hjust = 1)
  )+
  labs(
    fill = "Round",
    caption  = "Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )



# Finish type -------------------------------------------------------------


table.method.type <- 
  data.fight.outcomes.clean%>%
  count(Method)%>%
  mutate(
    group = 
      case_when(
        str_detect(Method, "SUB ") ~ "Submission",
        (str_detect(Method, "KO/TKO ")|str_detect(Method, "KO/TKO")) ~ "Knockout / Technical Knockout",
        str_detect(Method, "-DEC") ~ "Decision",
        str_detect(Method, "Overturned") ~ "Overturned",
        TRUE ~ "Other"
      ),
    sub.group.rough = 
      case_when(
        str_detect(Method, "SUB ") ~ str_remove(Method,  "SUB "),
        str_detect(Method, "KO/TKO ") ~ str_remove(Method, "KO/TKO "),
        str_detect(Method, "U-DEC") ~ "Unanimous",
        str_detect(Method, "M-DEC") ~ "Majority",
        str_detect(Method, "S-DEC") ~ "Split",
        str_detect(group, "Other") ~ Method,
        str_detect(Method, "Overturned ") ~ str_remove(Method, "Overturned "),
        TRUE ~ "Other"
      ),
    sub.group.clean = 
      case_when(
        str_detect(sub.group.rough, "Elbow") ~ "Elbow(s)",
        str_detect(sub.group.rough, "Knee") & group == "KO/TKO"
        ~ "Knee(s)",
        str_detect(sub.group.rough, "Headbutt") ~ "Headbutt(s)",
        str_detect(sub.group.rough, "Punch") ~ "Punch(es)",
        str_detect(sub.group.rough, "Other") ~ "Other",
        str_detect(sub.group.rough, "Kick") ~ "Kick(s)",
        (str_detect(sub.group.rough, "Choke")|str_detect(sub.group.rough, "Triangle")) & group == "Overturned" ~ "Submission",
        n < 30 ~ "Other",
        str_detect(group, "Overturned") ~ "Overturned",
        TRUE ~ sub.group.rough
      )
  )%>%
  group_by(group, sub.group.clean)%>%
  summarise(n = sum(n))


treemap(
  table.method.type,
  index = c("group","sub.group.clean"),
  vSize = "n",
  type = "index",
  aspRatio = 1:1.999
)+
  geom_treemap_text(
    family = "Audiowide",   # specify font here
    colour = "white",
    place = "centre",
    grow = TRUE
  )

plot.7 <- ggplot(table.method.type, 
       aes(
  area = n,
  fill = group,
  subgroup = group,# fill by group
  label = sub.group.clean     # label for each tile
)) +
  geom_treemap() +
  geom_treemap_subgroup_border()+
  geom_treemap_text(
    family = "Audiowide",     # custom font
    colour = "white",         # white text
    place = "centre",         # center text in tile
    grow = TRUE# auto-scale text to fit tile
  ) +
  theme(
    plot.title = element_text(colour = "white", size = 16, face = "bold"),
    legend.position = c(0.02, 0.02),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("left", "bottom"),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    plot.caption = element_text(colour = "white", size = 10, hjust = 1),
    legend.key.size = unit(0.3, "cm")         # key (box) size
  )+
  labs(
    fill = "Round",
    caption  = "Aditya Ratan, UFC Datasets (1994–2025), Kaggle",
    title = "Method of Fight Outcomes, 1994-2025"
      )

# Event Outcome Totals ----------------------------------------------------

table.event.totals <-
  data.fight.outcomes.clean%>%
  left_join(
    data.events,
    by = "Event_Id"
  )%>%
  mutate(
    Submission = case_when(
      str_detect(Method, "SUB ") ~ 1, 
      TRUE ~ 0
      ),
    KO = case_when(
      str_detect(Method, "KO/TKO") ~ 1,
      TRUE ~ 0
      ),
    Decision = case_when(
      str_detect(Method, "-DEC") ~ 1,
      TRUE ~ 0),
    No.of.Fights = 1
  )%>%
  group_by(Event_Id)%>%
  summarise(
    Submission = sum(Submission),
    KO = sum(KO),
    Decision = sum(Decision),
    No.of.Fights = sum(No.of.Fights)
  )%>%
  ungroup()%>%
  mutate(
    Submission = round((Submission/No.of.Fights)*100,0),
    KO = round((KO/No.of.Fights)*100,0),
    Decision= round((Decision/No.of.Fights)*100,0)
  )%>%
  left_join(
    data.events,
    by = "Event_Id"
  )%>%
  mutate(
    Date = as.Date(Date)
  )%>%
  pivot_longer(
    cols = c("Submission", "KO", "Decision"),
    names_to = "Type",
    values_to = "Percent"
  )%>%
  mutate(
    label = 
      paste0(
        `Percent`, 
        "% (",
        round(No.of.Fights*(Percent/100),0),  
        " of ", 
        `No.of.Fights`, 
        " fights)")
  )%>%
  group_by(Type)%>%
  mutate(
    top.8 = 
      rank(-Percent, ties.method = "first") <=5
  )%>%
  ungroup()%>%
  filter(
    top.8 == T
  )%>%
  arrange(Type, desc(Percent)) %>%        # sort within Type by Percent
  mutate(x_axis = factor(
    paste(Type, Name, sep = " - "),       # combine Type + Name
    levels = paste(Type, Name, sep = " - ")  # preserves order
  ))



plot.8 <- ggplot(
  data = table.event.totals,
  aes(
    x = x_axis,
    y = Percent,
    fill = Type
  )
)+
  geom_col(
    position = "dodge"
  )+
  geom_text(
    aes(
      label = label),
    position = position_dodge(width = 0.9),
    angle = 80,
    hjust = 0,
    vjust = -0.2,
    colour = "grey90",
    size = 3
  ) +
  theme(
    legend.position = c(0.99, 0.99),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "top"),
    axis.text.x = element_text(angle = 80, hjust = 1, size =8),
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white", size = 12),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    legend.key.size = unit(0.7, "cm")
  )+
  scale_x_discrete(labels = str_wrap(table.event.totals$Name, width = 20)
                   )+
  scale_y_continuous(expand = expansion(mult = c(.2, 0.6)))+
  labs(
    x = "UFC Event",
    y = "Percent of Fights (%)",
    title = "Top UFC Events by Fight Outcomes",
    caption = "Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
    
  )

# Strikes Accumulated Before Belt -----------------------------------------

# Done by Weight division (Due to strike difference and more interesting comparison)
# Cap for last 5-10 champions
# First time only, No interim unless promoted to full champ
# Fighters moving up in weight will bypass a fight streak. In this case go off their previous best streak. (Will need two strends overlayed to highlight this)

# Lookup to have Fighter Name, Date of Fight. Match to long format fighter data.
# cumulative sum fight-time, Fight count, Strikes absorbed 

hw.champion.fights <-
  tibble(
    Fighter = c(
      "Jon Jones",
      "Tom Aspinall",
      "Francis Ngannou",
      "Daniel Cormier",
      "Stipe Miocic",
      "Fabricio Werdum",
      "Junior Dos Santos",
      "Cain Velasquez",
      "Brock Lesnar"
      ),
    Fight.Date = c(
      "2023-03-04",
      "2025-06-21",
      "2021-03-27",
      "2018-07-07",
      "2016-05-14",
      "2015-06-13",
      "2011-11-12",
      "2010-10-23",
      "2008-11-15"
  )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order. 

lhw.champion.fights <-
  tibble(
    Fighter = c(
      "Magomed Ankalaev",
      "Alex Pereira",
      "Jamahal Hill",
      "Jiri Prochazka",
      "Glover Teixeira",
      "Jan Blachowicz",
      "Daniel Cormier",
      "Jon Jones",
      "Mauricio Rua"
    ),
    Fight.Date = c(
      "2025-03-08",
      "2023-11-11",
      "2023-01-21",
      "2022-06-12",
      "2021-10-30",
      "2020-09-27",
      "2015-05-23",
      "2011-03-19",
      "2010-05-08"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order. 


mw.champion.fights <-
  tibble(
    Fighter = c(
      "Khamzat Chimaev",
      "Dricus du Plessis",
      "Sean Strickland",
      "Alex Pereira",
      "Israel Adesanya",
      "Robert Whittaker",
      "Georges St-Pierre",
      "Michael Bisping",
      "Luke Rockhold",
      "Chris Weidman",
      "Anderson Silva"
    ),
    Fight.Date = c(
      "2025-08-16",
      "2024-01-20",
      "2023-09-10",
      "2022-11-12",
      "2019-10-06",
      "2017-07-08",
      "2017-11-04",
      "2016-06-04",
      "2015-12-12",
      "2013-07-06",
      "2006-10-14"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order. 


ww.champion.fights <-
  tibble(
    Fighter = c(
     "Islam Makhachev",
     "Jack Della Maddelena",
     "Belal Muhammad",
     "Leon Edwards",
     "Kamaru Usman",
     "Tyron Woodley",
     "Robbie Lawler",
     "Johny Hendricks",
     "Georges St-Pierre",
     "BJ Penn",
     "Matt Hughes"
    ),
    Fight.Date = c(
      "2025-11-15",
      "2025-05-10",
      "2024-07-27",
      "2022-08-20",
      "2019-05-02",
      "2016-07-30",
      "2014-12-06",
      "2014-03-15",
      "2006-11-18",
      "2004-01-31",
      "2001-11-02"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order. 

lw.champion.fights <-
  tibble(
    Fighter = c(
      "Ilia Topuria",
      "Islam Makhachev",
      "Charles Oliveira",
      "Khabib Nurmagomedov",
      "Conor McGregor",
      "Eddie Alvarez",
      "Rafael dos Anjos",
      "Anthony Pettis",
      "Benson Henderson",
      "Frankie Edgar",
      "BJ Penn"
    ),
    Fight.Date = c(
      "2025-06-28",
      "2022-10-22",
      "2021-05-15",
      "2018-04-07",
      "2016-11-12",
      "2016-07-07",
      "2015-03-14",
      "2013-08-31",
      "2012-02-26",
      "2010-04-10",
      "2008-01-19"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order.

fw.champion.fights <-
  tibble(
    Fighter = c(
      "Ilia Topuria",
      "Yair Rodriguez",
      "Alexander Volkanovski",
      "Max Holloway",
      "Conor McGregor",
      "Jose Aldo"
    ),
    Fight.Date = c(
      "2024-02-17",
      "2023-02-12",
      "2019-12-14",
      "2015-12-12",
      "2010-11-20"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order.

fw.champion.fights <-
  tibble(
    Fighter = c(
      "Ilia Topuria",
      "Yair Rodriguez",
      "Alexander Volkanovski",
      "Max Holloway",
      "Conor McGregor",
      "Jose Aldo"
    ),
    Fight.Date = c(
      "2024-02-17",
      "2023-02-12",
      "2019-12-14",
      "2017-06-03",
      "2015-12-12",
      "2010-11-20"
    )
  )%>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter))) # unique returns them in the originally inserted order.


bw.champion.fights <-
  tibble(
    Fighter = c(
      "Dominick Cruz",
      "Renan Barao",
      "T.J. Dillashaw",
      "Cody Garbrandt",
      "Henry Cejudo",
      "Petr Yan",
      "Aljamain Sterling",
      "Sean O'Malley",
      "Merab Dvalishvili"
    ),
    Fight.Date = c(
      "2010-12-16",
      "2014-01-06",
      "2014-05-24",
      "2016-12-30",
      "2019-06-08",
      "2020-07-12",
      "2021-03-06",
      "2023-08-19",
      "2024-09-14"
    )
  ) %>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter)))


flw.champion.fights <-
  tibble(
    Fighter = c(
      "Demetrious Johnson",
      "Henry Cejudo",
      "Deiveson Figueiredo",
      "Brandon Moreno",
      "Alexandre Pantoja",
      "Joshua Van"
    ),
    Fight.Date = c(
      "2012-09-22",
      "2018-08-04",
      "2020-07-19",
      "2021-06-12",
      "2023-07-08",
      "2025-12-06"
    )
  ) %>%
  mutate(Fighter = factor(Fighter, levels = unique(Fighter)))

# Heavyweight

table.champions.cumulative.hw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    hw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )
    

plot.9 <- ggplot(
  data = table.champions.cumulative.hw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.hw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.05, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("left", "top"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Heavyweight",
    caption = "Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )



# LightheavyWeight


table.champions.cumulative.lhw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    lhw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.10 <- ggplot(
  data = table.champions.cumulative.lhw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.lhw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.05, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("left", "top"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Light Heavyweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )


# MiddleWeight 


table.champions.cumulative.mw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    mw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.11 <-ggplot(
  data = table.champions.cumulative.mw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.mw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.1
  )+
  theme(
    legend.position = c(0.05, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("left", "top"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, MiddleWeight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )





# WelterWeight 


table.champions.cumulative.ww <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    ww.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.12 <- ggplot(
  data = table.champions.cumulative.ww,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.ww%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.1
  )+
  theme(
    legend.position = c(0.05, 0.95),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("left", "top"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Welterweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )


# Lightweight


table.champions.cumulative.lw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    lw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.13 <- ggplot(
  data = table.champions.cumulative.lw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.lw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.95, 0.05),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Lightweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )

# Featherweight


table.champions.cumulative.fw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    fw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.14 <- ggplot(
  data = table.champions.cumulative.fw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.fw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.95, 0.05),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Featherweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )


# Bantamweight


table.champions.cumulative.bw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    bw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.15 <- ggplot(
  data = table.champions.cumulative.bw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.bw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.95, 0.05),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Bantamweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )



# Flyweight


table.champions.cumulative.flw <-
  bind_rows(
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_1, Fighter_1, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_1",
        "Fighter" = "Fighter_1",
        "strikes.landed" = "STR_1",
        "strikes.absorbed" = "STR_2"
      ),
    data.fight.outcomes.clean%>%
      select(
        Fight_Id, Fighter_Id_2, Fighter_2, STR_1, STR_2, Date, total.time.seconds, Weight_Class
      )%>%
      rename(
        "Fighter_Id" = "Fighter_Id_2",
        "Fighter" = "Fighter_2",
        "strikes.landed" = "STR_2",
        "strikes.absorbed" = "STR_1"
      )
  )%>%
  inner_join(
    flw.champion.fights,
    by = "Fighter",
    keep = F
  )%>%
  mutate(
    Date = as.Date(Date),
    Fight.Date = as.Date(Fight.Date)
  )%>%
  group_by(Fighter
  )%>%
  filter(
    Date <= Fight.Date
  )%>%
  arrange(Fighter, Date)%>%
  mutate(
    counter = 1,
    cumulative.fight.time = cumsum(total.time.seconds),
    cumulative.strikes.absorbed = cumsum(strikes.absorbed),
    cumulative.strikes.landed = cumsum(strikes.landed),
    cumulative.fight.count = cumsum(counter)
  )%>%
  mutate(
    belt.icon = "belt.icon.png"
  )


plot.16 <- ggplot(
  data = table.champions.cumulative.flw,
  aes(
    x = cumulative.fight.count,
    y = cumulative.strikes.absorbed
  )
)+
  geom_line(
    aes(
      colour = Fighter
    ),
    linewidth = 2,
    alpha = 0.7
  )+
  geom_image(
    data = 
      table.champions.cumulative.flw%>%
      group_by(Fighter)%>%
      filter(Date == max(Date)),
    aes(
      x = cumulative.fight.count,
      y = cumulative.strikes.absorbed,
      image = belt.icon),
    size = 0.07
  )+
  theme(
    legend.position = c(0.95, 0.05),   # x = 0.95, y = 0.95 → top-right
    legend.justification = c("right", "bottom"),
    plot.background = element_rect(fill = "grey15", colour = NA),
    panel.background = element_rect(fill = "grey15", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey30"),
    legend.background = element_rect(fill = "grey30", colour = NA),
    axis.text.x = element_text(size = 10)
  )+
  labs(
    x = "Cumulative Number of Fights",
    y = "Cumulative Number of Significant Strikes Absorbed",
    title = "Total Fights and Strikes Absorbed Before First Title, Flyweight",
    caption = "Source: Source: Aditya Ratan, UFC Datasets (1994–2025), Kaggle"
  )




# Reach + Ape Index ---------------------------------------------------------------

table.ape.index <-
  data.fighters.stats%>%
  left_join(
    data.fighters.profile%>%
      select(
        Fighter_Id,
        Reach
      ),
    by = "Fighter_Id"
  )%>%
  mutate(
    Ht. = as.character(Ht.)
  )%>%
  separate(
    Ht.,
    c("height.feet","height.inches"),
    sep = "\\."
   )%>%
  mutate(
    Height = ((as.numeric(height.feet) * 12) + (as.numeric(height.inches))),
    ape.index = Reach / Height
  )%>%
  filter(
    !str_detect(Weight_Class, "Women"),
    Weight_Class != "Catch Weight",
    Weight_Class != "Open Weight"
               )%>%
  mutate(
    Weight_Class = factor(
      Weight_Class,
      levels = c("Flyweight",
                 "Bantamweight",
                 "Featherweight",
                 "Lightweight",
                 "Welterweight",
                 "Middleweight",
                 "Light Heavyweight",
                 "Heavyweight")
    )
  )


table.ape.index.outliers <-
  table.ape.index %>%
  group_by(Weight_Class) %>%
  slice_max(ape.index, n = 1, with_ties = FALSE) %>%
  bind_rows(
    table.ape.index %>%
      group_by(Weight_Class) %>%
      slice_min(ape.index, n = 1, with_ties = FALSE)
  ) %>%
  mutate(
    label = paste0(Full.Name, " (", round(ape.index, 2), ")")
  )
    

plot.17 <- ggplot(
  data = table.ape.index,
  aes(
    x = Weight_Class,
    y = Reach
  )
)+
  geom_jitter(
    aes(
     # size = ape.index,
      colour = Weight_Class,
    ),
    alpha = 0.7,
    #height = 0,
    size = 3,
    show.legend = F
  )+
  theme(
    plot.background = element_rect(fill = "grey20", colour = NA),
    panel.background = element_rect(fill = "grey20", colour = NA),
    text = element_text(colour = "white"),
    axis.text = element_text(colour = "white"),
    axis.title = element_text(colour = "white"),
    panel.grid = element_line(colour = "grey35"),
    legend.background = element_rect(fill = "grey30", colour = NA)
  )+
  geom_point(
    data = table.ape.index.outliers,
    colour = "white",
    height = 0,
    alpha = 0.7,
    size = 3,
    aes(
   #   size = ape.index
    )
  )+
  geom_text_repel(
    data = table.ape.index.outliers,
    aes(
      label = label
    ),
    colour = "white",
    size = 3,
    fontface = "bold",
    nudge_x = 0.3,
    direction = "y",
    hjust = 0,
    box.padding = 0.3,
    point.padding = 0.2,
    segment.color = "grey70"
  )+
  labs(
    x = "Weight class",
    y = "Reach (inches)",
    title = "Fighter Reach by Weight Class (Ape Index Outliers Highlighted)"
  )