why ggplot and geom_tile create lines on the map? - r

Data: https://github.com/yuliaUU/data/blob/main/test.csv
griddf <- read_csv("test.csv")
create a map:
world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") # add continents
ggplot()+
geom_tile(data = Data |> dplyr::filter(Model.1=="RF"), aes(x = Lon, y = Lat, fill= value/1000))+geom_sf(data=world)+
viridis:: scale_fill_viridis(option = "H", na.value = NA) +
labs(fill="Probability")+
facet_wrap(~ Model.1)
My issue is that it creates a map with "lines" which I do not understand why. I know it has something to do with irregular grid I am using ( all grid cell should be equal area)
and when I add different projection:
+ coord_sf(crs = '+proj=moll')
I get nothing plotted

You basically answered the question yourself - your data is too granular. For a more "complete" look, you might want to 2d-interpolate the values. Here, I am using akima::interp, but there are other functions out there - this is not the place to discuss which is the best to use.
library(ggplot2)
griddf <- read.csv(url("https://raw.githubusercontent.com/yuliaUU/data/main/test.csv"))
world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") # add continents
val_interpol <- with(griddf, akima::interp(Lon, Lat, value, xo = -180:180, yo = -90:90))
#> Warning in akima::interp(Lon, Lat, value, xo = -180:180, yo = -90:90): collinear
#> points, trying to add some jitter to avoid colinearities!
#> Warning in akima::interp(Lon, Lat, value, xo = -180:180, yo = -90:90): success:
#> collinearities reduced through jitter
## thanks Akrun https://stackoverflow.com/q/58123551/7941188
## matrix doesn't allow negative values for subsetting
d1 <- expand.grid(x = 1:361, y = 1:181)
out <- transform(d1, z = val_interpol$z[as.matrix(d1)])
out$x <- out$x-181
out$y <- out$y-91
ggplot()+
geom_raster(data = out , aes(x = x, y = y, fill= z), interpolate = TRUE)+
geom_sf(data=world)+
labs(title=paste0("Swordfish Probability of Occurance"),
x="", y="", subtitle="data from 2000-present (0.5x0.5 grid)")+
viridis:: scale_fill_viridis(option = "H", na.value = "black")
Created on 2022-05-06 by the reprex package (v2.0.1)

Related

Create random points based in distance and boundary conditions

In my example, I have:
# Packages
library(sf)
library(ggplot2)
# Create some points
set.seed(1)
df <- data.frame(
gr = c(rep("a",5),rep("b",5)),
x = rnorm(10),
y = rnorm(10)
)
df <- st_as_sf(df,coords = c("x","y"),remove = F, crs = 4326)
df.laea = st_transform(
df,
crs = "+proj=laea +x_0=4600000 +y_0=4600000 +lon_0=0.13 +lat_0=0.24 +datum=WGS84 +units=m"
)
# Create a countour of the area
ch <- st_convex_hull(st_union(df.laea))
ggplot() +
geom_sf(data = ch, fill = "white", color = "black") +
geom_sf(data = df.laea,color = "black")
Now, I'd like to create 10 random points but the conditions are that this points must be inside the ch boundaries and a minimum distance of 10 meters of each df.laea points that exist inside this ch area.
Please, any help with it?
I think the only tricky thing here is that a simple st_difference() of your polygon and the buffered points will return ten polygons, each with one of the points removed. Thus you have to either use a for loop or reduce() to remove one buffered point after the other from the polygon. To use reduce() you have to transform the vector to a proper list of sf instead of an sfc vector. This is what I did below.
# Packages
library(sf)
library(ggplot2)
library(purrr)
ch_minus <- df.laea$geometry |>
st_buffer(10000) |>
{\(vec) map(seq_along(vec), \(x) vec[x])}() |> # Transform buffered points to reducible list
reduce(.init = ch, st_difference)
sampled_points <- st_sample(ch_minus, 10)
ch_minus |>
ggplot() +
geom_sf() +
geom_sf(data = sampled_points)
You can buffer the points by the distance you'd like, then intersect those polygons with the ch polygon. From there, use st_sample and the associated arguments to get the points you want.
Example code:
## buffer df.laea 10m
laea_buff <- st_buffer(df.laea, dist = 10000) #changed dist to 10km to make it noticable in plot
# area to sample from:
sample_area <- st_intersection(ch, laea_buff)
# sample above area, all within 10km of a point and inside the `ch` polygon
points <- st_sample(sample_area, size = 10)
#plotting:
ggplot() +
geom_sf(data = points, color = 'red') +
geom_sf(data = laea_buff, color = 'black', fill = NA) +
geom_sf(data = ch, color = 'black', fill = NA) +
geom_sf(data = sample_area, color = 'pink', fill = NA) +
geom_sf(data = df.laea, color = 'black', size = .5)
Created on 2023-02-14 by the reprex package (v2.0.1)
As a comment on the nice answer by shs: it is possible to first use a sf::st_combine() call on the df.laea object & merge the 10 points to a single multipoint geometry.
This, when buffered, will work as an input for the necessary sf::st_difference() call to form a sampling area with holes, removing the need for a for cycle / map & reduce call.
# Packages
library(sf)
library(ggplot2)
# Create some points
set.seed(1)
df <- data.frame(
gr = c(rep("a",5),rep("b",5)),
x = rnorm(10),
y = rnorm(10)
)
df <- st_as_sf(df,coords = c("x","y"),remove = F, crs = 4326)
df.laea = st_transform(
df,
crs = "+proj=laea +x_0=4600000 +y_0=4600000 +lon_0=0.13 +lat_0=0.24 +datum=WGS84 +units=m"
)
# merge 10 points to 1 multipoing
mod_laea <- df.laea %>%
st_combine()
# sampling area = difference between hull and buffered points
sampling_area <- mod_laea %>%
st_convex_hull() %>%
st_difference(st_buffer(mod_laea, 10000))
# sample over sampling area
sampled_points <- st_sample(sampling_area, 10)
# a visual overview
ggplot() +
geom_sf(data = sampling_area, fill = "white", color = "black") +
geom_sf(data = df.laea, color = "black") +
geom_sf(data = sampled_points, color = "red", pch = 4)

geom_map - names(map) not TRUE

I keep getting this error when trying to make a map...
Error in geom_map(data = all_states, map = all_states, mapping = aes(map_id = State, :
all(c("x", "y", "id") %in% names(map)) is not TRUE
My code so far...
all_states = read.csv(file = "https://public.opendatasoft.com/explore/dataset/us-zip-code-latitude-and-longitude/download/?format=csv&timezone=America/New_York&use_labels_for_header=true",
header = TRUE,
sep = ";")
all_states$State = state.name[match(all_states$State, state.abb)]
all_states = na.omit(all_states)
ggplot(data = all_states, aes(map_id = State)) +
geom_map(data = all_states,
map = all_states,
mapping = aes(map_id=State,x=Longitude,y=Latitude)) +
coord_fixed()
What am I doing wrong?
2 Problems.
You did not download the correct map. geom_map needs data for creating polygons, but your data contains the coordinates for cities
geom_map is very peculiar and restrictive about column names in data frames
Solution
get the right map (e.g., Just use the maps package for US)
rename the columns
I have also removed one or two lines and 'fortified' the data frame, as this is usually recommended before using it for maps.
library(tidyverse)
all_states = read.csv(file = "https://public.opendatasoft.com/explore/dataset/us-zip-code-latitude-and-longitude/download/?format=csv&timezone=America/New_York&use_labels_for_header=true", header = TRUE, sep = ";")
all_states = na.omit(all_states) %>%
mutate(region = State, long=Longitude, lat = Latitude) %>%fortify
US <- map_data('usa')
#>
#> Attaching package: 'maps'
#> map
ggplot()+
geom_map(data = US, map = US, mapping = aes( map_id = region, x = long, y = lat), fill = 'white') +
# now this is the US background
geom_point(data = filter(all_states, ! region %in% c('HI','AK','AS')), aes(x = long, y = lat), size = .01, color = 'black')
# and this is YOUR data. Use geom_point for it!!!
#I have removed Alaska, Hawaii and a third little bit which I ignorantly don't know. 'AS'.
#> Warning: Ignoring unknown aesthetics: x, y
Created on 2019-08-02 by the reprex package (v0.2.1)

Create shaded polygons around points with ggplot2

I saw yesterday this beautiful map of McDonalds restaurants in USA. I wanted to replicate it for France (I found some data that can be downloaded here).
I have no problem plotting the dots:
library(readxl)
library(ggplot2)
library(raster)
#open data
mac_do_FR <- read_excel("./mcdo_france.xlsx")
mac_do_FR_df <- as.data.frame(mac_do_FR)
#get a map of France
mapaFR <- getData("GADM", country="France", level=0)
#plot dots on the map
ggplot() +
geom_polygon(data = mapaFR, aes(x = long, y = lat, group = group),
fill = "transparent", size = 0.1, color="black") +
geom_point(data = mac_do_FR_df, aes(x = lon, y = lat),
colour = "orange", size = 1)
I tried several methods (Thiessen polygons, heat maps, buffers), but the results I get are very poor. I can't figure out how the shaded polygons were plotted on the American map. Any pointers?
Here's my result, but it did take some manual data wrangling.
Step 1: Get geospatial data.
library(sp)
# generate a map of France, along with a fortified dataframe version for ease of
# referencing lat / long ranges
mapaFR <- raster::getData("GADM", country="France", level=0)
map.FR <- fortify(mapaFR)
# generate a spatial point version of the same map, defining your own grid size
# (a smaller size yields a higher resolution heatmap in the final product, but will
# take longer to calculate)
grid.size = 0.01
points.FR <- expand.grid(
x = seq(min(map.FR$long), max(map.FR$long), by = grid.size),
y = seq(min(map.FR$lat), max(map.FR$lat), by = grid.size)
)
points.FR <- SpatialPoints(coords = points.FR, proj4string = mapaFR#proj4string)
Step 2: Generate a voronoi diagram based on store locations, & obtain the corresponding polygons as a SpatialPolygonsDataFrame object.
library(deldir)
library(dplyr)
voronoi.tiles <- deldir(mac_do_FR_df$lon, mac_do_FR_df$lat,
rw = c(min(map.FR$long), max(map.FR$long),
min(map.FR$lat), max(map.FR$lat)))
voronoi.tiles <- tile.list(voronoi.tiles)
voronoi.center <- lapply(voronoi.tiles,
function(l) data.frame(x.center = l$pt[1],
y.center = l$pt[2],
ptNum = l$ptNum)) %>%
data.table::rbindlist()
voronoi.polygons <- lapply(voronoi.tiles,
function(l) Polygon(coords = matrix(c(l$x, l$y),
ncol = 2),
hole = FALSE) %>%
list() %>%
Polygons(ID = l$ptNum)) %>%
SpatialPolygons(proj4string = mapaFR#proj4string) %>%
SpatialPolygonsDataFrame(data = voronoi.center,
match.ID = "ptNum")
rm(voronoi.tiles, voronoi.center)
Step 3. Check which voronoi polygon each point on the map overlaps with, & calculate its distance to the corresponding nearest store.
which.voronoi <- over(points.FR, voronoi.polygons)
points.FR <- cbind(as.data.frame(points.FR), which.voronoi)
rm(which.voronoi)
points.FR <- points.FR %>%
rowwise() %>%
mutate(dist = geosphere::distm(x = c(x, y), y = c(x.center, y.center))) %>%
ungroup() %>%
mutate(dist = ifelse(is.na(dist), max(dist, na.rm = TRUE), dist)) %>%
mutate(dist = dist / 1000) # convert from m to km for easier reading
Step 4. Plot, adjusting the fill gradient parameters as needed. I felt the result of a square root transformation looks quite good for emphasizing distances close to a store, while a log transformation is rather too exaggerated, but your mileage may vary.
ggplot() +
geom_raster(data = points.FR %>%
mutate(dist = pmin(dist, 100)),
aes(x = x, y = y, fill = dist)) +
# optional. shows outline of France for reference
geom_polygon(data = map.FR,
aes(x = long, y = lat, group = group),
fill = NA, colour = "white") +
# define colour range, mid point, & transformation (if desired) for fill
scale_fill_gradient2(low = "yellow", mid = "red", high = "black",
midpoint = 4, trans = "sqrt") +
labs(x = "longitude",
y = "latitude",
fill = "Distance in km") +
coord_quickmap()

ggmap and plot shows different zone on map

With help of ggmap and plot I want to show the centers of states on the map. The result should be something like this
I tried this block of code but is doesnt show above map
data(state)
cen_df <- as.data.frame(state.center)
library(ggmap)
library(ggplot2)
d <- data.frame(lat = cen_df[2],
lon = cen_df[1])
US <- get_map("united states", zoom = 12)
p <- ggmap(US)
p + geom_point(data = d, aes(x = lon, y = lat), color = "red", size = 30, alpha = 0.5)
ggplot_build(p)
But it shows something lie this:
Any help?
I modified your code as follows. The zoom should be 4. It is also better to use base_layer argument to put your ggplot2 object.
data(state)
library(ggmap)
library(ggplot2)
d <- data.frame(lat = state.center$y,
lon = state.center$x)
US <- get_map("united states", zoom = 4)
p <- ggmap(US, base_layer = ggplot(data = d)) +
geom_point(aes(x = lon, y = lat), color = "red", size = 2, alpha = 0.5)
p

How to add diagonal lines in NA value polygons using ggplot?

I'm working to plot the consolidated Z-value deviations (for a series of factors) from the national average for Pakistan on a fortified SPDF. For the purposes of this question, my data is irrelevant. I could provide it if necessary.
I am using ggplot to create my output where the command and result look something like this:
ggplot() + geom_polygon(data = plot.pakmod_sumZ, aes(x = long, y = lat, group = group, fill = SumZ.Cat), color = "black", size = 0.25, na.rm = TRUE) + scale_fill_manual(name = "Deviations from National Average", labels = c("-7", "-6", "-5", "-4", "-3", "-2", "-1", "Positive"), values = c("darkorange4","brown", "orangered1","tomato1","darkorange3","orange","yellow", "greenyellow"), na.value = "Grey", guide = guide_legend(reverse = TRUE)) + coord_map() + labs(x = NULL, y = NULL) + scale_x_discrete(breaks = NULL) + scale_y_discrete(breaks = NULL) + theme_minimal()
Deviations from National Average
I am trying to figure out now if it's possible to add diagonal lines in the polygons which have missing values and are coloured grey. Can this be done using ggplot?
This is an example I took from here. I opted to use the horizontal error bar geom. Mind that this isn't the only way of doing this.
library(ggplot2)
library(sp)
library(rgdal)
library(rgeos)
# create a local directory for the data
localDir <- "R_GIS_data"
if (!file.exists(localDir)) {
dir.create(localDir)
}
# download and unzip the data
url <- "ftp://www.ecy.wa.gov/gis_a/inlandWaters/wria.zip"
file <- paste(localDir, basename(url), sep='/')
if (!file.exists(file)) {
download.file(url, file)
unzip(file,exdir=localDir)
}
# create a layer name for the shapefiles (text before file extension)
layerName <- "WRIA_poly"
# read data into a SpatialPolygonsDataFrame object
dataProjected <- readOGR(dsn=localDir, layer=layerName)
dataProjected#data$id <- rownames(dataProjected#data)
# create a data.frame from our spatial object
watershedPoints <- fortify(dataProjected)
# merge the "fortified" data with the data from our spatial object
watershedDF <- merge(watershedPoints, dataProjected#data, by = "id")
dataProjected#data$id <- rownames(dataProjected#data)
watershedPoints <- fortify(dataProjected)
watershedDF <- merge(watershedPoints, dataProjected#data, by = "id")
ggWatershed <- ggplot(data = watershedDF, aes(x=long, y=lat, group = group, fill = WRIA_NM)) +
geom_polygon() +
geom_path(color = "white") +
scale_fill_hue(l = 40) +
coord_equal() +
theme(legend.position = "none", title = element_blank())
# Adding coordinates to the data part of SPDF. `sd` is the variable of interest
# which is beign plotted here. Each line extends sd away from long coordinate
dataProjected#data$sd <- rnorm(nrow(xy), mean = 50000, sd = 10000)
xy <- coordinates(dataProjected)
dataProjected#data$long <- xy[, 1]
dataProjected#data$lat <- xy[, 2]
ggWatershed +
geom_errorbarh(data = dataProjected#data, aes(group = id, xmin = long - sd, xmax = long + sd))

Resources