How to add a SpatialPolygons to a bubble plot in R - r

I would like to use the function bubble from the packge sp to plot data and I would like to add a SpatialPolygons layer. I can easily plot the data using spplot but for some reason it doesn't work with bubble. For example:
library(sp)
# Create SpatialPolygons
Sr1 <- Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Srs1 <- Polygons(list(Sr1), "s1")
SpP <- SpatialPolygons(list(Srs1))
# Create SpatialPointsDataFrame
pp <- data.frame(x1=2:4,x2=2:4,att=2:4)
coordinates(pp) <- ~x1+x2
# Plot using spplot
spplot(pp, sp.layout=list("sp.polygons", SpP, fill="blue"))
# Plot using bubble
bubble(pp, sp.layout=list("sp.polygons", SpP, fill="blue"))
Some have done this through transforming the SpatialPolygons into SpatialLines and it looks like I could do it through ggplot2 (see post), but I'm confused why the bubble plot doesn't work with SpatialPolygons. Any trick to make it work?

A workaround is to use a custom panel function:
bubble(pp, "att",
panel=function(...) {
sp.polygons(SpP, fill="blue")
sp:::panel.bubble(...)
})

I'm not sure why your spplots aren't working but this is right up ggplot's alley:
library(sp)
library(ggplot2)
Sr1 <- Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Srs1 <- Polygons(list(Sr1), "s1")
SpP <- SpatialPolygons(list(Srs1))
pp <- data.frame(x1=2:4,x2=2:4,att=2:4)
spdf <- SpatialPolygonsDataFrame(SpP, data=data.frame(row.names="s1", val=1))
sp_map <- fortify(spdf)
gg <- ggplot()
gg <- gg + geom_map(data=sp_map, map=sp_map,
aes(x=long, y=lat, map_id=id),
color="black", fill="blue")
gg <- gg + geom_point(data=pp, aes(x=x1, y=x2, size=att), color="orange")
gg <- gg + scale_size_continuous(range=c(5,10))
gg <- gg + coord_equal(ylim=c(1.5,5), xlim=c(1,4.5))
gg <- gg + labs(x=NULL, y=NULL)
gg <- gg + theme_bw()
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.border=element_blank())
gg
(I might have mixed up which is x & y for the bubbles)
You have (IMO) much better control over aesthetics this way.

Related

What is the "Simplest" way to add a scale to a map in ggmap

For real, I searched everywhere, and coding a scale in a map is so hard...
Adding scale bar to ggplot map
Is there a way to add a scale bar (for linear distances) to ggmap?
Could it be possible to make a simple line that scale differently to the zoom preset that we select in the function?
I have this simple map:
library(ggmap)
pngMAP_df2 = get_map(location = c(-90.5, -0.5), source = "google", zoom = 8,color = "bw")
s = ggmap(pngMAP_df2)
s
I wanted to add as well GPS coordinate in this graph:
myGPS = data.frame(lat=c( -0.6850556,-0.6854722, -0.6857778 ),lon=c(-90.22275,-90.22261, -90.22272))
Is it easy to implement?
I just want to add something realllllllllly simple. Like a line with always a round number that give an indication of the zoom in the map.
Also, is it possible with this code to make the map look even simpler. Like seeing the water in white and the contour of the land in black?
Thanks,
Something like:
library(rgdal)
library(rgeos)
library(ggplot2)
library(ggthemes)
library(ggsn)
URL <- "https://osm2.cartodb.com/api/v2/sql?filename=public.galapagos_islands&q=select+*+from+public.galapagos_islands&format=geojson&bounds=&api_key="
fil <- "gal.json"
if (!file.exists(fil)) download.file(URL, fil)
gal <- readOGR(fil, "OGRGeoJSON")
# sample some points BEFORE we convert gal
rand_pts <- SpatialPointsDataFrame(spsample(gal, 100, type="random"), data=data.frame(id=1:100))
gal <- gSimplify(gUnaryUnion(spTransform(gal, CRS("+init=epsg:31983")), id=NULL), tol=0.001)
gal_map <- fortify(gal)
# now convert our points to the new CRS
rand_pts <- spTransform(rand_pts, CRS("+init=epsg:31983"))
# and make it something ggplot can use
rand_pts_df <- as.data.frame(rand_pts)
gg <- ggplot()
gg <- gg + geom_map(map=gal_map, data=gal_map,
aes(x=long, y=lat, map_id=id),
color="black", fill="#7f7f7f", size=0.25)
gg <- gg + geom_point(data=rand_pts_df, aes(x=x, y=y), color="steelblue")
gg <- gg + coord_equal()
gg <- gg + scalebar(gal_map, dist=100, location="topright", st.size=2)
gg <- gg + theme_map()
gg
This would be the complete answer with specific points on the map.
library(rgdal)
library(rgeos)
library(ggplot2)
library(ggthemes)
library(ggsn)
myGPS = data.frame(lat=c( -0.6850556,-0.6854722, -0.6857778 ),lon=c(-90.22275,-90.22261, -90.22272))
coord.deg = myGPS
class(coord.deg)
## "data.frame"
coordinates(coord.deg)<-~lon+lat
class(coord.deg)
## "SpatialPointsDataFrame"
## attr(,"package")
## "sp"
# does it have a projection/coordinate system assigned?
proj4string(coord.deg) # nope
## NA
# Manually tell R what the coordinate system is
proj4string(coord.deg)<-CRS("+proj=longlat +ellps=WGS84 +datum=WGS84")
# now we can use the spTransform function to project. We will project
# the mapdata and for coordinate reference system (CRS) we will
# assign the projection from counties
coord.deg<-spTransform(coord.deg, CRS(proj4string(gal)))
# double check that they match
identical(proj4string(coord.deg),proj4string(gal))
## [1] TRUE
my_pts <- SpatialPointsDataFrame(coords = coord.deg, data=data.frame(id=1:length(coord.deg)))
URL <- "https://osm2.cartodb.com/api/v2/sql?filename=public.galapagos_islands&q=select+*+from+public.galapagos_islands&format=geojson&bounds=&api_key="
fil <- "gal.json"
if (!file.exists(fil)) download.file(URL, fil)
gal <- readOGR(fil, "OGRGeoJSON")
gal <- gSimplify(gUnaryUnion(spTransform(gal, CRS("+init=epsg:31983")), id=NULL), tol=0.001)
gal_map <- fortify(gal)
rand_pts <- spTransform(my_pts, CRS("+init=epsg:31983"))
# ggplot can't deal with a SpatialPointsDataFrame so we can convert back to a data.frame
my_pts <- data.frame(my_pts)
my_pts.final = my_pts[,2:3]
# we're not dealing with lat/long but with x/y
# this is not necessary but for clarity change variable names
names(my_pts.final)[names(my_pts.final)=="lat"]<-"y"
names(my_pts.final)[names(my_pts.final)=="lon"]<-"x"
gg <- ggplot()
gg <- gg + geom_map(map=gal_map, data=gal_map,
aes(x=long, y=lat, map_id=id),
color="black", fill="#FFFFFF", size=.5)
gg <- gg + coord_equal()
gg <- gg + ggsn:::scalebar(gal_map, dist=50, location="bottomleft", st.size=5)
gg <- gg + theme_map()
gg <- gg + geom_point(data=my_pts.final, aes(x=x, y=y), color="red")
gg

Plot the intensity of a continuous with geom_tile in ggplot

I'm trying to plot a continuous variable on space. I saw this example that gets the same result that I need:
library("MASS")
library("ggplot2")
library(reshape2)
DB<-melt(volcano)
ggplot(DB, aes(x=Var1, y=Var2, fill=value)) +geom_tile()
So I did with my data:
library(repmis)
url<-"https://www.dropbox.com/s/4m5qk32wjgrjq40/dato.RDATA"
source_data(url)
library(ggplot2)
ggplot(dato,aes(y=variable,x=y,fill=value))+geom_tile()
That's wonderful. But my "x" and "y" are kilometers distance (east and north) from a point in space. I transformed these in latitude and longitude. But now my plot doesn't work!
ggplot(dato,aes(y=lat,x=long,fill=value))+geom_tile()
I don't understand why. Anyway plotting my data like points the result is very similar:
ggplot(dato,aes(y=lat,x=long,fill=value))+geom_point()
ggplot(dato,aes(y=variable,x=y,fill=value))+geom_point()
You can cheat a bit and use geom_point with a square shape:
#devtools::install_github("sjmgarnier/viridis")
library(viridis)
library(ggplot2)
library(ggthemes)
library(scales)
library(grid)
gg <- ggplot(dato)
gg <- gg + geom_point(aes(x=long, y=lat, color=value), shape=15, size=5)
gg <- gg + coord_equal()
gg <- gg + scale_color_viridis(na.value="#FFFFFF00")
gg <- gg + theme_map()
gg <- gg + theme(legend.position="right")
gg
I did not project the lat/long pairs and just used coord_equal. You should use a proper projection for the region being mapped.
And, now you have me curious as to what those hot spots are around Milan :-)
gmap <- get_map(location=c(9.051062, 45.38804, 9.277473, 45.53438),
source="stamen", maptype="toner", crop=TRUE)
gg <- ggmap(gmap)
gg <- gg + geom_point(data=dato, aes(x=long, y=lat, color=value), shape=15, size=5, alpha=0.25)
gg <- gg + coord_map()
gg <- gg + scale_color_viridis(na.value="#FFFFFF00")
gg <- gg + theme_map()
gg <- gg + theme(legend.position="right")
gg

How to colour a single country in R maps package (worldhires)

I am new here and I am trying to plot points on a map of a coastal region - therefore I would like to show a coastline and colour just one country, surrounded by adjoining countries.
My code is
library(maps)
library(mapdata)
map("worldHires", xlim=c(-90,-70), ylim=c(-20,-2), # Re-defines the latitude and longitude range
col = "gray", fill=TRUE)
However I would like to colour in just Peru. I have so far managed to do this:
map('worldHires', 'Peru', col = "grey90", fill=TRUE, xlim=c(-90,-70), ylim=c(-20,-2))
but this doesn't show adjoining countries, and I would really like to show all adjoining countries and just colour Peru.
I have seen advice in another thread using the simple map tool - but there is slightly less detail (see below)
library(maptools)
data(wrld_simpl)
plot(wrld_simpl,
col = c(gray(.80), "red")[grepl("Peru", wrld_simpl#data$NAME) + 1],
xlim=c(-90,-70), ylim=c(-20,-2))
Does anyone know how to do it using worldhires? It's probably really simple and I just haven't worked it out.
The trick is to use map() to extract the Peru boundaries, then overplotting the Peru fill on a worlmap outline.
library(maps)
library(mapdata)
peru <- map("worldHires", regions="Peru", plot=FALSE, fill=TRUE)
map("worldHires", xlim=c(-100,-30), ylim=c(-30,10))
map(peru, col="red", fill=TRUE, add=TRUE)
A Hadleyverse version via ggplot:
library(maps)
library(mapdata)
library(ggplot2)
coast_map <- fortify(map("worldHires", fill=TRUE, plot=FALSE))
gg <- ggplot()
gg <- gg + geom_map(data=coast_map, map=coast_map,
aes(x=long, y=lat, map_id=region),
fill="white", color="black")
gg <- gg + geom_map(data=data.frame(region="Peru"), map=coast_map,
aes(map_id=region), fill="steelblue")
gg <- gg + xlim(-90,-70) + ylim(-20,-2)
gg <- gg + coord_map()
gg <- gg + theme_bw()
gg

Add bathymetry lines to ggplot using marmap package and getNOAA.bathy

I am wanting to add bathymetry lines to a map plot I am looking at. I am plotting points off the coast and we are interested as to how close to the continental shelf they are. I have seen a package called Marmap - but now I am using ggplot as it gives a higher resolution.
The code I've seen for getting bathymetry lines is this:
library(marmap)
Peru.bath <- getNOAA.bathy (lon1 = -90, lon2 = -70, lat1 = -20,
lat2 = -2, resolution = 10)
plot(Peru.bath)
The code I'm using which I want to add the bathymetry lines to is below:
coast_map <- fortify(map("worldHires", fill=TRUE, plot=FALSE))
gg <- ggplot()
gg <- gg + geom_map(data=coast_map, map=coast_map,
aes(x=long, y=lat, map_id=region),
fill="white", color="black") +
theme(panel.background = element_blank()) +
theme(panel.grid.major = element_blank()) +
theme(panel.grid.minor = element_blank()) +
theme(axis.text.x = element_blank(), axis.text.y = element_blank(), axis.ticks = element_blank())
gg <- gg + xlab("") + ylab("")
gg <- gg + geom_map(data=data.frame(region="Peru"), map=coast_map,
aes(map_id=region), fill="gray")
gg <- gg + xlim(-90,-70) + ylim(-20,-2)
gg <- gg + coord_map()
gg
Therefore I assumed it would be
gg <- gg + Peru.bath
However I am getting 'Error: Don't know how to add Peru.bath to a plot'
NB Just to make it clear, I do not have bathymetry data, I just wish to plot known shelf lines onto a map I have created, if that is possible.
I've just updated the development version of marmap on github. You can install it with:
library(devtools)
install_github("ericpante/marmap")
A function autoplot.bathy() for plotting bathy objects with ggplot2 is now included. Be sure to check it's help file and the examples to see what's possible. Here is an example with your dataset dat:
library(marmap) ; library(ggplot2)
dat <- getNOAA.bathy(-90,-70,-20,-2,res=4, keep=TRUE)
# Plot bathy object using custom ggplot2 functions
autoplot(dat, geom=c("r", "c"), colour="white", size=0.1) + scale_fill_etopo()
If you want to (i) add isobath lines to your map and (ii) determine the depth of your data points using get.depth() it would be much easier to stick with standard plots (marmap is designed to work with these). As a matter of fact, the "better resolution" you mention has nothing to do with base graphics nor ggplot2. In your example, the coastline you're plotting comes from the "worldHires" dataset from package mapdata and it has nothing to do with ggplot2. Indeed, you can add the same coastline on marmap plots.
Here is some code to produce two more than decent maps using base graphics and marmap:
library(marmap) ; library(mapdata)
# Get bathymetric data
dat <- getNOAA.bathy(-90,-70,-20,-2,res=4, keep=TRUE)
# Create nice color palettes
blues <- c("lightsteelblue4", "lightsteelblue3", "lightsteelblue2", "lightsteelblue1")
greys <- c(grey(0.6), grey(0.93), grey(0.99))
## First option for plotting
plot(dat, land=TRUE, n=100, lwd=0.03)
map("worldHires", res=0, add=TRUE)
# Second option
plot(dat, im=TRUE, land=TRUE, bpal=list(c(min(dat),0,blues),c(0,max(dat),greys)), lwd=.05, las=1 )
map("worldHires", res=0, lwd=0.7, add=TRUE)
# Add -200m and -1000m isobath
plot(dat, deep=-200, shallow=-200, step=0, lwd=0.5, drawlabel=TRUE, add=TRUE)
plot(dat, deep=-1000, shallow=-1000, step=0, lwd=0.3, drawlabel=TRUE, add=TRUE)
Note that the resolution used here is not the highest possible. the res argument of getNOAA.bathy() is set to 4 here. This downloads a 2.7Mb dataset that can be saved locally by setting the keep argument to TRUE. The highest resolution possible would be res=1, but in my opinion, it is overkill for such a wide geographical scale. This code produces the 2 plots below:
Running a bit short on time this morning, but this should help you get started (and, can no doubt be improved by other R geo folks:
library(maps)
library(mapdata)
library(ggplot2)
library(marmap)
library(Grid2Polygons)
coast_map <- fortify(map("worldHires", fill = TRUE, plot = FALSE))
Peru.bath <- getNOAA.bathy (lon1 = -90, lon2 = -70, lat1 = -20,
lat2 = -2, resolution = 10)
peru_bathy_df <- Grid2Polygons(as.SpatialGridDataFrame(Peru.bath),
level=TRUE, pretty=TRUE)
peru_bathy_map <- fortify(peru_bathy_df)
gg <- ggplot()
gg <- gg + geom_map(data=peru_bathy_map, map=peru_bathy_map,
aes(map_id=id), color="black", fill="white")
gg <- gg + geom_map(data=coast_map, map=coast_map,
aes(x=long, y=lat, map_id=region),
fill="white", color="black")
gg <- gg + geom_map(data=data.frame(region="Peru"), map=coast_map,
aes(map_id=region), fill="steelblue")
gg <- gg + xlim(-90,-70) + ylim(-20,-2)
gg <- gg + coord_map()
gg <- gg + theme_bw()
gg
Obviously you want a better picture than that, but the basic idea is to get it converted into an object that ggplot can handle (so, a SpatialPolygonsDataFrame). Lots of good non-ggplot examples in the bathy and Grid2Polygons help.
NOTE: these take some time to convert/render and the bathy examples do show a way to do this without ggplot that will be much faster.

How to control the range of values in horizontal Stacked Bar Plot using R

Following is the code which gives a stacked bar chart with Timeline values from 0-300. But I want it to be from 1-24.
R code:
library(ggplot2)
dataFrame <- data.frame(sr=c(1:72),
hours=c(1:24),
mode=factor(c(""),levels = c("SecureMessaging","WebLogs","IVR")),
status=factor(c("Inactive"),levels = c("Active","Inactive")))
dataFrame$mode[1:24] <- "SecureMessaging"
dataFrame$mode[25:48] <- "WebLogs"
dataFrame$mode[49:72] <- "IVR"
dataFrame$status[2] <- "Active"
dataFrame$status[7] <- "Active"
dataFrame$status[24] <- "Active"
dataFrame$status[2+24] <- "Active"
dataFrame$status[12+24] <- "Active"
dataFrame$status[15+24] <- "Active"
dataFrame$status[3+48] <- "Active"
dataFrame$status[5+48] <- "Active"
dataFrame <- na.omit(dataFrame)
plot <- ggplot(data=dataFrame, aes(x=mode, y=hours, fill=status)) + geom_bar(stat="identity")
plot <- plot+coord_flip()
plot <- plot+ggtitle("Data Analytics")
plot <- plot+xlab("Mode")
plot <- plot+ylab("Time Line")
print(plot)
Technically not a direct answer as I'm suggesting an alternate implementation using geom_tile:
gg <- ggplot(data=dataFrame, aes(y=mode, x=factor(hours)))
gg <- gg + geom_tile(aes(fill=status))
gg <- gg + coord_equal()
gg <- gg + labs(x="Mode", y="Time Line", title="Data Analytics")
gg <- gg + theme_bw()
gg <- gg + theme(panel.grid=element_blank())
gg <- gg + theme(panel.border=element_blank())
gg <- gg + theme(legend.position="bottom")
gg
Bar chart with proper x-axis:
ggplot(dataFrame, aes(x=hours,y=status, fill=status))+ geom_bar(stat='identity')+ facet_grid(mode~.)
If you'd like to cut the result at 24 (in the range 0,300) then add before print(plot) the following line. The result is however not perfect yet, because the "inactive" bars stop before 24.
plot <- plot+ylim(0,24)
However, I am not sure if you wanted this. Probably you are not happy with the scaling from 0-300 that r applies and want to have it 0-24. In that case, try the following. "1" should replace "hours" in your plot function as indicated here:
plot <- ggplot(data=dataFrame, aes(x=mode, 1, fill=status)) + geom_bar(stat="identity")

Resources