2

I recognize that this has been an issue that's been asked in many other instances, but none of the solutions provided worked for my particular problem.

Here, I have the following data:

library(tidyverse)
library(scales)
mydata <- tibble(Category = c("A", "B", "C", "D"),
                 Result = c(0.442, 0.537, 0.426, 0.387),
                 A = c(NA, "A", NA, NA),
                 B = rep(NA, 4),
                 C = c(NA, "C", NA, NA),
                 D = c("D", "D", NA, NA))
mydata$Category <- factor(mydata$Category)

And I have the following vector for the colors:

colors_vct <- c(A = "#0079c0", B = "#cc9900", C = "#252525", D = "#c5120e")

With this information, I can create the following plot:

p <- ggplot(data = mydata , aes(x = Category, y = Result, fill = Category)) + 
geom_bar(stat = "identity") + geom_text(aes(label = percent(Result), color = Category), hjust = -.25) +
coord_flip() + scale_y_continuous(limits = c(0,1), labels = percent) + 
scale_colour_manual(values = colors_vct) + scale_fill_manual(values = colors_vct)
p

enter image description here

And I'd like to have little triangles appear after the labels based on whether a certain category is mentioned in the last 4 columns of mydata, colored by that category's color, as so:

p <- p + geom_text(data = filter(mydata, mydata[,3] == "A"), aes(label = sprintf("\u25b2")), colour = colors_vct["A"], hjust = -4)
#p <- p + geom_text(data = filter(mydata, mydata[,4] == "B"), aes(label = sprintf("\u25b2")), colour = colors_vct["B"], hjust = -5) #This is commented out because there are no instances where the layer ends up being applied.
p <- p + geom_text(data = filter(mydata, mydata[,5] == "C"), aes(label = sprintf("\u25b2")), colour = colors_vct["C"], hjust = -6)
p <- p + geom_text(data = filter(mydata, mydata[,6] == "D"), aes(label = sprintf("\u25b2")), colour = colors_vct["D"], hjust = -7)
p

enter image description here

This is what I want the final chart to look like (more or less, see bonus question below). Now, I'd like to iterate the last bit of code using a for loop. And this is where I'm running into trouble. It just ends up adding one layer only. How do I make this work? Here is my attempt:

#Set the colors into another table for matching:
colors_tbl <- tibble(Category = levels(mydata$Category),
                                colors = c("#0079c0", "#cc9900", "#252525", "#c5120e"))

for (i in seq_along(mydata$Category)) {
if (is_character(mydata[[i]])) { #This makes the loop skip if there is nothing to be applied, as with category B.
#Filters to just the specific categories I need to have the triangles shown.
    triangles <- filter(mydata, mydata[,(i+2)] == levels(mydata$Category)[i])
#Matches up with the colors_tbl to determine which color to use for that triangle.
    triangles <- mutate(triangles, colors = colors_tbl$colors[match(levels(triangles$Category)[i], colors_tbl$Category)])
#Sets a particular position for that triangle for the hjust argument below.
    pos <- -(i+3)
#Adding the layer to the plot object
 p <- p + geom_text(data = triangles, aes(label = sprintf("\u25b2")), color = triangles$colors, hjust = pos)
  }
}
p

enter image description here

:(

Bonus question: Is there a way I can avoid gaps in between the triangles, as per the 2nd chart?


EDIT: As per @baptiste 's suggestion, I re-processed the data as such:

mydata2 <- mydata %>% gather(key = comp, value = Present, -Result, -Category) 
mydata2 <- mydata2 %>% mutate(colors = colors_tbl$colors[match(mydata2$Present, colors_tbl$Category)]) %>%
filter(!is.na(mydata2$Present)) %>% select(-comp)
mydata2 <- mydata2 %>% mutate(pos = if_else(Present == "A", -4, if_else(Present == "B", -5, if_else(Present == "C", -6, -7))))
p <- p + geom_text(data = mydata2, aes(x = Category, label = sprintf("\u25b2")), colour = mydata2$colors, hjust = mydata2$pos)
p

Ok, I got it to work. my bonus question still stands.

6
  • one doesn't usually need a for loop in ggplot2 (I don't remember ever needing one for the past 8 years). You should be able to plot all the triangles as one layer, provided their info was summarised in a pre-processed data.frame. Commented Dec 4, 2016 at 18:42
  • @baptiste I considered that, but I was facing the problem of making the triangles appear multiple times with their different colors. Also, my intent is to create a function that will automate the process, so I need to allow some dynamism in terms of how many categories there are. Commented Dec 4, 2016 at 18:52
  • a more elegant solution to the gap problem would be to create a custom geom I think, but one should be able to figure out the required pos/hjust values from the data.frame mydata2 to avoid those gaps. Commented Dec 4, 2016 at 21:24
  • Be wary of the $ references in the dplyr verbs. Unless you're referring to data outside the pipe it's not required and can cause issues. Commented Dec 4, 2016 at 21:25
  • @JakeKaupp Should I use df[["var"]] instead? Commented Dec 4, 2016 at 21:40

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.