I'm trying to plot (using ggplot) a topoJSON file I generated from https://pitchinteractiveinc.github.io/tilegrams/.
I used the code below to try to plot the example npr 1-to-1 data:
library(rgeos)
library(rgdal)
library(ggplot2)
library(dplyr)
map = readOGR("data/npr.json", "tiles")
map_df <- fortify(map)
gg = ggplot(data = map_df, aes(long,lat, group=group))
gg = gg + geom_polygon(colour="gray65", size=1.0)
print(gg)
The result is not right.
I've tried plotting this with geom_map, and tried adding coord_equal and coord_map without impact.
I also tried to plot a single polygon and got the image below. Perhaps it suggests that points of the polygon are in incorrect order? Anyone have an idea on how to correct?
Actually, the issues seems to be in the conversion done by the readOGR. I imported the json manually and extract the polygons and it worked fine.
Related
I am attempting to draw lines in polar coordinates on a ggmap. The general method works fine in ggplot:
library(ggmap)
library(rgdal)
library(ggplot2)
#####################################
## build data frame with triangulation data
t1 <- c(534325, 4858925, 338, 0955)
t2 <- c(534383, 4859261, 290, 1010)
t3 <- c(534386, 4859011, 301, 1015)
df <- as.data.frame(rbind(t1, t2, t3))
colnames(df) <- c("Easting", "Northing", "Azimuth", "Time")
df$Time <- as.character(df$Time)
## plot coordinates with triangulation
ggplot(df, aes(x=Easting, y=Northing, label=Time)) +
geom_point() +
geom_text(nudge_x = 50) +
geom_spoke(aes(angle = Azimuth, radius = -500)) +
theme_bw()
Triangulation with no base map:
This is what I want, but with no base map in the background.
However, when I attempt this method in ggmap:
## convert utms to lat long
utmcoor <- SpatialPoints(cbind(df$Easting,df$Northing),
proj4string=CRS("+proj=utm +zone=12"))
lonlatcoor <- as.data.frame(spTransform(utmcoor,CRS("+proj=longlat")))
colnames(lonlatcoor) <- c("lon", "lat")
df$lon <- lonlatcoor$lon
df$lat <- lonlatcoor$lat
## plot on base map
zoom <- 15
meanlon <- mean(df$lon)
meanlat <- mean(df$lat)
basemap <- get_googlemap(center=c(lon=meanlon, lat=meanlat), zoom=zoom,
maptype="hybrid")
ggmap(basemap) +
geom_point(aes(x=lon, y=lat), colour="red", size=2, data=df) +
geom_spoke(aes(x=lon, y=lat, angle = Azimuth), data=df, radius=-200) +
theme_void()
I get the error
Warning message:
Removed 3 rows containing missing values (geom_segment).
The code works fine without the geom_spoke line, resulting in basemap without triangulations:
I understand that this function is generally used for things like quiver plots. Does ggmap not support geom_spoke? Is there a better function altogether that I am not aware of?
Thanks in advance.
The issue is with the coordinates: You're giving geom_spoke a radius of -200, but the coordinates you're working with are several orders of magnitude smaller. I took out the theme_void just to remind myself of how small the scale is; you want a radius of something like 0.01. Mess around with the radius value I put here.
geom_spoke basically does a little trigonometry behind the scenes to calculate the endpoint of each spoke, then draws a segment. If that endpoint is out of the bounds of the plot, you get that missing values warning. I'm not sure if -200 is the radius you're sticking with, or just a dummy value, but you could use your original coordinates and angles to calculate the endpoints, then project those points to figure out the radius. Or just use those endpoints to draw the geom_segment yourself. I'll leave those calculations to you, or it might make for another question. I'm pretty partial to sf and have a feeling that could provide an easy enough way to get those points.
library(ggmap)
library(rgdal)
library(ggplot2)
# .....
# everything up until ggmap is the same as in question
ggmap(basemap) +
geom_point(aes(x=lon, y=lat), colour="red", size=2, data=df) +
geom_spoke(aes(x=lon, y=lat, angle = Azimuth), data=df, radius = -1e-2)
Created on 2018-07-18 by the reprex package (v0.2.0).
I am attempting to plot a small raster using ggplot(gplot) with a manual color scale for the seven discrete values in the raster. However, scale_colour_manual does not seem to be working as expected (and as indicated in other similar posts on this and other sites) and instead resorts to the default coloration.
Here is the incorrect ggplot version:
Here is the correct coloration using R plot:
Here is my sample raster:
https://dl.dropboxusercontent.com/u/11618932/map.tif
or
https://dl.dropboxusercontent.com/u/11618932/map.r
And here is the code:
library(raster)
library(ggplot2)
my_raster<-raster("map.tif")
my_color<-c("#177798","#D239A0","#A3E0AE","#D29D52","#8F4F3E","#917FD9","#6EC848")
gplot(my_raster) + geom_tile(aes(fill = as.factor(value))) + scale_colour_manual(values= c(my_color))
Thanks in advance for your help
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:
I'm trying to get districts of Warsaw and draw them on google map. Using this code, where 2536107 is relation code for OpenStreetMap single Warsaw district, gives me almost what I want but with a few bugs. There is general outline but also lines between points which shouldn't be connected. What am I doing wrong?
map <- get_googlemap('warsaw', zoom =10)
warszawa <- get_osm(relation(2536107), full = T)
warszawa.sp <- as_sp(warszawa, what='lines')
warsawfort <- fortify(warszawa.sp)
mapa_polski <- ggmap(map, extent='device', legend="bottomleft")
warsawfort2 <- geom_polygon(aes(x = long, y = lat),
data = warsawfort, fill="blue", colour="black",
alpha=0.0, size = 0.3)
base <- mapa_polski + warsawfort2
base
Edit: I figured it must be somehow connected with order of plotting every point/line but I have no idea how to fix this.
There is a way to generate your map without using external packages: don't use osmar...
This link, to the excellent Mapzen website, provides a set of shapefiles of administrative areas in Poland. If you download and unzip it, you will see a shapfile set called warsaw.osm-admin.*. This is a polygon shapefile of all the districts in Poland, conveniantly indexed by osm_id(!!). The code below assumes you have downloaded the file and unzipped it into the "directory with your shapefiles".
library(ggmap)
library(ggplot2)
library(rgdal)
setwd(" <directory with your shapefiles> ")
pol <- readOGR(dsn=".",layer="warsaw.osm-admin")
spp <- pol[pol$osm_id==-2536107,]
wgs.84 <- "+proj=longlat +datum=WGS84"
spp <- spTransform(spp,CRS(wgs.84))
map <- get_googlemap('warsaw', zoom =10)
spp.df <- fortify(spp)
ggmap(map, extent='device', legend="bottomleft") +
geom_polygon(data = spp.df, aes(x = long, y=lat, group=group),
fill="blue", alpha=0.2) +
geom_path(data=spp.df, aes(x=long, y=lat, group=group),
color="gray50", size=0.3)
Two nuances: (1) The osm IDs are stored as negative numbers, so you have to use, e.g.,
spp <- pol[pol$osm_id==-2536107,]
to extract the relevant district, and (2) the shapefile is not projected in WGS84 (long/lat). So we have to reproject it using:
spp <- spTransform(spp,CRS(wgs.84))
The reason osmar doesn't work is that the paths are in the wrong order. Your warszawa.sp is a SpatialLinesDataframe, made up of a set of paths (12 in your case), each of which is made up of a set of line segments. When you use fortify(...) on this, ggplot tries to combine them into a single sequence of points. But since the paths are not in convex order, ggplot tries, for example, to connect a path that ends in the northeast, to a path the begins in the southwest. This is why you're getting all the extra lines. You can see this by coloring the segments:
xx=coordinates(warszawa.sp)
colors=rainbow(11)
plot(t(bbox(warszawa.sp)))
lapply(1:11,function(i)lines(xx[[i]][[1]],col=colors[i],lwd=2))
The colors are in "rainbow" order (red, orange, yellow, green, etc.). Clearly, the lines are not in that order.
EDIT Response to #ako's comment.
There is a way to "fix" the SpatialLines object, but it's not trivial. The function gPolygonize(...) in the rgeos package will take a list of SpatialLines and convert to a SpatialPolygons object, which can be used in ggplot with fortify(...). One huge problem (which I don't understand, frankly), is that OP's warszaw.sp object has 12 lines, two of which seem to be duplicates - this causes gPolygonize(...) to fail. So if you create a SpatialLines list with just the first 11 paths, you can convert warszawa.sp to a polygon. This is not general however, as I can't predict how or if it would work with other SpatialLines objects converted from osm. Here's the code, which leads to the same map as above.
library(rgeos)
coords <- coordinates(warszawa.sp)
sll <- lapply(coords[1:11],function(x) SpatialLines(list(Lines(list(Line(x[[1]])),ID=1))))
spp <- gPolygonize(sll)
spp.df <- fortify(spp)
ggmap(map, extent='device', legend="bottomleft") +
geom_polygon(data = spp.df, aes(x = long, y=lat, group=group),
fill="blue", alpha=0.2) +
geom_path(data=spp.df, aes(x=long, y=lat, group=group),
color="gray50", size=0.3)
I am not sure this is a general hangup--I can reproduce your example and see the issue. My first thought was that you didn't supply group=id which are typically used for polygons with many lines, but you have lines, so that should not be needed.
The only way I could get it to display properly was by changing your lines into a polygon off script. Qgis' line to polygon didn't get this "right", getting a large donut hole, so I used ArcMap, which produced a full polygon. If this is a one off that may work for your workflow. Odds are it is not. In that case, perhaps RGDAL can transform lines to polygons, assuming that is indeed a general problem.
Upon reading the polygon shapefile and fortifying that, your code ran without problems.
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()