Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Left-adjust (hjust = 0) vertical x axis labels on facets with free scale

Tags:

r

ggplot2

I have decided to rephrase this question. (Editing would have taken more time and in my opinion would also not have helped the OP.)

How can one left-adjust (hjust = 0, i.e., in text direction) over facets, when scale = 'free_x'?

I don't really think that left-adjustment of x-labels is a very necessary thing to do (long labels generally being difficult to read, and right-adjusting probably the better choice) - but I find the problem interesting enough.

I tried with empty padding to the maximum character length, but this doesn't result in the same length for all strings. Also, setting axis.text.x = element.text(margin = margin()) doesn't help. Needless to say, hjust = 0 does not help, because it is adjusting within each facet.

library(ggplot2)

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

ggplot(data = diamonds, aes(cut_label, carat)) +
  facet_grid(~ cut, scales = "free_x") +
  theme(axis.text.x = element_text(angle = 90))

enter image description here

The red arrows and dashed line indicate how the labels should adjust. hjust = 0 or margins or empty padding do not result in adjustment of those labels over all facets.

Data modification from this famous question

like image 432
tjebo Avatar asked Mar 14 '20 12:03

tjebo


2 Answers

I tried with empty padding to the maximum character length, but this doesn't result in the same length for all strings.

This caught my attention. Actually, it would result in the same length for all strings if you padded the labels with spaces, made them all the same length, and ensured the font family was non-proportionally spaced.

First, pad the labels with spaces such that all labels have the same length. I'm going to ustilise the str_pad function from the stringr package.

library(ggplot2)

data("diamonds")

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

library(stringr)
diamonds$cut_label <- str_pad(diamonds$cut_label, side="right",
                              width=max(nchar(diamonds$cut_label)), pad=" ")

Then, you may need to load a non-proportionally-spaced font using the extrafont package.

library(extrafont)
font_import(pattern='consola')  # Or any other of your choice.

Then, run the ggplot command and specify a proportionally spaced font using the family argument.

ggplot(data = diamonds, aes(cut_label, carat)) +
  facet_grid(~cut, scales = "free_x") +
  theme(axis.text.x = element_text(angle = 90, family="Consolas"))

enter image description here

like image 149
Edward Avatar answered Nov 10 '22 16:11

Edward


One way, and possibly the most straight forward hack, would be to annotate outside the coordinates.

Disadvantage is that the parameters would need manual adjustments (y coordinate, and plot margin), and I don't see how to automate this.

library(ggplot2)

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

ann_x <- data.frame(x = unique(diamonds$cut_label), y = -16, cut = unique(diamonds$cut))

ggplot(data = diamonds, aes(cut_label, carat)) +
  facet_grid(~cut, scales = "free_x") +
  geom_text(data = ann_x, aes(x, y, label = x), angle = 90, hjust = 0) +
  theme(
    axis.text.x = element_blank(),
    plot.margin = margin(t = 0.1, r = 0.1, b = 2.2, l = 0.1, unit = "in")
  ) +
  coord_cartesian(ylim = c(0, 14), clip = "off")

Created on 2020-03-14 by the reprex package (v0.3.0)

like image 38
tjebo Avatar answered Nov 10 '22 18:11

tjebo