Alex Dometrius
Alex Dometrius

Reputation: 820

Coloring geom_bars based upon values in dataset

I would like my bars to be red when the value is below zero. This is not the actual data I am working with but I hope this will create a reproduce-able example:

library(ggplot2)
library(car)

mtcars$carnames <- rownames(mtcars)
rownames(mtcars) <- 1:nrow(mtcars)

subsetCars <- as.data.frame(head(mtcars, n = 20))
subsetCars[1,4] <- -50

myplot.p <- ggplot(subsetCars, aes(x = subsetCars$carnames, y = subsetCars$hp))
myplot.p + geom_bar(stat = 'identity', 
                    fill = ifelse(subsetCars$hp > 0, "lightblue", "firebrick")) +
  coord_flip()

link to cars barplot

One bar is colored red, but not the one with the negative value. I have a similar problem with the current viz I am working on as well. Advice?

Upvotes: 0

Views: 3762

Answers (2)

Will Jones
Will Jones

Reputation: 36

The problem you are having is that when you are specifying the fill, ggplot is not assigning that aesthetic in the same order that it is for the names. So to make sure the order is preserved, you need to put the greater than zero variable with the other aesthetics.

The unfortunate side effect of this is you need to manually set the colors and remove the fill scale legend.

ggplot(subsetCars, aes(x = subsetCars$carnames, y = subsetCars$hp,
fill = hp > 0)) +
geom_bar(stat = 'identity') +
coord_flip() +
scale_fill_manual(values = c("TRUE" = "lightblue",
"FALSE" = "firebrick")) +
theme(legend.position = "none")

I hope that helps!

Upvotes: 1

Weihuang Wong
Weihuang Wong

Reputation: 13118

Note that your fill argument in geom_bar takes a vector created by ifelse, of which the first element is "firebrick" and all other elements are "lightblue". So the first (bottom-most) bar will be filled with red. However, the first bar does not correspond to the row with the negative value, since the observations have been re-ordered by carnames in alphabetical order.

A more idiomatic way of plotting your desired chart is

myplot.p <- ggplot(subsetCars, aes(x = carnames, y = hp, fill = hp < 0))
myplot.p + geom_bar(stat = 'identity') +
  scale_fill_manual("Negative hp", values = c("lightblue", "firebrick")) +
  coord_flip()

where the $ subsetting is unnecessary, as @alistaire pointed out, and the fill aesthetic can be stated in ggplot().

enter image description here

Upvotes: 2

Related Questions