I want to plot data points for various cities over a greyed-out map from google. As these cities are some distance from each other, I thought I would use a faceted plot.
Creating the map is easy enough; see image and code below. However, each facet shows the same area - in this case Greater London - with the result that the points for other cities are not shown.
Ideally I would like each facet to show each city with the relevant points overlaid. So the facet 'Cardiff' would show a zoomed map of Cardiff and its data points, 'Birmingham' would show Birmingham and its points and so on. I've tried changing various parameters such as zoom and center but I haven't been successful.
How can I show a different city and the relevant points in each facet?
require(ggmap)
require(reshape)
# create fake data
sites <- data.frame(site = 1:6,
name = c(
"Royal Albert Hall",
"Tower of London",
"Wales Millenium Centre",
"Cardiff Bay Barrage",
"Birmingham Bullring",
"Birmingham New Street Station"
),
coords = c(
"51.501076,-0.177265",
"51.508075,-0.07605",
"51.465211,-3.163208",
"51.44609,-3.166652",
"52.477644,-1.894158",
"52.477487,-1.898836"),
subzone = rep(c('London','Cardiff','Birmingham'), each = 2)
)
# use function from reshape to split/add column
sites = transform(sites,
new = colsplit(coords, split = ",", names = c('lat', 'lon')))
names(sites) <- c(names(sites)[1:4], 'lat','lon')
ggmap(get_googlemap(center = "London", # omitting this doesn't help
scale = 2,
zoom = 11, # fiddling with zoom doesn't work
color = 'bw',
maptype = 'roadmap',
extent = 'panel',
format = "png8",
filename = "facet_map_test",
)) +
facet_wrap(~ subzone, ncol = 1) +
geom_point(data = sites,
aes(x = lon, y = lat),
fill = "red",
size = 3,
colour = "black",
shape = 21,
alpha = 1) +
theme(legend.position = "none") +
theme()
Using the gridExtra package is probably the best way to go. The code:
# getting the maps
londonmap <- get_map(location = c(lon = -0.1266575, lat = 51.504575), zoom = 12)
cardiffmap <- get_map(location = c(lon = -3.16493, lat = 51.45565), zoom = 13)
birminghammap <- get_map(location = c(lon = -1.896497, lat = 52.477565), zoom = 14)
# plotting the maps
p1 <- ggmap(londonmap) +
geom_point(data = sites[sites$subzone == "London",],
aes(x = lon, y = lat, fill = "red", alpha = 0.8, size = 3),
shape = 21) +
ggtitle("London") +
theme(axis.title = element_blank(), legend.position = "none", plot.margin = unit(c(0,0,0,0), "lines"))
p2 <- ggmap(cardiffmap) +
geom_point(data = sites[sites$subzone == "Cardiff",],
aes(x = lon, y = lat, fill = "red", alpha = 0.8, size = 3),
shape = 21) +
ggtitle("Cardiff") +
theme(axis.title = element_blank(), legend.position = "none", plot.margin = unit(c(0,0,0,0), "lines"))
p3 <- ggmap(birminghammap) +
geom_point(data = sites[sites$subzone == "Birmingham",],
aes(x = lon, y = lat, fill = "red", alpha = 0.8, size = 3),
shape = 21) +
ggtitle("Birmingham") +
theme(axis.title = element_blank(), legend.position = "none", plot.margin = unit(c(0,0,0,0), "lines"))
# grouping the plots together in one plot
grid.arrange(p1, p2, p3, ncol = 1)
The result:
Related
Based on the code and data below how can I get an output similar to the desired output?
Current output:
2D output:
Desired 3D output (obtained from here):
Code + data:
library(tidyverse)
library(maps)
library(rayshader)
# Read the state population data
StatePopulation = read.csv("https://raw.githubusercontent.com/ds4stats/r-tutorials/master/intro-maps/data/StatePopulation.csv", as.is = TRUE)
# Plot all states with ggplot2, using black borders and light blue fill
# Load United States state map data
MainStates = map_data("state")
# Use the dplyr package to merge the MainStates and StatePopulation files
MergedStates = inner_join(MainStates, StatePopulation, by = "region")
MainCities = filter(us.cities, long >= -130)
# 2D
g = ggplot()
g = g + geom_polygon(data = MergedStates,
aes(x = long,
y = lat,
group = group,
fill = population/1000000),
color = "black",
size = 0.2) +
scale_fill_continuous(name = "State Population",
low = "lightblue",
high = "darkblue",
limits = c(0,40),
breaks = c(5,10,15,20,25,30,35),
na.value = "grey50") +
labs(title="Population (in millions) in the Mainland United States")
g_pt = g + geom_point(data = MainCities,
aes(x = long,
y = lat,
size = pop/1000000),
color = "gold",
alpha = .5) + scale_size(name = "City Population")
# 3D
plot_gg(g_pt,
raytrace = TRUE,
multicore = TRUE,
width = 5,
height = 3,
scale = 310)
I have two dataframes both recording the top 10 stations riders went. One is for casual rider, the other one is for member rider. Both dataframes contain column 'station','freq','latitude','longitude'. I'm able to use ggmap to plot the graph showing the locations of the stations from both dataframes, but not able to show the legend.
R scripe is showing below:
library(ggplot2)
library(rstudioapi)
library(ggmap)
map_location <- c (lon = -87.623177, lat = 41.881832)
chicago_map_zoom <- get_map (location = map_location,
maptype = 'roadmap',
color='bw',
source='google',
zoom=13,
)
chicago_plot <- ggmap(chicago_map_zoom) +
geom_point (data = casual_top_station,
aes (x = longitude,
y = latitude),
color = "red",
shape = 15,
alpha = 0.5,
size = 3) +
geom_point (data = member_top_station,
aes (x = longitude,
y = latitude),
color = "blue",
shape = 16,
alpha = 0.5,
size = 2) +
scale_color_identity (name = "Subscription type",
breaks = c("red","blue"),
labels = c("Casual","Member"),
guide = "legend") +
theme (axis.ticks = element_blank(),
axis.text = element_blank(),
axis.title = element_blank()) +
labs (title = "Top 10 casual and member rider stations",
subtitle = "Both start and end stations")
Result graph: Chicago_map
Instead of using scale_color_identity ... to set the values for color, shape and size I would suggest to first an id column to your data.frames
which could then be mapped on aesthetics inside aes. Afterwards set your desired colors, shapes and sizes via the scale_xxx_manual family of functions.
Using some fake data for the points:
library(ggplot2)
library(ggmap)
casual_top_station <- data.frame(
longitude = -87.65,
latitude = 41.9
)
member_top_station <- data.frame(
longitude = -87.65,
latitude = 41.86
)
casual_top_station$id <- "Casual"
member_top_station$id <- "Member"
legend_title <- "Subscription type"
base <- ggmap(chicago_map_zoom) +
scale_color_manual(values = c(Casual = "red", Member = "blue")) +
scale_shape_manual(values = c(Casual = 15, Member = 16)) +
scale_size_manual(values = c(Casual = 3, Member = 2)) +
theme(
axis.ticks = element_blank(),
axis.text = element_blank(),
axis.title = element_blank()
) +
labs(
title = "Top 10 casual and member rider stations",
subtitle = "Both start and end stations",
color = legend_title, shape = legend_title, size = legend_title
)
base +
geom_point(
data = casual_top_station,
aes(
x = longitude,
y = latitude,
color = id, shape = id, size = id
),
alpha = 0.5
) +
geom_point(
data = member_top_station,
aes(
x = longitude,
y = latitude,
color = id, shape = id, size = id
),
alpha = 0.5
)
Also, to simplify your code further I would suggest to bind both data frames by row using e.g. dplyr::bind_rows which would allow to add your points via just one geom_point.
top_station <- dplyr::bind_rows(casual_top_station, member_top_station)
base +
geom_point(
data = top_station,
aes(
x = longitude,
y = latitude,
color = id, shape = id, size = id
), alpha = .5)
I created a multi-layer map using ggmap() in R. I would like to add an arc between two points on the map. I tried doing so with geom_curve(). This doesn't work. The two maps in the overlay are then no longer properly superimposed. I suspect this is due to the different projections within the map overlay, but I don't fully understand this.
Is there a way to specify a coordinate reference system (CRS) for an arc that matches the CRS in use in the map already? Or a totally different way I could add one arc between two points in my exisiting map?
A similar question with an accepted solution was already asked on stack overflow ("Draw curved lines in ggmap, geom_curve not working"). However, as noted there, the solution doesn't work for larger map areas.
Here is a minimal working example with some comments:
My system
I'm using R 4.2.0 with RStudio version 2022.02.3 Build 492.
Required Packages
install.packages("rnaturalearth")
install.packages("devtools") # Needed for rnaturalearthhires
devtools::install_github("ropensci/rnaturalearthhires") # Ditto
install.packages("ggmap")
install.packages("ggplot2")
install.packages("dplyr")
install.packages("PBSmapping") #For clipping polygons
install.packages("ggsn") #For the scale bar
library(rnaturalearth)
library(rnaturalearthhires) # Needed for scale = large in ne_countries()
library(ggmap)
library(ggplot2)
library(dplyr)
library(PBSmapping)
library(ggsn)
Plot a map that includes Germany and Saudi Arabia
Define the map for the region including Germany and Saudi Arabia (KSA) with
latitude and longitude (x min, y min, x max, y max)
GermanyKSA_map_coordinates <- c(5, 16, 56, 56)
Set unique values for the two countries for coloring them on the larger map
GermanyKSA_values <- data.frame(region = factor(c("Germany", "Saudi Arabia")), data = c(15, 15))
Get an existing map of the region including both countries
GermanyKSA_map <- get_map(location = GermanyKSA_map_coordinates, source = "stamen", zoom = 6)
Get country polygon data and join these to the unique values
world <- ne_countries(scale = "large", returnclass = "sf")
mapdata <- map_data("world")
GermanyKSA_mapdata <- left_join(mapdata, GermanyKSA_values, by = "region")`
Create a bounding box for the region map
GermanyKSA_map_bb <- attr(GermanyKSA_map, "bb")
GermanyKSA_ylim <- c(GermanyKSA_map_bb$ll.lat, GermanyKSA_map_bb$ur.lat)
GermanyKSA_xlim <- c(GermanyKSA_map_bb$ll.lon, GermanyKSA_map_bb$ur.lon)`
Clip polygons to match the map
colnames(GermanyKSA_mapdata)[1:6] <- c("X","Y","PID","POS","region","subregion")
GermanyKSA_mapdata <- clipPolys(GermanyKSA_mapdata, xlim = GermanyKSA_xlim, ylim = GermanyKSA_ylim, keepExtra = TRUE)`
Add dots for the cities Regensburg, Germany, and Al-Hofuf, Saudi Arabia
Regensburg_Dot <- c(12.1015461, 49.0204469)
AlHofuf_Dot <- c(49.401569, 25.363091)`
Create a data frame with the dot coordinates
Dots <- rbind(Regensburg_Dot, AlHofuf_Dot) %>% as.data.frame()
Rename the columns
colnames(Dots) <- c("long", "lat")
Plot map overlay. Provides exactly what I need, only an arc between the two cities is missing
ggmap(GermanyKSA_map) +
coord_map(xlim = GermanyKSA_xlim, ylim = GermanyKSA_ylim) +
geom_polygon(data = GermanyKSA_mapdata, aes(x = X, y = Y, group = PID, fill = data),
color = "black", alpha=0.5) +
geom_point(data = Dots, aes(x = long, y = lat), col = "#990022", size = 4) +
scalebar(x.min = 5, x.max = 56, y.min = 16, y.max = 56, dist = 500,
dist_unit = "km", transform = TRUE, anchor = c(x = 52, y = 54),
box.fill = c("#990022", 'grey'), box.color = c("#990022", 'grey'),
st.dist = .025, st.size = 3) +
theme(legend.position = "none") +
theme(axis.title.x = element_blank(), axis.title.y = element_blank()) +
ggtitle("Regensburg–Al-Hofuf: 4,093 km")`
Unsuccessful attempt to add an arc between both points (Regensburg and Al-Hofuf)
Create data frame for drawing an arc
RegensburgToAlHofuf <- data.frame(Regensburg_x = 12.1015461,
Alhofuf_x = 49.401569, Regensburg_y = 49.0204469, Alhofuf_y = 25.363091)`
Plot map overlay, now with an attempt to draw an arc with geom_curve(). Resulting warning: "geom_curve is not implemented for non-linear coordinates"
ggmap(GermanyKSA_map) +
coord_map(xlim = GermanyKSA_xlim, ylim = GermanyKSA_ylim) +
geom_polygon(data = GermanyKSA_mapdata, aes(x = X, y = Y, group = PID,
fill = data), color = "black", alpha=0.5) +
geom_point(data = Dots, aes(x = long, y = lat), col = "#990022", size = 4) +
geom_curve(data = RegensburgToAlHofuf,
aes(x = Regensburg_x, y = Regensburg_y, xend = Alhofuf_x, yend = Alhofuf_y),
size = 1.5, color = "#990022", curvature = 0.15, inherit.aes = TRUE) +
scalebar(x.min = 5, x.max = 56, y.min = 16, y.max = 56, dist = 500,
dist_unit = "km", transform = TRUE, anchor = c(x = 52, y = 54),
box.fill = c("#990022", 'grey'), box.color = c("#990022", 'grey'),
st.dist = .025, st.size = 3) +
theme(legend.position = "none") +
theme(axis.title.x = element_blank(), axis.title.y = element_blank()) +
ggtitle("Regensburg–Al-Hofuf: 4,093 km")`
I added a call to a map projection, coord_cartesian(), following suggestion in "Draw curved lines in ggmap, geom_curve not working". However, plots are not correctly superimposed. I also tried coord_quickmap() instead of coord_cartesian(), which also didn't work.
ggmap(GermanyKSA_map) +
coord_map(xlim = GermanyKSA_xlim, ylim = GermanyKSA_ylim) +
geom_polygon(data = GermanyKSA_mapdata, aes(x = X, y = Y, group = PID,
fill = data), color = "black", alpha=0.5) +
geom_point(data = Dots, aes(x = long, y = lat), col = "#990022", size = 4) +
geom_curve(data = RegensburgToAlHofuf,
aes(x = Regensburg_x, y = Regensburg_y, xend = Alhofuf_x, yend = Alhofuf_y),
size = 1.5, color = "#990022", curvature = 0.15, inherit.aes = TRUE) +
scalebar(x.min = 5, x.max = 56, y.min = 16, y.max = 56, dist = 500,
dist_unit = "km", transform = TRUE, anchor = c(x = 52, y = 54),
box.fill = c("#990022", 'grey'), box.color = c("#990022", 'grey'),
st.dist = .025, st.size = 3) +
theme(legend.position = "none") +
theme(axis.title.x = element_blank(), axis.title.y = element_blank()) +
ggtitle("Regensburg–Al-Hofuf: 4,093 km") +
coord_cartesian()`
I am new to Spatial data & cartogram lib and getting some issues while trying to recreate plot from: https://www.r-graph-gallery.com/a-smooth-transition-between-chloropleth-and-cartogram.html
Lib & Data
library(tidyverse)
library(maptools)
library(cartogram)
library(viridis)
library(sf)
data("wrld_simpl")
afr_cartogram = wrld_simpl[wrld_simpl$REGION==2,]
After this, I had some error: like st_transform ..... which I fixed it after some googling using sf lib.
afr_sf <- st_as_sf(afr_cartogram)
afr_sf_proj = st_transform(afr_sf,3857)
afr_plot <- cartogram::cartogram(afr_sf_proj, "POP2005", itermax =7)
ISSUE: Now after this step I am unable to recreate the code as it is in the demo website as I do not have column group in my data.
ggplot() +
geom_polygon(data = afr_plot, aes(fill = POP2005/1000000, x = LON, y = LAT, group = group) , size=0, alpha=0.9) +
theme_void()
From where can I get group column ???
Code used in website:
data(wrld_simpl)
afr=wrld_simpl[wrld_simpl$REGION==2,]
afr_cartogram <- cartogram(afr, "POP2005", itermax=7)
# Transform these 2 objects in dataframe, plotable with ggplot2
afr_cartogram_df <- tidy(afr_cartogram) %>% left_join(. , afr_cartogram#data, by=c("id"="ISO3"))
afr_df <- tidy(afr) %>% left_join(. , afr#data, by=c("id"="ISO3"))
# And using the advices of chart #331 we can custom it to get a better result:
ggplot() +
geom_polygon(data = afr_df, aes(fill = POP2005/1000000, x = long, y = lat, group = group) , size=0, alpha=0.9) +
theme_void() +
scale_fill_viridis(name="Population (M)", breaks=c(1,50,100, 140), guide = guide_legend( keyheight = unit(3, units = "mm"), keywidth=unit(12, units = "mm"), label.position = "bottom", title.position = 'top', nrow=1)) +
labs( title = "Africa", subtitle="Population per country in 2005" ) +
ylim(-35,35) +
theme(
text = element_text(color = "#22211d"),
plot.background = element_rect(fill = "#f5f5f4", color = NA),
panel.background = element_rect(fill = "#f5f5f4", color = NA),
legend.background = element_rect(fill = "#f5f5f4", color = NA),
plot.title = element_text(size= 22, hjust=0.5, color = "#4e4d47", margin = margin(b = -0.1, t = 0.4, l = 2, unit = "cm")),
plot.subtitle = element_text(size= 13, hjust=0.5, color = "#4e4d47", margin = margin(b = -0.1, t = 0.4, l = 2, unit = "cm")),
legend.position = c(0.2, 0.26)
) +
coord_map()
The group columns are produced in these lines
afr_cartogram_df <- tidy(afr_cartogram) %>%
left_join(afr_cartogram#data, by = ("id" = "ISO3"))
afr_df <- tidy(afr) %>%
left_join(afr#data, by = c("id" = "ISO3"))
by the tidy function from package broom which is not attached in your code!
Attach broom using library(broom) or call tidy() from its namespace like this: broom::tidy(...).
The 'data section' in your code should look like this:
data(wrld_simpl)
afr <- wrld_simpl[wrld_simpl$REGION==2, ]
afr_cartogram <- wrld_simpl[wrld_simpl$REGION == 2,]
afr_sf <- st_as_sf(afr_cartogram)
afr_sf_proj <- st_transform(afr_sf, 3857)
afr_plot <- cartogram_cont(afr_sf_proj, "POP2005", itermax =7)
afr_cartogram_df <- broom::tidy(afr_cartogram) %>%
left_join(afr_cartogram#data, by=c("id" = "ISO3"))
afr_df <- broom::tidy(afr) %>%
left_join(afr#data, by=c("id" = "ISO3"))
The subsequent ggplot code works fine then:
I am trying to plot a heatmap of a country with some points that are probabilities of occurrence of a event.
What I did up to now is next:
library(raster)
library(ggplot2)
Uruguay <- getData("GADM",country="Uruguay",level=0)
ggplot(Uruguay,aes(x=long,y=lat,group=group)) +
ggplot2::lims(x = c(-60, -50), y = c(-35, -30))+
geom_polygon(aes(x = long, y = lat, group = group, fill=id),color="grey30")+
coord_map(xlim=c(-1,1)+bbox(Uruguay)["x",],ylim=c(-1,1)+bbox(Uruguay)["y",])+
scale_fill_discrete(guide="none")+
theme_bw()+theme(panel.grid=element_blank())
my data to produce the heatmap is
prob <- c(10,20,90,40)
lat <- c(-30.52,-32.04,-33.16,-34.28)
long <- c(-57.40,-55.45,-56.35,-56.40)
data <- data.frame(prob, lat, long)
I think that using ggplot2::stat_density2d and ggplot2::scale_fill_gradientn is the way to go but I don't know how to implement it. I want to produce a heatmap like that
Any help is Welcome.
Thanks in advance.
To plot the example data you could just use plot
library(raster)
Uruguay <- getData("GADM",country="Uruguay",level=0)
plot(Uruguay, col="orange")
As for the map you want to make, there are a lot of choices involved. But here is a basic example
prob <- c(10,20,90,40)
lat <- c(-30.52,-32.04,-33.16,-34.28)
long <- c(-57.40,-55.45,-56.35,-56.40)
data <- data.frame(prob, lat, long)
r <- raster(Uruguay, res=.5)
x <- rasterize(cbind(long, lat), r, prob)
plot(x)
lines(Uruguay)
Finally I could get what I wanted. Henrik's answer in this post was very helpful
I share the code with you
library(raster)
library(reshape2)
library(ggplot2)
Uruguay <- getData("GADM",country="Uruguay",level=1)
#invented data
prob <- c(5, 90,10,15,99,40,90,25,70,90)
lat <- c(-31,-31.2,-31.3,-34,-32.5,-32.6,-33.7,-34.9,-34.2,-32.5)
long <- c(-58.3,-55.1,-57.3,-58.4,-56.5,-54,-57.7,-55.8,-54.1,-53.5)
prueba <- data.frame(prob, lat, long)
library(akima)
fld <- with(prueba, interp(x = long, y = lat, z = prob))
class(Uruguay)
uru <- fortify(Uruguay)
library(reshape2)
# prepare data in long format
df <- melt(fld$z, na.rm = TRUE)
names(df) <- c("x", "y", "prob")
df$long <- fld$x[df$x]
df$lat <- fld$y[df$y]
ggplot() +
geom_polygon(data = uru, aes(x = long, y = lat, group = group),
colour = "black", size = 0.5, fill = "white") +
geom_tile(data = df, aes(x = long, y = lat, z = prob, fill = prob), alpha = 0.8) +
ggtitle("Frost probability") +
xlab("Longitude") +
ylab("Latitude") +
scale_fill_continuous(name = "Probability (%)",
low = "red", high = "blue") +
theme_bw() +`enter code here`
theme(plot.title = element_text(size = 25, face = "bold"),
legend.title = element_text(size = 15),
axis.text = element_text(size = 15),
axis.title.x = element_text(size = 20, vjust = -0.5),
axis.title.y = element_text(size = 20, vjust = 0.2),
legend.text = element_text(size = 10)) +
coord_map()