I'm trying to reproduce this tutorial on how to plot a scatterplot-like map. Below is the full code and the output:
library(readr)
library(dplyr)
library(DT)
datatable(rladies, rownames = FALSE,
options = list(pageLength = 5))
url_csv <- 'https://raw.githubusercontent.com/d4tagirl/R-Ladies-growth-maps/master/rladies.csv'
rladies <- read_csv(url(url_csv)) %>%
select(-1)
library(ggplot2)
library(maps)
library(ggthemes)
world <- ggplot() +
borders("world", colour = "gray85", fill = "gray80") +
theme_map()
map <- world +
geom_point(aes(x = lon, y = lat, size = followers),
data = rladies,
colour = 'purple', alpha = .5) +
scale_size_continuous(range = c(1, 8),
breaks = c(250, 500, 750, 1000)) +
labs(size = 'Followers')
I want to remove Antartica from the map so that it doesn't take so much empty space. I tried to follow the solution from another similar Stackoverflow question as follows:
world <- map_data("world") %>%
filter(region != "Antarctica") %>%
ggplot(aes(long, lat, group = paste(region, group))) +
geom_polygon() +
coord_fixed()
map <- world +
geom_point(aes(x = lon, y = lat, size = followers),
data = rladies,
colour = 'purple', alpha = .5) +
scale_size_continuous(range = c(1, 8),
breaks = c(250, 500, 750, 1000)) +
labs(size = 'Followers')
But when I try to display the map I get the following error:
Error in paste(region, group) : object 'region' not found
Is there any other way to remove Antartica?
UPDATE: Failed subset attempt
countries <- map_data("world")
map_df <- subset(countries, region != "Antarctica")
map_base <- ggplot(data = map_df, mapping = aes(x = long, y = lat, group = group)) + coord_fixed(1.3) + geom_polygon(color = "black", fill = "gray")
# The base map is created successfully but I cannot plot points on it
map_base + geom_point(aes(x = lon, y = lat, size = followers), data = rladies, colour = 'purple', alpha = .5)
Error:
Error in eval(expr, envir, enclos) : object 'group' not found
Following on hrbmstr's advice, here is a solution using a proper projection and the sf package (with geom_sf from the development version of ggplot2). Note we use coord_sf to set the limits.
library(sf)
world <- map_data("world")
world.sf <- sf::st_as_sf(world, coords = c("long", "lat"), crs = 4326) %>%
group_by(group) %>%
summarize(do_union = FALSE) %>%
st_cast("POLYGON") %>%
ungroup()
world <- ggplot() +
geom_sf(data = world.sf, colour = "gray85", fill = "gray80") +
coord_sf(ylim = c(-50, 90), datum = NA) +
theme(panel.background = element_rect(fill = 'white'))
world +
geom_point(aes(x = lon, y = lat, size = followers),
data = rladies,
colour = 'purple', alpha = .5) +
scale_size_continuous(range = c(1, 8),
breaks = c(250, 500, 750, 1000)) +
labs(size = 'Followers', x = NULL, y = NULL)
We can also use coord_cartesian(ylim = c(-50, 90)) to set the y limits.
library(ggplot2)
library(maps)
library(ggthemes)
world <- ggplot() +
borders("world", colour = "gray85", fill = "gray80") +
theme_map() +
coord_cartesian(ylim = c(-50, 90))
map <- world +
geom_point(aes(x = lon, y = lat, size = followers),
data = rladies,
colour = 'purple', alpha = .5) +
scale_size_continuous(range = c(1, 8),
breaks = c(250, 500, 750, 1000)) +
labs(size = 'Followers')
map
Related
I am pretty new to R and want to learn how to plot points on R. I have managed to create a map of the UK with the following code
the Trust/longlat.csv data is a list of organisations with Longitude and Lattitude co-ordinates.
Any help greatly appreciated.
library(ggplot2)
library(maps)
worldmap = map_data('world')
knitr::kable(head(worldmap, 20))
ggplot() +
geom_polygon(data = worldmap,
aes(x = long, y = lat, group = group))
ggplot() + geom_polygon(data = worldmap,
aes(x = long,
y = lat,
group = group)) +
coord_fixed(xlim = c(-10,3),
ylim = c(50.3, 59))
ggplot() +
geom_polygon(data = worldmap,
aes(x = long,
y = lat,
group = group)) +
coord_fixed(ratio = 1.3,
xlim = c(-10,3),
ylim = c(50, 59))
library(tidyverse)
ggplot() +
geom_polygon(data = worldmap,
aes(x = long, y = lat,
group = group),
fill = 'gray90',
color = 'black') +
coord_fixed(ratio = 1.3,
xlim = c(-10,3),
ylim = c(50, 59))
ggplot() +
geom_polygon(data = worldmap,
aes(x = long, y = lat,
group = group),
fill = 'gray90',
color = 'black') +
coord_fixed(ratio = 1.3,
xlim = c(-10,3),
ylim = c(50, 59)) +
theme_void()
Data<-read.csv("C:/Users/Digital/Desktop/longlat.csv")
I'm trying to align each bcr_code to their respective polygons, however, the numbers come out of place. How do I get the right alignment, preferably in the middle?
here's the code:
library(tidyverse)
library(broom)
library(rgdal)
file1 <- "bcr.gpkg"
if (!file.exists(file.path("data/data/", file1))) {
download.file(paste0("https://raw.githubusercontent.com/lime-n/data/main/", file1),
file.path("data/data/", file1), mode = "wb")
}
p <- readOGR(dsn = "bcr.gpkg")
tidy_bcr <- tidy(p)
ggplot(p, aes(x = long, y = lat, group = group)) +
geom_polygon(color = "black", size = 0.1, fill = "lightgrey") +
coord_equal() +
theme_minimal()
p$id <- row.names(p)
tidy_bcr <- left_join(tidy_bcr, p#data)
bcrcop <- data.frame(bcr_name = sort(p#data$bcr_name),
bcr_code = c(28,17,12,24,19,22,13,26,30,21,31,29,23,11,18,27,25))
tidy_bcr <- left_join(tidy_bcr, bcrcop)
bcrLabel <- tidy_bcr %>%
group_by(bcr_name) %>%
summarise(label_long = mean(range(long)), label_lat = mean(range(lat)), bcr_code = mean(bcr_code))
map <- ggplot(tidy_bcr, aes(x = long, y = lat, group = group, fill = bcr_name)) +
geom_polygon(color = "black", size = 0.1) +
coord_equal() +
theme_void() +
theme(plot.title = element_text(margin = margin(t = 40, b = -40)))
map + geom_text(data = bcrLabel, mapping = aes(x=label_long, y = label_lat, label = bcr_code, group = NA), cex = 4, col = "white")
And the output:
Although, is there also a way to get these codes on the legend, something like:
28: Appalachian Mountains
Try using the sf package for the data and ggsflabel for the labels.
A minimal examle:
library(sf)
library(ggsflabel)
my_data <- read_sf('https://raw.githubusercontent.com/lime-n/data/main//bcr.gpkg') ## Replace with your path to the data
ggplot() +
geom_sf(data = my_data,
aes(fill = bcr_name)) +
geom_sf_label(data = my_data, aes(label = bcr_code))
Change the legend names in the legend using unite on the data first.
my_data <- my_data %>%
unite('new_col', bcr_code, bcr_name, sep = ': ', remove = F)
ggplot() +
geom_sf(data = my_data2,
aes(fill = new_col)) +
geom_sf_label(data = my_data2,
aes(label = bcr_code))
Created on 2020-12-26 by the reprex package (v0.3.0)
I'm posting this quite stupid question after unsuccessfully googleing for a while.
I have the following situation:
dta1 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
dta2 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
ggplot() +
geom_point(data=dta1, color = "blue", alpha = 0.5, aes(x=LON, y=LAT, size = VALUE)) +
geom_point(data=dta2, color = "red", alpha = 0.5, aes(x=LON, y=LAT, size = VALUE))
Which yields something like this (points' positions and sizes can change, it does not matter):
The result is quite good, but I want the circles in the legend to be draw with black borders and filled with white.
Any idea?
Would this be an acceptable result?
I supposed your point was to make the size legend of an anonymous colour, unrelated to the blue or the red of the actual points.
set.seed(1)
dta1 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
dta2 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
library(ggplot2)
ggplot() +
geom_point(data=dta1, alpha = 0.5, aes(x=LON, y=LAT, size = VALUE, colour = "value1")) +
geom_point(data=dta2, alpha = 0.5, aes(x=LON, y=LAT, size = VALUE, colour = "value2")) +
scale_color_manual(values = c(value1 = "blue", value2 = "red"))
Alternately, closely related to the "fill" answer:
library(ggplot2)
ggplot() +
geom_point(data = dta1, shape = 21, alpha = 0.5, aes(x = LON, y = LAT, size = VALUE, fill = "value1")) +
geom_point(data = dta2, shape = 21, alpha = 0.5, aes(x = LON, y = LAT, size = VALUE, fill = "value2")) +
scale_fill_manual(values = c(value1 = "blue", value2 = "red")) +
theme_light() +
guides(fill = FALSE)
Hmm. I dont know of a way of changing something in the legend only. In a way thats contrary to the point of the legend. This is the best i got.
library(ggplot2)
dta1 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
dta2 <- data.frame(LON = runif(20)*100, LAT = runif(20)*100, VALUE = runif(20)*10)
ggplot() +
geom_point(data=dta1, color = "blue", alpha = 0.5,shape = 21, aes(x=LON, y=LAT, size = VALUE)) +
geom_point(data=dta2, color = "red", alpha = 0.5,shape = 21, aes(x=LON, y=LAT, size = VALUE)) +
theme_classic()
Created on 2020-12-09 by the reprex package (v0.3.0)
Alternatively, it could be something like this:
dta1$C <- 1
dta2$C <- 2
dta1 <- rbind(dta1, dta2)
ggplot(dta1, aes(x = LON, y = LAT, size = VALUE, fill = C)) +
geom_point(shape=21)
Which yields:
But without the inferior (rectangle titled "C") part of the legend.
I map the southern part of the South hemisphere. My issue is Australia which has poorly drawn borders.
My data :
library("maptools")
library("ggplot2")
library("tidyverse")
ylim_map <- c(-90, -30)
xlim_map <- c(-180, 180)
world <- maps::map("world", fill=TRUE, plot=FALSE, ylim = ylim_map)
Convert data in correct format for ggplot :
IDs <- sapply(strsplit(world$names, ":"), function(x) x[1])
world <- map2SpatialPolygons(world, IDs = IDs,
proj4string = CRS("+proj=longlat +datum=WGS84"))
world_map <- fortify(world)
world_map <- world_map[which(between(world_map$lat, ylim_map[1], ylim_map[2]) &
between(world_map$lon, xlim_map[1], xlim_map[2])),]
And my plot :
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)
TLDR:
You need to close your polygons.
Explanation:
Let's trim away extraneous code & zoom in onto Australia. (Though actually the problem exists for Africa & South America as well; it's just not as obvious there...)
We can see that the top line is misbehaving. It's intersecting with the coastline further down south, rather than sticking to its correct latitude level:
ggplot() +
coord_map("orthographic", orientation = c(-40, 130, 0)) +
geom_map(data = world_map, map = world_map,
aes(x = long, y = lat, map_id=id),
fill = "darkgrey") +
theme_bw()
Now a geom_map layer is essentially plotting polygons, and ?geom_polygon states:
Polygons are very similar to paths (as drawn by geom_path()) except
that the start and end points are connected and the inside is coloured
by fill. The group aesthetic determines which cases are connected
together into a polygon.
If we replace the geom_map layer with its geom_polygon / geom_path equivalents, the situation becomes much more obvious: the polygon corresponding to Australia has no top line. Instead, the path starts at the one corner and ends at the opposite corner. geom_polygon connects them with a straight line, which may intersect other lines when the coordinate system isn't linear (and coord_map isn't):
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map,
aes(x = long, y = lat, group = group)) +
theme_bw()
Solution:
We can manually close each polygon by repeating its first point at the end. (For polygons that are already closed, this has no additional effect.)
library(dplyr)
world_map2 <- world_map %>%
group_by(group) %>% # each group corresponds to a unique polygon
arrange(order) %>% # sort points in the appropriate sequence
slice(c(1:n(), 1)) %>% # repeat first row after last row
mutate(order = seq(1, n())) %>% # define new order for n+1 rows
ungroup()
Check that the polygons are now closed, & the top line for Australia now traces its latitude level nicely:
ggplot() +
coord_map("orthographic",
orientation = c(-40, 130, 0)) +
geom_polygon(data = world_map2,
aes(x = long, y = lat, group = group),
fill = "lightgrey") +
geom_path(data = world_map2,
aes(x = long, y = lat, group = group)) +
theme_bw()
Applying this to the original use case:
ggplot() +
coord_map("orthographic", orientation = c(-90, 0, 0),
xlim = xlim_map, ylim = c(ylim_map[1], ylim_map[2] + 10)) +
geom_map(data = world_map2, map = world_map2,
aes(x = long, y = lat, map_id = id), fill = "black") +
geom_text(aes(x = 180, y = ylim_map[2]+5, label = "180°E"), color = "black") +
geom_text(aes(x = 90, y = ylim_map[2]+5, label = "90°E"), angle = -90, color = "black") +
geom_text(aes(x = 0, y = ylim_map[2]+5, label = "0°"), color = "black") +
geom_text(aes(x = -90, y = ylim_map[2]+5, label = "90°W"), angle = 90, color = "black") +
labs(y = "", x = "") +
# Theme
theme(text = element_text(size = 20),
panel.background = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
aspect.ratio = 1)
I am trying to plot a map with Peru and Ecuador, that presents two simple lat and long points (San Jose and Lima in Peru).
I'm having some issue with the fill when incorporating both Peru and Ecuador into my map.
library(ggplot2)
library(ggmap)
library(maps)
library(mapdata)
peru_ecuador <- map_data("world",c("peru", "ecuador"))
# Add study site points (San Jose and Lima)
points <- data.frame(
long = c(-79.81, -77.04),
lat = c(-6.77, -12.04),
names = c("San Jose", "Lima"),
stringsAsFactors = FALSE
)
# Plot the map
ggplot() +
geom_polygon(data = peru_ecuador, aes(x=long, y = lat), fill = "grey40", color
= "grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)
I would also really love some advise on how best to resize the plot area window of the map. As in change the x and y axis width and length. When I plot just a map of Peru, some of my map information is cut off by the size of the plot area. Please see below:
peru <- map_data("world","peru")
ggplot() +
geom_polygon(data = peru, aes(x=long, y = lat), fill = "grey40", color =
"grey90", alpha = 1) +
geom_point(data = points, aes(x = long, y = lat), color = "red", size = 2,
alpha = 0.8) +
geom_text(aes(x = long, y = lat, label = c("San Jose", "Lima")), data =
points, size = 2, hjust = 1.3) +
geom_area(x = 10) +
coord_fixed(1.3) +
labs(x = "Longitude", y = "Latitude", size = 2) +
theme_bw(base_size = 5)