Asked  7 Months ago    Answers:  5   Viewed   45 times

I've been getting up to speed with R in the last month.

Here is my question:

What is a good way to assign colors to categorical variables in ggplot2 that have stable mapping? I need consistent colors across a set of graphs that have different subsets and different number of categorical variables.

For example,

plot1 <- ggplot(data, aes(xData, yData,color=categoricaldData)) + geom_line()

where categoricalData has 5 levels.

And then

plot2 <- ggplot(data.subset, aes(xData.subset, yData.subset, 
                                 color=categoricaldData.subset)) + geom_line()

where categoricalData.subset has 3 levels.

However, a particular level that is in both sets will end up with a different color, which makes it harder to read the graphs together.

Do I need to create a vector of colors in the data frame? Or is there another way to assigns specific colors to categories?

 Answers

42

For simple situations like the exact example in the OP, I agree that Thierry's answer is the best. However, I think it's useful to point out another approach that becomes easier when you're trying to maintain consistent color schemes across multiple data frames that are not all obtained by subsetting a single large data frame. Managing the factors levels in multiple data frames can become tedious if they are being pulled from separate files and not all factor levels appear in each file.

One way to address this is to create a custom manual colour scale as follows:

#Some test data
dat <- data.frame(x=runif(10),y=runif(10),
        grp = rep(LETTERS[1:5],each = 2),stringsAsFactors = TRUE)

#Create a custom color scale
library(RColorBrewer)
myColors <- brewer.pal(5,"Set1")
names(myColors) <- levels(dat$grp)
colScale <- scale_colour_manual(name = "grp",values = myColors)

and then add the color scale onto the plot as needed:

#One plot with all the data
p <- ggplot(dat,aes(x,y,colour = grp)) + geom_point()
p1 <- p + colScale

#A second plot with only four of the levels
p2 <- p %+% droplevels(subset(dat[4:10,])) + colScale

The first plot looks like this:

enter image description here

and the second plot looks like this:

enter image description here

This way you don't need to remember or check each data frame to see that they have the appropriate levels.

Tuesday, June 1, 2021
 
cusejuice
answered 7 Months ago
96

ggplot can use colorbrewer palettes. Some of these are "photocopy" friendly. So mabe something like this will work for you?

ggplot(diamonds, aes(x=cut, y=price, group=cut))+
geom_boxplot(aes(fill=cut))+scale_fill_brewer(palette="OrRd")

in this case OrRd is a palette found on the colorbrewer webpage: http://colorbrewer2.org/

Photocopy Friendly: This indicates that a given color scheme will withstand black and white photocopying. Diverging schemes can not be photocopied successfully. Differences in lightness should be preserved with sequential schemes.

Tuesday, June 1, 2021
 
BetaRide
answered 7 Months ago
40

It's an R FAQ -- you need print() around it, or a ggsave() which is particular to ggplot2.

From the FAQ:

7.22 Why do lattice/trellis graphics not work?

The most likely reason is that you forgot to tell R to display the graph. Lattice functions such as xyplot() create a graph object, but do not display it (the same is true of ggplot2 graphics, and Trellis graphics in S-Plus). The print() method for the graph object produces the actual display. When you use these functions interactively at the command line, the result is automatically printed, but in source() or inside your own functions you will need an explicit print() statement.

Tuesday, June 15, 2021
 
inVader
answered 6 Months ago
78

vrajs5 you are not alone! We struggled with this issue. In our case we wanted to fill bar charts like in ggplot. This is the solution. You need to add specifically named columns, linked to your variables, to your data table for googleVis to pick up.

In my fill example, these are called roles, but once you see my syntax you can abstract it to annotations and other cool features. Google has them all documented here (check out superheroes example!) but it was not obvious how it applied to r.

@mages has this documented on this webpage, which shows features not in demo(googleVis):

http://cran.r-project.org/web/packages/googleVis/vignettes/Using_Roles_via_googleVis.html

EXAMPLE ADDING NEW DIMENSIONS TO GOOGLEVIS CHARTS

# in this case
# How do we fill a bar chart showing bars depend on another variable? 
#   We wanted to show C in a different fill to other assets

suppressPackageStartupMessages(library(googleVis))
library(data.table) # You can use data frames if you don't like DT

test.dt  = data.table(px = c("A","B","C"), py = c(1,4,9),
                      "py.style" = c('silver', 'silver', 'gold'))

# Add your modifier to your chart as a new variable e.g. py1.style
test <-gvisBarChart(test.dt, 
                    xvar = "px",
                    yvar = c("py", "py.style"),
                    options = list(legend = 'none'))
plot(test)

We have shown py.style deterministically here, but you could code it to be dependent on your categories.

The secret is myvar.googleVis_thing_youneed linking the variable myvar to the googleVis feature.

RESULT BEFORE FILL (yvar = "py") GoogleVisBarChartBeforeRoleStyleExample

RESULT AFTER FILL (yvar = c("py", "py.style"))

GoogleVisBarChartRoleStyleExample

Take a look at mages examples (code also on Github) and you will have cracked the "categorization based on column values" issue.

Thursday, August 5, 2021
 
Hilmi
answered 4 Months ago
59

You have to change colormap and 4th parameter of octave's scatter. The parameter is vector 1xn indexing colormap. You can have maximally 255^3 vectors. And how to do that?

Example solution:

  1. Set colormap (matrix 3 x n), which will contain each color exactly ones
  2. Use as 4th parameter vector, which is containing each number exactly ones, and has same size like x and y

clf;
x = randn (100, 1);
y = randn (100, 1);
cmap=[];
for R = 1:255
  for G = 1:255
    for B = 1:255
      if (size(cmap) ./ [1,3] == size(x))
        break;
      endif
      cmap=[cmap;R/255,G/255,B/255];

    endfor
    if (size(cmap) ./ [1,3] == size(x))
        break;
    endif
  endfor 
 if (size(cmap) ./ [1,3] == size(x))
        break;
 endif 
endfor

colormap(cmap);

scatter(x,y,20, 1:100);
Saturday, August 7, 2021
 
axiomer
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share