I am working with some global data from before 1991, so before the USSR, Yugoslavia and Czechoslovakia split up. I would like to plot the data using rworldmap or maps, but the package appears to only have the modern world map easily accessible. All the pre-1991 countries show up blank and with the boundaries dividing their post-1991 counterparts.
This code produces the historical map:
if (requireNamespace("mapdata", quietly=TRUE) && packageVersion("mapdata") >= "2.3")
{map("mapdata::worldLores", fill = TRUE, col = 1:10)}
EDIT: also, as per the helpful comment below, a historical map shapefile is easily obtained from:
library(cshapes)
cshp.data<-cshp(as.Date("1990-01-01"))
plot(cshp.data)
But I cannot figure out if it is possible to combine this with the rworldmap functions ... or if I will have to figure out how to use the maps package, which seems to work differently. (Or maybe there is a ggplot solution?)
The rworldmap code I use currently (to get the modern map) is:
#make example data including Soviet Union
country <- as.vector(c("Afghanistan","Australia","Iceland","Soviet Union",
"Zimbabwe"))
value <- as.vector(c(5,10,100,10,50))
df<-data.frame(country,value)
#make map
map1 <- joinCountryData2Map(df, joinCode = "NAME", nameJoinColumn =
"country")
mapCountryData( map1, addLegend=F, catMethod="fixedWidth",
nameColumnToPlot="value" )
#...Soviet Union is blank
Ahah, there is a ggplot solution using the old map from the mapdata package:
library(ggplot2)
library(dplyr)
library(mapdata)
df<-data.frame(country=c("Afghanistan","Australia","Iceland","USSR","Zimbabwe"),
value=c(5,10,100,10,50),stringsAsFactors=FALSE)
WorldData <- map_data('worldLores') #use the old map
WorldData <- fortify(WorldData)
mapped <- ggplot() +
geom_map(data=WorldData, map=WorldData,
aes(x=long, y=lat, group=group, map_id=region),
fill="white", colour="#7f7f7f", size=0.5) +
geom_map(data=df, map=WorldData,
aes(fill=value, map_id=country),
colour="#7f7f7f", size=0.5)
mapped
(mapping code borrowed from this post, cheers #hrbrmstr)
Related
I have a largish polyline shapefile (Bavarian rivers, which can be accessed here) which I would like to plot and save via ggplot. This can easily be done via e.g. this code:
library(ggplot2)
library(rgdal)
library(sp)
library(rgeos)
riv <- readOGR(paste0(getwd(),"\\rivers_bavaria","rivers_bavaria"))
riv1 <- subset(riv,WDM=="1310"|WDM=="1320")
riv2 <- subset(riv,WDM=="1330")
p <- ggplot() +
geom_line(data=riv1, aes(x=long, y=lat, group=group), color="dodgerblue", size=1) +
geom_line(data=riv2, aes(x=long, y=lat, group=group), color="dodgerblue")
ggsave(paste0(getwd(),"\\riv.tiff",p,device="tiff",units="cm",dpi=300)
This is not exactly efficient, due to the large file size, but it works. However, without further specifying aspect ratio or projection, the dimensions of the output file are defined by the plot window - not desirable for maps. This can be remedied by using coord_quickmap().
p1 <- ggplot() +
geom_line(data=riv1, aes(x=long, y=lat, group=group), color="dodgerblue", size=1) +
geom_line(data=riv2, aes(x=long, y=lat, group=group), color="dodgerblue") +
coord_quickmap()
p1
Unfortunately, the projection is completely off. I have tried coord_map() for a better result, but due to the large file size, it takes forever and is therefore not a realistic option. Simplifying the polyline via gLinemerge() produces a much smaller object, but cannot be handled by ggplot, as it is a SpatialLines object. Using fortify() or data.frame() to coerce it into a ggplot-friendly data frame format also produces Error: ggplot2 doesn't know how to deal with data of class SpatialLines.
I'm therefore desperately looking for a workflow that will allow me to plot and save this kind of spatial data in good quality with ggplot. Any suggestions will be much appreciated!
Here's a quick walkthrough with sf. I recommend the sf vignettes and docs to see more details of any of the functions. I'm first reading the shapefile in as an sf object using sf::st_read, then filtering, mutating, and selecting the same as you would in dplyr to get a smaller version of the shape.
library(tidyverse)
library(sf)
rivers_sf <- st_read("rivers_bavaria/rivers_bavaria.shp") %>%
filter(WDM %in% c("1310", "1320", "1330")) %>%
mutate(name2 = ifelse(WDM == "1330", "river 2", "river 1")) %>%
select(name2, NAM, geometry)
The object is pretty big, and will be very slow to plot, so I simplified it by uniting the geometries by name, then using st_simplify. There's also rmapshaper::ms_simplify, which uses Mapshaper and which I prefer for better control over how much information you keep. Then to show a CRS transformation, I picked a projection from Spatial Reference for Germany.
riv_simple <- rivers_sf %>%
group_by(name2, NAM) %>%
summarise(geometry = st_union(geometry)) %>%
ungroup() %>%
st_simplify(preserveTopology = T, dTolerance = 1e6) %>%
st_transform(31493)
The dev version of ggplot2 on GitHub has a function geom_sf for plotting different types of sf objects. To get this version, run devtools::install_github("tidyverse/ggplot2").
geom_sf has some quirks, and works a little differently from other geoms, but it's pretty versatile. I believe it's being included in the next CRAN release. geom_sf has corresponding stat_sf and coord_sf. By default, it plots graticule lines; to turn those off, add coord_sf(ndiscr = F).
ggplot(riv_simple) +
geom_sf(aes(size = name2), color = "dodgerblue", show.legend = "line") +
scale_size_manual(values = c("river 1" = 1, "river 2" = 0.5)) +
theme_minimal() +
coord_sf(ndiscr = F)
Hope that helps you get started!
I am trying to plot a reprojected world map using data from the cshapes package and sp::spTransform, but the projection leads to distorted plots. How can I correctly reproject and plot a cshapes map?
Here is an example that shows that the map plots fine by itself (code adapted from this blog post):
library("cshapes")
library("ggplot2")
library("rgdal")
wmap <- cshp(date=as.Date("2012-06-30"))
wmap_df <- fortify(wmap)
ggplot(wmap_df, aes(long,lat, group=group)) +
geom_polygon() +
labs(title="World map (longlat)") +
coord_equal()
ggsave("~/Desktop/map1.png", height=4, width=7)
And here is the distorted version when I reproject to Robinson:
wmap_robin <- spTransform(wmap, CRS("+proj=robin"))
wmap_df_robin <- fortify(wmap_robin)
ggplot(wmap_df_robin, aes(long,lat, group=group)) +
geom_polygon() +
labs(title="World map (robinson)") +
coord_equal()
ggsave("~/Desktop/map2.png", height=4, width=7)
Some additional info:
I know there are other data sources for country borders, but I need maps that reflect changes in country borders, which cshapes does.
My guess is the the problem is related to issues with the underlying map polygons, but I have no idea where to begin looking and it's probably better to ask what I want to get in the end, not how to fix a hunch.
The problem is not with ggplot2, plotting the map with base graphics shows the same distortions (plot(wmap_robin)).
You can use raster::crop to remove nodes that are just smaller than -180 or larger than 180
library(cshapes)
library(raster)
wmap <- cshp(date=as.Date("2012-06-30"))
w <- crop(wmap, extent(-180, 180,-90,90))
w_robin <- spTransform(w, CRS("+proj=robin"))
plot(w_robin)
Update for 2018, using a solution with sf:
library("cshapes")
library("sf")
cshp(as.Date("2015-01-01")) %>%
st_as_sf() %>%
st_crop(ymin = -90, ymax = 90, xmin=-180, xmax=180) %>%
st_transform(crs = "+proj=robin") %>%
`[`(1) %>% plot()
The output is:
perhaps you have an idea and could help me. I have following data:
lon.x <- c(11.581981, 13.404954, 9.993682, 7.842104 , 11.741185)
lat.x <- c(48.135125, 52.520007, 53.551085, 47.999008, 48.402880)
lon.y <- c(8.801694, 7.842104 , 11.581981, 13.404954, 7.842104 )
lat.y <- c(53.079296,47.999008, 48.135125, 52.520007, 47.999008)
pred <- c(1,2,3,4,5)
data <- data.frame(cbind(lon.x, lat.x, lon.y, lat.y, pred))
where "lon.x" and "lat.x" are longitude-latitude points of a city and "lon.y" and "lat.y" of another city. So there are pairs of cities.
Now, I would like to make a map in R, with
(1) the direct distances between the x and y coordinates as a line
(2) which will receive a different color based on the variable "pred", this could be red for higher values and blue for lower, or thicker lines with higher values of "pred".
The result should be a simple map, with lines between the cities, that are shaped based on the variable "pred". For instance, the line between the first pair of cities would be thinner, while the last one would be thicker. Is that possible?
I have currently only made to receive a (very complicated) google map of Germany:
library(mapproj)
map <- get_map(location = 'Germany', zoom = 6.2)
ggmap(map)
But I am not sure how to plot points and especially relations between the points that differ based on "pred". Also a very simple map (not so detailed google map) would be best! Any idea? THANKS!
You can use ggplot2 to add lines onto the plot.
library(ggplot2)
library(ggmap)
map <- get_map(location = 'Germany', zoom = 6)
ggmap(map) +
geom_segment(data=data, aes(x=lon.x, xend=lon.y, y=lat.x, yend=lat.y, color=pred), size=2) +
scale_color_continuous(high="red", low="blue")
As for the simpler map, you can download shape files (just the outlines of countries) from www.gadm.org. Level 0 maps are just the country, level 1 have state boundaries, etc. To use one of these, download the file from the website and use this code:
load("DEU_adm0.RData")
gadm <- fortify(gadm)
ggplot(gadm) +
geom_path(aes(x=long, y=lat, group=group)) +
geom_segment(data=data, aes(x=lon.x, xend=lon.y, y=lat.x, yend=lat.y, color=pred), size=2) +
scale_color_continuous(high="red", low="blue")
How do you make a 50 state map in R?
It seems like all the example maps people have created are just of the lower 48
There are lots of ways that you can do this. Personally, I find Google to have the most attractive maps. I recommend ggmap, googleVis, and/or RgoogleMaps.
For example:
require(googleVis)
G4 <- gvisGeoChart(CityPopularity, locationvar='City', colorvar='Popularity',
options=list(region='US', height=350,
displayMode='markers',
colorAxis="{values:[200,400,600,800],
colors:[\'red', \'pink\', \'orange',\'green']}")
)
plot(G4)
Produces this:
Another approach that will give you a more attractive result than maps is to follow the approach of this tutorial which shows how to import custom maps from Inkscape (or, equivalently, Adobe Illustrator) into R for plotting.
You'll end up with something like this:
Here's a way to it with choroplethr and ggplot2:
library(choroplethr)
library(ggplot2)
library(devtools)
install_github('arilamstein/choroplethrZip#v1.3.0')
library(choroplethrZip)
data(df_zip_demographics)
df_zip_demographics$value = df_zip_demographics$percent_asian
zip_map = ZipChoropleth$new(df_zip_demographics)
zip_map$ggplot_polygon = geom_polygon(aes(fill = value),
color = NA)
zip_map$set_zoom_zip(state_zoom = NULL,
county_zoom = NULL,
msa_zoom = NULL,
zip_zoom = NULL)
zip_map$title = "50 State Map for StackOverflow"
zip_map$legend = "Asians"
zip_map$set_num_colors(4)
choro = zip_map$render()
choro
data(df_pop_state)
outline = StateChoropleth$new(df_pop_state)
outline = outline$render_state_outline(tolower(state.name))
choro_with_outline = choro + outline
choro_with_outline
which gives you:
This R-bloggers link might be useful for you.
To give you a look, you can get started on a 50-state map with
library(maps)
map("world", c("USA", "hawaii"), xlim = c(-180, -65), ylim = c(19, 72))
Believe it or not, Hawaii is on there. It's just really small because of the margins.
Resurrecting an old thread because it still doesn't have an accepted answer.
Check out #hrbrmstr's albersusa package:
devtools::install_github("hrbrmstr/albersusa")
library(albersusa)
plot(usa_composite(proj="laea"))
which produces
and can do much more
us <- usa_composite()
us_map <- fortify(us, region="name")
gg <- ggplot()
gg <- gg + geom_map(data=us_map, map=us_map,
aes(x=long, y=lat, map_id=id),
color="#2b2b2b", size=0.1, fill=NA)
gg <- gg + theme_map()
gg +
geom_map(data=us#data, map=us_map,
aes(fill=pop_2014, map_id=name),
color="white", size=0.1) +
coord_proj(us_laea_proj) +
scale_fill_viridis(name="2014 Populaton Estimates", labels=comma) +
theme(legend.position="right")
You might want to consider using the state.vbm map in the maptools package, this includes all 50 states and makes the smaller states more visible (works fine for coloring, or adding plots to each state, but distances between sites will not be exact).
Another option is to draw the contiguous 48 states, then in open areas add Alaska and Hawaii yourself. One option for doing this is to use the subplot function from the TeachingDemos package.
Here is some example code using a couple of the shapefiles provided by the maptools package:
library(maptools)
library(TeachingDemos)
data(state.vbm)
plot(state.vbm)
yy <- readShapePoly(system.file("shapes/co37_d90.shp", package="maptools")[1])
zz <- readShapePoly(system.file("shapes/co51_d90.shp", package="maptools")[1])
xx <- readShapePoly(system.file("shapes/co45_d90.shp", package="maptools")[1])
plot(yy)
par('usr')
subplot( plot(zz), c(-84,-81), c(31,33) )
subplot( plot(xx), c(-81, -78), c(31,33) )
You would just need to find the appropriate shape files for the states.
Using choroplethr you can create a simple and quick state map by doing the following:
#install.packages("choroplethr")
#install.packages("choroplethrMaps")
library(choroplethr)
library(choroplethrMaps)
data(df_pop_state)
StateChoropleth$new(df_pop_state)$render()
I like this method because it's fast and easy. If you don't want the state labels, removing them requires a little bit more:
c = StateChoropleth$new(df_pop_state)
c$title = "2012 State Population Estimates"
c$legend = "Population"
c$set_num_colors(7)
c$set_zoom(NULL)
c$show_labels = FALSE
without_abbr = c$render()
without_abbr
Here's a comparison of the two methods:
Sources 1 and 2
How do I plot a choropleth or thematic map using ggplot2 from a KML data source?
Example KML: https://dl.dropbox.com/u/1156404/nhs_pct.kml
Example data: https://dl.dropbox.com/u/1156404/nhs_dent_stat_pct.csv
Here's what I've got so far:
install.packages("rgdal")
library(rgdal)
library(ggplot2)
fn='nhs_pct.kml'
#Look up the list of layers
ogrListLayers(fn)
#The KML file was originally grabbed from Google Fusion Tables
#There's only one layer...but we still need to identify it
kml=readOGR(fn,layer='Fusiontables folder')
#This seems to work for plotting boundaries:
plot(kml)
#And this:
kk=fortify(kml)
ggplot(kk, aes(x=long, y=lat,group=group))+ geom_polygon()
#Add some data into the mix
nhs <- read.csv("nhs_dent_stat_pct.csv")
kml#data=merge(kml#data,nhs,by.x='Name',by.y='PCT.ONS.CODE')
#I think I can plot against this data using plot()?
plot(kml,col=gray(kml#data$A.30.Sep.2012/100))
#But is that actually doing what I think it's doing?!
#And if so, how can experiment using other colour palettes?
#But the real question is: HOW DO I DO COLOUR PLOTS USING gggplot?
ggplot(kk, aes(x=long, y=lat,group=group)) #+ ????
So my question is: how do I use eg kml#data$A.30.Sep.2012 values to colour the regions?
And as a supplementary question: how might I then experiment with different colour palettes, again in the ggplot context?
Plotting maps in R is very often a pain. Here's an answer which largely follows Hadley's tutorial at https://github.com/hadley/ggplot2/wiki/plotting-polygon-shapefiles
library(maptools)
library(rgdal)
library(ggplot2)
library(plyr)
fn='nhs_pct.kml'
nhs <- read.csv("nhs_dent_stat_pct.csv")
kml <- readOGR(fn, layer="Fusiontables folder")
Note: I got a message about orphan holes. I included the following line after reading https://stat.ethz.ch/pipermail/r-help/2011-July/283281.html
slot(kml, "polygons") <- lapply(slot(kml, "polygons"), checkPolygonsHoles)
## The rest more or less follows Hadley's tutorial
kml.points = fortify(kml, region="Name")
kml.df = merge(kml.points, kml#data, by.x="id",by.y="Name",sort=FALSE)
kml.df <- merge(kml.df,nhs,by.x="id",by.y="PCT.ONS.CODE",sort=FALSE,all.x=T,all.y=F)
## Order matters for geom_path!
kml.df <- kml.df[order(kml.df$order),]
nhs.plot <- ggplot(kml.df, aes(long,lat,group=group,fill=A.30.Sep.2012)) +
geom_polygon() +
geom_path(color="gray") +
coord_equal() +
scale_fill_gradient("The outcome") +
scale_x_continuous("") + scale_y_continuous("") + theme_bw()