I'm trying to plot a map small multiples grid that shows hurricanes/tropical storms that have intersected with Florida since 1900. I used some spatial queries to subset the database of all Atlantic storms for this project.
I'm now plotting a line shapefile of my limited number of hurricane tracks on top of polygons of the state of Florida, some contiguous states, a few major cities in Florida and, of course, Lake Okeechobee. Here's the simple code:
library(maptools)
library(gdata)
library(RColorBrewer)
setwd("~/hurricanes")
# read shapefiles
florida <- readShapePoly("florida.shp")
south <- readShapePoly("south.shp")
hurricanes <- readShapeLines("hurricanes-florida.shp")
cities <- readShapePoints("cities.shp")
lakes <- readShapePoly("lakes.shp")
# miami, orlando and tallahassee (in FL)
cities <- subset(cities, ST == "FL")
# don't need ALL the 'canes
hurricanes1900 <- subset(hurricanes, Season >= 1900)
mycolors <- brewer.pal(5, "YlOrRd")
pdf(file = "hurricanemaps.pdf", ,width=8,height=20)
par(mfrow=c(15,5), mar=c(1,1,1,1))
for(i in 1:nrow(hurricanes1900))
{
plot(south, col="#e6e6e6", border = "#999999")
plot(florida, col="#999999", border = "#999999", add = TRUE)
plot(lakes, col="#ffffff", border = "#999999", add = TRUE)
plot(cities, pch=10, cex=.1,col="#000000", bg="#e38d2c", lwd=1, add = TRUE)
plot(hurricanes1900[i,], col = mycolors[cut(hurricanes$MAX_Wind_W, breaks = 5)],
lwd=3, add = TRUE); title(hurricanes1900$Title[i])
}
dev.off()
Three big issues I'm encountering:
1) The loop is giving me a map of each storm. I would prefer to have the code produce a Florida/South map in the grid for each year (even on those years without storms) and all the storms for that year, preferably with labels.
2) I would like to set the colors for wind speed among ALL the storms, not just those in each particular row of the loop. That way strong storms (like Andrew in 1992) show as darker even when they are the only storm of the year. Perhaps I can solve this my recoding a categorical (H1, H2, etc) variable that can be styled accordingly.
3) Assuming I can figure out No. 1, I'm having trouble getting labels to render on each storm path. The maptools documentation isn't great.
Anyway, here's the output so far (the title is a concatenation of two fields in the shapefile):
The real issue is No. 1. Thanks in advance for your help.
Given there is no reproducible data, I collected some data for this demonstration. Please provide a minimal reproducible data for SO users from next time. That will help you receive more help.
What you want to achieve can be done with ggplot2. If you want to draw a map for each year, you can use facet_wrap(). If you want to add colors based on wind, you can do that in aes() when you draw paths. If you want to add hurricanes' names, you can use the ggrepel package, which allows you to provide annotations with an ease. Note that, if you want to draw smooth paths, you further need data process.
library(stringi)
library(tibble)
library(raster)
library(ggplot2)
library(ggthemes)
library(ggrepel)
library(RColorBrewer)
library(data.table)
# Get some data. Credit to hmbrmstr for a few lines in the following code.
mylist <- c("http://weather.unisys.com/hurricane/atlantic/2007H/BARRY/track.dat",
"http://weather.unisys.com/hurricane/atlantic/2007H/TEN/track.dat",
"http://weather.unisys.com/hurricane/atlantic/2006H/ERNESTO/track.dat",
"http://weather.unisys.com/hurricane/atlantic/2006H/ALBERTO/track.dat")
temp <- rbindlist(
lapply(mylist, function(x){
foo <- readLines(x)
foo <- read.table(textConnection(gsub("TROPICAL ", "TROPICAL_",
foo[3:length(foo)])),
header=TRUE, stringsAsFactors=FALSE)
year <- stri_extract_first(str = x, regex = "[0-9]+")
name <- stri_extract_first(str = x, regex = "[A-Z]{2,}")
cbind(foo, year, name)
}
))
### Add a fake row for 2017
temp <- temp %>%
add_row(ADV = NA, LAT = NA, LON = NA, TIME = NA, WIND = NA,
PR = NA, STAT = NA, year = 2017, name = NA)
### Prepare a map
usa <- getData('GADM', country = "usa", level = 1)
mymap <- subset(usa, NAME_1 %in% c("Florida", "Arkansas", "Louisiana",
"Alabama", "Georgia", "Tennessee",
"Mississippi",
"North Carolina", "South Carolina"))
mymap <- fortify(mymap)
# Create a data.table for labeling hurricanes later.
label <- temp[, .SD[1], by = name][complete.cases(name)]
g <- ggplot() +
geom_map(data = mymap, map = mymap,
aes(x = long, y = lat, group = group, map_id = id),
color = "black", size = 0.2, fill = "white") +
geom_path(data = temp, aes(x = LON, y = LAT, group = name, color = WIND), size = 1) +
scale_color_gradientn(colours = rev(brewer.pal(5, "Spectral")), name = "Wind (mph)") +
facet_wrap(~ year) +
coord_map() +
theme_map() +
geom_text_repel(data = label,
aes(x = LON, y = LAT, label = name),
size = 2,
force = 1,
max.iter = 2e3,
nudge_x = 1,
nudge_y = -1) +
theme(legend.position = "right")
Related
I'm using the Taiwan housing data found on UCI ML repository.
I'm trying to plot the houses on a map using ggplot, and fill the points with the house_price_unit_area. However, when I use fill = house_price_unit_area in the aesthetic call, it doesn't fill the points based on price, but rather it leaves them black.
Any suggestions on how to fix this? Code included below, as well as a screenshot of what is produced.
library(ggplot)
library(ggmap)
library(readxl)
df <- read_xlsx("data/real_estate.xlsx")
df$No = NULL
colnames(df)= c("trans_date",
"house_age",
"distance_to_nearest_mrt",
"number_of_conv_store",
"lat",
"long",
"house_price_unit_area",
"id")
world <- map_data(database = "world", regions = "Taiwan")
ggmap(get_stamenmap(bbox = c(left = 121.4, right = 121.64, bottom=24.9,top=25.1),location = "Taiwan"))+
geom_point(data =df, mapping = aes(x=long,y=lat, fill = house_price_unit_area))+
scale_fill_viridis_b()
I switch the fill argument for col and got this:
library(ggplot)
library(ggmap)
library(readxl)
df <- read_xlsx("Real estate valuation data set.xlsx")
df$No = NULL
colnames(df)= c("trans_date",
"house_age",
"distance_to_nearest_mrt",
"number_of_conv_store",
"lat",
"long",
"house_price_unit_area",
"id")
world <- map_data(database = "world", regions = "Taiwan")
ggmap(get_stamenmap(bbox = c(left = 121.4, right = 121.64, bottom=24.9,top=25.1),location = "Taiwan"))+
geom_point(data =df, mapping = aes(x=long,y=lat, col = house_price_unit_area))+
scale_fill_viridis_b()
output:
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()
I have already generated a simple map for Nigerian states, and now I would like to highlight in my map the borders for the Nigerian regions (that group Nigerian states).
When I add the layer for the borders with geom_polygon, they appear lines that do not correspond to region borders. I found a similar problem here Map county borders on to a ggmap
but this does not seem to be working for my case.
Here are the shapefiles and the database I am working on:
https://www.dropbox.com/sh/cek92s50jixowfx/AABwIVZKvtff8-9slhfCbxEca?dl=0
The code I am using is
#LOAD SHAPEFILES AND DATABASE
ng_dist <- readShapeSpatial("NGA_adm1.shp")
ng_dist_regions <- readShapeSpatial("NGA_adm_Region.shp")
NG_States <- read.csv("State_color_map.csv", header = TRUE, sep=",")
#VERIFY THE MAPS LOADED PROPERLY
plot(ng_dist)
plot(ng_dist_regions)
# STATE MAP - fortify and match shapefile and database IDs names
intersect(ng_dist$NAME_1, NG_States$STATE)
ng_dist <- fortify(ng_dist, region = "NAME_1")
ng_dist$id[which(ng_dist$id == "Akwa Ibom")] <- "Akwa-ibom"
ng_dist$id[which(ng_dist$id == "Nassarawa")] <- "Nasarawa"
ng_dist$id[which(ng_dist$id == "Cross River")] <- "C/river"
ng_dist$id[which(ng_dist$id == "Federal Capital Territory")] <- "FCT"
intersect(ng_dist$id, NG_States$STATE)
# REGION MAP - fortify
ng_dist_regions <- fortify(ng_dist_regions, region = "Region")
### Convert dummy variable to factor
NG_States$Abia <- as.factor(NG_States$Abia)
#PLOT MAP with coloured Abia State
cols <- c("0" = "#e6e6e6","1" = "#6eab27")
ABIA <- NG_States$Abia
Abia_map <- ggplot(NG_States, aes(fill = ABIA)) +
geom_map(data = NG_States, aes(map_id = NG_States$STATE, fill = ABIA), map = ng_dist, color = "black", size = 0.10) +
expand_limits(x = ng_dist$long, y = ng_dist$lat) +
theme_nothing(legend = FALSE) +
labs(title="Abia") +
coord_map() +
scale_fill_manual(name="", values=cols, labels=c("","Abia"))
Abia_map
#Add layer for region borders
d <- Abia_map +
geom_polygon(aes(x = ng_dist_regions$long, y = ng_dist_regions$lat, group = ng_dist_regions$id, fill = NA), data = ng_dist_regions, color = "red", size = 0.8)
d
Here is my result
Nigerian States and Regions
I have tried to add other options, such as coord_fixed() or expand_limits(x = ng_dist_regions$long, y = ng_dist_regions$lat), but I am quite basic R user and I don't know other solutions.
Using group, instead of id as group seems to solve the problem.
d <- Abia_map +
geom_path(aes(x = long, y = lat, group = group), data = ng_dist_regions, color = "red", size = 0.8, inherit.aes = FALSE)
d
I have a csv file with variables name "Latitude","Longitude","PM10 concentration". You can download data here. I want to plot PM10 data on a map of South Korea according to their latitude and Longitude. Also I want to show them as bubble with different size and color.
Following this example I have already plotted PM10 data on Google Map. But now I want do this without using Google map rather by creating spatial object or in any other way.
I tried to write some code but I have download the spatial data for administration area (GADM) of South Korea. But I am not sure that approach is right or wrong.
library(rgdal)
library(ggplot2)
library(maptools)
map<-readOGR('D:/BACKUP/R/GSTAT/R File/shape file korea map',layer ='KOR_adm2')
summary(kmap)
EPSG<-make_EPSG()
EPSG[grepl("WGS 84$", EPSG$note), ]
kmap84<-spTransform(kmap, CRS("+init=epsg:4326"))
kmaps<-fortify(kmap84)
I don't understand what should I do next.
Here's an example:
library(raster)
library(ggplot2)
download.file("https://docs.google.com/uc?id=0ByY3OAw62EShakxJZkplOXZ0RGM&export=download", tf <- tempfile(fileext = ".csv"))
df <- read.csv(tf, row.names = 1)
skorea <- getData("GADM", country = "South Korea", level = 2)
skorea <- fortify(skorea)
ggplot() +
geom_map(data = skorea, map = skorea, aes(x = long, y = lat, map_id = id, group = group),
fill = NA, colour = "black") +
geom_point(data = df, aes(x = LON, y = LAT, size = PM10), colour = "red", alpha = .5) +
scale_size(range = c(1, 5))
I want to plot different states of India with respective districts in R software. I have tried using GADM, level 2 data to get the coordinates.
I have followed this thread Mapping just one State of India and writing its name inside the state boundary. However, I am unable to subset the data for any state and use it for mapping.
What I've tried:
map <- fortify(Karnataka)
map$id <- as.integer(map$id)
dat <- data.frame(id = 216:242, district = Karnataka)
map_df <- inner_join(map, dat, by = "id")
centers <- data.frame(gCentroid(Karnataka, byid = TRUE))
centers$state <- dat$district
I could map a state with its district borders by using following commands.
India <- getData("GADM", country = "India", level = 2)
Karnataka <- subset(India, NAME_1 == "Karnataka")
map <- fortify(Karnataka);
map$id <- as.integer(map$id);
dat <- data.frame(id = 216:242, district = Karnataka#data$NAME_2);
map_df <- inner_join(map, dat, by = "id");
centers <- data.frame(gCentroid(Karnataka, byid = TRUE));
centers$state <- dat$district;
ggplot() +
geom_map(data = map_df, map = map_df,
aes(map_id = id, x = long, y = lat, group = group),
color = "#ffffff", fill = "#bbbbbb", size = 0.25) +
geom_text(data = centers, aes(label = state, x = x, y = y), size = 2) +
coord_map() + labs(x = "", y = "", title = "Districts of Karnataka")
You can do this beautifully and easily with Google Maps in R. Within ggmap there are a lot of options. The examples below are very basic but it's fully customizable by setting the options however you like them.
map <- qmap('Karnataka', zoom = 7, maptype = 'hybrid')
map
library(ggmap)
qmap('Karnataka')