I am trying to add US cities to my map in R.
When I add world cities:
ggplot(data = usa) +
geom_polygon(aes(x = longitude, y = latitude, group = group, fill = id)) +
coord_quickmap() +
guides(fill = FALSE) +
theme(axis.text = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.title = element_blank()) +
xlim(-169, -67) +
ylim(17,72)+
scale_fill_discrete()+
geom_point(data=world.cities, aes(x=long, y = lat, size= capital))
or canada cities:
ggplot(data = usa) +
geom_polygon(aes(x = longitude, y = latitude, group = group, fill = id)) +
coord_quickmap() +
guides(fill = FALSE) +
theme(axis.text = element_blank()) +
theme(axis.ticks = element_blank()) +
theme(axis.title = element_blank()) +
xlim(-169, -67) +
ylim(17,72)+
scale_fill_discrete()+
geom_point(data=canada.cities, aes(x=long, y = lat, size= capital))
it works just fine. However, when I try replacing it with us.cities, which is supposed to be part of the maps package (https://cran.r-project.org/web/packages/maps/maps.pdf), it gives the error:
ggplot2 doesn't know how to deal with data of class character.
any ideas on what could be the issue??
edit: more code:
library(maps)
library(fiftystater)
usa <- data("fifty_states")
us.cities <- data(us.cities)
usa.cities <- world.cities %>% filter(country.etc=="USA")
map <- map_data("world")
hawaii <- read.csv("hawaii.csv", stringsAsFactors = FALSE)
alaska <- read.csv("alaska.csv", stringsAsFactors = FALSE)
forty8states <- fifty_states %>% filter(id != "hawaii") %>% filter(id !="alaska") %>% select(long, lat, id, group)
alaska <- read.csv("alaska.csv", stringsAsFactors = FALSE)
hawaii <- read.csv("hawaii.csv", stringsAsFactors = FALSE)
usa <- rbind(forty8states, alaska, hawaii)
usa <- usa %>% mutate(longitude = round(long, digits = 2))
usa <- usa %>% mutate(latitude = round(lat, digits = 2))
the hawaii and alaska csv's are the hawaii and alaska data from the world data frame from maps, with some editing so they're in the same format as the rest.
Related
I am trying to incorporate labels of provinces, and cities with labels and dots into a South African map.I can get a map with provincial subdivisions from a spdf file, from website https://gadm.org/download_country_v3.html
SA1spdf <- readRDS("gadm36_ZAF_1_sp.rds")
And I am trying to use the information in the slot:
SA1spdf#data#ADM1_EN
that contains the label of the 9 provinces
I want to place the labels in the center of the polygons, if possible, so I got the centroids of the 9 provinces:
centroids_SAdf <- as.data.frame(coordinates(SA1spdf))
and change names V1 and V2 to Longitude and Latitude
names(centroids_SAdf) <- c("Longitude", "Latitude")
Also I want to add a few cities to the plot:
coordinates_cities <- data.frame(city = c("Cape Town", "Durban", "Johannesburg", "Port Elizabeth"),lat = c(-33.930, -29.870, -26.190, -33.960 ), lon = c(18.460, 30.990, 28.040,25.590 )
but I cannot link all these together.
I can get a map with:
qtm(SA1spdf, fill = "white")
Using maptools and the following codes all return error messages
qtm(SA1spdf, fill = "white") + tm_text("SA1spdf$data#ADMN1_EN")
tm_shape(SA1spdf) + tm_polygons() + tm_fill(col = "white")
I dont get a white filled map, its filled with grey colour
the following codes return error messages:
tm_shape(SA1spdf) + tm_polygons() + tm_text(c("Eastern Cape","Free State" , "Gauteng","KwaZulu-Natal", "Limpopo","Mpumalanga","North West","Nothern Cape","Western Cape"))
ggplot(SA1spdf, aes(x = lon, y = lat), group = group) + geom_polygon(fill = "white") + geom_point(data = coordinates_cities, aes(x = lat, y = lon)) + geom_text(data= coordinate_cities, aes(label = city))
library(sp)
library(ggplot2)
library(tmap)
library(rgeos)
I'll use the same object SA1spdf you created with data from ZAF as sp object from GADM
coordinate_cities <- data.frame(
city = c("Cape Town", "Durban", "Johannesburg", "Port Elizabeth"),
lat = c(-33.930, -29.870, -26.190, -33.960),
long = c(18.460, 30.990, 28.040,25.590))
base plot
plot(SA1spdf)
points(coordinate_cities$lon, coordinate_cities$lat, pch = 16, col = "red", cex = 1)
text(coordinate_cities$lon, coordinate_cities$lat, coordinate_cities$city, adj = c(0, 0), cex = 0.7)
title(main = "South Africa", sub = "Main cities")
ggplot2
sa_df <- fortify(SA1spdf)
#> Regions defined for each Polygons
ggplot(sa_df, aes(long, lat)) +
geom_polygon(aes(group = group), fill = "white", colour = "black") +
geom_point(data = coordinate_cities, aes(x = long, y = lat), colour = "red") +
geom_text(data = coordinate_cities, aes(label = city), vjust = -1) +
coord_equal()
tmap
# convert coordinate_cities to sp object
sa_cities_spdf <- SpatialPointsDataFrame(coords = coordinate_cities[, c("long", "lat")],
data = coordinate_cities[, "city", drop = FALSE],
proj4string = CRS("+proj=longlat +datum=WGS84"))
tm_shape(SA1spdf) +
tm_borders() +
tm_layout(main.title = "South Africa regions") +
tm_text("NAME_1", size = 0.7) +
tm_shape(sa_cities_spdf) + tm_symbols(size = 0.5, col = "red")
Created on 2021-06-17 by the reprex package (v0.3.0)
I'm trying to align each bcr_code to their respective polygons, however, the numbers come out of place. How do I get the right alignment, preferably in the middle?
here's the code:
library(tidyverse)
library(broom)
library(rgdal)
file1 <- "bcr.gpkg"
if (!file.exists(file.path("data/data/", file1))) {
download.file(paste0("https://raw.githubusercontent.com/lime-n/data/main/", file1),
file.path("data/data/", file1), mode = "wb")
}
p <- readOGR(dsn = "bcr.gpkg")
tidy_bcr <- tidy(p)
ggplot(p, aes(x = long, y = lat, group = group)) +
geom_polygon(color = "black", size = 0.1, fill = "lightgrey") +
coord_equal() +
theme_minimal()
p$id <- row.names(p)
tidy_bcr <- left_join(tidy_bcr, p#data)
bcrcop <- data.frame(bcr_name = sort(p#data$bcr_name),
bcr_code = c(28,17,12,24,19,22,13,26,30,21,31,29,23,11,18,27,25))
tidy_bcr <- left_join(tidy_bcr, bcrcop)
bcrLabel <- tidy_bcr %>%
group_by(bcr_name) %>%
summarise(label_long = mean(range(long)), label_lat = mean(range(lat)), bcr_code = mean(bcr_code))
map <- ggplot(tidy_bcr, aes(x = long, y = lat, group = group, fill = bcr_name)) +
geom_polygon(color = "black", size = 0.1) +
coord_equal() +
theme_void() +
theme(plot.title = element_text(margin = margin(t = 40, b = -40)))
map + geom_text(data = bcrLabel, mapping = aes(x=label_long, y = label_lat, label = bcr_code, group = NA), cex = 4, col = "white")
And the output:
Although, is there also a way to get these codes on the legend, something like:
28: Appalachian Mountains
Try using the sf package for the data and ggsflabel for the labels.
A minimal examle:
library(sf)
library(ggsflabel)
my_data <- read_sf('https://raw.githubusercontent.com/lime-n/data/main//bcr.gpkg') ## Replace with your path to the data
ggplot() +
geom_sf(data = my_data,
aes(fill = bcr_name)) +
geom_sf_label(data = my_data, aes(label = bcr_code))
Change the legend names in the legend using unite on the data first.
my_data <- my_data %>%
unite('new_col', bcr_code, bcr_name, sep = ': ', remove = F)
ggplot() +
geom_sf(data = my_data2,
aes(fill = new_col)) +
geom_sf_label(data = my_data2,
aes(label = bcr_code))
Created on 2020-12-26 by the reprex package (v0.3.0)
Hi I have this R script that shows Australia map with state boundaries and I need to add abbreviated state names in the middle of each state. Any idea how to do that?
library(RColorBrewer)
aus_b1 <- getData(name = "GADM", country = "Australia", level = 1)
nrow(tidy(aus_b1))
aus_b1 <- tidy(ms_simplify(aus_b1))
nrow(aus_b1)
head(aus_b1)
aussie <- ggplot(data = aus_b1, aes(x = long, y = lat, group = group)) +
geom_polygon(aes(fill = id)) +
coord_quickmap() + theme_map() +
guides(fill = F) +
scale_fill_manual(values = brewer.pal(n = 11, name = "BrBG"))
aussie
I am still learning about R and I want to map the States of US with the labels of number of crimes occurred in each state. I want to create the below image.
I used the below code which was available online but I could not label the No of crimes.
library(ggplot2)
library(fiftystater)
data("fifty_states")
crimes <- data.frame(state = tolower(rownames(USArrests)), USArrests)
p <- ggplot(crimes, aes(map_id = state)) +
# map points to the fifty_states shape data
geom_map(aes(fill = Assault), map = fifty_states) +
expand_limits(x = fifty_states$long, y = fifty_states$lat) +
coord_map() +
scale_x_continuous(breaks = NULL) + scale_y_continuous(breaks = NULL) +
labs(x = "", y = "") + theme(legend.position = "bottom",
panel.background = element_blank())
Please can someone help me ?
To add text to a plot (map in this case) one needs the text label and the coordinates of the text. Here is an approach with your data:
library(ggplot2)
library(fiftystater)
library(tidyverse)
data("fifty_states")
ggplot(data= crimes, aes(map_id = state)) +
geom_map(aes(fill = Assault), color= "black", map = fifty_states) +
expand_limits(x = fifty_states$long, y = fifty_states$lat) +
coord_map() +
geom_text(data = fifty_states %>%
group_by(id) %>%
summarise(lat = mean(c(max(lat), min(lat))),
long = mean(c(max(long), min(long)))) %>%
mutate(state = id) %>%
left_join(crimes, by = "state"), aes(x = long, y = lat, label = Assault ))+
scale_x_continuous(breaks = NULL) + scale_y_continuous(breaks = NULL) +
labs(x = "", y = "") + theme(legend.position = "bottom",
panel.background = element_blank())
Here I used the Assault number as label and mean of the maximum and minimum of lat and long coordinates of each state as text coordinates. The coordinates could be better for some states, one can add them by hand or use chosen city coordinates.
EDIT: with the updated question:
First select the year and type of crime and aggregate the data
homicide %>%
filter(Year == 1980 & Crime.Type == "Murder or Manslaughter") %>%
group_by(State) %>%
summarise(n = n()) %>%
mutate(state = tolower(State)) -> homicide_1980
and then plot:
ggplot(data = homicide_1980, aes(map_id = state)) +
geom_map(aes(fill = n), color= "black", map = fifty_states) +
expand_limits(x = fifty_states$long, y = fifty_states$lat) +
coord_map() +
geom_text(data = fifty_states %>%
group_by(id) %>%
summarise(lat = mean(c(max(lat), min(lat))),
long = mean(c(max(long), min(long)))) %>%
mutate(state = id) %>%
left_join(homicide_1980, by = "state"), aes(x = long, y = lat, label = n))+
scale_x_continuous(breaks = NULL) + scale_y_continuous(breaks = NULL) +
labs(x = "", y = "") + theme(legend.position = "bottom",
panel.background = element_blank())
If one wants to compare all years I suggest doing it without text since it will be very cluttered:
homicide %>%
filter(Crime.Type == "Murder or Manslaughter") %>%
group_by(State, Year) %>%
summarise(n = n()) %>%
mutate(state = tolower(State)) %>%
ggplot(aes(map_id = state)) +
geom_map(aes(fill = n), color= "black", map = fifty_states) +
expand_limits(x = fifty_states$long, y = fifty_states$lat) +
coord_map() +
scale_x_continuous(breaks = NULL) + scale_y_continuous(breaks = NULL) +
labs(x = "", y = "") + theme(legend.position = "bottom",
panel.background = element_blank())+
facet_wrap(~Year, ncol = 5)
One can see not much has changed during the years.
I trust a more informative plot is:
homocide %>%
filter(Crime.Type == "Murder or Manslaughter") %>%
group_by(State, Year) %>%
summarise(n = n()) %>%
mutate(state = tolower(State)) %>%
ggplot()+
geom_line(aes(x = Year, y = n))+
facet_wrap(~state, ncol = 6, scales= "free_y")+
theme_bw()
I can make USA state level unemployment graph with the following code.
library(XML)
library(ggplot2)
library(plyr)
library(maps)
unemp <-
readHTMLTable('http://www.bls.gov/web/laus/laumstrk.htm',
colClasses = c('character', 'character', 'numeric'))[[2]]
names(unemp) <- c('rank', 'region', 'rate')
unemp$region <- tolower(unemp$region)
us_state_map <- map_data('state')
map_data <- merge(unemp, us_state_map, by = 'region')
map_data <- arrange(map_data, order)
states <- data.frame(state.center, state.abb)
p1 <- ggplot(data = map_data, aes(x = long, y = lat, group = group))
p1 <- p1 + geom_polygon(aes(fill = cut_number(rate, 5)))
p1 <- p1 + geom_path(colour = 'gray', linestyle = 2)
p1 <- p1 + scale_fill_brewer('Unemployment Rate (Jan 2011)', palette = 'PuRd')
p1 <- p1 + coord_map()
p1 <- p1 + geom_text(data = states, aes(x = x, y = y, label = state.abb, group = NULL), size = 2)
p1 <- p1 + theme_bw()
p1
Now I want to similar kind of graph for Pakistan. My few attempts results are below:
data(world.cities)
Pakistan <- data.frame(map("world", "Pakistan", plot=FALSE)[c("x","y")])
p <- ggplot(Pakistan, aes(x=x, y=y)) +
geom_path(colour = 'green', linestyle = 2) +
coord_map() + theme_bw()
p <- p + labs(x=" ", y=" ")
p <- p + theme(panel.grid.minor=element_blank(), panel.grid.major=element_blank())
p <- p + theme(axis.ticks = element_blank(), axis.text.x = element_blank(), axis.text.y = element_blank())
p <- p + theme(panel.border = element_blank())
print(p)
and
library(mapproj)
Country <- "Pakistan"
Get_Map_Country <-
get_map(
location = Country
, zoom = 5
, scale = "auto"
, maptype = "roadmap"
, messaging = FALSE
, urlonly = FALSE
, filename = "ggmapTemp"
, crop = TRUE
, color = "color"
, source = "google"
, api_key
)
Country1 <-
ggmap(
ggmap = Get_Map_Country
, extent = "panel"
# , base_layer
, maprange = FALSE
, legend = "right"
, padding = 0.02
, darken = c(0, "black")
)
Country1 <- Country1 + labs(x="Longitude", y="Latitude")
print(Country1)
Country2 <- Country1 + geom_polygon(data = Pakistan
, aes(x=x, y=y)
, color = 'white', alpha = .75, size = .2)
print(Country2)
Questions
I wonder how to get map of administrative regions of Pakistan as of USA. I know for this we need longitude and latitude of administrative boundaries. I'm wondering how to get longitude and latitude of administrative boundaries for a country. I tried Global Administrative Areas but without success.
I don't know the spatial level of administrative areas you require, but here's two ways
to read in shapefile data and .RData formats from Global Administrative Areas (gadm.org), and converting them into data frames for use in ggplot2. Also, in order to replicate the U.S. map, you will need to plot the administrative area names located at the polygon centroids.
library(ggplot2)
library(rgdal)
Method 1. SpatialPolygonDataFrames stored as .RData format
# Data from the Global Administrative Areas
# 1) Read in administrative area level 2 data
load("/Users/jmuirhead/Downloads/PAK_adm2.RData")
pakistan.adm2.spdf <- get("gadm")
Method2. Shapefile format read in with rgdal::readOGR
pakistan.adm2.spdf <- readOGR("/Users/jmuirhead/Downloads/PAK_adm", "PAK_adm2",
verbose = TRUE, stringsAsFactors = FALSE)
Creating a data.frame from the spatialPolygonDataframes and merging with a data.frame containing the information on unemployment, for example.
pakistan.adm2.df <- fortify(pakistan.adm2.spdf, region = "NAME_2")
# Sample dataframe of unemployment info
unemployment.df <- data.frame(id= unique(pakistan.adm2.df[,'id']),
unemployment = runif(n = length(unique(pakistan.adm2.df[,'id'])), min = 0, max = 25))
pakistan.adm2.df <- merge(pakistan.adm2.df, unemployment.df, by.y = 'id', all.x = TRUE)
Extracting names and centoids of administrative areas for plotting
# Get centroids of spatialPolygonDataFrame and convert to dataframe
# for use in plotting area names.
pakistan.adm2.centroids.df <- data.frame(long = coordinates(pakistan.adm2.spdf)[, 1],
lat = coordinates(pakistan.adm2.spdf)[, 2])
# Get names and id numbers corresponding to administrative areas
pakistan.adm2.centroids.df[, 'ID_2'] <- pakistan.adm2.spdf#data[,'ID_2']
pakistan.adm2.centroids.df[, 'NAME_2'] <- pakistan.adm2.spdf#data[,'NAME_2']
Create ggplot with labels for administrative areas
p <- ggplot(pakistan.adm2.df, aes(x = long, y = lat, group = group)) + geom_polygon(aes(fill = cut(unemployment,5))) +
geom_text(data = pakistan.adm2.centroids.df, aes(label = NAME_2, x = long, y = lat, group = NAME_2), size = 3) +
labs(x=" ", y=" ") +
theme_bw() + scale_fill_brewer('Unemployment Rate (Jan 2011)', palette = 'PuRd') +
coord_map() +
theme(panel.grid.minor=element_blank(), panel.grid.major=element_blank()) +
theme(axis.ticks = element_blank(), axis.text.x = element_blank(), axis.text.y = element_blank()) +
theme(panel.border = element_blank())
print(p)
Have you tried http://www.diva-gis.org/gdata? That should give you Shapefiles with state/district boundaries for Pakistan.
The maptools package has functions that let you read and convert Shapefiles to a dataframe that can be used to lay out the boundary polygons.