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.

Community
  • 1
  • 1
Phil
  • 7,287
  • 3
  • 36
  • 66
  • 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. – baptiste Dec 04 '16 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. – Phil Dec 04 '16 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. – baptiste Dec 04 '16 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. – Jake Kaupp Dec 04 '16 at 21:25
  • @JakeKaupp Should I use df[["var"]] instead? – Phil Dec 04 '16 at 21:40
  • You just refer to the column by name, bare, no quotes – Jake Kaupp Dec 04 '16 at 22:03

0 Answers0