loki
loki

Reputation: 10340

Two font faces in ggplot labels

I am trying to create a bar plot with two font faces for the y labels (don't confuse: it's called x due to coord_flip()). However, I have not found any solution for this on the internet.

Is it even possible?

I've got this so far.

library(ggplot2)

labs <- paste(rep("1st", 40), rep("2nd", 40), rep("3rd", 40))
labs <- strsplit(labs, " ")

v1 <- ggplot(data.frame(x = 1:40, y = 1:40), aes(x,y)) + 
  geom_bar(stat = "identity", fill = "grey50") + 
  coord_flip() + 
  scale_x_discrete(labels = paste(sapply(labs, "[[", 1), 
                                  .(bold(.(sapply(labs, "[[", 2)))),
                                  sapply(labs, "[[", 3)), 
                   breaks = 1:40)
v1

I want to be the 2nd in all ylabs as bold face. Yet, I get this: enter image description here

The tick labels should look like this ([=====] indicate the bars in the plot):

1st 2nd 3rd [================================]

1st 2nd 3rd [=============================]

1st 2nd 3rd [==========================]

...

Upvotes: 2

Views: 1295

Answers (2)

sargas
sargas

Reputation: 558

minimal example

You have to define an expression.

library(ggplot2)

all.data <- data.frame(group=c('a','b'),count=c(5,8))

ggplot(data=all.data, aes(group, count)) + 
  geom_bar(stat = "identity") + 
  scale_x_discrete(label=c( expression(paste("xxx",bold("foo"))), expression(paste("yyy",bold("bar")))  ))

enter image description here

example using variables

A post here on stackoverflow got me on the right track: Use expression with a variable r

labs <- paste(rep("1st", 40), rep("2nd", 40), rep("3rd", 40))
labs <- strsplit(labs, " ")

# create a vector of expressions
# everything in .() is evaluated and ~ forms an expression
plot.labs <- bquote( .(labs[[1]][1]) ~ bold(.(labs[[1]][2])) ~ .(labs[[1]][3]))

# produce a list of expressions
plot.labs.apply <- lapply(labs, function(x) {plot.labs <- bquote( .(x[1]) ~ bold(.(x[2])) ~ .(x[3]))})

# was it done correctly?
class(plot.labs.apply[[2]])

# i used a smaller data frame to not overload the plot
ggplot(data.frame(x = c('a','b'), y = c(40,25)), aes(x,y)) + 
    geom_bar(stat = "identity", fill = "grey50") + 
    coord_flip() + 
    scale_x_discrete(label = c(plot.labs.apply) )

enter image description here

Upvotes: 2

sargas
sargas

Reputation: 558

general

You need to change the axis.text.x instead of working directly on the scale.x.discrete.

As a side comment to create your labs vector, you can use:

labs <- rep( c("1st","2nd","3rd"), 40)
font.faces <- rep( c("plain","bold","plain"), 40 )

The bold/plain face can be done like this:

library(ggplot2)

# have some example data
all.data <- data.frame(group=c('a','b'),count=c(5,8))

ggplot(data=all.data, aes(group, count)) + 
 geom_bar(stat = "identity") + 
 # put your names here
 scale_x_discrete(label=c("foo","bar")) + 
 # put a vector assigning bold and plain here
 # e.g. you can put font.faces vector here if you have 40 labels
 theme( axis.text.x = element_text(face=c("bold","plain")) )

example

A more explicit example would be this one. Please make sure that the error about unequal amounts of elements in your ggplot statement does not result from the fact that your sample naming on the x-axis (y-axis after flipping) are repetitive. They may need to be unique.

# generate some data
all.data <- as.data.frame(matrix(seq(30), nrow = 30, ncol = 1))

# produce labels and font faces
# labels need to be unique to make sure ggplot2 doesn't summarise the categories
labs <- rep( c("1st","2nd","3rd"), 10)
labs.ext <- paste(labs, rep(seq(10), each=3), sep='_')
font.faces <- rep( c("plain", "bold", "plain"), 10)

# add a label column to the data frame (and make sure that it will be a  factor with levels in your intended order)
all.data[,2] <- factor(labs.ext, levels = labs.ext)
colnames(all.data) <- c("count","name")

# including your coord_flip(), x axis transforms to y axis
ggplot(data=all.data, aes(name, count)) + geom_bar(stat='identity') + theme(axis.text.y = element_text(face = font.faces)) + coord_flip()

example

Upvotes: 0

Related Questions