21

Below is a reproducible example of the issue I am trying to solve. I have created a heatmap of sorts in ggplot2 and things have been going well. Since I have put percentage signs on the data to use with geom_text I would like to make the legend of geom_tile also to display percent signs (I can only multiply the actual values by 100 right now). Ideally I would like the legend bar on the right to show 8%, 4%, 0%, -4%, -8%.

#load in libraries
require(plyr)
require(dplyr)
require(reshape2)
require(ggplot2)
require(scales)

testDF <- structure(list(strategies = structure(c(8L, 7L, 6L, 5L, 4L, 3L, 
                                                  2L, 1L), .Label = c("Class 1", "Class 2", 
                                                                      "Class 3", "Class 4", "Class 5", "Class 6", 
                                                                      "Class 7", "Class 8"), class = "factor"), 
                         School1 = c(0.0355662887589396, 0.0316753241146625, 0.00606392341292672, 
                                     0.0250738342627283, -0.0405709181701368, 0.0237665074609996, 
                                     0.00587364885411765, -0.0343914002059331), School2 = c(NA, NA, 
                                                                                            NA, 0.0225535750673764, NA, -0.00448947685878404, NA, -0.0446386763157662
                                     ), School3 = c(NA, NA, NA, 0.0261099462365593, NA, 0.0199735626692146, 
                                                    NA, -0.0272279264519992), School4 = c(NA, NA, NA, 0.0164004151291513, 
                                                                                          NA, 0.00567638888888868, NA, -0.0384017249374949)), .Names = c("schools", 
                                                                                                                                                         "School1", "School2", "School3", "School4"), row.names = c(NA, -8L), class = "data.frame")


GraphMelt <- melt(testDF)
GraphMelt <- GraphMelt %>% mutate(text = sprintf("%1.2f%%", 100*value))
GraphMelt[,"text"] <- ifelse(GraphMelt[,"text"]=="NA%",NA,GraphMelt[,"text"])                                    
p <- ggplot(GraphMelt, aes(variable, schools))
p <- p + geom_tile(aes(fill = value*100), colour =   "white") + geom_text(aes(label=text),size=7)
p <- p + scale_fill_gradient(low = "red", high = "green",limits=c(-8,8))
p <- p + theme(
  axis.text.x= element_text(color="black", size=14, vjust=0.5),
  axis.text.y= element_text(color="black", size=14, vjust=0.5),
  axis.title.y = element_text(color="black",size=14, vjust=0.5),
  plot.title = element_text(color="black",size=14,face="bold", hjust=0.5,vjust=1),
  panel.background = element_blank(),
  legend.position="right",
  legend.title = element_blank(),
  legend.key = element_rect(fill="white"), legend.background = element_rect(fill=NA)
)
p <- p + xlab("") + ylab("") + ggtitle("Schools")
Trevor Nederlof
  • 2,546
  • 5
  • 22
  • 40
  • Just a suggestion---next time, instead of `dput`ing raw data, then loading plyr and dplyr and reshape2 and reshaping into `GraphMelt`, then plotting, just use `dput(GraphMelt)` so the code in your question is simpler and we don't have to load 3 extra packages to run your code. Thanks for making things reproducible! – Gregor Thomas Mar 23 '15 at 15:54
  • Thats really good feedback and makes total sense. Still trying to get the hang of posting here, I try to only ask questions when I am really stuck. My next post will be better! – Trevor Nederlof Mar 23 '15 at 16:08
  • 1
    No worries! You're already doing very well making reproducible examples---the challenge is making them minimal without cutting out too much. In this case it's all about a plot display option, so the data manipulation isn't necessary. Sometimes, though, it is important to see a bit more of the process, like if there's a potential bug there. – Gregor Thomas Mar 23 '15 at 16:15

1 Answers1

34

Load the scales package (you already have it, but I want to be explicit about this dependency)

library(scales)

and add labels = label_percent() to your fill scale (or use scales::label_percent() if you don't want to use library(scales) for whatever reason).

scale_fill_gradient(low = "red", high = "green", limits = c(-8, 8), labels = scales::label_percent())
Arthur Yip
  • 5,810
  • 2
  • 31
  • 50
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • 1
    Cant believe it was that simple. Should have read the docs more for scales. Really helpful package. Thanks again for your advice. – Trevor Nederlof Mar 23 '15 at 16:09
  • I really appreciate this answer, it fixed two problems I was having with a map. – Andrew Brēza May 01 '20 at 20:06
  • 1
    For me `labels = percent` did not work. However, `labels = scales::percent` did work. For the sake of the googlers, when I tried `labels = percent` it threw the error: `Error in check_breaks_labels(breaks, labels) : object 'percent' not found` – Brad Turek Sep 19 '20 at 03:08
  • @BradTurek Yeah, you either need to do `scales::percent` as in your comment, or `library(scales)`, as in my answer. I'll edit to make the choice clearer. – Gregor Thomas Sep 19 '20 at 16:30
  • @GregorThomas, funnily enough, I did have `library(scales)` in my source as you suggested; but perhaps I forgot to run my source from the start to *actually* use it. Thanks for the great answer! – Brad Turek Sep 19 '20 at 20:12
  • 2
    Please note that percent() and percent_format() are retired; please use label_percent() instead. – Arthur Yip Sep 19 '21 at 07:48
  • 1
    Adding to @ArthurYip - `scales::label_percent()` has to be called as a function, so your code would look like `scale_fill_gradient2(labels = scales::label_percent())` – Dannid Mar 30 '23 at 21:15