geom_segment not recognising factored x-axis

659 Views Asked by At

Aim: produce a bar plot representing a time series of measurements (variables) taken at 14 Sites (factors), including drawing horizontal lines to demonstrate benchmark levels for each site.

Problem: As the site labels are discrete and not quite a continuous series, i had to factorised the sites in ggplot mapping. However, when attempting to use geom_segment to add the benchmark lines, they are shifted in the same way the bars were drawn prior to factorising the sites. But, as.factor doesn't work in the mapping of geom_segment in the same way as ggplot mapping. Please help.

ive checked another similar question and tried both solutions: Order of x-axis with geom_segment

neither + scale_x_discrete(limits = levels(m_df$sites)) or

+ scale_x_discrete(drop = FALSE)

Data:

df <- tibble(
  sites = c(2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
  T1 = c(6, 2, 4, 7, 8, 6, 2, 4, 7, 8, 6, 2, 4, 5),
  T2 = c(8, 5, 6, 8, 9, 8, 5, 6, 8, 9, 8, 5, 6, 8),
  T3 = c(4, 1, 6, 3, 4, 4, 1, 6, 3, 4, 4, 1, 6, 3),
  Le = c(6.0, 2.7, 5.3, 6.0, 7.0, 6.0, 2.7, 5.3, 6.0, 7.0, 6.0, 2.7, 5.3, 5.3)
)

Melt the dataframe

m_df <-  reshape2::melt(
  df,
  id.vars = c("sites", "Le"),
  variable.name = "Year",
  value.name = "value"
)

plot the bar chart - black lines are shifted

ggplot(m_df, aes(as.factor(sites), value, fill = Year)) +
  geom_bar(stat = "identity",
           position = "dodge",
           colour = "black") +
  geom_segment(aes(
    x = sites - .45,
    xend = sites + .45,
    y = Le,
    yend = Le
  ),
  colour = "black")

enter image description here

I tried factorising which didn't work

ggplot(m_df, aes(as.factor(sites), value, fill = Year)) +
  geom_bar(stat = "identity",
           position = "dodge",
           colour = "black") +
  geom_segment(aes(
    x = as.factor(sites) - .45,
    xend = as.factor(sites) + .45,
    y = Le,
    yend = Le
  ),
  colour = "black")

Warning messages:
1: In Ops.factor(factor(Client_Ref), 0.45) :
‘-’ not meaningful for factors
2: In Ops.factor(factor(Client_Ref), 0.45) :
‘+’ not meaningful for factors

1

There are 1 best solutions below

3
On

You could change it to a factor (moved into a pre-plotting process here) and then change it back to numeric to get the numeric value of where it's plotting on the x axis:

library(tidyverse)


df <- tibble(
  sites = c(2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17),
  T1 = c(6, 2, 4, 7, 8, 6, 2, 4, 7, 8, 6, 2, 4, 5),
  T2 = c(8, 5, 6, 8, 9, 8, 5, 6, 8, 9, 8, 5, 6, 8),
  T3 = c(4, 1, 6, 3, 4, 4, 1, 6, 3, 4, 4, 1, 6, 3),
  Le = c(6.0, 2.7, 5.3, 6.0, 7.0, 6.0, 2.7, 5.3, 6.0, 7.0, 6.0, 2.7, 5.3, 5.3)
)


m_df <-  reshape2::melt(
  df,
  id.vars = c("sites", "Le"),
  variable.name = "Year",
  value.name = "value"
)

m_df %>%
  mutate(sites = factor(sites)) %>%
  ggplot(aes(sites, value, fill = Year)) +
  geom_bar(stat = "identity",
           position = "dodge",
           colour = "black") +
  geom_segment(aes(
    x = as.numeric(sites) - .45,
    xend = as.numeric(sites) + .45,
    y = Le,
    yend = Le
  ),
  colour = "black")

Created on 2022-03-31 by the reprex package (v2.0.1)

Edit - adding line to legend

You can add a line to the legend using scale_linetype_manual as follows (putting labels in as text in two places):

m_df %>%
  mutate(sites = factor(sites)) %>%
  ggplot(aes(sites, value, fill = Year)) +
  geom_bar(stat = "identity",
           position = "dodge",
           colour = "black") +
  geom_segment(aes(
    x = as.numeric(sites) - .45,
    xend = as.numeric(sites) + .45,
    y = Le,
    yend = Le,
    linetype = "Benchmark"
  ),
  colour = "black") + 
  scale_linetype_manual("By site", values = 1)

Created on 2022-04-19 by the reprex package (v2.0.1)