I am trying to plot few points on map. But I get a blank map with just the points marked in red. The map is missing
Below code is reporducible
library(maps)
library(mapdata)
library(ggplot2)
library(ggmap)
lon <- c(-122.1817252,-119.4179324,-95.7128910,-71.0588801,-81.0348144)
lat <- c(37.452960,36.778261,37.090240,42.360082,34.000710)
all_places_geocoded <- data.frame(lon,lat)
gc <- geocode('australia')
center <- as.numeric(gc)
map <- get_googlemap(location = center,maptype = "roadmap", zoom=1)
ggmap(map) +
geom_point(data = all_places_geocoded, color = "red3", size = 1)
Related
I'm trying to create a map of Europe with grid cells coloured based on the number of records within a cell. Here I attach an image as illustrative of the desired output (see Fig 1 of https://doi.org/10.3897/phytokeys.74.9723).
In order to produce this image I have developed a minimal reproducible example with random points distributed across Europe. I have been able to produce a similar figure with levelplot but I'm particulary interested in doing this with ggplot as it will allow further customising. Is it possible to do produce a similar figure with ggplot? And if so, any advice of what path should I follow?
Note: The size of the grids/cells is irrelevant at the moment but I'll adjust it depending on point density. All of them have to be the same size as in the first example and they only will differ on the pattern of colour.
#Load libraries
library(rgdal) #v1.5-28
library(rgeos) #v.0.5-9
library(ggplot2) # 3.3.5
library(rworldmap) #plot worldmap v.1.3-6
library(dplyr) #v.1.0.7
#Create dataframe of coordinates that fall in Europe
coord <- data.frame(cbind(runif(1000,-15,45),runif(1000,30,75)))
colnames(coord) <- c("long","lat")
#Exlude ocean points following this post
URL <- "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/physical/ne_110m_ocean.zip"
fil <- basename(URL)
if (!file.exists(fil)) download.file(URL, fil)
fils <- unzip(fil)
oceans <- readOGR(grep("shp$", fils, value=TRUE), "ne_110m_ocean",
stringsAsFactors=FALSE, verbose=FALSE)
europe_coord <- data.frame(long = coord$long,
lat = coord$lat)
coordinates(europe_coord) <- ~long+lat
proj4string(europe_coord) <- CRS(proj4string(oceans))
ocean_points <- over(europe_coord, oceans)
#Add ocean points to dataset
coord$ocean <- ocean_points$featurecla
#Exlude ocean points
europe_land <- coord %>% filter(is.na(ocean))
#Load worldmap
world <- map_data("world")
#Plot europe spatial data
ggplot() + geom_map(data = world, map = world,
aes(long, lat, map_id = region), color = "white",
fill = "lightgray", size = 0.1) +
geom_point(data = europe_land,aes(long, lat),
alpha = 0.7, size = 0.05) + ylim(0,70) +
coord_sf(xlim = c(-15, 45), ylim = c(30, 75), expand = FALSE)
I want to produce a 2d-density plot based on spatial point data. In the background I want to show an open map (e.g. stamen terrain). Besides I want to plot the borders of Austria. Both datasets (data points and border) are shapefiles in EPSG 4326.
I managed to produce such a plot (see screenshots and code V1 below), but the problem is that there is a shift between the map in the background on the one side and the plotted points and the borders of Austria on the other side, as you can see below.
2D-Density Plot V1 - full
2D-Density Plot V1 - detail
Here is the code (V1):
library(sf)
library(rgdal)
library(ggplot2)
library(ggmap)
# Read point data (EPSG: 4326)
sk <- st_read("points.shp")
# Read country border polygon (EPSG: 4326)
blogr4326 <- readOGR(<path>, <layer name>)
bl4326_df <- fortify(blogr4326)
# Austria box (extent)
# Longitude: 9.6 to 16.94504
# Latitude: 46.52694 to 48.81667
map <- get_map(c(left = +9.6, bottom = 46.52694, right = +16.90, top = 48.99), color = "color", crop = FALSE)
hm_sk <- ggmap(map, extent = "panel", maprange=FALSE, darken=0.0) +
geom_point(data = sk, aes(x=X_WGS84, y=Y_WGS84)) +
stat_density2d(data = sk, aes(x=X_WGS84, y=Y_WGS84, fill = ..density.., alpha=cut(..density..,breaks=c(-Inf,0.08,Inf))), contour = FALSE, bins=16, geom = 'raster', n=500) +
ggtitle("Schwarzkiefer 2016/2020") + xlab("X_WGS84") + ylab("X_WGS84") +
scale_fill_distiller(palette= "Spectral", direction=-1, limits = c(0.08, 8.50)) +
scale_alpha_manual(values=c(0,0.7), guide="none") +
geom_polygon(data=bl4326_df, aes(long, lat, group=group), color='black', fill='NA', inherit.aes = TRUE) +
coord_fixed(1.5)
hm_sk
I found out that the shift is caused by the fact that the map in the background is in the projection EPSG:3857 and my shapefiles are in the projection EPSG:4326, as explained in this post. So I projected my shapefiles to EPSG 3857 and inserted the provided code into my code, as you can see here (V2):
library(sf)
library(rgdal)
library(ggplot2)
library(ggmap)
# Read point data (EPSG: 3857)
sk <- st_read("points.shp")
# Read country border polygon (EPSG: 3857)
blogr3857 <- readOGR(<path>, <layer name>)
bl3857_df <- fortify(blogr3857)
# Austria box (extent)
# Longitude: 9.6 to 16.94504
# Latitude: 46.52694 to 48.81667
map <- get_map(c(left = +9.6, bottom = 46.52694, right = +16.90, top = 48.99), color = "color", crop = FALSE)
#-------------------------------------------------------------------------------------------------
# Following code according to this link to avoid the shift between map and country border polygon:
# https://stackoverflow.com/questions/47749078/how-to-put-a-geom-sf-produced-map-on-top-of-a-ggmap-produced-raster
# Define a function to fix the bbox to be in EPSG:3857
ggmap_bbox <- function(map) {
if (!inherits(map, "ggmap")) stop("map must be a ggmap object")
# Extract the bounding box (in lat/lon) from the ggmap to a numeric vector,
# and set the names to what sf::st_bbox expects:
map_bbox <- setNames(unlist(attr(map, "bb")),
c("ymin", "xmin", "ymax", "xmax"))
# Convert the bbox to an sf polygon, transform it to 3857,
# and convert back to a bbox (convoluted, but it works)
bbox_3857 <- st_bbox(st_transform(st_as_sfc(st_bbox(map_bbox, crs = 4326)), 3857))
# Overwrite the bbox of the ggmap object with the transformed coordinates
attr(map, "bb")$ll.lat <- bbox_3857["ymin"]
attr(map, "bb")$ll.lon <- bbox_3857["xmin"]
attr(map, "bb")$ur.lat <- bbox_3857["ymax"]
attr(map, "bb")$ur.lon <- bbox_3857["xmax"]
map
}
# Use the function:
map <- ggmap_bbox(map)
#-------------------------------------------------------------------------------------------------
hm_sk <- ggmap(map,extent = "device", maprange=FALSE) +#, extent = "panel", maprange=FALSE, darken=0.0) +
coord_sf(crs = st_crs(3857)) + # f867orce the ggplot2 map to be in 3857
geom_point(data = sk, aes(x=X_PM, y=Y_PM)) +
stat_density2d(data = sk, aes(x=X_PM, y=X_PM, fill = ..density.., alpha=cut(..density..,breaks=c(-Inf,0.08,Inf))), contour = FALSE, bins=16, geom = 'raster', n=500) +
scale_fill_distiller(palette= "Spectral", direction=-1, limits = c(0.08, 8.50)) +
scale_alpha_manual(values=c(0,0.7), guide="none") +
geom_polygon(data=bl3857_df, aes(long, lat, group=group), color='black', fill='NA', inherit.aes = FALSE) +
ggtitle("Schwarzkiefer 2016/2020") + xlab("X_3857") + ylab("X_3857")
hm_sk
Now, the problem with the shift is solved, but the density plot is not visible anymore (only map, points and borders are plotted), as you can see here:
2D-Density Plot V2 - full
2D-Density Plot V2 - detail
Any suggestions, how I can produce a plot that is proper aligned AND includes the density plot? Thanks a lot in advance!
Is it possible to have a layer in ggplot that acts as a mask for a ggmap layer? Here they added a country polygon on top of a ggmap.
What I am looking for is that the country would be a "hole" in a layer (with alpha) covering everything but the country. In a way the inverse of the example above. The code from that answer (with transparency added and updated to use geom_cartogram).
library(mapdata)
library(ggmap)
library(ggplot2)
library(ggalt)
# Get Peru map
Peru <- get_map(location = "Peru", zoom = 5, maptype="satellite")
# This is the layer I wish to put over the top
coast_map <- fortify(map("worldHires", fill = TRUE, plot = FALSE))
# Subset data for Peru
peru.coast <- subset(coast_map, region == "Peru")
# Draw a graphic
ggmap(Peru) +
geom_cartogram(data = peru.coast, map = peru.coast, aes(x = long, y = lat, map_id = region),
fill="white", color="grey", alpha=.1) +
xlim(-86, -68) +
ylim(-20, 0) +
labs(x = "Longitude", y = "Latitude") +
coord_map() +
theme_classic()
Is there a way to fill everything but a polygon in ggplot2?
Is there a way to fill everything but a polygon in ggplot2?
This method may be a bit unorthodox, but anyway:
library(mapdata)
library(ggmap)
library(ggplot2)
library(raster)
ggmap_rast <- function(map){
map_bbox <- attr(map, 'bb')
.extent <- extent(as.numeric(map_bbox[c(2,4,1,3)]))
my_map <- raster(.extent, nrow= nrow(map), ncol = ncol(map))
rgb_cols <- setNames(as.data.frame(t(col2rgb(map))), c('red','green','blue'))
red <- my_map
values(red) <- rgb_cols[['red']]
green <- my_map
values(green) <- rgb_cols[['green']]
blue <- my_map
values(blue) <- rgb_cols[['blue']]
stack(red,green,blue)
}
Peru <- get_map(location = "Peru", zoom = 5, maptype="satellite")
data(wrld_simpl, package = "maptools")
polygonMask <- subset(wrld_simpl, NAME=="Peru")
peru <- ggmap_rast(Peru)
peru_masked <- mask(peru, polygonMask, inverse=T)
peru_masked_df <- data.frame(rasterToPoints(peru_masked))
ggplot(peru_masked_df) +
geom_point(aes(x=x, y=y, col=rgb(layer.1/255, layer.2/255, layer.3/255))) +
scale_color_identity() +
coord_quickmap()
Via this, this, and this questions/answers.
What I am looking for is the surroundings with a transparent fill
layer and Peru with alpha=1
If first thought this is easy. However, then I saw and remembered that geom_polygon does not like polygons with holes very much. Luckily, geom_polypath from the package ggpolypath does. However, it will throw an "Error in grid.Call.graphics(L_path, x$x, x$y, index, switch(x$rule, winding = 1L..." error with ggmaps default panel extend.
So you could do
library(mapdata)
library(ggmap)
library(ggplot2)
library(raster)
library(ggpolypath) ## plot polygons with holes
Peru <- get_map(location = "Peru", zoom = 5, maptype="satellite")
data(wrld_simpl, package = "maptools")
polygonMask <- subset(wrld_simpl, NAME=="Peru")
bb <- unlist(attr(Peru, "bb"))
coords <- cbind(
bb[c(2,2,4,4)],
bb[c(1,3,3,1)])
sp <- SpatialPolygons(
list(Polygons(list(Polygon(coords)), "id")),
proj4string = CRS(proj4string(polygonMask)))
sp_diff <- erase(sp, polygonMask)
sp_diff_df <- fortify(sp_diff)
ggmap(Peru,extent="normal") +
geom_polypath(
aes(long,lat,group=group),
sp_diff_df,
fill="white",
alpha=.7
)
I am plotting all latitude longitude values which I receive on a map like this.
The map has the color as per the time duration of halt recorded at that point.
My agonies are the following:
I cannot zoom in and zoom out - Centering the map is very painful - And I have 10*100 such collections to be plotted and evaluated
I can hardly make out the areas where the halt was specific, all I can see is that it was good with no halt but reality is not that
Hence I looked for plotly and to my surprise they don't have the support.
How can I achieve the results? I don't have a tool like tableau
Please suggest if you can help.
Below code is an example of what I am trying to do with ggmap :
library(ggplot2)
library(data.table)
library(ggmap)
library(maps)
library(mapdata)
lat <- seq(31.26415,31.26831,0.00010)
lon <- seq(76.80890,76.82320,0.00015)
lon <- lon[seq(1,96.2)]
lon <- lon[1:42]
lat_long <- data.frame(lat,lon)
lat_median <- 31.26751
lon_median <- 76.82003
#map <- get_map(location = c(lon_median, lat_median), maptype = "roadmap", zoom = 15)
map <- get_googlemap(center = c(lon_median, lat_median), zoom = 12, maptype = "roadmap",size = c(600, 300), scale = 2)
ggmap(map) +
geom_path(data = lat_long, aes(), size = 2, lineend = "butt") +
geom_point(data = lat_long, color = "red3", size = 1)
I am plotting few lat longs using ggmap and I get the output like this
I use the following code to generate this output, below code is part of the o/p
library(ggplot2)
library(data.table)
library(ggmap)
library(maps)
library(mapdata)
lat <- seq(31.26415,31.26831,0.00010)
lon <- seq(76.80890,76.82320,0.00015)
lon <- lon[seq(1,96.2)]
lon <- lon[1:42]
lat_long <- data.frame(lat,lon)
lat_median <- 31.26751
lon_median <- 76.82003
map <- get_map(location = c(lon_median, lat_median), maptype = "roadmap", zoom = 15)
ggmap(map) +
geom_path(data = lat_long, aes(), size = 2, lineend = "butt") +
geom_point(data = lat_long, color = "red3", size = 1)
My output window has lot of white space, which I could have used to show in the map. Can I increase this map output to better fit the window?
If you use the get_googlemap function you can specify the dimensions and it doesn't have to be square e.g.:
map <- get_googlemap('paris', zoom = 15, size = c(500, 200), scale = 2)