Reputation: 61254
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
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()
)
Upvotes: 1
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
Upvotes: 2
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
Upvotes: 4