vestland
vestland

Reputation: 61254

How to customize ggplot2 axis labels with different colors when values are continuous

The post customize ggplot2 axis labels with different colors describes how you can change the colors of each label when each (discrete) value in your data source has got its own corresponding label. But how do you efficiently reference and format each label when you have a larger dataset and each value in that dataset is not represented by its own value (which quickly becomes the case for continuous values)?

Upvotes: 1

Views: 1356

Answers (3)

Paul
Paul

Reputation: 9107

Selectively colouring axis text can be done more idiomatically using labels in scale_y_continuous paired with ggtext::element_markdown().

scale_y_continuous takes a parameter labels which can be a function. This function maps a break value to the text that is displayed on the plot.

Use the ggtext package to interpret the y axis text as markdown.

library(ggplot2)

set.seed(123)
df <- data.frame(
  x = rnorm(10, mean = 0, sd = 1),
  y = rnorm(10, mean = 0, sd = 1)
)

ggplot(df, aes(x, y)) +
  geom_line() +
  scale_y_continuous(
    labels = \(break_value) {
      dplyr::case_when(
        break_value %in% c(-1, -2) ~ paste0("<span style = 'color:red'>", break_value, "</span>"),
        break_value == 1 ~ paste0("<span style = 'color:blue'>", break_value, "</span>"),
        TRUE ~ as.character(break_value)
      )
    }
  ) +
  theme(
    axis.text.y = ggtext::element_markdown()
  )

Selectively Coloured Axis Text

Upvotes: 1

Andrew M
Andrew M

Reputation: 540

For ggplot2 >= 3.3.0, the scales use proto now. Here's a new hack that seems to work. This whole approach remains very fragile, and ggplot throws a warning about supplying a vector to element_text. It would be worth finding a more robust solution.

# settings
library(ggplot2)
set.seed(123)

# data
A = rnorm(10, mean=0, sd=1)
B = rnorm(10, mean=0, sd=1)
df <- data.frame(A,B)

# initial plot
plt1 <- ggplot(data = df) + aes(x=A, y=B)+geom_line()

# retrieve lables using ggplot_build()
yLabVals <- as.numeric(ggplot_build(plt1)$layout$panel_params[[1]]$y$get_labels())    
# create color list
yLabs <- ifelse(yLabVals < 0, "red", "blue")
yLabs[yLabVals == 0] <- 'black'

# plot
plt2 <- plt1 + theme(axis.text.y = element_text(angle = 0, hjust = 1, colour = yLabs))
plt2

ggplot output

Upvotes: 2

vestland
vestland

Reputation: 61254

The following will work for ggplot2 3.0.0. For earlier versions of ggplot2, the exact structure of ggplot_build(plt1)$layout$panel_params[[1]]$y.label will vary.


In the reproducible dataset and corresponding chart below, you'll se that both columns A and B in the dataframe df have 10 observations, and that B displayed on the y-axis is assigned with 4 labels. Using the ggplot_build() and theme() you can reference and format the y labels any way you like. Below, negative and positive numbers are assigned the colors red and blue, respectively. Zero remains black.

Snippet

# settings
library(ggplot2)
set.seed(123)

# data
A = rnorm(10, mean=0, sd=1)
B = rnorm(10, mean=0, sd=1)
df <- data.frame(A,B)

# initial plot
plt1 <- ggplot(data = df) + aes(x=A, y=B)+geom_line()

# retrieve lables using ggplot_build()
yLabVals <- as.numeric(ggplot_build(plt1)$layout$panel_params[[1]]$y.labels)

# create color list
yLabs <- ifelse(yLabVals < 0, "red", "blue")
yLabs[yLabVals == 0] <- 'black'

# plot
plt2 <- plt1 + theme(axis.text.y = element_text(angle = 0, hjust = 1, colour = yLabs))
plt2

Plot

enter image description here

Upvotes: 4

Related Questions