How to represent different borders in tmap legend - r

my map looks similar to this one:
# import shapefile
shape_data <- system.file("shape/nc.shp", package="sf")
shape_data <- st_read(shape_data)
sample_data <- filter(shape_data, CNTY_ID >2100)
shape_area <- st_union(shape_data)
#map data
tm_shape(shape_data) + tm_borders(alpha = 0.4,lwd = 0.1, col = "blue") +
tm_fill(col = "BIR79", style = "equal") +
tm_shape(sample_data) + tm_borders(col = "red", lwd = 3, lty = 4) +
tm_shape(shape_area) + tm_borders(col = "black", lwd = 2)
the polygons in the map are distinguished by three types of boundaries, with different colours, size and, in one case, by dashes.
Now, I would like to find a way to represent these 3 boundaries in a legend, either in addition to the data legend or even separate. So I would like to have the representation of the type of boundaries (red dashed, black and blue with their different size, and next to them add a text explaining what they represent, i.e. districts, boundaries of the study area and so on.
Do you have any idea how to do this with tmap? Thanks

Here's a solution using the viewport function from the grid package:
library(tmap)
library(sf)
library(tidyverse)
library(grid)
shape_data <- system.file("shape/nc.shp", package="sf")
shape_data <- st_read(shape_data)
sample_data <- filter(shape_data, CNTY_ID >2100)
shape_area <- st_union(shape_data)
tm1 <- tm_shape(shape_data) +
tm_fill(col = "BIR79", style = "equal") +
tm_shape(shape_data) + tm_borders(alpha = 0.4,lwd = 1.5, col = "blue") +
tm_shape(sample_data) + tm_borders(col = "red", lwd = 3, lty = 4) +
tm_shape(shape_area) + tm_borders(col = "black", lwd = 2)
# add second legend
tm_leg = tm_shape(sample_data) + tm_fill(alpha = 0) + # dummy layer
tm_add_legend("line",
col = c("blue", "red", "black"),
lwd = c(1.5, 3, 2),
lty = c(1, 4, 1),
labels = c("var1", "var2", "var3"),
title = "type") +
tm_layout(legend.position = c(.15 ,-.2),
bg.color = NA,
frame = F,
legend.width = 10,
legend.height = 10)
tmap_save(tm1, insets_tm = tm_leg, insets_vp = viewport(), "test_map.png")

Related

Display more than three variables using different aesthetics in a ggplot2 bar chart

Can the following chart be generated using ggplot2:
There are two variables mapped onto the axises, one variable (Region) mapped onto the colour (using grouped bars) and one variable (Product) mapped onto some other aethetics (alpha, pattern, line style)
How would that be possible? An example using R is welcome.
Update
In my original question I did not think about facets. Of course with facets you are able to display four variables. The question should be reformulated as Display more than four variables using different aesthetics in a ggplot2 bar chart ...
Here is an approach by abusing facets to serve as an x-axis so you can both stack and "dodge" the data. You can look into the ggpattern package, but I'm not fluent in its use.
library(ggplot2)
df <- expand.grid(
region = c("North", "East", "South", "West"),
product = c("Red wine", 'White wine'),
year = 2013:2015
)
set.seed(42)
df$value <- runif(nrow(df))
ggplot(df, aes(region, value)) +
geom_col(aes(alpha = product, fill = region), width = 1) +
# Expand x axis to control the width of 'dodging'
scale_x_discrete(expand = c(0.5, 0), breaks = NULL, name = NULL) +
scale_alpha_manual(values = c(0.6, 1)) +
facet_grid(~ year, switch = "x") +
# 0 spacing gives impression it is a single panel
theme(panel.spacing.x = unit(0, "pt"))
Created on 2021-09-24 by the reprex package (v2.0.1)
EDIT: An alternative without using facets, but with use of a helper function to position everything on the x-axis:
helper <- function(center, offset, width = 0.6) {
if (!is.numeric(center)) {
center <- match(center, sort(unique(center)))
}
offset <- match(offset, sort(unique(offset)))
offset <- scales::rescale(offset, to = c(-0.5, 0.5) * width)
center + offset
}
ggplot(df, aes(helper(year, region), value)) +
geom_col(aes(alpha = product, fill = region), width = 0.15) +
scale_alpha_manual(values = c(0.6, 1)) +
scale_x_continuous(breaks = scales::breaks_width(1)) +
theme(panel.spacing.x = unit(0, "pt"))
Here's a base version that gets most of the way there
set.seed(1)
d <- replicate(15, rpois(2, 10))
s <- replace(rep(0.1, 15), 1:2 * 5 + 1, 1)
op <- par(mar = c(5, 4, 2, 7), las = 1)
bp <- barplot(colSums(d), space = s, col = 2:6)
barplot(d, space = s, add = TRUE, density = c(0, 10), col = 'black', border = 'black')
abline(h = 0)
axis(1L, bp[1:3 * 5 - 2], 13:15 + 2000, lwd = 0)
title(xlab = 'Year', cex.lab = 1.5)
l <- list(
list(
title = 'Region', fill = 2:6,
legend = c('North', 'South', 'East', 'West', 'Center')
),
list(
title = 'Product', density = c(20, 0),
legend = c('Red wine', 'White wine')
)
)
lg <- legend('topright', legend = '', bty = 'n', inset = c(-0.025, 0))
for (ii in seq_along(l)) {
lg <- do.call('legend', c(
list(x = lg$rect$left, y = lg$rect$top - lg$rect$h,
xpd = NA, bty = 'n', title.adj = 0), l[[ii]]
))
}
par(op)

Include a legend of node size of a ggnet2 object modified with ggplot

I am modifying the a ggnet object using ggplot2 to increase the size of the nodes. However, if I use this approach I cannot manage to include the size parameter in a legend. I have tried the scale_size_manual and including size within aes approaches but still not successful.
library(network)
library(dplyr)
library(ggplot2)
library(GGally)
# weighted adjacency matrix
bip = data.frame(event1 = c(1, 2, 1, 0),
event2 = c(0, 0, 3, 0),
event3 = c(1, 1, 0, 4),
row.names = letters[1:4])
# weighted bipartite network
bip = network(bip,
matrix.type = "bipartite",
ignore.eval = FALSE,
names.eval = "weights")
# set colors for each mode
col = c("actor" = "grey", "event" = "gold")
## I have tried including the size in the ggnet2 but the points are not as big as I want
p <- ggnet2(bip, color = "mode", label = F, shape = "mode",
palette = col,
shape.palette=c(24,19))
## add a size variable to the network data
p$data <- p$data %>%
mutate(index=1:7)
## create a vector of the sizes
aa <- p$data$index
Here I add the ggplot2 functions to ggnet and include size outside aes. I am struggling to have a legend of the size parameter
p +
geom_point(aes(color = color, shape=shape), size = aa*2, color = "#92D050") +
geom_point(aes(color = color), alpha = 0.1) +
geom_text(aes(label = toupper(label )), color = "black", fontface = "bold", size=3 ,
position = position_nudge(y = -0.015)) +
scale_size_manual(name="Antigen" ,values=p$data$index ,
guide = "legend",
guide_legend(override.aes = list(size=c(1,2,3,4,5,6,7)))) +
guides(color = FALSE) +
theme_minimal()

ggplot2 guide_color_bar cannot put label at beginning and end of the legend elements

I am trying to plot some data ranges from 1 to 6 using scale_color_gradientn (ggplot2 package) based on the following code. By default, guide_color_bar will put the label as the "center" of the bin in legend (see code block 1). But I would like to set the label to be at the "upper" and "lower" boundary of each bin. I tried to set breaks and labels accordingly, however, the 2,3,4,5 is properly aligned but 1,6 is not showing (see code block2).
Please see code attached.
library(ggplot2)
###provide dataset
dat <- data.frame(list(x = c(0.214137620411313,0.553775825041679,-1.0595195186151,
-1.61004932625145,-0.338151062634607,0.204937753426245,
-0.224345039271189,-0.909609704018834,-0.808109884248038,
0.553083514142192,-0.389177932603183,-0.447245638594407,
-0.0211388451690059,-0.599417455124725,-0.310866189554078,
-0.681632468885545,-0.202055723512808,1.11680032924059,0.82599921267075,1.2509189798129),
y = c(2.60809809498069,-0.051039961195504,2.22719419433773,-0.0138721238155097,-1.54739969676097,
-1.37988910915699,1.47987074083825,-0.254921944338877,-0.326280380145921,-0.726638665692272,
-1.95234864995199,0.422940041768889,1.18168478575317,0.91795937727616,0.0954675468852296,
-1.68443178674375,0.990329350606127,-0.707831781928625,-0.594029169314093,-1.06589703339072)),
z = c(1,3,3,1,2,2,2,4,2,1,1,1,1,5,2,4,3,4,1,4))
###define breaks and colors
my_breaks <- c(0,1,2,3,4,5,6)
colors <- c('#e41a1c','#377eb8','#4daf4a',
'#ff7f00','#ffff33','#a65628')
###the label is in the center.
ggplot(dat, aes(x,y,color=z, label = round(z,2))) + geom_point() +
scale_color_gradientn(
colours = colors,
values = scales::rescale(c(1:6)),
limit = c(1,6),
guide = guide_colourbar(nbin = 6, raster = FALSE, frame.colour = "black", ticks.colour = NA,
direction = "horizontal",
barwidth = 30, barheight = 2, label.hjust = 0)) +
geom_text() +
theme(legend.position = 'bottom')
###the label shows the upper and lower boundary for each bin, but the beginning (1) and ending (6) is not showing.
ggplot(dat, aes(x,y,color=z, label = round(z,2))) + geom_point() +
scale_color_gradientn(
colours = colors,
values = scales::rescale(c(1:6)),
limit = c(1,6),
breaks = c(1:7)-0.5, ###the label should be at 0.5,1.5,2.5,...,6.5
labels = my_breaks,
guide = guide_colourbar(nbin = 6, raster = FALSE, frame.colour = "black", ticks.colour = NA,
direction = "horizontal",
barwidth = 30, barheight = 2, label.hjust = 0)) +
geom_text() +
theme(legend.position = 'bottom')
Any help is appreciated.
Might not be the most elegant, but take a look at the following. I also added some adjustment to your point labels.
library(ggplot2)
#> Registered S3 methods overwritten by 'ggplot2':
#> method from
#> [.quosures rlang
#> c.quosures rlang
#> print.quosures rlang
###provide dataset
dat <- data.frame(list(x = c(0.214137620411313,0.553775825041679,-1.0595195186151,
-1.61004932625145,-0.338151062634607,0.204937753426245,
-0.224345039271189,-0.909609704018834,-0.808109884248038,
0.553083514142192,-0.389177932603183,-0.447245638594407,
-0.0211388451690059,-0.599417455124725,-0.310866189554078,
-0.681632468885545,-0.202055723512808,1.11680032924059,0.82599921267075,1.2509189798129),
y = c(2.60809809498069,-0.051039961195504,2.22719419433773,-0.0138721238155097,-1.54739969676097,
-1.37988910915699,1.47987074083825,-0.254921944338877,-0.326280380145921,-0.726638665692272,
-1.95234864995199,0.422940041768889,1.18168478575317,0.91795937727616,0.0954675468852296,
-1.68443178674375,0.990329350606127,-0.707831781928625,-0.594029169314093,-1.06589703339072)),
z = c(1,3,3,1,2,2,2,4,2,1,1,1,1,5,2,4,3,4,1,4))
###define breaks and colors
my_breaks <- c(0,1,2,3,4,5,6)
colors <- c('#e41a1c','#377eb8','#4daf4a',
'#ff7f00','#ffff33','#a65628')
# Charting
ggplot(dat, aes(x,y,color=z, label = round(z,2))) + geom_point() +
scale_color_gradientn(
colours = colors,
values = scales::rescale(c(1:6)),
limit = c(1,6), # Changed the limit to 1:6
breaks = c(1:6), # Set the breaks to 1:6
labels = c(1,2,3,4,5,6), # Set the labels manually
guide = guide_colourbar(nbin = 6, raster = FALSE, frame.colour = "black", ticks.colour = NA,
direction = "horizontal",
barwidth = 30, barheight = 2, label.hjust = -6.5)) + # Set the adjustment to -6.5
geom_text(hjust = -1, vjust = -0.3) +
theme(legend.position = 'bottom')
Created on 2019-06-14 by the reprex package (v0.3.0)

Add item to existing legend

I am new to ggplot2 and I am struggling since hours to add a second legend in my plot.
I am using two data.frames (df_1 and df_2) and two geom_point calls for them. I managed to create a legend for df_2 but I was not able to add a second legend for df_1.
Here a code example with also plot:
########## Create sample data
set.seed(69)
df_1 = data.frame(lat = rnorm(20),
lon = rnorm(20),
cor = c(rep('positive', 12), rep('negative', 8)),
sign = 0)
df_2 = data.frame(lat = rnorm(20),
lon = rnorm(20),
cor = c(rep('positive', 7), rep('negative', 13)),
sign = c(rep(99, 5), rep(95, 6), rep(90,9)))
#### Plot data
library(ggplot2)
p = ggplot() +
# geom_point for df_1
geom_point(data=df_1, aes(x=lon, y=lat),
alpha=0.7, color = 'darkgrey', size = 3) +
# geom_point for df_2
geom_point(data=df_2, aes(x=lon, y=lat, size=sign, colour = cor), alpha = 0.5) +
scale_color_manual(values=c("red", "blue"),
name='cor',
labels = c('neg', 'pos'),
guide = guide_legend(override.aes = list(alpha = 1, size = 3))) +
scale_size(range = c(1,3),
breaks = c(90, 95, 99),
labels = c(0.1, 0.05, 0.01),
name = 'sign',
guide = guide_legend(override.aes = list(colour = 'black',
alpha = 1)))
print(p)
How can I add a legend for the geom_point call of df_1?
It would be enough to add a 3rd darkgrey point to cor (right legend) with label 'not sign'.
I guess the straightforward solution is too do what you ask add 3rd darkgrey point to cor legend. To do this you have to:
Change cor values in df_1 to be all the same.
Specify color in df_1 aes.
Add information for the third point in scale_color_manual.
Code:
# Change values so we would have single color for them
df_1$cor <- "foo"
library(ggplot2)
ggplot() +
geom_point(aes(lon, lat, color = cor), df_1,
alpha = 0.7, size = 3) +
geom_point(aes(lon, lat, size = sign, colour = cor), df_2,
alpha = 0.5) +
scale_color_manual(values = c("darkgrey", "red", "blue"),
labels = c("not sign", "neg", "pos"),
guide = guide_legend(override.aes = list(alpha = 1, size = 3))) +
scale_size(range = c(1, 3),
breaks = c(90, 95, 99),
labels = c(0.1, 0.05, 0.01),
guide = guide_legend(override.aes = list(colour = "black", alpha = 1)))
Result:

Add a single point to legend from geom_point and scale_fill_gradient

Has been now a few months I am working with ggplot2 but I still get stuck very easily on basic things, as the options out here are close to infinite.
Let's assume I have a simple plot created as follows:
set.seed(100)
df_1 = data.frame(lat = rnorm(20),
lon = rnorm(20),
x = rnorm(20))
library(ggplot2)
p = ggplot() +
geom_point(data = df_1,
aes(x=lon, y=lat, fill = x),
size = 5, colour = 'black', pch = 21) +
scale_fill_gradient2(low = "green", mid = 'white', high = "yellow",
breaks = c(-1, 0, 1),
labels = c('-1', '0', '1'),
limits = c(-1,1))
print(p)
How can I add a second legend with title (e.g. y) showing only one of those circles with white background and black contour?
To add extra element to legend, you have to add it to a plot. You can do this with:
geom_point(aes(alpha = ""), head(df_1, 1),
size = 5, fill = "white", pch = 21) +
Here we are adding first point in your dataset, setting it's fill and dummy alpha value (we need to set something within aes to add it to legend). I'm using "" so we won't have any text next to a point.
Also, it's important to add this point before main geom_point because it will cover original point (with white fill). You also need to reset alpha values from "" to 1 and to set wanted legend name for alpha in labs().
library(ggplot2)
ggplot(df_1, aes(lon, lat, fill = x)) +
geom_point(aes(alpha = ""), head(df_1, 1),
size = 5, fill = "white", pch = 21) +
geom_point(size = 5, pch = 21) +
scale_fill_gradient2(low = "green", mid = "white", high = "yellow",
breaks = c(-1, 0, 1),
labels = c("-1", "0", "1"),
limits = c(-1, 1)) +
scale_alpha_manual(values = 1) +
labs(alpha = "y")
PS. I have made some changes in your ggplot2 code:
You can specify data and aes within first ggplot call.
In geom layers aes is first argument, data is second. So instead of geom_point(data = df_1, aes(...). You have use geom_point(aes(...), df_1).
color = "black" is a default setting - you don't need to specify it.
You could add a factor with one level and use scale_color_manual:
set.seed(100)
df_1 = data.frame(lat = rnorm(20),
lon = rnorm(20),
x = rnorm(20),
new = rep('Coordinates', 20))
library(ggplot2)
p = ggplot() +
geom_point(data = df_1,
aes(x=lon, y=lat, fill = x, colour = new),
size = 5, pch = 21) +
scale_fill_gradient2(low = "green", mid = 'white', high = "yellow",
breaks = c(-1, 0, 1),
labels = c('-1', '0', '1'),
limits = c(-1,1)) +
scale_color_manual(name = "", values = "black")
print(p)

Resources