0

I am using the ndodge function explained by @jan-glx here; https://stackoverflow.com/a/60650595/13399047

However I could not figure out how to align the axis ticks aligned as for example; like this

I should probably use theme(axis.ticks.length=) but I am not sure how to do it in an even/odd way.

Please help!

r2evans
  • 77,184
  • 4
  • 55
  • 96
Jesse
  • 13
  • 5
  • Why not wrap or line break the axis text? like here: https://stackoverflow.com/questions/21878974/auto-wrapping-of-labels-via-labeller-label-wrap-in-ggplot2 – Peter May 18 '20 at 15:08
  • @Peter Because I have a lot of groups on my x-axis which already have an angle of 90 and use ndodge to make all the labels readable; therefore it would be even better to read if the ticks align with the labels – Jesse May 18 '20 at 15:16
  • Fair enough. I don't fully understand in what way do you mean aligning the tick marks with the labels? Do you mean as in the plot you have included in your question? How did you achieve the longer tick marks over ...Good and ... Premium? – Peter May 18 '20 at 15:27

2 Answers2

2

As far as I am aware there is no build in way to do this in ggplot, though that might change when they rewrite the guide system.

It is neither pretty nor easy, but here is an example how you could do it by messing around in the gtable / grid.

library(ggplot2)
library(grid)
data(diamonds)
diamonds$cut <- paste("Super Dee-Duper",as.character(diamonds$cut))

g <- ggplot(diamonds, aes(cut, carat)) + 
  geom_boxplot() +
  scale_x_discrete(guide = guide_axis(n.dodge = 2))

# Convert to gtable
gt <- ggplotGrob(g)

# Grab bottom axis
is_axis <- grep("axis-b", gt$layout$name)
axisgrob <- gt$grobs[is_axis][[1]]
axis <- axisgrob$children$axis

# Grab tickmarks
is_ticks <- which(vapply(axis$grobs, inherits, logical(1), "polyline"))
ticks <- axis$grobs[[is_ticks]]

# Modify tickmarks
labelheight <- axis$heights[[2]] # First row of labels
modify <- which(seq_along(ticks$y) %% 4 == 0) - 1 # Change every the 3rd item in every quadruplet
ticks$y[modify] <- ticks$y[modify] - labelheight

# Insert ticks back into axis back into table
axis$grobs[[is_ticks]] <- ticks
axisgrob$children$axis <- axis
gt$grobs[[is_axis]] <- axisgrob

# Plot
grid.newpage()
grid.draw(gt)

Created on 2020-05-18 by the reprex package (v0.3.0)

teunbrand
  • 17,545
  • 3
  • 14
  • 30
0

Here is a solution using just ggplot2 stuff and not modifying any grobs. It requires ggplot2 3.0.0 and is based off https://stackoverflow.com/a/51312611/6615512

library(ggplot2)
data(diamonds)
diamonds$cut <- paste("Super Dee-Duper",as.character(diamonds$cut))


tick_min_pos_odd = -0.6
tick_min_pos_even = -0.4
custom_ticks = data.frame(cut = sort(unique(diamonds$cut)))
n_discrete_x_values = nrow(custom_ticks)

# Alternate tick lengths
custom_ticks$tick_min_pos = ifelse(1:n_discrete_x_values %% 2 == 0, tick_min_pos_odd, tick_min_pos_even)

ggplot(diamonds, aes(cut, carat)) + 
  geom_boxplot() +
  scale_x_discrete(guide = guide_axis(n.dodge = 2)) +  
  geom_linerange(data = custom_ticks,                        # The custom tickmarks
                 aes(x=cut, ymax=-0.25, ymin=tick_min_pos), 
                 size=0.5, color='black',
                 inherit.aes = F) +
  coord_cartesian(clip='off', ylim=c(0,NA)) +        # Clip off makes it so the geoms can be drawn outside the plot
                                                     # ylim sets the y-axis from 0 to the max.
  theme(plot.margin = margin(0,0,20,0),              # Add some whitespace to the bottom of the plot
        axis.title.x = element_text(vjust=-1.5),     # nudge the x-axis title and text down a tad
        axis.text.x = element_text(vjust=-1.5))

enter image description here

Shawn
  • 224
  • 2
  • 7