ggplot_stat_density2d plots for ecological distribution - r

I'm trying to plot ecological distribution of some species of organisms I'm studying over the Arabian/Persian Gulf. Here is a sample of a code I've tried:
Backround layer
library(ggplot2)
library(ggmap)
nc <- get_map("Persian Gulf", zoom = 6, maptype = 'terrain', language = "English")
ncmap <- ggmap(nc, extent = "device")
Other layers
ncmap+
stat_density2d(data=sample.data3, aes(x=long, y=lat, fill=..level.., alpha=..level..),geom="polygon")+
geom_point(data=sample.data3, aes(x=long, y=lat))+
geom_point(aes(x =50.626444, y = 26.044472), color="red", size = 4)+
scale_fill_gradient(low = "green", high = "red") + scale_alpha(range = c(0.00, 0.25), guide = FALSE)
but, I will like to use the stat_density2d to show the distributions of hundreds of species (which are recorded in columns e.g SP1....SPn) over the water body rather than just displaying latitude and longitude.
Also, is it possible to restrict my heat map to just the water body?
I'll appreciate any help and recommendations I can get on this please

My approach to your question is a pragmatic one: simply put the layer of gulf countries over the heatmap distribution. This crops the heatmap accordingly. Note, however, that the heatmap is still calculated as if it weren't cropped. That means the density calculation is not restricted to the water body only, but it is simply cropped visually.
For the sake of reproducibility, the following code assumes that you've unzipped the .rar file provided by #Hammao and execute the code in the resulting Persian Gulf folder.
# get sample data
sample.data <- read.csv("sample.data3.csv")
Now, we need to get the country shapes for the Gulf countries. I use the rworldmap package for this.
# loading country shapes
library(rworldmap)
# download map of the world
worldmap <- getMap(resolution = "high") # note that for 'resolution="high"'
# you also need the "rworldxtra" pkg
# extract Persian Gulf countries...
gulf_simpl <- worldmap[worldmap$SOVEREIGNT == "Oman" |
worldmap$SOVEREIGNT == "Qatar" |
worldmap$SOVEREIGNT == "United Arab Emirates" |
worldmap$SOVEREIGNT == "Bahrain" |
worldmap$SOVEREIGNT == "Saudi Arabia" |
worldmap$SOVEREIGNT == "Kuwait" |
worldmap$SOVEREIGNT == "Iraq" |
worldmap$SOVEREIGNT == "Iran", ]
# ... and fortify the data for plotting in ggplot2
gulf_simpl_fort <- fortify(gulf_simpl)
# Now read data for the Persian Gulf, which we need to get the distances for
# the extension of the map
PG <- readOGR(dsn = ".", "iho")
PG <- readShapePoly("iho.shp")
PG <- fortify(PG)
Now, it's simply a matter of plotting the layers in the correct order.
# generate plot
ggplot(sample.data) +
# first we plot the density...
stat_density_2d(aes(x = long, y = lat,
fill = ..level..),
geom="polygon",
alpha = 0.5) +
# ... then we plot the points
geom_point(aes(x = long, y = lat)) +
# gradient options
scale_fill_gradient(low = "green", high = "red") +
scale_alpha(range = c(0.00, 0.25), guide = FALSE) +
# and now put the shapes of the gulf states on top
geom_polygon(data = gulf_simpl_fort,
aes(x = long,
y = lat, group = group),
color = "black", fill = "white",
inherit.aes = F) +
# now, limit the displayed map only to the gulf
coord_equal(xlim = c(min(PG_fort$long), max(PG_fort$long)),
ylim = c(min(PG_fort$lat), max(PG_fort$lat))) +
theme_bw()

Related

Subsetting a shapefile

I have a shapefile here: https://login.filesanywhere.com/fs/v.aspx?v=8c6c63865a6574bcaa69
I have a shapefile of California red legged frog that I am overlaying on top of California, however, the range of these frogs extends outside of California and going into Mexico. I only want the frog data from California, how can I trim data extending into Mexico? I tried to use subset to separate the 'ORIGIN' but it doesn't seem to have any effect. Thanks for any help beforehand..
library(rgdal)
library(tidyverse)
ranas <- readOGR(dsn = ".", layer = "data_0")
names(ranas)
# Coerce into a dataframe
ranas4 <- fortify(ranas)
head(ranas4)
cali_map <- map_data("state",region="california")
counties <- map_data("county",region="California")
head(counties)
windows(w=9)
ggplot(cali_map, aes(x = long, y = lat, group = group)) +
geom_polygon() +
geom_polygon(data = ranas4, fill = "green")
ggplot(cali_map, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "cornsilk4", col = "cornsilk") +
geom_polygon(data=counties,color="black",fill="lightgoldenrod") +
geom_polygon(data = ranas4, fill = "green", alpha = 0.5) +
theme_void() +
theme(panel.background = element_rect(fill = "cornsilk")) +
coord_map("albers",lat=90,lat1=80)
# Tried to trim data outside California (Mexico data) with no success.
#I tried:
ranas2 <- subset(ranas,ORIGIN !=1)
but it doesn't have any effect or subsets anything.
Subsetting your spatial dataframe won't be of much use, because neither of its features (rows) is entirely within California:
## plot features by origin:
library(ggplot2)
library(sf)
my_shp <- read_sf(dsn = "path_to_shp_directory")
my_shp %>%
ggplot() +
geom_sf() +
facet_wrap(~ ORIGIN)
You can still crop (clip) a feature with California's boundaries ...:
## make sure both geometries have the same CRS,
## if necessary, by st_transform(your_epsg_code)
my_shp_cropped <- st_crop(my_shp, cali_map)
... but note that won't recalculate the underlying frog data (e.g. frog count in California only).

Using geom_text() to display text in geom_polygon() [duplicate]

I am trying to label my polygons by using ggplot in R. I found a topic here on stackoverflow that I think is very close to what I want except with points.
Label points in geom_point
I found some methods online. Now I first need to find the central location of each shape and then I have to put these locations together with the name together. Then link this to the labeling function in geom_text()
ggplot centered names on a map
Since I have been trying for a long time now I decided to ask the question and hope that someone here can give me the final push to what I want. My plotting function:
region_of_interest.fort <- fortify(region_of_interest, region = "score")
region_of_interest.fort$id <- as.numeric(region_of_interest.fort$id)
region_of_interest.fort$id <- region_of_interest.fort$id
region_of_interest.fort1 <- fortify(region_of_interest, region = "GM_NAAM")
region_of_interest.fort1$id <- as.character(region_of_interest.fort1$id)
region_of_interest.fort1$id <- region_of_interest.fort1$id
idList <- unique(region_of_interest.fort1$id)
centroids.df <- as.data.frame(coordinates(region_of_interest))
names(centroids.df) <- c("Longitude", "Latitude")
randomMap.df <- data.frame(id = idList, shading = runif(length(idList)), centroids.df)
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
It gives me the error: ggplot2 doesn't know how to deal with data of class uneval
My data
region_of_interest$GM_NAAM
[1] Groningen Haren Ooststellingwerf Assen Aa en Hunze Borger- Odoorn
[7] Noordenveld Westerveld Tynaarlo Midden-Drenthe
415 Levels: 's-Gravenhage 's-Hertogenbosch Aa en Hunze Aalburg Aalsmeer Aalten ... Zwolle
region_of_interest$score
[1] 10 -2 -1 2 -1 -4 -4 -5 0 0
Try something like this?
Get a data frame of the centroids of your polygons from the
original map object.
In the data frame you are plotting, ensure there are columns for
the ID you want to label, and the longitude and latitude of those
centroids.
Use geom_text in ggplot to add the labels.
Based on this example I read a world map, extracting the ISO3 IDs to use as my polygon labels, and make a data frame of countries' ID, population, and longitude and latitude of centroids. I then plot the population data on a world map and add labels at the centroids.
library(rgdal) # used to read world map data
library(rgeos) # to fortify without needing gpclib
library(maptools)
library(ggplot2)
library(scales) # for formatting ggplot scales with commas
# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'
worldMap <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
# Change "data" to your path in the above!
worldMap.fort <- fortify(world.map, region = "ISO3")
# Fortifying a map makes the data frame ggplot uses to draw the map outlines.
# "region" or "id" identifies those polygons, and links them to your data.
# Look at head(worldMap#data) to see other choices for id.
# Your data frame needs a column with matching ids to set as the map_id aesthetic in ggplot.
idList <- worldMap#data$ISO3
# "coordinates" extracts centroids of the polygons, in the order listed at worldMap#data
centroids.df <- as.data.frame(coordinates(worldMap))
names(centroids.df) <- c("Longitude", "Latitude") #more sensible column names
# This shapefile contained population data, let's plot it.
popList <- worldMap#data$POP2005
pop.df <- data.frame(id = idList, population = popList, centroids.df)
ggplot(pop.df, aes(map_id = id)) + #"id" is col in your df, not in the map object
geom_map(aes(fill = population), colour= "grey", map = worldMap.fort) +
expand_limits(x = worldMap.fort$long, y = worldMap.fort$lat) +
scale_fill_gradient(high = "red", low = "white", guide = "colorbar", labels = comma) +
geom_text(aes(label = id, x = Longitude, y = Latitude)) + #add labels at centroids
coord_equal(xlim = c(-90,-30), ylim = c(-60, 20)) + #let's view South America
labs(x = "Longitude", y = "Latitude", title = "World Population") +
theme_bw()
Minor technical note: actually coordinates in the sp package doesn't quite find the centroid, but it should usually give a sensible location for a label. Use gCentroid in the rgeos package if you want to label at the true centroid in more complex situations like non-contiguous shapes.
The accepted answer here may work, but the actual question asked specifically notes that there is an error "ggplot2 doesn't know how to deal with data of class uneval."
The reason that it is giving you the error is because the inclusion of centroids.df needs to be a named variable (e.g. accompanied by "data=")
Currently:
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
Should be (note: "data=centroids.df"):
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(data=centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
This issue was addressed here: How to deal with "data of class uneval" error from ggplot2?

King County map not displaying the boundaries correctly

Hi I'm trying to plot the map of King County in Washington because I'm having few data points which need to be placed in the map. The following is what I used.
long <- c(47.5112,47.7210 ,47.3684,44)
lat <- c(-122.257, -122.319, -122.031,-120)
price <- c(287655,456355,662500,234563)
House <- data.frame(long, lat, price)
states <- map_data("state")
# west_coast <- states %>%
# filter(region %in% c("washington"))
wa_df <- states %>%
filter(region == "washington", subregion == 'king')
counties <- map_data("county")
wa_county <- counties %>%
filter(region == "washington", subregion == 'king')
wa_base <-
ggplot(data = wa_df,
mapping = aes(x = long, y = lat, group = group)) +
geom_point(
data = House,
mapping = aes(x = long, y = lat),
color = "red",
inherit.aes = FALSE
) +
coord_fixed(1.3) +
geom_polygon(color = "black", fill = "gray")
#geom_point(data = House, mapping = aes(x = long, y = lat), color = "red")
wa_base + theme_nothing() +
geom_polygon(data = wa_county, fill = NA, color = "black") +
geom_polygon(color = "black", fill = NA) # get the state border back on top
The following is the map I received. I do not find that the map looks good. Please help
I am new to R and this is my first response, but I might have found a solution to this problem. The boundaries downloaded from the maps package are not exact. You can download correct boundary data as a shapefile here: https://gis-kingcounty.opendata.arcgis.com/datasets/kingcounty::king-county-political-boundary-no-waterbodies-kingco-area/explore?location=47.477749%2C-121.920728%2C9.83
Use:
library(ggmap)
library(mapdata)
library(rgdal)
library(tidyverse)
After that, read the shapefile into R and use map_data() to convert it into a data frame:
kc_bound <- readOGR(dsn="~/Desktop/King_County",layer="King_County_Political_Boundary_(no_waterbodies)___kingco_area")
kc_bound_df <- map_data(kc_bound)
Assuming that you also work on the house price prediction data set from kaggle (https://www.kaggle.com/harlfoxem/housesalesprediction) you can run the following code to get a plot of the houses with the King County boundary around it (df is your data frame):
ggplot() + geom_point(df,mapping=aes(x=long,y=lat),color="red") + geom_polygon(kc_bound_df,mapping=aes(x=long,y=lat),fill=NA, color="black")
See this picture for the result: Houses in King County plotted with county boundary
Hope this helps, let me know what you think!

Plot of Russia split in two

I am trying to plot Russia from a shp-file, but Russia always comes up as in two parts. How do I get Russia back together in one piece?
I have tried several shp-files e.g.
http://www.naturalearthdata.com/downloads/10m-cultural-vectors/
Admin 1 – States, Provinces ; Download without large lakes (14.11 MB) version 3.0.0
shp <- readOGR("ne_10m_admin_1_states_provinces_lakes.shp")
Subset to Russia
names(shp)
rus <- shp[shp$admin == "Russia" , ]
x11()
plot(rus)
Since you want to plot it, you can fortify the shapefile to data frame, modify the longitude coordinates in the -180 region, & plot the result in ggplot:
library(rgdal); library(ggplot2)
# read in the shapefile & subset to Russia
shp <- readOGR(dsn = "ne_10m", layer = "ne_10m_admin_1_states_provinces_lakes")
rus <- shp[shp$admin == "Russia", ]
# fortify to data frame & modify longitude coordinates in the -180 region.
rus.fortify <- fortify(rus) %>%
mutate(long = ifelse(long < -100, long + 180*2, long))
# plot to verify
ggplot(rus.fortify,
aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", col = "black") +
coord_map() #default projection is mercator
I've also just learned from this post that you can specify different projection systems. Given how large Russia is, this ought to be relevant:
ggplot(rus.fortify,
aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", col = "black") +
coord_map("azequalarea")

Labeling center of map polygons in R ggplot

I am trying to label my polygons by using ggplot in R. I found a topic here on stackoverflow that I think is very close to what I want except with points.
Label points in geom_point
I found some methods online. Now I first need to find the central location of each shape and then I have to put these locations together with the name together. Then link this to the labeling function in geom_text()
ggplot centered names on a map
Since I have been trying for a long time now I decided to ask the question and hope that someone here can give me the final push to what I want. My plotting function:
region_of_interest.fort <- fortify(region_of_interest, region = "score")
region_of_interest.fort$id <- as.numeric(region_of_interest.fort$id)
region_of_interest.fort$id <- region_of_interest.fort$id
region_of_interest.fort1 <- fortify(region_of_interest, region = "GM_NAAM")
region_of_interest.fort1$id <- as.character(region_of_interest.fort1$id)
region_of_interest.fort1$id <- region_of_interest.fort1$id
idList <- unique(region_of_interest.fort1$id)
centroids.df <- as.data.frame(coordinates(region_of_interest))
names(centroids.df) <- c("Longitude", "Latitude")
randomMap.df <- data.frame(id = idList, shading = runif(length(idList)), centroids.df)
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
It gives me the error: ggplot2 doesn't know how to deal with data of class uneval
My data
region_of_interest$GM_NAAM
[1] Groningen Haren Ooststellingwerf Assen Aa en Hunze Borger- Odoorn
[7] Noordenveld Westerveld Tynaarlo Midden-Drenthe
415 Levels: 's-Gravenhage 's-Hertogenbosch Aa en Hunze Aalburg Aalsmeer Aalten ... Zwolle
region_of_interest$score
[1] 10 -2 -1 2 -1 -4 -4 -5 0 0
Try something like this?
Get a data frame of the centroids of your polygons from the
original map object.
In the data frame you are plotting, ensure there are columns for
the ID you want to label, and the longitude and latitude of those
centroids.
Use geom_text in ggplot to add the labels.
Based on this example I read a world map, extracting the ISO3 IDs to use as my polygon labels, and make a data frame of countries' ID, population, and longitude and latitude of centroids. I then plot the population data on a world map and add labels at the centroids.
library(rgdal) # used to read world map data
library(rgeos) # to fortify without needing gpclib
library(maptools)
library(ggplot2)
library(scales) # for formatting ggplot scales with commas
# Data from http://thematicmapping.org/downloads/world_borders.php.
# Direct link: http://thematicmapping.org/downloads/TM_WORLD_BORDERS_SIMPL-0.3.zip
# Unpack and put the files in a dir 'data'
worldMap <- readOGR(dsn="data", layer="TM_WORLD_BORDERS_SIMPL-0.3")
# Change "data" to your path in the above!
worldMap.fort <- fortify(world.map, region = "ISO3")
# Fortifying a map makes the data frame ggplot uses to draw the map outlines.
# "region" or "id" identifies those polygons, and links them to your data.
# Look at head(worldMap#data) to see other choices for id.
# Your data frame needs a column with matching ids to set as the map_id aesthetic in ggplot.
idList <- worldMap#data$ISO3
# "coordinates" extracts centroids of the polygons, in the order listed at worldMap#data
centroids.df <- as.data.frame(coordinates(worldMap))
names(centroids.df) <- c("Longitude", "Latitude") #more sensible column names
# This shapefile contained population data, let's plot it.
popList <- worldMap#data$POP2005
pop.df <- data.frame(id = idList, population = popList, centroids.df)
ggplot(pop.df, aes(map_id = id)) + #"id" is col in your df, not in the map object
geom_map(aes(fill = population), colour= "grey", map = worldMap.fort) +
expand_limits(x = worldMap.fort$long, y = worldMap.fort$lat) +
scale_fill_gradient(high = "red", low = "white", guide = "colorbar", labels = comma) +
geom_text(aes(label = id, x = Longitude, y = Latitude)) + #add labels at centroids
coord_equal(xlim = c(-90,-30), ylim = c(-60, 20)) + #let's view South America
labs(x = "Longitude", y = "Latitude", title = "World Population") +
theme_bw()
Minor technical note: actually coordinates in the sp package doesn't quite find the centroid, but it should usually give a sensible location for a label. Use gCentroid in the rgeos package if you want to label at the true centroid in more complex situations like non-contiguous shapes.
The accepted answer here may work, but the actual question asked specifically notes that there is an error "ggplot2 doesn't know how to deal with data of class uneval."
The reason that it is giving you the error is because the inclusion of centroids.df needs to be a named variable (e.g. accompanied by "data=")
Currently:
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
Should be (note: "data=centroids.df"):
ggplot(data = region_of_interest.fort, aes(x = long, y = lat, fill = id, group = group)) +
geom_polygon() +
geom_text(data=centroids.df, aes(label = id, x = Longitude, y = Latitude)) +
scale_fill_gradient(high = "green", low = "red", guide = "colorbar") +
coord_equal() +
theme() +
ggtitle("Title")
This issue was addressed here: How to deal with "data of class uneval" error from ggplot2?

Resources