Creating a second legend with ggplot? - r

I created the following plot using ggplot:
y1 <- runif(20,-2,7)
y2 <- c(-0.30306664,0.14744265 , 0.43857131 ,-0.04536794 ,-1.41432016,0.51887010 , 6.34925495 , 2.82511601 , 2.84251791, 4.05300569,-2.34208042, -0.29278747 , 0.49661933 , 0.75099908 ,1.12097713,2.72244949 , 2.23933230 , 1.86667714 , 2.17540024 , 7.56568823)
x <- 2001:2020
ggplot() +
geom_rect(aes(xmin=2006.90, xmax=2009.15,ymin=-Inf,ymax=10, fill='blue'), alpha= 0.4)+geom_rect(aes(xmin=2019.80, xmax=Inf,ymin=-Inf,ymax=10, fill='orange'), alpha= 0.3)+geom_rect(aes(xmin=2009.90, xmax=2013.15,ymin=-Inf,ymax=10, fill="lightgreen"), alpha= 0.4)+
geom_line(aes(x=x,y = y1),colour="black")+geom_line(aes(x=x,y = y2),colour="red")+
geom_point(aes(x=x,y = y1),col="black")+
geom_point(aes(x=x,y = y2),col="red")+
theme_classic()+
scale_fill_manual(name="",values = c("lightblue","lightgreen","orange"),labels=c(" R","k","C"))+theme(legend.position = "bottom")+ theme(axis.text.x = element_text(angle = 90))+geom_hline(yintercept = 0, color="black", size=1)
I have one legend to explain the content of the rectangles of the graph, but I need to add another legend to explain the two lines which are black and red. I wondered how to add another legend with a different position than the one that already exists to explain the names of the lines?
Can anyone help?

Move color inside aes, add scale_color_identity to get the right colors and to set the labels for the legend:
library(ggplot2)
ggplot() +
geom_rect(aes(xmin = 2006.90, xmax = 2009.15, ymin = -Inf, ymax = 10, fill = "blue"), alpha = 0.4) +
geom_rect(aes(xmin = 2019.80, xmax = Inf, ymin = -Inf, ymax = 10, fill = "orange"), alpha = 0.3) +
geom_rect(aes(xmin = 2009.90, xmax = 2013.15, ymin = -Inf, ymax = 10, fill = "lightgreen"), alpha = 0.4) +
geom_line(aes(x = x, y = y1, colour = "black")) +
geom_line(aes(x = x, y = y2, colour = "red")) +
geom_point(aes(x = x, y = y1, col = "black")) +
geom_point(aes(x = x, y = y2, col = "red")) +
scale_color_identity(name = NULL, labels = c(black = "Label 1", red = "Label 2"), guide = "legend") +
theme_classic() +
scale_fill_manual(name = "", values = c("lightblue", "lightgreen", "orange"), labels = c(" Rezession", "krise", "Corona 2020-")) +
theme(legend.position = "bottom") +
theme(axis.text.x = element_text(angle = 90)) +
geom_hline(yintercept = 0, color = "black", size = 1)

Related

Adjust background alpha of geom_richtext

I have below ggplot (from https://wilkelab.org/ggtext/reference/geom_richtext.html)
library(ggplot2)
df <- data.frame(
label = c(
"Some text **in bold.**",
"Linebreaks<br>Linebreaks<br>Linebreaks",
"*x*<sup>2</sup> + 5*x* + *C*<sub>*i*</sub>",
"Some <span style='color:blue'>blue text **in bold.**</span><br>And *italics text.*<br>
And some <span style='font-size:18pt; color:black'>large</span> text."
),
x = c(.2, .1, .5, .9),
y = c(.8, .4, .1, .5),
hjust = c(0.5, 0, 0, 1),
vjust = c(0.5, 1, 0, 0.5),
angle = c(0, 0, 45, -45),
color = c("black", "blue", "black", "red"),
fill = c("cornsilk", "white", "lightblue1", "white")
)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color, fill = fill,
hjust = hjust, vjust = vjust
) +
geom_richtext() +
geom_point(color = "black", size = 2) +
scale_color_identity() +
scale_fill_identity() +
xlim(0, 1) + ylim(0, 1)
I would like to add some transparency to the label background. When I apply alpha = 0.30, both text and background are affected. I there any way to adjust alpha of background?
#stefan suggested to use scales::alpha, however this is not working in below case
library(ggplot2)
library(ggtext)
ggplot(data.frame(x = c(-2, 2)), aes(x = x)) +
stat_function(fun = dnorm) +
geom_richtext(data = data.frame(x = c(-1.4, -.5), y = rep(dnorm(0, 2)), y1 = c('First', 'Second')),
aes(x = x, y = y, label = y1, fill = alpha(y1, 0.2))) +
scale_fill_manual(breaks = c('First', 'Second'), values = c('#c1121f', '#023e8a'), aesthetics = 'fill')
With this I am getting below error
Error: Unknown colour name: First
One option would be to use scales::alpha to set the alpha for the fill color:
library(ggplot2)
library(ggtext)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color, fill = fill,
hjust = hjust, vjust = vjust
) +
geom_richtext(aes(fill = alpha(fill, 0.30))) +
geom_point(color = "black", size = 2) +
scale_color_identity() +
scale_fill_identity() +
xlim(0, 1) + ylim(0, 1)
EDIT For your second example we could or have to apply scales::alpha on the values of the fill scale. This however works only if we use the fill aes only in geom_richtext. If this is not the case than of course could we still apply one of both approaches side-by-side with the ggnewscale package.
library(ggplot2)
library(ggtext)
ggplot(data.frame(x = c(-2, 2)), aes(x = x)) +
stat_function(fun = dnorm) +
geom_richtext(
data = data.frame(x = c(-1.4, -.5), y = rep(dnorm(0, 2)), y1 = c("First", "Second")),
aes(x = x, y = y, label = y1, fill = y1)
) +
scale_fill_manual(
breaks = c("First", "Second"),
values = alpha(c("#c1121f", "#023e8a"), .2),
aesthetics = "fill"
)
Here is an alternative approach:
According to the documentation of ggtext
library(ggplot2)
library(ggtext)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color,
hjust = hjust, vjust = vjust
) +
geom_richtext(
fill = NA, label.color = df$color, # remove background and outline
label.padding = grid::unit(rep(5, 10), "pt") # remove padding
) +
geom_point(color = "black", size = 2) +
scale_color_identity() +
xlim(0, 1) + ylim(0, 1)

Legend with geom_line and geom_ribbon and geom_point

I've been searching the answer for two days and still can't find how to do this. The closest cases I found here and here. But the former has no points on the plots and the latter has no answer. Without much ado, how to add points to my legend?
This is my data:
Year <- c(2003:2020)
TheData <- c(72.6, 72.7, 72.6, 72.5, 72.4, 72.1, 71.8, 71.7, 71.8, 72.3, 72.7,
72.9, 73.1, 73.3, 73.8, 74.7, 75.7, 77.1)
Lower <- c(72.33316, 72.05961, 71.8218, 71.62303, 71.46657, 71.35567, 71.29362,
71.28368, 71.32915, 71.43331, 71.59947, 71.83096, 72.13113, 72.50333,
72.95092, 73.47728, 74.08581, 74.77989)
Upper <- c(73.46626, 73.24078, 73.05676, 72.91817, 72.82899, 72.79323, 72.81489,
72.89794, 73.04639, 73.26418, 73.55528, 73.92363, 74.37315, 74.90775,
75.53132, 76.24776, 77.06094, 77.97473)
Model <- c(72.89971, 72.65020, 72.43928, 72.27060, 72.14778, 72.07445, 72.05425,
72.09081, 72.18777, 72.34874, 72.57738, 72.87730, 73.25214, 73.70554,
74.24112, 74.86252, 75.57337, 76.37731)
MyDF <- data.frame(Year, TheData, Lower, Upper, Model)
This is my code:
library("ggplot2")
ggplot(MyDF, aes(x = Year, y = TheData)) +
geom_point(aes(y = TheData), size = 2.5) +
geom_line(aes(x = Year, y = Model, color = "Model", fill = "Model")) +
geom_ribbon(aes(ymin = Lower, ymax = Upper, x = Year,
fill = "Confidence Interval"), alpha = 0.15) +
scale_colour_manual(
name = "", values = c("Confidence Interval" = "transparent",
"Model" = "black")) +
scale_fill_manual(
name = "", values = c("Confidence Interval" = "grey12",
"Model" = "transparent")) +
theme(legend.position = "bottom")
This is my plot.
If you want to get a legend you have to map on an aesthetic, e.g. you could map on the shape aes to get a legend for your points too:
library("ggplot2")
ggplot(MyDF, aes(x = Year, y = TheData)) +
geom_point(aes(y = TheData, shape = "TheData"), size = 2.5) +
geom_line(aes(x = Year, y = Model, color = "Model")) +
geom_ribbon(aes(ymin = Lower, ymax = Upper, x = Year,
fill = "Confidence Interval"), alpha = 0.15) +
scale_colour_manual(
name = "", values = c("Confidence Interval" = "transparent",
"Model" = "black")) +
scale_fill_manual(
name = "", values = c("Confidence Interval" = "grey12",
"Model" = "transparent")) +
theme(legend.position = "bottom") +
labs(shape = "")
If somebody is interested to move the legend to free space on the plot there is an obvious way to do so:
ggplot(MyDF, aes(x = Year, y = TheData)) +
geom_point(aes(y = TheData, shape = "TheData"), size = 2.5) +
geom_line(aes(x = Year, y = Model, color = "Model")) +
geom_ribbon(aes(ymin = Lower, ymax = Upper, x = Year,
fill = "Confidence Interval"), alpha = 0.15) +
scale_colour_manual(
name = "", values = c("Confidence Interval" = "transparent",
"Model" = "black")) +
scale_fill_manual(
name = "", values = c("Confidence Interval" = "grey12",
"Model" = "transparent")) +
theme(legend.position = "bottom") +
labs(shape = "") +
theme(legend.position = c(.4, .7))
But the legend appears stacked:
Adding + guides(color = guide_legend(nrow = 1)) does not work:
My colleague have proposed to add legend.box = "horizontal". This code works:
ggplot(MyDF, aes(x = Year, y = TheData)) +
geom_point(aes(y = TheData, shape = "TheData"), size = 2.5) +
geom_line(aes(x = Year, y = Model, color = "Model")) +
geom_ribbon(aes(ymin = Lower, ymax = Upper, x = Year,
fill = "Confidence Interval"), alpha = 0.15) +
scale_colour_manual(
name = "", values = c("Confidence Interval" = "transparent",
"Model" = "black")) +
scale_fill_manual(
name = "", values = c("Confidence Interval" = "grey12",
"Model" = "transparent")) +
theme(legend.position = "bottom") +
labs(shape = "") +
theme(legend.position = c(.4, .7), legend.box = "horizontal") +
guides(color = guide_legend(nrow = 1))
The plot looks like this:
Still, I wonder why the legend appears in different boxes and how to put it together?

How to fix axis and add polygon to inset map in ggplot2

I'm trying to add a couple details to my map in ggplot2 but I'm new to the package and I'm not sure how to proceed. Code and map are below (ignore the weird spacing on the map, I took a screen shot in Rstudio). Thanks for taking a look!
I'm trying to do the following:
Add latitude and longitude tick marks on the x and y axis. I coded it in the script below but nothing is happening, not sure why - no errors pop up.
If possible, I'd like to add a box in the inset map showing the extent/coverage of the larger map, since the points in the smaller map (the red ones) are barely visible. I'm not sure how to add and place a polygon in the inset map.
Here is what the map currently looks like for reference:
library(raster)
library(ggplot2)
library(ggthemes)
library(ggsn)
library(ggmap)
library(maps)
library(mapdata)
mapdata <- getData("GADM", country = "panama", level = 1)
mymap <- fortify(mapdata)
mypoint <- data.frame(long=c(-79.743, -79.696, -79.645, -79.595),
lat=c(9.160, 9.117, 9.058, 9.015),
group=c("L", "GW", "OGR", "LC"))
mypoint2 <- data.frame(long=c(-79.846, -79.707, -79.665, -79.610),
lat=c(9.181, 9.112, 9.057, 9.014),
group=c("BCI", "G", "EH", "MF"))
g1 <- ggplot() +
geom_blank(data = mymap, aes(x=long, y=lat)) +
geom_map(data = mymap, map = mymap,
aes(group = group, map_id = id),
fill = "#b2b2b2", color = "black", size = 0.3) +
coord_sf(xlim=c(-80,-79.5), ylim=c(8.9, 9.25), expand = FALSE) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "black", size = 3) +
geom_label(data = mypoint, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(0.015, 0.02, 0.022, 0.018)) +
geom_point(data = mypoint2, aes(x = long, y = lat),
color = "blue", size = 3) +
geom_label(data = mypoint2, aes(label = group, x = long, y = lat),
size = 3, fontface = "bold", nudge_x = c(-0.02, -0.018, -0.02, -0.02)) +
scale_x_continuous(limits = c(-80,-79.5), expand = c(0, 0)) +
scale_y_continuous(limits = c(8.9, 9.25), expand = c(0, 0)) +
theme_map() +
ggsn::scalebar(location = "bottomleft", dist = 5,
transform = TRUE, dist_unit = "km", model = 'WGS84',
x.min = -79.97, x.max = -79.8,
y.min = 8.93, y.max = 9.25) +
north(x.min = -79.6, x.max = -79.5,
y.min = 9.2, y.max = 9.24,
location = "toprgiht", scale = 0.1)
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(panel.background = element_rect(fill = NULL))
)
g3 <- g1 +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Latitude and longitude tick marks are disappearing because of theme_map() - it sets axis_ticks and axis_text (among other things) to element_blank(). One way to get them back is to override theme_map() with
g1_with_lbls <- g1 +
theme(
axis.text = element_text(),
axis.ticks = element_line(),
axis.title = element_text()
) +
xlab("Longitude") +
ylab("Lattitude")
You would place the polygon on the smaller map as a part of the ggplotGrob object you are creating
g2 <- ggplotGrob(
ggplot() +
geom_polygon(data = mymap,
aes(x = long, y = lat, group = group),
fill = "#b2b2b2", color = "black", size = 0.3) +
geom_point(data = mypoint, aes(x = long, y = lat),
color = "red", size = 0.5) +
coord_map("polyconic") +
theme_map() +
theme(
panel.background = element_rect(fill = NULL)
) +
geom_rect(
aes(xmin = -80, xmax = -79, ymin = 8.5, ymax = 9.5), fill = NA,
col = "red", size = 1
)
)
Then
g3 <- g1_with_lbls +
annotation_custom(grob = g2, xmin = -79.75, xmax = -79.51,
ymin = 8.9, ymax = 9.0)
g3
Has both the ticks and the rectangle.

Increase the margin of every second x-axis tick ggplot2

I'm looking for a way to move every second x-axis tick downwards and have the tick line go down with it.
I can change the general margin and tick length for all ticks with:
#MWE
library(ggplot2)
ggplot(cars, aes(dist, speed))+
geom_point()+
theme(
axis.ticks.length.x = unit(15, "pt")
)
But, I would like the x-axis ticks 0, 50, and 100 (i.e., every second tick) to be without the added top margin.
A generalized answer is preferred as my x-axis is categorical and not numerical (and contains 430 ticks, so nothing I can set by hand).
Any ideas?
Edit:
Output should be:
Edit2:
A more intricate example would be:
#MWE
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge')+
theme(
axis.ticks.length.x = unit(15, "pt")
)
Edit -- added categorical approach at bottom.
Here's a hack. Hope there's a better way!
ticks <- data.frame(
x = 25*0:5,
y = rep(c(-0.2, -2), 3)
)
ggplot(cars, aes(dist, speed))+
geom_point()+
geom_rect(fill = "white", xmin = -Inf, xmax = Inf,
ymin = 0, ymax = -5) +
geom_segment(data = ticks,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks,
aes(x = x, y = y, label = x), vjust = 1.5) +
theme(axis.ticks.x = element_blank()) +
scale_x_continuous(breaks = 25*0:5, labels = NULL, name = "") +
coord_cartesian(clip = "off")
Here's a similar approach used with a categorical x.
cats <- sort(as.character(unique(diamonds$cut)))
ticks <- data.frame(x = cats)
ticks$y = ifelse(seq_along(cats) %% 2, -500, -2000)
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge') +
annotate("rect", fill = "white",
xmin = 0.4, xmax = length(cats) + 0.6,
ymin = 0, ymax = -3000) +
geom_segment(data = ticks, inherit.aes = F,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks, inherit.aes = F,
aes(x = x, y = y, label = x), vjust = 1.5) +
scale_x_discrete(labels = NULL, name = "cut") +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.05))) +
theme(axis.ticks.x = element_blank()) +
coord_cartesian(clip = "off")

Defining order of appearence in geom_boxplot

I have this data.frame:
df = data.frame(x = c(1,1,2,2,3,3), factor = c("crb","crb","ctx","ctx","bsl","bsl"), factor.level = c("pat","mat","pat","mat","pat","mat"), factor.level.color = c("blue","red","blue","red","blue","red"), ymin = c(0.031,0.152,0.071,0.026,0.051,0.032), lower = c(0.119,0.522,0.415,0.185,0.287,0.285), middle = c(0.298,0.701,0.615,0.384,0.500,0.499), upper = c(0.477,0.880,0.814,0.584,0.714,0.714), ymax = c(0.848,0.870,0.874,0.929,0.967,0.950),stringsAsFactors=F)
and I'd like to plot it in a geom_boxplot so that df$x defines the x-axis location, df$ymin, df$lower, df$middle, df$upper, df$ymax define the boxes, df$factor defines the x-axis ticks labels, df$factor.level.color defines the color of the boxes, and df$factor.level should appear in the legend (unique values). A pair of boxes should be plotted on the same x-axis location. For this reason a transparency factor needs to be defined
This is an improvised version of how I want it to look like:
(obviously the x and y axes tick values are missing)
I thought this code is that I need:
pl = ggplot(data = df, aes(x = x)) + geom_boxplot(aes(lower = lower,upper = upper, middle = middle, ymin = ymin, ymax = ymax,color = factor.level.color, fill = factor.level.color),
position = position_dodge(width = 0), width = 0.5, alpha = 0.5, stat = "identity") + scale_fill_identity("factor level", guide="legend", labels = df$factor.level) +
scale_color_identity("factor level", guide = "legend", labels = df$factor.level) +
scale_x_discrete(breaks = seq(1,length(unique(df$factor)),1), labels = unique(df$factor), limits = seq(1,length(unique(df$factor)),1)) +
labs(x = "factor",y = "fraction") + theme(axis.title.x = element_text(size = rel(0.8)), axis.title.y = element_text(size = rel(0.8)))
But the outcome is a bit messed up:
I guess levels need to be somehow defined but I don't know how to do that.
Try aes(x = factor(x)) in the call to ggplot(...)
pl = ggplot(data = df, aes(x = factor(x))) +
geom_boxplot(aes(lower = lower,upper = upper, middle = middle,
ymin = ymin, ymax = ymax,
color = factor.level.color, fill = factor.level.color),
position = position_dodge(width = 0),
width = 0.5, alpha = 0.5, stat = "identity") +
scale_fill_identity("factor level", guide="legend", labels = df$factor.level) +
scale_color_identity("factor level", guide = "legend", labels = df$factor.level) +
scale_x_discrete(breaks = seq(1,length(unique(df$factor)),1),
labels = unique(df$factor),
limits = seq(1,length(unique(df$factor)),1)) +
labs(x = "factor",y = "fraction") +
theme(axis.title.x = element_text(size = rel(0.8)), axis.title.y = element_text(size = rel(0.8)))

Resources