Reputation: 777
Using this dataset, I created this graph:
I wish to shade under the geom_smooth
lines, like so:
I want points only under the blue line or only under the pink line to have those colors, and everything under both lines to be dark-grey.
I used this code to create the graph:
p3 <- ggplot(df, aes(x = SECONDS, y = AGE, color = GENDER)) +
geom_point() + theme_fivethirtyeight_mod() + ggtitle('Seconds vs. Age') +
geom_hline(yintercept = 0, size = 1.2, colour = "#535353") +
geom_vline(xintercept = 0, size = 1.2, colour = "#535353") +
geom_smooth(se = F) +
geom_ribbon(aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))), alpha = 1)
The code for theme_fivethirtyeight_mod()
is this:
require(ggplot2)
require(ggthemes)
require(ggrepel)
require(grid)
require(gtable)
theme_fivethirtyeight_mod <- function (base_size = 12, base_family = "sans") {
(theme_foundation(base_size = base_size, base_family = base_family) +
theme(line = element_line(colour = "black"),
rect = element_rect(fill = ggthemes_data$fivethirtyeight["ltgray"], linetype = 0, colour = NA),
text = element_text(colour = ggthemes_data$fivethirtyeight["dkgray"]),
axis.text = element_text(size = 11, colour = ggthemes_data$fivethirtyeight["dkgray"], face = "bold"),
axis.ticks = element_blank(),
axis.line = element_blank(),
axis.title = element_text(size = 11, colour = ggthemes_data$fivethirtyeight["dkgray"], face = "bold", vjust = 1.5),
legend.title = element_blank(),
legend.background = element_rect(fill="gray90", size=.5, linetype="dotted"),
legend.position = "bottom",
legend.direction = "horizontal",
legend.box = "vertical",
panel.grid = element_line(colour = NULL),
panel.grid.major = element_line(colour = ggthemes_data$fivethirtyeight["medgray"]),
panel.grid.minor = element_blank(),
plot.title = element_text(hjust = 0.05, size = rel(1.5), face = "bold"),
plot.margin = unit(c(1, 1, 1, 1), "lines"),
panel.background = element_rect(fill = "#F0F0F0"),
plot.background = element_rect(fill = "#F0F0F0"),
panel.border = element_rect(colour = "#F0F0F0"),
strip.background = element_rect()))
}
Thanks for all the help!
EDIT:
@MLavoie commented a link to a question that gave me a basic idea of how to shade under the geom_smooth
lines by using a predict(loess(AGE ~ SECONDS))
. predict()
works like geom_smooth
, and loess
is the method used when n < 1000
.This enabled me to shade under the male and female lines, but did not allow me to find the area under both curves. The dark-grey shaded area is the area under the geom_smooth
for the entire dataset.
I suspect that to find the area under the male and female curves I would first need to capture the data from the geom_smooth
s (male and female). I would then create a data.frame
with the x-values as rows and a column for each set of y-values. I would find the minimum y-value for each x-value and I would shade the dark-grey underneath that curve.
Interestingly, the shaded areas are outlined in a light blue, like the points, and the legend shows red or blue outlined boxes filled with a dark-grey color. I added this to the code instead of the original geom_ribbon
:
geom_ribbon(data = df[df$GENDER == 'F',], aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))), alpha = 1, fill = "red") +
geom_ribbon(data = df[df$GENDER == 'M',], aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))), alpha = 1, fill = "blue") +
geom_ribbon(aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))), alpha = 1)
That was the only new code involved in creating this graph:
In essence, I want to remove the blue outlines of the filled areas and I want to remove the dark-grey fill from the boxes in the legend, and if someone can figure out how I would love to shade the area underneath both lines. Thanks again!
Upvotes: 5
Views: 3340
Reputation: 1344
Switch off the legend either for the colours or for the fill to get what you want.
Switching off colours legend:
p3 <- ggplot(df, aes(x = SECONDS, y = AGE, color = GENDER)) +
geom_point() +
theme_fivethirtyeight_mod() +
ggtitle('Seconds vs. Age') +
geom_hline(yintercept = 0, size = 1.2, colour = "#535353") +
geom_vline(xintercept = 0, size = 1.2, colour = "#535353") +
geom_smooth(se = F) +
geom_ribbon(data = df[df$GENDER == 'F',],
aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS)),
fill = "Female"),colour = F) +
geom_ribbon(data = df[df$GENDER == 'M',],
aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS)),
fill = "Male"),colour = F) +
geom_ribbon(aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))),
colour = F) +
scale_fill_manual(values = c('Female' = 'red','Male' = 'blue')) +
guides(colour = F)
Switching off fill legend:
p4 <- ggplot(df, aes(x = SECONDS, y = AGE, color = GENDER)) +
geom_point() +
theme_fivethirtyeight_mod() +
ggtitle('Seconds vs. Age') +
geom_hline(yintercept = 0, size = 1.2, colour = "#535353") +
geom_vline(xintercept = 0, size = 1.2, colour = "#535353") +
geom_smooth(se = F) +
geom_ribbon(data = df[df$GENDER == 'F',],
aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))),
fill = 'red',colour = F) +
geom_ribbon(data = df[df$GENDER == 'M',],
aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))),
fill = 'blue',colour = F) +
geom_ribbon(aes(ymin = 0, ymax = predict(loess(AGE ~ SECONDS))),
colour = F) +
guides(fill = F)
Few points to note:
geom_ribbon
. If you want to shade the intersection of the areas under the other two ribbons, shading the area under the loess for the full data does not give you the intersection - you can observe that by making the graphs less opaque (by specifying alpha
< 1)alpha
=1 by default, so you don't need to specify it explicitly.Upvotes: 1