29

I want to color only one bar in ggplot. This is my data frame:

area <- c("Północ", "Południe", "Wschód", "Zachód")
sale <- c(16.5, 13.5, 14, 13)
df.sale <- data.frame(area, sale)
colnames(df.sale) <- c("Obszar sprzedaży", "Liczba sprzedanych produktów (w tys.)")

And code for plotting:

plot.sale.bad <- ggplot(data=df.sale, aes(x=area, y=sale, fill=area)) +
  geom_bar(stat="identity") +
  scale_fill_manual(values=c("black", "red", "black", "black")) +
  xlab(colnames(df.sale)[1]) +
  ylab(colnames(df.sale)[2]) +
  ggtitle("Porównanie sprzedaży") 

I would like to have only one bar colored and 3 others to have default color (darkgrey, not black, it looks bad for me). How can I change color of only on bar or how to get name of the default color of bars to put them instead of black?

Russ Thomas
  • 938
  • 4
  • 13
  • 23
jjankowiak
  • 3,010
  • 6
  • 28
  • 45
  • If you don't want to map `fill` to 'area', why do you use it in your `aes`? It might be better to add a variable to your data frame that reflects the conditions you wish map to `fill`. But you need to describe your objectives more clearly. – Henrik Apr 06 '14 at 12:56
  • I want to distinguish second bar form others by color and other bars should have default, unchanged color. That's what I want. – jjankowiak Apr 06 '14 at 13:03
  • For the example you've provided, `scale_fill_manual` is spot on. If you want to do it more "programmatically" then you'll need to provide some indicator (calculation, `cut` range, etc) that would make it possible to determine which bar(s) should be a different color. For your example, what condition indicated that `Południe` should be red? – hrbrmstr Apr 06 '14 at 13:12

2 Answers2

37

If you like having everything in the ggplot call, you can use an ifelse statement within factor() for the fill as shown below.

This also separates the legend into two categories (i.e. highlighted and not highlighted) so that you aren't repeating the values shown on the x axis. This also provides another illustrative dimension to the plot in the legend.

plot.sale.bad2 <- ggplot(data=df.sale,
                         aes(x=area,
                             y=sale,
                             fill=factor(ifelse(area=="Południe","Highlighted","Normal")))) +
  geom_bar(stat="identity") +
  scale_fill_manual(name = "area", values=c("red","grey50")) +
  xlab(colnames(df.sale)[1]) +
  ylab(colnames(df.sale)[2]) +
  ggtitle("Porównanie sprzedaży") 

plot.sale.bad2

Plot with legend

If the legend isn't needed you can add show.legend = FALSE to the geom_bar() call to produce the following:

Plot without legend

YBS
  • 19,324
  • 2
  • 9
  • 27
Russ Thomas
  • 938
  • 4
  • 13
  • 23
28

Option 1: Change color of only one bar. Following Henrick's suggestion, you can create a new variable with NAs for the default color and character strings/factors for non-default colors (the first one happens to be red):

area.color <- c(NA, "withcolor", NA, NA)
plot.sale.bad <- ggplot(data=df.sale, aes(x=area, y=sale, fill=area.color)) +
  geom_bar(stat="identity") +
  xlab(colnames(df.sale)[1]) +
  ylab(colnames(df.sale)[2]) +
  ggtitle("Porównanie sprzedaży") 
plot.sale.bad

Option 2: Find the name of the default dark gray color you like. This is not the default color if you simply remove the scale_fill_manual line in your original code (in that case, you get four different pastels), so I assume you mean the grey color produced by the code chunk just above this paragraph, for those bars where area.color==NA. In that case, you might look at the source code (or args, anyway) for scale_fill_discrete:

> args(scale_fill_discrete)
# function (..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, 
#     direction = 1, na.value = "grey50") 
# NULL

The default for na.value is "grey50". So if you wanted to use scale_fill_manual, you could do it like so:

plot.sale.bad <- ggplot(data=df.sale, aes(x=area, y=sale, fill=area)) +
  geom_bar(stat="identity") +
  scale_fill_manual(values=c("grey50", "red", "grey50", "grey50")) +
  xlab(colnames(df.sale)[1]) +
  ylab(colnames(df.sale)[2]) +
  ggtitle("Porównanie sprzedaży") 
plot.sale.bad
pangia
  • 1,164
  • 10
  • 11
  • Just a small update, as the `area.colour <- c(NA, "withcolor", NA, NA)` did not work for me (bars 1, 3 and 4 were simply missing). Instead, I used `area.colour <- c("one", "two", "one", "one")` and then `scale_fill_manual(values = c("gray50", "red"))`, which worked like a charm (and you can easily control legend labels with whatever is in `area.colour`). – m-dz Apr 26 '16 at 08:33