Reputation: 1299
I'd like to be able to control the color of a geom_line based on a logical test. For my actual application this is a line plot overlaid on a bar plot, but hopefully this simple example will get me close enough
Starting with
library(ggplot2)
library(dplyr)
library(babynames)
data <- babynames %>%
filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
filter(sex=="F")
data <- data %>% group_by(name) %>%
mutate(change = n - lag(n)) %>%
mutate(meanC = mean(change, na.rm = TRUE)) %>%
ungroup()
data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )
minYear = min(data$year)
maxYear = max(data$year)
namePlot <- data %>%
ggplot(mapping = aes(x=year, y=n)) +
geom_line(show.legend = FALSE) +
geom_label(aes(label=label, x = 1950, y=40000)) +
facet_wrap(~ name)
print(namePlot)
I get
Then using a bit of a hack I got from elsewhere on this site, I can color the labels based on whether the value in the label is negative or not
library(ggplot2)
library(dplyr)
library(babynames)
data <- babynames %>%
filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
filter(sex=="F")
data <- data %>% group_by(name) %>%
mutate(change = n - lag(n)) %>%
mutate(meanC = mean(change, na.rm = TRUE)) %>%
ungroup()
data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )
minYear = min(data$year)
maxYear = max(data$year)
namePlot <- data %>%
ggplot(mapping = aes(x=year, y=n)) +
geom_line(show.legend = FALSE) +
geom_label(aes(label=label, x = 1950, y=40000),
color = c("forestgreen", "red")[1+grepl("\\-\\d",data$label)]) +
facet_wrap(~ name)
print(namePlot)
Which produces
Now I'd like to make the line itself red or green to match the label color. I tried using the same hack (thought that would be too easy)
library(ggplot2)
library(dplyr)
library(babynames)
data <- babynames %>%
filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
filter(sex=="F")
data <- data %>% group_by(name) %>%
mutate(change = n - lag(n)) %>%
mutate(meanC = mean(change, na.rm = TRUE)) %>%
ungroup()
data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )
minYear = min(data$year)
maxYear = max(data$year)
namePlot <- data %>%
ggplot(mapping = aes(x=year, y=n)) +
geom_line(show.legend = FALSE,
color = c("forestgreen", "red")[1+grepl("\\-\\d",data$label)]) +
geom_label(aes(label=label, x = 1950, y=40000),
color = c("forestgreen", "red")[1+grepl("\\-\\d",data$label)]) +
facet_wrap(~ name)
print(namePlot)
And got this
Thanks in advance!
Upvotes: 1
Views: 203
Reputation: 37913
I think because geom line orders the data on the x-axis the colour you're trying to feed the layers are out of sync with the data as it is handled under the hood.
You could counter this by simply mapping the colour to an aesthetic, and adding a scale for the correct colours. Example below:
library(ggplot2)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(babynames)
data <- babynames %>%
filter(name %in% c("Ashley", "Patricia", "Mary", "Minnie")) %>%
filter(sex=="F")
data <- data %>% group_by(name) %>%
mutate(change = n - lag(n)) %>%
mutate(meanC = mean(change, na.rm = TRUE)) %>%
ungroup()
data$label <- paste(data$name,"\n",round(data$meanC,0),sep="" )
minYear = min(data$year)
maxYear = max(data$year)
namePlot <- data %>%
ggplot(mapping = aes(x=year, y=n)) +
geom_line(show.legend = FALSE,
aes(colour = grepl("\\-\\d", label))) +
geom_label(aes(label=label, x = 1950, y=40000,
colour = grepl("\\-\\d", label))) +
scale_colour_manual(
name = "Negative?",
values = c("forestgreen", "red")
) +
facet_wrap(~ name)
print(namePlot)
If you're really intent on keeping the colour outside of the mappings, you could use geom_path()
instead.
namePlot <- data %>%
ggplot(mapping = aes(x=year, y=n)) +
geom_path(show.legend = FALSE,
color = c("forestgreen", "red")[1+grepl("\\-\\d",data$label)]) +
geom_label(aes(label=label, x = 1950, y=40000),
color = c("forestgreen", "red")[1+grepl("\\-\\d",data$label)]) +
facet_wrap(~ name)
The resulting plot is almost the same but without a legend.
Upvotes: 1