Consistently place an arrow relative to a plot regardless of that plot's range

Viewed 53

I need to make several copies of the same kind of plot and would like all of them to have a little arrow below the x-axis to help the reader. However, the only way I have found of placing such an arrow is the geom_segment element which requires me to specify start and end points which change according to the range of data.

Ideally, if I could access the values at which ggplot2 places tickmarks along the x-axis, that would solve my problem as I could use those as start and end points.

A minimal example is:

library(dplyr)
library(tidyr)
library(ggplot2)

data <- mtcars %>% 
  mutate(names = rownames(mtcars)) %>% 
  pivot_longer(c("mpg", "cyl", "disp"), names_to = "type", values_to = "val") %>% 
  select(names:val)

data1 <- mtcars %>% 
  mutate(names = rownames(mtcars)) %>% 
  filter(mpg > 15) %>% 
  pivot_longer(c("mpg", "cyl", "disp"), names_to = "type", values_to = "val") %>% 
  select(names:val)

facet_df <- data.frame(
  type = "mpg"
)

plot_func <- function(df) {
  df %>% ggplot +
    geom_point(aes(x = val, y = names)) +
    facet_wrap(facets = vars(type), ncol = 3, scales = "free_x") +
    geom_segment(data = facet_df, x = 11, xend = 14, y = -1, yend = -1,
                 arrow = arrow(length = unit(3, "pt"))) +
    coord_cartesian(clip = "off")
}

plot_func(data)
plot_func(data1)

plot_func(data)

enter image description here

plot_func(data1)

enter image description here

1 Answers
library(dplyr)
library(tidyr)
library(grid)
library(ggplot2)

data <- mtcars %>% 
  mutate(names = rownames(mtcars)) %>% 
  pivot_longer(c("mpg", "cyl", "disp"), names_to = "type", values_to = "val") %>% 
  select(names:val)

data1 <- mtcars %>% 
  mutate(names = rownames(mtcars)) %>% 
  filter(mpg > 15) %>% 
  pivot_longer(c("mpg", "cyl", "disp"), names_to = "type", values_to = "val") %>% 
  select(names:val)

facet_df <- data.frame(
  type = "mpg"
)

plot_func <- function(df) {
  p <- df %>% ggplot +
    geom_point(aes(x = val, y = names)) +
    facet_wrap(facets = vars(type), ncol = 3, scales = "free_x") +
    # xlab(expression(atop("val", symbol('\256'))))+
    labs(
     x = NULL
    ) +
    coord_cartesian(clip = "off") +
    theme(
      plot.margin=unit(c(0.3,0.3,1.4,0.3), "cm")
    )
  print(p)
  grid.lines(x = c(0.4, 0.7), 
             y = c(0.08, 0.08),
             arrow = arrow(type="open", ends="last", angle = 40,
                          length=unit(3,"mm")))
  grid.text(x = 0.58, y = 0.035, label = "val", )
}

plot_func(data)

plot_func(data1)

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

Does this work for You??

Related