4

Is it possible, in ggplot2, to colorize labels for a group of points?

I would like to color some of the left-hand-side text labels in the plot below to show the swing states in red colour, in addition to the red marker shown in the plot itself:

electoral dot plot

The code (with data) is here. -- edited to reflect answer

The plot is far from perfect, so additional suggestions are very welcome. There are far better graphs out there if anyone's interested (but I'm not good enough to code them).

Community
  • 1
  • 1
Fr.
  • 2,865
  • 2
  • 24
  • 44
  • In your link for colouring labels, instead of just using "red" you could use a colour vector of blue and red etc , colouring the labels in the order they appear in your axis – user1317221_G Jan 13 '13 at 14:26
  • Does this answer your question? [customize ggplot2 axis labels with different colors](https://stackoverflow.com/questions/38862303/customize-ggplot2-axis-labels-with-different-colors) – camille Dec 29 '21 at 14:59
  • @camille yes, it looks like the answer below. – Fr. Jan 01 '22 at 22:09

3 Answers3

7

Colors of labels (axis texts) are set by argument element_text= in function theme(). You can set different colors for each label. As there is a column Swing with levels, it can be used to set colors.

dw_plot + theme(axis.text.y = element_text(colour = ifelse(dw_data$Swing=="Swing State","red","grey")))
Didzis Elferts
  • 95,661
  • 14
  • 264
  • 201
  • Brilliant! Thank you very much. The [documentation](http://docs.ggplot2.org/current/element_text.html) should mention that. Have a nice day. – Fr. Jan 13 '13 at 15:02
4

The answers stated above work as of today; however, they throw warning which discourages from using the suggested method with ifelse inside element_text(). The reason why vectorisation in element_text() is not documented in ggplot2 is because it is not supported feature (it works due to a chance). Please see the following issue on GitHub where this specific problem was discussed.

The answers provided above will result in the following warning:

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

The following code illustrates the point (using slightly updated example provided by SlowLearner - original data are not available) and shows my solution that supports the vectorisation using the ggtext package and element_markdown().

library(ggplot2); packageVersion("ggplot2")
# ‘3.3.0’
library(ggtext); packageVersion("ggtext") #; install.packages("ggtext") # https://github.com/wilkelab/ggtext
# ‘0.1.0’

set.seed(1234)
df <- data.frame(state = paste("State_", LETTERS, sep = ""), 
                margin = runif(26, -50, 50), 
                swing = rep(c("no", "yes", "no"), times = c(10, 6, 10)))

mycolours <- c("yes" = "red", "no" = "black")

ggplot(data = df, aes(x = margin, y = state)) +
     geom_point(size = 5, aes(colour = swing)) +
     scale_color_manual("Swing", values = mycolours) +
     theme(
          # The following line uses vectorisation (such as rep or ifelse).
          # This is not officially supported. Works by a chance and gives impression of a feature.
          axis.text.y = element_text(colour = rep(c("black", "red", "black"), times = c(10, 6, 10)))
          )

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

# The following code uses ggtext method # element_markdown(),
# This is how this question should be solved because the vectorisation method may not work in the future inside element_text().
ggplot(data = df, aes(x = margin, y = state)) +
     geom_point(size = 5, aes(colour = swing)) +
     scale_color_manual("Swing", values = mycolours) +
     theme(axis.text.y = element_markdown(colour = rep(c("black", "red", "black"), times = c(10, 6, 10))))
# No warning occurs. This will also correctly calculate other aesthetic such as size.
gofraidh
  • 673
  • 8
  • 26
3

Other answer already accepted, but just as a visual example... For more complex schemes you can simply add a column to the data frame with the required colours and reference that instead of using 'red' and 'black' as per below.

library(ggplot2)

set.seed(1234)
x <- data.frame(state = paste("State_", LETTERS, sep = ""), 
   margin = runif(26, -50, 50), swing = rep("no", 26))
x[c(10:15), 'swing'] <- "yes"
mycolours <- c("yes" = 'red', "no" = "black")

ggplot(data = x, aes(x = margin, y = state)) +
    geom_point(size = 5, aes(colour = swing)) +
    scale_color_manual("Swing", values = mycolours) +
    theme(axis.text.y = element_text(colour = 
        ifelse(x$swing == 'yes', 'red', 'black'))) +
    theme()

screenshot

SlowLearner
  • 7,907
  • 11
  • 49
  • 80
  • Your method might be simpler than my code, so thanks -- and thanks again for your comprehension at Cross Validated. My data, however, is a bit more complex because of the 2008/2012/swing three elements. I hope to simplify the code in the future. – Fr. Jan 13 '13 at 15:42
  • @Fr. Yes, your data (and chart) is more complex while this is just a minimal reproducible example. I looked at your original code and it seemed serviceable so I assume you'll be able to patch things together. – SlowLearner Jan 13 '13 at 21:59