Jesse
Jesse

Reputation: 13

ggplot - Align ticks with axis

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!

Upvotes: 0

Views: 560

Answers (2)

Shawn
Shawn

Reputation: 382

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

Upvotes: 0

teunbrand
teunbrand

Reputation: 37913

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)

Upvotes: 2

Related Questions