Suppose I have some data and would like to plot the forecasts and 95% prediction intervals using ggplot. The following code works and gives an acceptable legend.
ExampleData = data.frame(t = 1:10, f = rep(1,10), Lower = rep(0.5, 10), Upper = rep(1.5, 10))
library (ggplot2)
ggplot(data = ExampleData)+
geom_point(aes(x=t, y =f, colour = "Forecasts"))+
geom_point(aes(x=t, y =Lower), shape=95)+
geom_segment(aes(x=t, y = Lower, xend=t, yend = f))+
geom_point(aes(x=t, y =Upper), shape=95)+
geom_segment(aes(x=t, y = f, xend=t, yend = Upper))+
geom_vline(aes(xintercept = 11, colour = "95% PI"))+
scale_colour_manual(values = c("95% PI" = "black","Forecasts" = "red"),
guide = guide_legend(override.aes = list(
linetype = c('solid','blank'),
shape = c(NA,16))))+
scale_x_continuous(name="Time", limits=c(1, 10), breaks = c(0,5,10))+
labs(title="Example")+
labs(y = "Forecasts")+
theme_bw()
I would also like to add a horizontal line, at say y = 0.75
. However, the legend does not seem to be able to accommodate a horizontal and vertical line. Is there a way that I can use ggplot to do this? What about including shorter, horizontal lines, also? For example, the upper and lower points are represented by short horizontal lines.
If the aesthetics color
, fill
, group
, ... are defined, the element is automatically added to the legend. Therefore, something like geom_line(aes(color = 'foo'))
will produce a legend element named foo, but geom_line(color = 'black')
won't.
library (ggplot2)
ExampleData = data.frame(t = 1:10, f = 1, Lower = 0.5, Upper = 1.5)
g <- ggplot(data = ExampleData, aes(x = t))
g <- g + geom_point(aes(y = f, color = "95% PI"), size = 0)
g <- g + geom_errorbar(aes(ymin = Lower, ymax = Upper, color = "95% PI"))
g <- g + geom_point(aes(y = f), color = "red")
g <- g + geom_line(aes(y = 0.75, color = "Threshold"))
g <- g + scale_colour_manual(values = c("95% PI" = "black",
"Threshold" = "green"),
guide = guide_legend(override.aes = list(
linetype = c('blank', 'solid'),
shape = c('|', NA),
size = c(5, 0.5))))
g <- g + theme_bw()
g <- g + scale_x_continuous(name="Time", breaks = c(0, 5, 10))
g <- g + labs(title = "Example")
g <- g + labs(y = "Forecasts")
print(g)
This will produce an output like this:
To get the vertical line in the legend, I added an invisible geom_point
(size to 0, see below for the reason of this). Note that the color
aesthetics is defined, therefore the legend will be populated by this element. To add an horizontal line to the plot at fix y value, and to the legend, the easiest is to use a geom_line
element and to set the color
aesthetics. Finally, to display the red points and exclude them from the legend, you must not set the color
aesthetics.
g <- g + geom_point(aes(y = f, color = "95% PI"), size = 0)
g <- g + geom_errorbar(aes(ymin = Lower, ymax = Upper, color = "95% PI"))
g <- g + geom_line(aes(y = 0.75, color = "Threshold"))
g <- g + geom_point(aes(y = f), color = "red")
Regarding the legend, to have a vertical bar, rather than an horizontal bar (default), you can use the shape |
. This is a rather small shape by default (at least on my computer), so you may have to increase its size a bit. You can do this by playing with the guides. Note that geom_errorbar
or geom_segment
do not have the shape
property. To use a shape rather than a line, you need to add the invisible geom_point
first.
g <- g + scale_colour_manual(values = c("95% PI" = "black",
"Threshold" = "green"),
guide = guide_legend(override.aes = list(
linetype = c('blank', 'solid'),
shape = c('|', NA),
size = c(5, 0.5))))
Assuming you want the points, vertical segments, the horizontal segments and the horizontal lines all in the legend, here is my suggestion:
ExampleData = data.frame(t = 1:10, f = rep(1,10), Lower = rep(0.5, 10), Upper = rep(1.5, 10))
library (ggplot2)
tipw <- 0.2
g <- ggplot(data = ExampleData)
g <- g + geom_segment(aes(x = t, y = Lower, xend = t, yend = Upper, color = "95% PI"))
g <- g + geom_segment(aes(x = t - tipw / 2, y = Lower, xend = t + tipw / 2, yend = Lower, color = "Minimum"))
g <- g + geom_segment(aes(x = t - tipw / 2, y = Upper, xend = t + tipw / 2, yend = Upper, color = "Maximum"))
g <- g + geom_point(aes(x = t, y = f, color = "Forecasts"))
g <- g + geom_line(aes(x = t, y = 0.75, color = "Some value"))
g <- g + scale_x_continuous(name="Time", limits=c(1 - tipw/2, 10 + tipw/2), breaks = c(0, 5, 10))
g <- g + labs(title = "Example")
g <- g + labs(y = "Forecasts")
g <- g + scale_colour_manual(values = c("95% PI" = "black",
"Forecasts" = "red",
"Minimum" = "orange",
"Maximum" = "green",
"Some value" = "light blue"),
guide = guide_legend(override.aes = list(
linetype = c('solid', 'blank', 'solid', 'solid', 'solid'),
shape = c(NA, 16, NA, NA, NA))))
g <- g + theme_bw()
print(g)
tipw <- 0.2
g <- ggplot(data = ExampleData)
Creates the plot with your data. The tipw
variable is the width of the tips (using the same unit as the x-axis). See below.
g <- g + geom_segment(aes(x = t, y = Lower, xend = t, yend = Upper, color = "95% PI"))
g <- g + geom_segment(aes(x = t - tipw / 2, y = Lower, xend = t + tipw / 2, yend = Lower, color = "Minimum"))
g <- g + geom_segment(aes(x = t - tipw / 2, y = Upper, xend = t + tipw / 2, yend = Upper, color = "Maximum"))
g <- g + geom_point(aes(x = t, y = f, color = "Forecasts"))
g <- g + geom_line(aes(x = t, y = 0.75, color = "Some value"))
Adds the lines, segments and points. The elements will be stacked in the order you write them. So here the short horizontal bars at the tips will be drawn first, then the vertical bar, then the points on top of the bars and then the arbitrary horizontal line on top of the rest.
Remember you can do some logic in aesthetics of ggplot. The short horizontal bars are defined here as segments starting from x = t - tipw / 2
and ending to x = t + tipw / 2
. The long horizontal bar can be manually defined to y = 0.75
. This works because you can always use a vector of length 1 for aesthetics and the value will be used for all points (aes(x = t, y = 0.75)
gives the same result as aes(x = t, y = rep(0.75, length(t)))
).
g <- g + scale_x_continuous(name = "Time", limits=c(1 - tipw/2, 10 + tipw/2), breaks = c(0, 5, 10))
You must include the xstart and xend of the horizontal segments for them to be drawn. That's why the limits are extended by tipw/2
. Otherwise the horizontal bar on the far left and far right won't be visible, and a warning will be thrown.
Warning messages:
1: Removed 2 rows containing missing values (geom_segment).
2: Removed 2 rows containing missing values (geom_segment).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With