4

Using ggplot2's guide-axis n.dodge = 2, I get the following:

enter image description here

Is there a (hopefully simple) way to extend the tick marks for the three labels on the right, so that they become some sort of leader lines?

Řídící
  • 248
  • 1
  • 9
  • 1
    I like this request ... unfortunately I think it's a FR and not something that is currently (easily) supported. I hope I'm wrong :-) – r2evans Nov 04 '22 at 19:21
  • 2
    A brilliant way to do this is described here: https://gist.github.com/sdtaylor/4f92f0e620aada78ae4c07472d20d973 – MarBlo Nov 04 '22 at 21:26

2 Answers2

1

The code in this answer was made by Shawn Taylor and accessed at the following link: https://gist.github.com/sdtaylor/4f92f0e620aada78ae4c07472d20d973. I simply copy the code and the output here in case the link no longer works in the future.


library(tibble)
library(ggplot2)
library(forcats)

#------------------------------------
# Have x-axis labels offset slightly for clarity using guide_axis(n.dodge = 2),
# but also have different length tickmarks to make  it look nicer. 
# See https://twitter.com/ecologyofgavin/status/1344102509585997824
# Derived from https://stackoverflow.com/a/51312611/6615512
# Requires ggplot 3.0.0 or greater
#------------------------------------

# Some data to plot
lizards = tribble(
  ~group, ~n,
  'Ag',   5,
  '0-3',  8,
  '8-10', 7.5,
  '12-15',8,
  '20-32',7.8,
  'Natural',8.1
)
# put groups in order defined above
lizards$group = fct_inorder(lizards$group)

# Tick mark lengths adjusted here
top_y_pos = 2
bot_y_pos = 0.8
custom_ticks = tribble(
  ~group, ~y_end,
  'Ag',     top_y_pos,
  '0-3',    bot_y_pos,
  '8-10',   top_y_pos,
  '12-15',  bot_y_pos,
  '20-32',  top_y_pos,
  'Natural',bot_y_pos
)

ggplot(lizards, aes(x=group,y=n)) + 
  geom_point(aes(color=group),size=8) + 
  scale_color_viridis_d() +
  scale_x_discrete(guide = guide_axis(n.dodge = 2)) + 
  geom_linerange(data = custom_ticks, aes(x=group, ymax=2.7, ymin=y_end), # The custom tickmarks
                 size=2,
                 inherit.aes = F) + 
  theme_bw(50) + 
  coord_cartesian(clip='off', ylim=c(3,10)) + # clip off allow geoms, here the tickmarks, to be drawn outside the plots
  theme(legend.position = 'none',
        axis.title = element_blank(),    
        panel.border = element_rect(color='black'), # make the border and y ticks match the custom ticks
        axis.ticks.y = element_line(color='black'),
        axis.ticks.x = element_blank()) # turn offf the regular tickmarks
#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
#> ℹ Please use `linewidth` instead.

Created on 2023-01-03 with reprex v2.0.2

bretauv
  • 7,756
  • 2
  • 20
  • 57
0

I recently spent quite a bit of time banging my head on this for a more general solution: Here's one I came up with based largely on this other StackOverflow solution.

This function elongates every other tick along a certain axis (and thus generalizes across facets:

library(tidyverse)
library(grid)
library(gridExtra)

add_dodged_ticks <- function(plot, axis = 'bottom') {
  plot_grob <- ggplotGrob(plot)
  plot_grob$layout %>% as.tibble() %>%
    rownames_to_column('index') %>%
    filter(str_detect(name, paste0('axis-',axis[0]))) %>% 
    pull(index) %>% as.numeric() %>% 
    map(function(x) {
      ticks <- plot_grob$grobs[[x]]$children[[2]]$grobs[[1]]$y
      fourseq <- ifelse(length(ticks) < 3, 3, length(ticks)) 
      for (i in 1:length(ticks)) {
        if (i %in% seq(3, fourseq, 4)) {
          plot_grob$grobs[[x]]$children[[2]]$grobs[[1]]$y[[i]] <<- unit(1,'npc') - unit(12,'pt')
        }
      }
    })
  return(plot_grob)
}

I was successfully able to convert the output of this function (a ggplotGrob) to a regular ggplot object with the as_ggplot() function from ggpubr:

library(ggpubr)
add_dodged_ticks(your_plot_here, axis = 'bottom') %>% as_ggplot()