Creating a consistent dynamic color palette in ggplot in a loop?

I have a dataset named d1 similar to:

location, depth.from, depth.to, val, type 

I have a loop that creates a rather complex graph for each unique location (it glues a lot of things with grid.arrange , so I can not use facet_wrap in this place to keep the legend / color compatible with one part of the plot).

Let's say that for type "4" there are 4 categories, the problem is that in one place there is a different number of "types" than the other, the assigned colors are not consistent between each plot. I can manually make them be the same, but I'm trying to generalize this function. Google failed me.

For the next block, d1 is a subset of the data based on the location type, for example.

 d1 <- subset(myData, location == location.list[i]) 

Looking at the graph that is inside the loop:

 p1 <- ggplot(data = d1, aes (y=val, x=depth.from))+ layer(geom = "point", size = 2) + geom_rect(data=d1, aes(xmin=Depth.to, xmax=Depth.from, ymin=0, ymax=100, fill = type), linetype =0, alpha=0.3)+ scale_fill_brewer(palette="Set1") 

The geom_rect command transmits data and is based on depth and depth, creating an overlay based on the fill type. I can use scale_fill_manual("Lith", c("Val1" = "DodgerBlue4"...) etc., to manually set it, but that defeats the goal. If I have types like where I want something like:

 Bird_one = blue Bird_two = red Bird_three = green 

I want bird_three be green, even if bird_two does not exist, without having to explicitly set it with scale_fill_manual . Is there a way to set a global list of names for a color palette? Perhaps by providing an array from something like:

 myData <- read.csv("mydata.csv" typeList <- unique(myData$type) 
+8
r ggplot2
source share
2 answers

Pretty late, but there really is a trivial solution by setting scale_fill_discrete(drop=F)

 plots <- lapply(dfs, function(df) { ggplot(df, aes( x=location, fill=type, y=(depth.from + depth.to) / 2, ymin=depth.from, ymax=depth.to ) ) + geom_crossbar() + scale_fill_discrete(drop=F) }) library(gridExtra) do.call(grid.arrange, plots) 

enter image description here

And here is the dummy data that I used:

 set.seed(12) items <- 2 dfs <- replicate(2, simplify=F, data.frame( location=sample(letters, items), depth.from=runif(items, -10, -5), depth.to=runif(items, 5, 10), val=runif(items), type=factor( sample(c("Bird_one", "Bird_two", "Bird_three"), items), levels=c("Bird_one", "Bird_two", "Bird_three") ) ) ) 
+5
source share

It doesn't matter if they are in a loop, you just need to associate each level with a color. In your case:

 colourList <- c(bird_one = "red", bird_two = "blue", bird_three = "green") 

In a simple example:

 #Make some data dat <- data.frame(location = rep(1:4, c(3,2,2,3)), val = rnorm(10), depth.from = sample(1:5, 10, replace = TRUE), depth.to = sample(6:10, 10, replace = TRUE), type = factor(LETTERS[c(1:3, 1,3,1,3,1:3)])) #Associate levels with colours colourList <- c(A = "red", B = "blue", C = "green") p <- list() for(i in 1:4) { d <- dat[dat$location == i,] p[[i]] <- ggplot(data = d, aes (y=val, x=depth.from))+ layer(geom = "point", size = 2) + geom_rect(aes(xmin=depth.to, xmax=depth.from, ymin=0, ymax=100, fill = type), linetype =0, alpha=0.3) + #This is where the assignment works scale_fill_manual(values=colourList) } grid.arrange(p[[1]], p[[2]]) 

You can see that the C level in both graphs is green.

In response to @BrodieG, here is a way to set colors semi-automatically. It creates a named vector using type levels and color values ​​from the RColorBrewer package. This could be pretty easy to design for inclusion in a function:

 library(RColorBrewer) colourList <- setNames(brewer.pal(length(levels(dat$type)), "Set1"), levels(dat$type)) 

As @hadley points out, in this case it’s even more straightforward to set scale limits, although in my typical use, I find it more useful to set up an object such as colourList , which can be used on multiple graphs simply by setting values . The limits setting also supports legend levels, which may or may not be what you need:

 scale_fill_brewer(limits = levels(dat$type), palette = "Set1") 

enter image description here

As @hadley points out, in this case it’s even more straightforward to set scale limits, although in my typical use, I find it more useful to set up an object such as colourList , which can be used on multiple graphs simply by setting values . The limits setting also supports legend levels, which may or may not be what you need:

 scale_fill_brewer(limits = levels(dat$type), palette = "Set1") 

enter image description here

+5
source share