Captain Hat
Captain Hat

Reputation: 3237

How can I move x-axis labels away from the centre of a ggplot that uses coord_polar?

I'm making a polar-transformed barplot in which several of the x-axis labels overlap with the plot area. For context, I'm working on a shiny application that you can find a copy of here.

I've tried using theme(axis.text.x = element_text(vjust = -someNumber)), but it doesn't seem to be doing anything.

Here is a reproducible example to demonstrate the problem:

## Tiny example plot
### Libraries
require(dplyr)
#> Loading required package: dplyr
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
require(ggplot2)
#> Loading required package: ggplot2

### Data
categories <- c("foo", "bar", "baz", "biff", "zoop", "sesquipedalian")
values <- c(100, 150, 42, 135.45, 177, 182)

plotThis <- tibble(names = categories, values = values)

### Plot the plot

ggplot(plotThis, aes(x = names, y = values)) + 
  geom_bar(stat = "identity", color = "black", fill = "blue", width = 1) + 
  coord_polar(clip = "off") +
  theme_minimal() +
  scale_y_continuous(name = NULL, breaks = NULL) +
  xlab(NULL)

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

How can I move the 'sesquipedalian' label (or, if necessary, all labels) further away from the centre so that it does not overlap with the plot?

Upvotes: 3

Views: 1029

Answers (2)

Dan Adams
Dan Adams

Reputation: 5214

This doesn't look nearly as nice as the answer from @Allan Cameron using his very slick {geomtextpath} library but has the (possible) advantage of being easy to implement with native {ggplot2}. Here we simply use expand_limits() in the y direction to push the axis further from the plot and leave room for the label. It's a bit of a hack because I came up with a fudge factor for how far to expand based on the length of the label and the size of that bar. It works OK with labels of a certain size but if they get really long it will break down a bit unless you introduce a line break. Also you can add theme(plot.margin = unit(c(3, 0, 3, 0), "lines")) to get more space around the plot to avoid cutting of super long labels.

library(tidyverse)

# data
plotThis <- 
  tibble(
  names = c("foo", "bar", "baz", "biff", "zoop", "sesquipedalian"),
  values = c(100, 150, 42, 135.45, 177, 182))

# calculate scaling of axis based on longest label
new_max_y <- 
  plotThis %>% 
  mutate(nchar = nchar(names),
         new_max_y = values * (1 + 0.01 * nchar)) %>% 
  pull(new_max_y) %>% 
  max()

# plot - expand margins if names get really long
plotThis %>% 
  ggplot(aes(x = names, y = values)) +
  geom_col(color = "black", fill = "blue", width = 1) +
  coord_polar(clip = "off") +
  theme_minimal() +
  scale_y_continuous(name = NULL, breaks = NULL) +
  expand_limits(y = c(0, new_max_y)) +
  xlab(NULL)

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

Upvotes: 1

Allan Cameron
Allan Cameron

Reputation: 173898

If you switch from coord_polar to coord_curvedpolar from the geomtextpath package, you can have curved labels that never overlap the plotting area. The problem you describe was the main reason for writing coord_curvedpolar in the first place.

In addition, the x axis labels are adjustable in the radial direction using the vjust setting inside theme(axis.text.x = element_text(...)).

No other parts of your code need to change, and the other elements of the plot are exactly the same as they would be with coord_polar.

I think this makes for a much nicer looking plot (though I am possibly biased...)

library(geomtextpath)

ggplot(plotThis, aes(x = names, y = values)) + 
  geom_bar(stat = "identity", color = "black", fill = "blue", width = 1) + 
  coord_curvedpolar(clip = "off") +
  theme_minimal() +
  scale_y_continuous(name = NULL, breaks = NULL) +
  xlab(NULL) +
  theme(axis.text.x = element_text(vjust = -1, size = 15))

enter image description here

Upvotes: 4

Related Questions