Using ggplot I want to add points to a sf map. Take this code:
ggplot(data = shapefile) +
geom_sf()+
geom_point(x = -70.67,y =-33.45, size = 10, colour = "red")
This code works fine for one of my shapefiles but not for another, and I'm not sure why. Here's the code's output with my first shapefile:
And here's the code's output with the second shapefile:
Potential reasons for why the second call is not recognizing the coordinates? The only difference I'm seeing between the two plots is that in the first, longitude and latitude are annotated numerically, and in the second, after their north/south and east/west orientation.
The inconsistent behavior is due to different projections for each shapefile. You typically need to supply the point locations that match the units of the projection you are using. You could either convert the points to your shapefile's projection, or, if you don't care if the data are in a geographic coordinate system, you can convert to 4326 which is lat/long on WGS84 datum.
Method 1: Maintaining your shapefile's projection. This method will convert your point(s) to a spatial sf data type, so you can just plot with geom_sf.
pts <- st_point(c(-70.67, -33.45)) %>% st_sfc() %>% st_as_sf(crs=st_crs(4326))
ggplot(data = shapefile) +
geom_sf() +
geom_sf(data = pts, size = 10, colour = "red")
Method 2: Converting the shapefile to EPSG 4326.
ggplot(data = shapefile %>% st_transform(st_crs(4326))) +
geom_sf() +
geom_point(x = -70.67,y =-33.45, size = 10, colour = "red")
Related
I'm trying to display labels on GIS polygon features in R using the st_centroid function in the sf library. Unfortunately, while the head() function seems to show that each polygon has different x and y coordinates associated with it, all labels get rendered overlapping at a single point on the map (which is apparently the centroid of one particular polygon). What am I doing wrong here?
Current code setup:
library("ggplot2")
library("sf")
sf::sf_use_s2(FALSE) #makes centroids not break
world <- st_read("C:/prgrm/gis/source/10m_land_and_islands.shp")
prov <- st_read("C:/prgrm/gis/edited ncm/ncm_provinces.shp")
prov <- cbind(prov, st_coordinates(st_centroid(prov))) #attaches centroids to 'prov' dataset
head(prov)
ggplot(data = world) +
geom_sf() +
geom_sf(data=prov, aes(fill="blue")) +
geom_text(data=prov, aes(X,Y, label=provname_r), size=5) +
coord_sf(xlim=c(-2000000,1000000),ylim=c(-1500000, 3000000), crs=st_crs(3310))
You may be better off with specifying the centroid placement via fun.geometry argument of the geom_sf_text() call / by the way the default is sf::st_point_on_surface() - which is a good default as it makes sure that the label is not placed inside a hole, should the polygon have one.
Consider this example, using the well known & much loved nc.shp shapefile that ships with {sf}.
library(sf)
library(ggplot2)
# in place of your world dataset
shape <- st_read(system.file("shape/nc.shp", package="sf")) # included with sf package
# in place of your prov dataset
ashe <- shape[1, ]
ggplot(data = shape) +
geom_sf() +
geom_sf(data = ashe, fill = "blue") +
geom_sf_text(data = ashe,
aes(label = NAME),
color = "red",
fun.geometry = st_centroid)
I want to generate 12 maps using ggplot and facet_wrap which illustrate ocean temperature across the Scotian shelf from Jan-Dec. I was given a ".csv" file with 25,000 observations, which has monthly temperature data from 2016-2018 with the associated latitude and longitude values. I have tried using geom_raster to map this data but I get the following error message
Error: cannot allocate vector of size 39.7 Gb
In addition: Warning messages:
1: In f(...) :
Raster pixels are placed at uneven horizontal intervals and will be shifted. Consider using geom_tile() instead.
2: In f(...) :
Raster pixels are placed at uneven vertical intervals and will be shifted. Consider using geom_tile() instead
So of course, I have also tried using geom_tile but when I run the code I get a blank map with no color even though I have specified both fill and color. Here is some sample data similar to my data frame, please note that my real data for latitude and longitude values are not evenly spaced by seq(...,...,0.1) (I'm not sure how to make sample data without the sequencing, sorry) so you won't get the same error as me, and the code will work
#In my data frame the lat and long values are not equally spaced!
mapoc_temp = expand.grid(data.frame(Longitude= seq(-64.5,-62.4,0.1),
Latitude= seq(42.7,44.8,0.1),
year = sample(c(2016,2017,2018), 22, replace = T),
month = sample(month.abb, 22, replace = T)))
mapoc_temp$Temp = runif(nrow(mapoc_temp))
Here is my code for geom_raster which gives me the error I mentioned
library(mapdata)
library(ggplot2)
#map I'm using for ggplot
Canada = map_data("wildfires", "Canada")
ggplot(mapoc_temp, aes(x=Longitude, y=Latitude)) +
#try to map my temp on the ocean
geom_raster(aes(fill = Temp, x = Longitude), interpolate = TRUE) +
geom_polygon(data = Canada, aes(x=long, y=lat, group=group), colour="grey50", fill = 'grey55')+
coord_sf(xlim=c(-64.5,-62.8), ylim=c(42.7,45)) +
#get months
facet_wrap(vars(month))
here is the code when I try geom_tile, again I noticed with my sample data it works, but with my real data it doesn't and I believe it has something to do with my coordinates not being equal distances apart.
ggplot(mapoc_temp, aes(x=Longitude, y=Latitude)) +
geom_tile(aes(fill = Temp, x = Longitude, y = Latitude), colour = mapoc_temp$Temp) +
geom_polygon(data = canada, aes(x=long, y=lat, group=group), colour="grey50", fill = 'grey55')+
coord_sf(xlim=c(-64.5,-62.8), ylim=c(42.7,45)) +
facet_wrap(vars(month))
here is the picture I get with geom_tile
and here is roughly what I am trying to produce, but obviously, 12 of these maps because I want a map for each month, with better resolution (if possible, but at this point, I'll take any map colored with my temperature data).
I have a feeling I'll have to do something more along the lines with this type of code (a snippet of something I found a while ago), but I have tried manipulating this with no success. Any suggestions?
#my CRS value!
latlong = "+proj=longlat +datum=NAD83 +no_defs +ellps=GRS80 +towgs84=0,0,0"
#for transforming
planar ="+proj=utm +zone=20 +datum=NAD83 +units=km +no_defs +ellps=GRS80 +towgs84=0,0,0"
out <- x%>%
st_as_sf(coords=c("Longitude","Latitude"),crs=latlong)%>%
st_transform(planar)%>%
st_coordinates()%>%
raster::rasterize(.,grid,field=xyz[,3],fun=rasterFun)%>%
raster::projectRaster(.,crs=latlong)%>%
raster::rasterToPolygons(.)%>% # this part is slow
st_as_sf()%>%
rename(MAP = layer)
You have sort of answered your own question with the example data you offered. The geom_raster and geom_tile functions have limits to their use. A big one is that because they require the data to be on an even grid, with very high res station data the machine will try to create an even grid before plotting, hence the error of needing 39.7 GB of memory. By rounding your lon/lat values to an even 0.1x0.1 grid the machine is now able to plot the data in the other answers in this post. Try running the following code chunk on your data.
mapoc_temp <- mapoc_temp %>%
ungroup() %>%
mutate(Longitude = plyr::round_any(Longitude, 0.1),
Latitude = plyr::round_any(Latitude, 0.1))
You may change the level of rounding as you prefer, but avoid going too fine scale unless it is absolutely necessary. Once your data have been rounded to an even grid you can plot them with the following chunk.
ggplot(mapoc_temp, aes(x = Longitude, y = Latitude)) +
borders(fill = "grey80") +
geom_raster(aes(fill = Temp)) +
coord_quickmap(xlim = c(-64.5,-62.8), ylim = c(42.7,45)) +
facet_wrap(~month)
There is no need to create any sf shape polygons or add any CRS information to the plot. The tidyverse is not designed to utilise this information and in my opinion it only complicates things unnecessarily to bring in the sf package. I hope this helps!
It looks like the geom_polygon(mapping layer) was overplotting the geom_tile layer. Below is an example using your example data with geom_tile called last, and with alpha set to 0.4 to show the map beneath.
#In my dataframe the lat and long values are not equally spaced!
mapoc_temp = expand.grid(data.frame(Longitude= seq(-64.5,-62.4,0.1),
Latitude= seq(42.7,44.8,0.1),
year = sample(c(2016,2017,2018), 22, replace = T),
month = sample(month.abb, 22, replace = T)))
mapoc_temp$Temp = runif(nrow(mapoc_temp))
library(mapdata)
#> Loading required package: maps
library(ggplot2)
#map I'm using for ggplot
canada = map_data("worldHires", "Canada")
## Use geom_raster as the last layer in the ggplot2 call,
## otherwise the polygons plot over the tiles.
## Below alpha is set on the raster layer to show underlying map.
ggplot(mapoc_temp, aes(x=Longitude, y=Latitude)) +
#try to map my temp on ocean
geom_polygon(data = canada, aes(x=long, y=lat, group=group), colour="grey50", fill = 'grey55')+
geom_raster(aes(fill = Temp, x = Longitude),alpha = .4, interpolate = TRUE) +
coord_sf(xlim=c(-64.5,-62.8), ylim=c(42.7,45)) +
#get months
facet_wrap(vars(month))
Created on 2020-02-22 by the reprex package (v0.3.0)
You can also set fill= NA within your geom_polygon function if you have that layer on top of the geom_raster
I am trying to create a simple map using ggplot2 to display a series of river basins and data points.
The data points are stored in a .csv file and look like this:
I've projected the points and created a SpatialPointDataFrame and then stored them in a dataframe:
points <- read.csv(c(paste0("./Points/", "points.csv")), header = T, sep = ",")
coordinates(points) <- ~Lat + Lon
cord <- "+init=epsg:2163"
proj4string(points) <- CRS(cord)
points_df <- as.data.frame(points, region = "id")
The basin files are all stored in the same directory and have been read into a single spatialpolygonsdataframe which looks like this:
then are converted to a dataframe using this:
basins_TX$id <- rownames(basins#data)
basins_TX_df <- tidy(basins, region = "id")
Then I try to create a map using this code:
ggplot() +
geom_polygon(data = basins_df,
aes(x = long, y = lat, group = group),
fill = "white", color = "black") +
geom_point(data = points_df,
aes(x = Lon, y = Lat),
color = "red")
this creates a map with polygons and one point at 0,0:
This happens no matter what subsection of the data I am looking at. I want to accurately display the points and the polygons.
The issue was in fact related to the projection of my data. I had defined the projection of the points file rather than projecting it, so it was incorrect. I was able to correct this by redefining it correctly and the projecting the points file using spTransform
leaving this up in case other run into similar issues, although the error was not in the ggplot2 script.
I am trying to plot a polygon with geom_sf() in any projection other than lat-long.
I am using the example found in the manual pages for geom_sf()
Importing the dataset:
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
transforming from latlong into epsg:3857
nc_3857 <- sf::st_transform(nc, "+init=epsg:3857")
Finally plot with ggplot2 defining the crs of the plot:
ggplot() +
geom_sf(data = nc_3857, colour = "red", fill = NA) +
coord_sf(crs=st_crs(3857))
I keep getting a map in wgs84 (i.e. epsg:4326) with lat-long axes. I want to have the axes in meters, so I need ggplot to plot the projected polygon. What am I doing wrong?
See also https://github.com/tidyverse/ggplot2/issues/2200 and try
ggplot() + geom_sf(data = nc_3857, colour = "red", fill = NA) +
coord_sf(datum=st_crs(3857))
which gives
It is plotting it in the requested projection, its just overlaying a lat-long graticule.
If you try a similar thing with Norway, for example, being close to the north pole you can see that the display X-Y coordinates are those of the transformation but the overlaying graticule is lat-long. This is a map of Norway which is in epsg 3035 (conical) coordinates:
So it is plotting the projected polygon. If the lat-long lines here were a grid then it would have been plotting the coordinates back in lat-long projection.
The only mention of graticules in the docs is an arg to coord_sf:
datum: CRS that provides datum to use when generating graticules
which doesn't really say much.
You just want a cartesian coordinate system? Oh lets try:
> ggplot() + geom_sf(data = rp, colour = "red", fill = NA) + coord_cartesian()
Error: geom_sf() must be used with coord_sf()
Check the ggplot2 issues for alternate graticules with geom_sf, and add an issue if there's nothing there.
I am having clipping problems when I try to combine ggmap with shape files. The example in Kahle and Wickham (2013: 158) works fine because the raster image from ggmap covers the entire shape file. Below is an example of what happens when I try to plot the shape file for U.S. states on a ggmap plot that covers a smaller area. The ggmap shows New York City and I want to overlay it with the borders for U.S. states (just as an example). The resulting map doesn't make any sense. The problem is that the shape file gets clipped and ggplot connects the unclipped points. Below is the code. The shape file is from here. I am just showing the last plot here.
How can I solve this problem?
path <- "PATH TO SHAPEFILE"
library("ggmap")
library("rgdal")
# shapefile
states <- readOGR(dsn = path, layer = "states")
states_df <- fortify(states)
# plot shapefile
plot(states, lwd = 0.1)
ggplot(states_df, aes(long, lat, group = group)) +
geom_polygon(colour = "black", fill = NA, size = 0.1)
# combine ggmap with shapefile
map <- get_map("new york city", zoom = 10, source = "stamen")
ggmap(map, extent = "device")
ggmap(map, extent = "device") +
geom_polygon(aes(long, lat, group=group), data = states_df, colour = "red", fill = NA, size = 1)
Kahle, David and Hadley Wickham. 2013. “Ggmap: Spatial Visualization with ggplot2.” The R Journal 5(1):144–61.
Here is my attempt. I often use GADM shapefiles, which you can directly import using the raster package. I subsetted the shape file for NY, NJ and CT. You may not have to do this in the end, but it is probably better to reduce the amount of data. When I drew the map, ggplot automatically removed data points which stay outside of the bbox of the ggmap image. Therefore, I did not have to do any additional work. I am not sure which shapefile you used. But, GADM's data seem to work well with ggmap images. Hope this helps you.
library(raster)
library(rgdal)
library(rgeos)
library(ggplot2)
### Get data (shapefile)
us <- getData("GADM", country = "US", level = 1)
### Select NY and NJ
states <- subset(us, NAME_1 %in% c("New York", "New Jersey", "Connecticut"))
### SPDF to DF
map <- fortify(states)
## Get a map
mymap <- get_map("new york city", zoom = 10, source = "stamen")
ggmap(mymap) +
geom_map(data = map, map = map, aes(x = long, y = lat, map_id = id, group = group))
If you just want lines, the following would be what you are after.
ggmap(mymap) +
geom_path(data = map, aes(x = long, y = lat, group = group))
I would check out this answer, it seems that ggmap as you expected doesn't handle polygon's in an ideal way when you zoom in, namely items not on the plot get truncated causing 'interesting' results with respect to the shape files.
Polygons nicely cropping ggplot2/ggmap at different zoom levels
# transform for good measure
states <- spTransform(states,CRS("+datum=WGS84 +proj=longlat") )
# combine ggmap with shapefile
states_df <- fortify(states)
# get your map
map <-get_map("new york city", zoom = 10, source = "stamen")
a <- ggmap(map, # this is where we get our raster
base_layer=ggplot(aes(x=long, y=lat), data=states_df), # this defines the region where things are plotted
extent = "normal", # this won't work with device, you need normal (see examples in ggmap documentation)
maprange=FALSE
) +
coord_map( # use map's bounding box to setup the 'viewport' we want to see
projection="mercator",
xlim= c(attr(map, "bb")$ll.lon, attr(map, "bb")$ur.lon),
ylim=c(attr(map, "bb")$ll.lat, attr(map, "bb")$ur.lat)
) +
geom_polygon( # plot the polygon
aes(x=long, y=lat,group=group), data =states_df, color = "red", fill=NA, size = 1)
print(a)
With output:
As a side note you might want to check out using the U.S. Census data for state maps, they seem to be of higher quality than the ESRI data set.
ftp://ftp2.census.gov/geo/pvs/tiger2010st/tl_2010_us_state10.zip
As a final note, there are issues with ggmap near the poles so I would also subset your data by the states you are interested in.