I want to draw a map like the below picture of untitled state and show the center of all state by a colorful circle.
There is google map API which can use in R.But it seems that it's no longer available to use free of charge.
How can I draw this picture by Stamn Maps library in R?
If there is a good tutorial about Stamn Maps, I'll appreciate any helps.
thanks for your answers I find one of the solutions that shows map in r by Stamn Maps
d <- data.frame(lat = state.center$y,
lon = state.center$x)
#-128.5, 27.5, -69, 49
US <- get_stamenmap(bbox = c(left = -128.5, bottom = 27.5, right =
-68, top = 50) ,zoom = 4, maptype = c("terrain",
"terrain-background", "terrain-labels", "terrain-lines", "toner",
"toner-2010", "toner-2011", "toner-background", "toner-hybrid",
"toner-labels", "toner-lines", "toner-lite", "watercolor"),
crop = TRUE, messaging = FALSE, urlonly = FALSE,
color = c("color", "bw"), force = FALSE, where = tempdir())
p <- ggmap(US, base_layer = ggplot(data = d)) +
geom_point(aes(x = lon, y = lat), color = "blue", size = 2, alpha = 0.5)
p
A minimal example to kickstart your journey:
set.seed(1702)
points <- data.frame(lon = rnorm(10, -95.4, 0.1),
lat = rnorm(10, 29.7, 0.1))
# get_stamenmap() defaults to the map of Houston, TX if there
# is no boundary box defined in the form of:
# c(lon_min, lat_min, lon_max, lat_max)
# For more information see ?get_stamenmap
ggmap(get_stamenmap()) +
geom_point(data = points,
aes(lon, lat),
color = "red")
Related
I have developed a genetic algorithm for estimating the probability of observing an animal, given its genotype, across a regular grid of locations, here in south-east England. Using ggplot2 I can easily generate either a probability contour plot or a land-only (polygon-filled) map, but what I want is a map where the contour plot is restricted to land:
()
The desired outcome is generated by adding a black mask to the contour plot in Powerpoint, a tedious procedure that is impractical for generating the hundreds I need. I am sure there must be a simple way to do this.
I generate the contour plot using:
v <- ggplot(data, aes(Lat, Lng, z = P))
v + geom_contour(bins = 20)
and the map using:
ggplot(data = world) +
geom_sf(color = "black", fill = "gray") +
coord_sf(xlim = c(-2.3, 1.9), ylim = c(50.9, 53.5), expand = FALSE)
my input file comprises all locations in 0.05 increments of longitude and latitude in the intervals specified. It is large but I would happily add it if this helps. I have looked online and cannot see any examples that match what I want.
I have tried adding one component to the other as an extra layer but I struggle to understand what is needed and what the syntax are. For example:
layer(geom = "contour", stat = "identity", data = data, mapping = aes(Lng,Lat,P))
Error: Attempted to create layer with no position.
but even if this works it does not mask the sea area.
Here's a worked example with some made-up data:
library(rnaturalearth)
library(ggplot2)
sea <- ne_download(scale = 10, type = 'ocean', category = "physical",
returnclass = "sf")
ggplot(data) +
geom_contour_filled(aes(Lng, Lat, z = P), bins = 20, color = "black") +
guides(fill = "none") +
geom_sf(data = sea, fill = "black") +
coord_sf(ylim = c(51, 53.5), xlim = c(-2.2, 1.8), expand = FALSE)
Data used
set.seed(1)
a <- MASS::kde2d(rnorm(100), rnorm(100, 53), n = 100,
lims = c(-2.2, 1.8, 51, 53.5))
b <- MASS::kde2d(rnorm(25, 0.5), rnorm(25, 52), n = 100,
lims = c(-2.2, 1.8, 51, 53.5))
a$z <- b$z - a$z + max(a$z)
data <- cbind(expand.grid(Lng = a$x, Lat = a$y), P = c(a$z))
Created on 2023-01-02 with reprex v2.0.2
I am trying to color in specific grid cells within a map to highlight sampling effort.
I can generate the map but then I am unsure how to utilize the data points I have to color in the entire grid cell. The data points I have are for the top left hand corner of a grid cell.
I have tried using stat_density2d (kernel density func), as far as I can work out the issue is I just want the discrete values plotted but currently it is filling in everything in-between.
library(ggOceanMaps)
library(ggOceanMapsData)
dt <- data.frame(lon = c(35, 35, 60, 60), lat = c(-25, -25, -40, -40))
grid_2_colour <- data.frame(lat=c(-29), long=c(50))
basemap(data = dt, bathymetry = TRUE,
lon.interval = 1,
lat.interval = 1,
# bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1) +
stat_density2d(data = grid_2_colour, aes(x = long, y = lat, fill =..density..), geom = 'tile', contour = F)
found a solution:
m1 = basemap(data = dt, bathymetry = TRUE,
lon.interval = 1,
lat.interval = 1,
# bathy.style = "contour_blues",
bathy.border.col = NA,
bathy.size = 0.1,
bathy.alpha = 1)
m1 + stat_density2d(data = grid_2_colour, aes(x = long, y = lat, fill =..density..), geom = 'tile', contour = F)
I'm trying to map crime incidents in Boston. I converted the lat/long to simple feature points but when I plotted it, I only got two points. Does anyone know how to remedy this?
crimedata = read.csv("2019 Crime Incidents.csv", stringsAsFactors = FALSE)
points = st_as_sf(crimedata, coords = c("Lat", "Long"), crs = 4326)
plot(points$geometry, pch=16, col="navy")
You need to plot the points on top of a map:
library(tidyverse)
library(ggmap)
points <- tibble(
lon = c(-100, -90),
lat = c(40, 40),
value = c("A", "B")
)
c(left = -125, bottom = 25.75, right = -67, top = 49) %>%
get_stamenmap(zoom = 5, maptype = "toner-lite") %>%
ggmap() +
geom_point(
data = points,
mapping = aes(color = value),
size = 7
)
I am trying to fix the following problem.
I use ggplot2 to plot a map of an island:
island = get_map(location = c(lon = -63.247593, lat = 17.631598), zoom = 14, maptype = "satellite")
islandMap = ggmap(island, extent = "panel", legend = "bottomright")
RL = geom_point(aes(x = longitude, y = latitude), data = data, size = 4, color = "#ff0000")
islandMap + RL
Coordinates of the RL points:
data = data.frame(
ID = as.numeric(c(1:8)),
longitude = as.numeric(c(-63.27462, -63.26499, -63.25658, -63.2519, -63.2311, -63.2175, -63.23623, -63.25958)),
latitude = as.numeric(c(17.6328, 17.64614, 17.64755, 17.64632, 17.64888, 17.63113, 17.61252, 17.62463))
)
Now the problem is that when I use zoom = 13 the island is too small in the plot and when I use zoom = 14 it is perfectly centered. But when I plot the RL points, two get cut off because its too much to the East and the other one too much to the West. I looked some solutions up like the following one, using a boundary box. However, I am bound to using satellite imagery, so bound to Google, which doesn't support the boundary box solution.
lon = data$longitude
lat = data$latitude
box = make_bbox(lon, lat, f = 0.1)
island = get_map(location = box, zoom = 14, source = "osm")
islandMap = ggmap(island, extent = "panel", legend = "bottomright")
RL = geom_point(aes(x = longitude, y = latitude), data = data, size = 4, color = "#ff0000")
islandMap + RL
How can I make sure that the map is as big as using zoom = 14, all the points are within the plot (plus a margin around this) and satellite imagery?
Using my answer from this question, I did the following. You may want to get a map with zoom = 13, and then you want to trim the map with scale_x_continuous() and scale_y_continuous().
library(ggmap)
library(ggplot2)
island = get_map(location = c(lon = -63.247593, lat = 17.631598), zoom = 13, maptype = "satellite")
RL <- read.table(text = "1 17.6328 -63.27462
2 17.64614 -63.26499
3 17.64755 -63.25658
4 17.64632 -63.2519
5 17.64888 -63.2311
6 17.63113 -63.2175
7 17.61252 -63.23623
8 17.62463 -63.25958", header = F)
RL <- setNames(RL, c("ID", "Latitude", "Longitude"))
ggmap(island, extent = "panel", legend = "bottomright") +
geom_point(aes(x = Longitude, y = Latitude), data = RL, size = 4, color = "#ff0000") +
scale_x_continuous(limits = c(-63.280, -63.20), expand = c(0, 0)) +
scale_y_continuous(limits = c(17.60, 17.66), expand = c(0, 0))
I am generating maps with world-scale data, and then zooming in to certain regions. On the zoomed-in view, I would like to show that there are other data points outside the bounding box, by putting arrowheads that point from the center of the box to where the data point is in the outside world.
Note: I do not need it to be a "great circle" path, just XY vectors in Mercator projection, because I imagine this will be useful for "normal" plots as well.
As an example, here is the world map showing the extent of the data:
And here is the zoomed in view, with magenta arrows manually added to show what I would like to generate.
Below is the code and data I am using to generate these two basic plots. What I need is a way to generate the arrowheads.
require(ggplot2)
te = structure(list(lat = c(33.7399, 32.8571, 50.2214, 36.96263, 33.5835,
33.54557, 47.76147, 48, 59.40289, 35.93411, 32.87962, 38.3241,
50.03844, 37.44, 50.07774, 50.26668, 36.5944), lng = c(-118.37608,
-117.25746, -5.3865, -122.00809, -117.86159, -117.79805, -124.45055,
-126, -146.35157, -122.931472, -117.25285, -123.07331, -5.26339,
25.4, -5.709894, -3.86828, -121.96201)), .Names = c("lat", "lng"
), class = "data.frame", row.names = c(NA, -17L))
all_states = map_data("world")
# world version:
wp = ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group), colour = "gray",
fill = "gray") +
coord_cartesian(ylim = c(0, 80), xlim = c(-155, 45)) +
geom_point(data = te, aes(x = lng, y = lat), color = "blue", size = 5,alpha = 0.6)
print(wp)
#states plot
sp = ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group), colour = "gray", fill = "gray") +
coord_cartesian(ylim = c(30, 52), xlim = c(-128, -114)) +
geom_point(data = te, aes(x = lng, y = lat), color = "blue", size = 5, alpha = 0.6)
print(sp)
This solution uses sp and rgeos packages to manipulate spatial data, the main crux being intersecting lines and a box polygon to get the edge points for arrows. Then if you draw arrows with geom_segment and zero width, the line is invisible and only the arrow head remains.
This function computes the line-box intersections:
boxint <- function(xlim, ylim, xp, yp){
## build box as SpatialPolygons
box = cbind(xlim[c(1,2,2,1,1)],
ylim[c(1,1,2,2,1)])
box <- sp::SpatialPolygons(list(sp::Polygons(list(sp::Polygon(box)),ID=1)))
## get centre of box
x0=mean(xlim)
y0=mean(ylim)
## construct line segments to points
sl = sp::SpatialLines(
lapply(1:length(xp),
function(i){
sp::Lines(list(sp::Line(cbind(c(x0,xp[i]),c(y0,yp[i])))),ID=i)
}
)
)
## intersect lines segments with boxes to make points
pts = rgeos::gIntersection(sl, as(box, "SpatialLines"))
as.data.frame(sp::coordinates(pts), row.names=1:length(xp))
}
And this returns the geom with arrows:
wherelse <- function(xlim, ylim, points){
## get points outside bounding box
outsides = points[!(
points$lng>=xlim[1] &
points$lng <= xlim[2] &
points$lat >= ylim[1] &
points$lat <= ylim[2]),]
npts = nrow(outsides)
## get centre point of box
x = rep(mean(xlim),npts)
y = rep(mean(ylim),npts)
## compute box-point intersections
pts = boxint(xlim, ylim, outsides$lng, outsides$lat)
pts$x0=x
pts$y0=y
## create arrow segments as invisible lines with visible arrowheads
ggplot2::geom_segment(data=pts, aes(x=x0,y=y0,xend=x,yend=y),
lwd=0, arrow=grid::arrow(length=unit(0.5,"cm"),
type="closed"),col="magenta")
}
So your example, the basic plot is:
sp = ggplot() +
geom_polygon(
data=all_states,
aes(x=long, y=lat, group = group),colour="gray",fill="gray" ) +
coord_cartesian(ylim=c(30, 52), xlim=c(-128,-114)) +
geom_point(data=te,aes(x=lng,y=lat),color="blue",size=5,alpha=0.6)
and then add the arrows with:
sp + wherelse(c(-128,-114), c(30,52), te)
Not sure if there's an option to draw arrows exactly like you want them though!
Here is my attempt. This is the closest I got. I used gcIntermediate() for calculating the shortest distance between the center point of your US map and the data points which stay outside of the bbox. Hence, the arrow positions may not be something you want. My hope is that somebody else would deliver a better solution based on this attempt.
I first arranged your df (i.e., te) with the center point in the US zoomed map. I then chose data points which are not in the bbox of the US map. Then, add two columns to indicate the center point of the US map. Rename two columns and calculate the shortest distance with gcIntermediate.
library(dplyr)
library(ggplot2)
library(geosphere)
filter(te, !between(lng, -128, -114) | !between(lat, 30, 52)) %>%
mutate(start_long = (-128 - 114) / 2,
start_lat = (30 + 52) / 2) %>%
rename(end_lat = lat, end_long = lng) %>%
do(fortify(as(gcIntermediate(.[,c("start_long", "start_lat")],
.[,c("end_long", "end_lat")],
100,
breakAtDateLine = FALSE,
addStartEnd = TRUE,
sp = TRUE), "SpatialLinesDataFrame"))) -> foo
foo contains 100 data points to draw respective line. I chose data points which stay close to the bbox boundary. I was specifically looking for two data points for each line so that I could use geom_segment() later. I admit that I played with the filter condition a bit. In the end, I did not subset data using lat in this case.
filter(foo, between(long, -128, -126.5) | between(long, -115.5, -114)) %>%
group_by(group) %>%
slice(c(1,n())) -> mydf
In the next step, I rearranged the data frame based on this link
mutate(mydf, end_long = lag(long), end_lat = lag(lat)) %>%
slice(n()) -> mydf2
Finally I drew the map with arrows. I hope this will provide some kind of base for you. I also hope that other SO users will provide better solutions.
ggplot() +
geom_polygon(data = all_states, aes(x = long, y = lat, group = group),
colour = "gray", fill = "gray" ) +
coord_cartesian(ylim = c(30, 52), xlim = c(-128,-114)) +
geom_point(data = te, aes(x = lng,y = lat), color = "blue", size = 5,alpha = 0.6) +
geom_segment(data = mydf2, aes(x = end_long, xend = long,
y = end_lat, yend = lat, group = group),
arrow = arrow(length = unit(0.2, "cm"), ends = "last"))