Home > Blockchain >  Slightly change geom_segment's position of x only, but keep position of xend constant
Slightly change geom_segment's position of x only, but keep position of xend constant

Time:12-03

I want to draw a bar chart with three columns, where two arrows start from one column to the other two columns and these arrows do not overlap each other, as shown below.

enter image description here

I managed to produce the chart and I used geom_segments to draw the arrows. However, the arrows overlap when they start from the column control.

enter image description here

I thought I could handle the problem by setting geom_segment(..., position = position_nudge(x = 0.25)). However, this changes not only the position of x but also xend. Then, how should I slightly change geom_segment's position of x only, keeping the position of xend constant?

enter image description here

MWE

library(tidyverse)

demoData <- tribble(
  ~priming, ~rt,
  "control", 374,
  "phonological", 267,
  "orthographic", 304
) |>
mutate(
  diff.from.baseline = rt - first(rt)
)
  
baseline <- demoData |>
  filter(priming == "control") |>
  dplyr::select(rt) |>
  pull()

demoData |>
  ggplot(
    aes(
      x = priming,
      y = rt
    )
  )  
  geom_col()  
  #### from control to orthographic
  geom_segment(
    aes(
      x = "control",
      y = baseline,
      xend = "control",
      yend = baseline   50
    )#,
    #position = position_dodge2(
    #  width = 0.5,
    #  preserve = "total"
    #  )
    #position = position_nudge(
    #  x = 0.25,
    #  xend = 0
    #)
  )  
  geom_segment(
    aes(
      x = "control"    0.25,
      y = baseline   50,
      xend = "orthographic",
      yend = baseline   50
    )#,
    #position = position_dodge2(
    #  width = 1,
    #  preserve = "total"
    #  )
    #position = position_nudge(
    #  x = 0.25,
    #  xend = 0
    #)
  )  
  geom_segment(
    aes(
      x = "orthographic",
      y = baseline   50,
      xend = "orthographic",
      yend = demoData |>
        filter(priming == "orthographic") |>
        dplyr::select(rt) |>
        pull()
    ),
    arrow = arrow()
  )  
  #### from control to phonological
  geom_segment(
    aes(
      x = "control",
      y = baseline,
      xend = "control",
      yend = baseline   100
    )
  )  
  geom_segment(
    aes(
      x = "control",
      y = baseline   100,
      xend = "phonological",
      yend = baseline   100
    )
  )  
  geom_segment(
    aes(
      x = "phonological",
      y = baseline   100,
      xend = "phonological",
      yend = demoData |>
        filter(priming == "phonological") |>
        dplyr::select(rt) |>
        pull()
    ),
    arrow = arrow()
  )

CodePudding user response:

Here's an approach:

segments <- data.frame(seg = rep(c(1:2), each = 4),
                       x = c(0.8, 0.8, 3, 3, 1.2, 1.2, 2, 2),
                       y = c(as.numeric(demoData[1,2]), 450, 
                                        450, as.numeric(demoData[3,2]),
                            as.numeric(demoData[1,2]), 425, 
                                       425, as.numeric(demoData[2,2])))

ggplot()  
  geom_path(data = segments, aes(x, y, group = seg), arrow = arrow())  
  geom_col(data = demoData, 
           aes(x = as.numeric(factor(demoData$priming, 
                                     levels = demoData$priming)), rt))  
  scale_x_continuous(breaks = 1:3, labels = demoData$priming)

enter image description here

  • Related