Customize Ggplot2 Axis Labels With Different Colors

customize ggplot2 axis labels with different colors

You can provide a vector of colors to the axis.text.x option of theme():

a <- ifelse(data$category == 0, "red", "blue")

ggplot(data, aes(x = x, y = y)) +
geom_bar(stat = "identity", aes(fill = category)) +
theme(axis.text.x = element_text(angle = 45, hjust = 1, colour = a))

Sample Image

Ggplot2 vary x axis label colors

One option to achieve your desired result would be to make use of the ggtext package which allows for styling of labels and theme elements via markdown or HTML.

As you offered no information about the type of chart you are trying to achieve I went for a bar chart:

dates = seq.Date(from =as.Date("01/01/2020", "%d/%m/%Y"), 
to=as.Date("01/03/2021", "%d/%m/%Y"), by="month")

y = c(1:1:15)
df = data.frame(dates,y)

mylabs <- function(x) {
cols <- ifelse(lubridate::year(x) == 2020, "blue", "green")
glue::glue("<span style = 'color: {cols}'>{format(x, '%b %Y')}</span>")
}

library(ggplot2)
library(ggtext)
library(lubridate)

ggplot(df, aes(dates, y, fill = lubridate::year(dates) == 2020)) +
geom_col() +
scale_x_date(date_breaks = "1 month",
labels = mylabs,
guide = guide_axis(n.dodge = 2),
expand = c(.01, .01)) +
scale_fill_manual(values = c("TRUE" = "grey", "FALSE" = "grey"),
labels = c("TRUE" = 2020, "FALSE" = 2021)) +
theme(axis.text.x = ggtext::element_markdown()) +
labs(fill = NULL, x = NULL, y = NULL) +
guides(fill = guide_legend(override.aes = list(fill = c("blue", "green"))))

Sample Image

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

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

Sample Image

Customize ggplot2 axis labels with specific colours

Adding to my own and Jon's comment you could add something like

f <- function(x){
d <- rep('black', NROW(x))
one <- which(x %in% c("08:00", "15:00", "18:30"))
two <- which(x %in% c("07:00", "15:30", "19:00", "21:00"))
d[one] <- '#FF9999'
d[two] <- '#0000FF'
d
}
colour <- f(df$time)

plot +
theme(axis.text.x = element_text(color = colour,
angle = 90))

Note that you will get a warning

Warning message:
Vectorized input to element_text() is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.

But it does work. It is however not aware of the tick labels themselves. By this I mean it will colour based on position in colour compared to the position on the axis. So You'll need to match the position somehow (I might have "misaligned" the colours in my example)

ggplot change the x axis label colors dynamically

I'm not entirely sure what the issue is here (I mean I understand that you provide the colors in the wrong order; in the theme you would have to use col[as.integer(df$color)] to mimic the order of the factor but I have no clue why) but I have a workaround that works well.

One less known function in ggplot2 is ggplot_build. Using this you can, as the name suggests, build the plot, which means you can extract the values you want from it. Based on this I wrote a little function which can do what you want.

axis_text_color <- function(plot, col = "fill") {
c <- ggplot_build(plot)$data[[1]]
plot +
theme(axis.text.y = element_text(colour = c[[col]]))
}

The way you use it is by first saving the plot in an object:

library(tidyverse)
plot <- ggplot(df, aes(
x = PCP,
y = percentage,
fill = color_fill,
color = color
)) +
geom_col() +
coord_flip() +
labs(x = "PCP Name",
y = "Percentage of Gap Closures",
title = "TOP 10 PCPs") +
scale_fill_manual(values = col) +
scale_color_manual(values = col) +
scale_y_continuous(labels = scales::percent_format(), limits = c(0, 1)) +
theme(
legend.position = "none",
panel.grid = element_blank(),
panel.background = element_blank(),
text = element_text(size = 15),
plot.caption = element_text(hjust = 0, face = "italic")
)

And then calling the function on that plot:

axis_text_color(plot)

Sample Image

Created on 2020-01-20 by the reprex package (v0.3.0)

R: Discrete axis labels with multiple colors in ggplot2

The vectorised input may not be supported by element_text(), but ggplot2 does support custom theme elements (ie, element_markdown()). Hence, you can write your own custom theme elements that just handles the vectorisation of the colour variable. Now, you don't have a scary warning, don't depend on ggtext, but do have the maintainer's responsibility to ensure this keeps working. If you're worried that the good folks of ggplot2 might change element_text() or element_grob.element_text(), you can write out your class' methods in full, instead of relying that the ggplot2 classes stay the same into perpetuity.

library(ggplot2)

element_text2 <- function(..., color = NULL) {
# Explicitly don't pass colour
# Note: user can still pass `colour`, but I'm not here to write perfect code,
# just to give a working example
elem <- element_text(...)
elem$colour <- color # Assign after element is constructed
class(elem) <- c("element_text2", "element_text", "element") # Re-class
elem
}

# S3 Method for your custom class' drawing code
element_grob.element_text2 <- function(element, label = "", ...,
colour = NULL) {
# Repeat colour to match length of label, if colour exists
if (length(colour)) {
colour <- rep_len(colour, length(label))
}
# Re-class to old class
class(element) <- c("element_text", "element")
# Call element_grob.element_text method
element_grob(element, label = label, ..., colour = colour)
}

mtcars |>
dplyr::mutate(
color =
c("BLUE", "RED") |> rep_len(dplyr::n()) |>
factor()
) |>
ggplot(aes(x = mpg, y = color)) +
geom_point() +
theme(axis.text.y.left = element_text2(color = c("blue", "red"))) +
labs(y = "")

Sample Image

Created on 2022-08-09 by the reprex package (v2.0.1)

how to add colored tick label to ggplot2?

One option to add some colored squares beneath your colored labels would be via an additional geom_text layer. As the label I use a filled square with UTF-8 code "\u25A0".

Using some fake random data to mimic your real data:

library(ggplot2)

ggplot(df, aes(x = Var2, y = Var1)) +
geom_tile(fill = "white", color = "gray") +
geom_point(aes(color = cor, size = log.P)) +
labs(color = "Correlation") +
scale_size_continuous(
range = c(1, 12), name = "P value",
guide = guide_legend(override.aes = list(colour = "grey")), breaks = bb, labels = labels
) +
scale_x_discrete(position = "top", limits = x) +
geom_text(aes(label = cor), color = "black", size = 4, vjust = 2.5) +
# Add square ticks
geom_text(data = data.frame(x = x, y = 7.5), aes(x = x, y = y), color = x, label = "\u25A0", size = 6, vjust = 0) +
scale_color_gradient2(low = "blue", mid = "white", high = "red") +
theme_minimal() +
theme(
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.x = element_text(size = 15, angle = 40, hjust = 0.1, vjust = 0.1, color = x),
axis.text.y = element_text(size = 15),
legend.text = element_text(size = 15),
legend.title = element_text(size = 15),
legend.key.height = unit(0.7, "cm"),
panel.grid.major.x = element_blank()
)

Sample Image

DATA

set.seed(123)

x <- c("Blue", "Magenta", "Yellow", "Brown", "Pink", "Red", "Grey")

df <- data.frame(
Var2 = rep(x, 7),
Var1 = rep(1:7, each = 7),
cor = round(runif(49, -1, 1), 2),
log.P = runif(49, 0, 10)
)

Coloring ggplot2 axis tick labels based on data displayed at axis tick positions

It's important to realize that when you're writing axis.text.y = element_text(color = ...), you're not mapping data to colors using the regular ggplot2 mapping mechanism, you're manually assigning colors to specific axis labels. Therefore, the colors you assign need to be exactly in the right order.

When you inspect your data frame, you can see that the rows are not in the order in which they are plotted; the order is set by the levels of the name factor. Therefore, you have to use that order for your colors as well. You can do that using the order() function:

colors <- top_bot_5_both$color[order(top_bot_5_both$name)]

Now, with this color vector, we can make the plot as intended:

ggplot(top_bot_5_both, aes(x = name, y = score, fill = Party)) +
geom_col(size = 1, color = "black") +
coord_flip() +
geom_vline(xintercept = 10.5, size = 1.5, linetype = "twodash") +
scale_fill_manual(values = c("Democratic" = "#1A80C4", "Republican" = "#CC3D3D")) +
theme(axis.text = element_text(size = 12),
axis.text.y = element_text(color = colors),
axis.title = element_text(size = 14),
legend.position = "bottom",
legend.title = element_blank())

Sample Image

Vary colors of axis labels in R based on another variable

If you ignore the vectorised possibilities like text and mtext, you can get there by repeatedly calling axis. The overhead timewise will be very minimal and it will allow all the axis calculations to occur as they normally do. E.g.:

# original code
grid = structure(c(1:12),.Dim = c(4,3))
labs = c("A","B","C")
image(1:4,1:3,grid,axes=FALSE, xlab="", ylab = "")
axiscolors = c("black","red","black")

# new code
Map(axis, side=2, at=1:3, col.axis=axiscolors, labels=labs, lwd=0, las=1)
axis(2,at=1:3,labels=FALSE)

Resulting in:

Sample Image



Related Topics



Leave a reply



Submit