Skip to content

Commit

Permalink
Added Natural Earth loading and plotting capabilities to spheRlab, to…
Browse files Browse the repository at this point in the history
… allow drawing nice standard coastlines, land/ocean polygons, and much more. Given this considerable functionality addition, the package version has been advanced to 1.1.0 with this commit.
  • Loading branch information
helgegoessling committed Jun 28, 2017
1 parent 4ef3213 commit fcf5561
Show file tree
Hide file tree
Showing 5 changed files with 341 additions and 6 deletions.
12 changes: 6 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Package: spheRlab
Type: Package
Title: Spherical Geometry, Unstructured Grids, and Plotting of Geoscientific Data
Version: 1.0.1
Date: 2016-12-08
Author: Helge Goessling
Title: Spherical Geometry, Analysis, and Plotting of Geoscientific Data on Arbitrary Grids
Version: 1.1.0
Date: 2017-06-28
Author: Helge Goessling, Lorenzo Zampieri
Maintainer: Helge Goessling <[email protected]>
Description: An R package with numerous functions related to spherical geometry. The package is intended in particular for analysis and plotting of geophysical unstructured-grid data, for example data produced by the Finite Element (or volumE) Sea-ice Ocean Model (FESOM).
Description: An R package for spherical geometry, analysis, and plotting of geoscientific data on arbitrary grids.
LazyData: true
Suggests: ncdf4
Suggests: ncdf4, rgdal
License: GPL-3
72 changes: 72 additions & 0 deletions R/sl.load.naturalearth.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
sl.load.naturalearth <-
function (what="all",resolution="medium",naturalearth.dir="~/naturalearthdata",force.download=FALSE,download.if.missing=TRUE,download.baseurl="http://www.naturalearthdata.com/http//www.naturalearthdata.com/download",read=TRUE,verbose=TRUE) {

if (length(what) == 1 && (what == "all" || what == "list" )) {
if (what == "all" && length(resolution) > 1) {stop("what='all' works only for one resolution at a time.")}
what.orig = what
if (resolution[1] == "coarse") {
what = c("coastline","geographic_lines","geography_marine_polys","geography_regions_elevation_points","geography_regions_points","geography_regions_polys","glaciated_areas","graticules_1","graticules_5","graticules_10","graticules_15","graticules_20","graticules_30","lakes","land","ocean","rivers_lake_centerlines","wgs84_bounding_box")
} else if (resolution[1] == "medium") {
what = c("antarctic_ice_shelves_lines","antarctic_ice_shelves_polys","coastline","geographic_lines","geography_marine_polys","geography_regions_elevation_points","geography_regions_points","geography_regions_polys","glaciated_areas","graticules_1","graticules_5","graticules_10","graticules_15","graticules_20","graticules_30","lakes_historic","lakes","land","ocean","playas","rivers_lake_centerlines_scale_rank","rivers_lake_centerlines","wgs84_bounding_box")
} else if (resolution[1] == "fine") {
what = c("antarctic_ice_shelves_lines","antarctic_ice_shelves_polys","bathymetry_A_10000","bathymetry_B_9000","bathymetry_C_8000","bathymetry_D_7000","bathymetry_E_6000","bathymetry_F_5000","bathymetry_G_4000","bathymetry_H_3000","bathymetry_I_2000","bathymetry_J_1000","bathymetry_K_200","bathymetry_L_0","coastline","geographic_lines","geography_marine_polys","geography_regions_elevation_points","geography_regions_points","geography_regions_polys","glaciated_areas","graticules_1","graticules_5","graticules_10","graticules_15","graticules_20","graticules_30","lakes_europe","lakes_historic","lakes_north_america","lakes_pluvial","lakes","land_ocean_label_points","land_ocean_seams","land_scale_rank","land","minor_islands_coastline","minor_islands_label_points","minor_islands","ocean_scale_rank","ocean","playas","reefs","rivers_europe","rivers_lake_centerlines_scale_rank","rivers_lake_centerlines","rivers_north_america","wgs84_bounding_box")
} else {stop("'resolution' must be one of 'coarse', 'medium', and 'fine'.")}
if (what.orig == "list") {
print(paste0("The following 'what' values are available for resolution='",resolution,"':"))
print(what)
return(NULL)
}
}

if (read) {require(rgdal)}

if (!dir.exists(naturalearth.dir)) {
if (verbose) {print(paste0("Creating directory ",naturalearth.dir," to store Natural Earth data."))}
dir.create(naturalearth.dir)
}

N = length(what)
resolution = rep(resolution,ceiling(N/length(resolution)))[1:N]

res.list = list()

for (i in 1:N) {

if (resolution[i] == "coarse") {resolution.str = "110m"}
else if (resolution[i] == "medium") {resolution.str = "50m"}
else if (resolution[i] == "fine") {resolution.str = "10m"}
else {stop("'resolution' must be one of 'coarse', 'medium', and 'fine'.")}
reswhat = paste0(resolution.str,"_",what[i])

fl = paste0(naturalearth.dir,"/ne_",reswhat,".shp")
if (.Platform$OS.type == "windows") {fl = paste(strsplit(fl,"/")[[1]],collapse="\\")}

if (!file.exists(fl) || force.download) {
if (download.if.missing || force.download) {
if (verbose) {print(paste0("Fetching Natural Earth data for ",fl," from the internet."))}
download.url = paste0(download.baseurl,"/",resolution.str,"/physical/ne_",reswhat,".zip")
destfile = paste0(naturalearth.dir,"/ne_",reswhat,".zip")
if (.Platform$OS.type == "windows") {destfile = paste(strsplit(destfile,"/")[[1]],collapse="\\")}
download.try = try(download.file(download.url,destfile))
if (class(download.try) != "try-error") {
unzip(destfile,exdir=naturalearth.dir)
} else {
print("Download failed.")
next
}
unlink(destfile)
} else {
print(paste0("Natural Earth shape file ",fl," does not exist locally. If it shall be fetched from the internet, set 'download.if.missing=TRUE' or 'force.download=TRUE'."))
next
}
}

if (read) {
res.list[[reswhat]] = readOGR(dsn=path.expand(naturalearth.dir),layer=paste0("ne_",reswhat))
}

}

return(res.list)

}
62 changes: 62 additions & 0 deletions R/sl.plot.naturalearth.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
sl.plot.naturalearth <-
function (plot.init.res=NULL,load.res=NULL,what="coastline",resolution="medium",lines.col="black",lwd=1,lty=1,fill.col="grey",fill.refine.boundary=TRUE,fill.refine.boundary.precision=1,polygon.borders=FALSE,points.text=TRUE,points.text.col="black",points.text.cex=1,points.text.adj=NULL,points.text.pos=NULL,points.text.offset=0.5,points.text.vfont=NULL,points.text.font=NULL,points.points=FALSE,points.pch=20,points.col="black",points.cex=1,ignore.visibility=FALSE,naturalearth.dir="~/naturalearthdata",verbose=TRUE) {

if (what[1] == "list") {
return(sl.load.naturalearth(what="list",resolution=resolution))
}

if (is.null(load.res)) {
if (verbose) {print("Argument 'load.res' not provided; using 'sl.load.naturalearth()' to load Natural Earth data.")}
load.res = sl.load.naturalearth(what=what,resolution=resolution,naturalearth.dir=naturalearth.dir,verbose=verbose)
}

N = length(load.res)
lines.col = rep(lines.col,ceiling(N/length(lines.col)))[1:N]
lwd = rep(lwd,ceiling(N/length(lwd)))[1:N]
lty = rep(lty,ceiling(N/length(lty)))[1:N]
fill.col = rep(fill.col,ceiling(N/length(fill.col)))[1:N]
fill.refine.boundary = rep(fill.refine.boundary,ceiling(N/length(fill.refine.boundary)))[1:N]
fill.refine.boundary.precision = rep(fill.refine.boundary.precision,ceiling(N/length(fill.refine.boundary.precision)))[1:N]
polygon.borders = rep(polygon.borders,ceiling(N/length(polygon.borders)))[1:N]
points.text = rep(points.text,ceiling(N/length(points.text)))[1:N]
points.text.col = rep(points.text.col,ceiling(N/length(points.text.col)))[1:N]
points.text.cex = rep(points.text.cex,ceiling(N/length(points.text.cex)))[1:N]
points.text.pos = rep(points.text.pos,ceiling(N/length(points.text.pos)))[1:N]
points.text.offset = rep(points.text.offset,ceiling(N/length(points.text.offset)))[1:N]
points.points = rep(points.points,ceiling(N/length(points.points)))[1:N]
points.pch = rep(points.pch,ceiling(N/length(points.pch)))[1:N]
points.col = rep(points.col,ceiling(N/length(points.col)))[1:N]
points.cex = rep(points.cex,ceiling(N/length(points.cex)))[1:N]
ignore.visibility = rep(ignore.visibility,ceiling(N/length(ignore.visibility)))[1:N]

for (k in 1:N) {

if (is(load.res[[k]])[2] == "SpatialLines") {
for (i in 1:length(load.res[[k]]@lines)) {
for (j in 1:length(load.res[[k]]@lines[[i]]@Lines)) {
sl.plot.lines(plot.init.res=plot.init.res,lon=load.res[[k]]@lines[[i]]@Lines[[j]]@coords[,1],lat=load.res[[k]]@lines[[i]]@Lines[[j]]@coords[,2],col=lines.col[k],lwd=lwd[k],lty=lty[k],ignore.visibility=ignore.visibility[k])
}
}
} else if (is(load.res[[k]])[2] == "SpatialPolygons") {
for (i in 1:length(load.res[[k]]@polygons)) {
for (j in 1:length(load.res[[k]]@polygons[[i]]@Polygons)) {
if (!is.na(fill.col[k])) {fill = TRUE} else {fill = FALSE}
sl.plot.polygon(plot.init.res=plot.init.res,lon=load.res[[k]]@polygons[[i]]@Polygons[[j]]@coords[,1],lat=load.res[[k]]@polygons[[i]]@Polygons[[j]]@coords[,2],fill=fill,col.fill=fill.col[k],border=polygon.borders[k],col.border=lines.col[k],border.lwd=lwd[k],border.lty=lty[k],ignore.visibility=ignore.visibility[k],remove.identical.neighbours=FALSE,refine.boundary=fill.refine.boundary[k],refine.boundary.precision=fill.refine.boundary.precision[k])
}
}
} else if (is(load.res[[k]])[2] == "SpatialPoints") {
for (i in 1:length(load.res[[k]]@data$name)) {
if (points.points[k]) {
sl.plot.points(plot.init.res=plot.init.res,lon=load.res[[k]]@data$long_x,lat=load.res[[k]]@data$lat_y,col=points.col[k],pch=points.pch[k],cex=points.cex[k],ignore.visibility=ignore.visibility[k])
}
if (points.text[k]) {
sl.plot.text(plot.init.res=plot.init.res,lon=load.res[[k]]@data$long_x,lat=load.res[[k]]@data$lat_y,labels=load.res[[k]]@data$name,col=points.text.col[k],cex=points.text.cex[k],ignore.visibility=ignore.visibility[k],adj=points.text.adj,pos=points.text.pos[k],offset=points.text.offset[k],vfont=points.text.vfont,font=points.text.font)
}
}
} else {
print("Unknown Natural Earth data type.")
}

}

}
73 changes: 73 additions & 0 deletions man/sl.load.naturalearth.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
\name{sl.load.naturalearth}
\alias{sl.load.naturalearth}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
Load Natural Earth Data
}
\description{
Load (read) and/or download Natural Earth data.
}
\usage{
sl.load.naturalearth(what="all", resolution="medium", naturalearth.dir="~/naturalearthdata", force.download=FALSE, download.if.missing=TRUE, download.baseurl="http://www.naturalearthdata.com/http//www.naturalearthdata.com/download", read=TRUE, verbose=TRUE)
}
%- maybe also 'usage' for other objects documented here.
\arguments{
\item{what}{
a character or character vector specifying which type of Natural Earth data
to load, e.g., 'coastline'. To list all possible values for the specified resolution, set what='list'. If what='all', all types available for the specified resolution are loaded.}
\item{resolution}{
a character or character vector sepcifying which resolution(s) to use. Possible values are 'coarse' (1:110Mio), 'medium' (1:50Mio; default), and 'fine' (1:10Mio).
}
\item{naturalearth.dir}{
a character specifying the local Natural Earth data directory. If data are downloaded from the internet, they will be save to this directory; if it does not yet exist, it will be created.
}
\item{force.download}{
a logical value indicating whether or not to download the data from the internet, even if it already exists locally, to replace the local file. This can be useful when updates are available. By default, force.download=FALSE .
}
\item{download.if.missing}{
a logical value indicating whether or not to download the data from the internet if it is missing locally. By default, download.if.missing=TRUE .
}
\item{download.baseurl}{
a character specifiying the internet base URL from which to download the data.
}
\item{read}{
a logical value indicating whether or not to load (read) tha data. If FALSE, data are only downloaded (if the corresponding arguments are set accordingly).
}
\item{verbose}{
a logical value indicating whether or not to print more information.
}
}
\details{
This function, together with \code{sl.plot.naturalearth()}, enables using the openly available and free-to-use Natural Earth data (http://www.naturalearthdata.com) - including coastlines, rivers, land and ocean polygons, and much more - in spheRlab. This function is also invoked from \code{sl.plot.naturalearth()} if needed, so it does not need to be used explicitly to plot Natural Earth data.

If \code{read=TRUE}, the package rgdal is needed to read the shape file(s).
}
\value{
If \code{read=TRUE}, a named list with each element corresponding to one Natural Earth data set, with naming convention 'resolution_what'. List elements are return values of the rgdal function \code{readOGR()}.
}
\references{
http://www.naturalearthdata.com
}
\author{
Helge Goessling
}
\note{
%%
}

%% ~Make other sections like Warning with \section{Warning }{....} ~

\seealso{
\code{sl.plot.naturalearth}
}
\examples{
# load coastlines at coarse resolution:
load.res = sl.load.naturalearth(what="coastline",resolution="coarse")

# list all possible 'what' values for fine resolution:
sl.load.naturalearth(what="list",resolution="fine")
}
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
%\keyword{ ~kwd1 }
%\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
128 changes: 128 additions & 0 deletions man/sl.plot.naturalearth.Rd
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
\name{sl.plot.naturalearth}
\alias{sl.plot.naturalearth}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
Plot Natural Earth Data
}
\description{
Plot Natural Earth data.
}
\usage{
sl.plot.naturalearth(plot.init.res=NULL, load.res=NULL, what="coastline", resolution="medium", lines.col="black", lwd=1, lty=1, fill.col="grey", fill.refine.boundary=TRUE, fill.refine.boundary.precision=1, polygon.borders=FALSE, points.text=TRUE, points.text.col="black", points.text.cex=1, points.text.adj=NULL, points.text.pos=NULL, points.text.offset=0.5, points.text.vfont=NULL, points.text.font=NULL, points.points=FALSE, points.pch=20, points.col="black", points.cex=1, ignore.visibility=FALSE, naturalearth.dir="~/naturalearthdata", verbose=TRUE)
}
%- maybe also 'usage' for other objects documented here.
\arguments{
\item{plot.init.res}{
a spheRlab plot specifics list as returned by \code{sl.plot.init} (or a variant thereof).
}
\item{load.res}{
a list as returned by \code{sl.load.naturalearth}. If NULL (default), \code{sl.load.naturalearth} is invoked automatically to load the data specified by the arguments 'what' and 'resolution'.}
\item{what}{
a character or character vector specifying which type of Natural Earth data
to plot, e.g., 'coastline'. To list all possible values for the specified resolution, set what='list'. If 'what' contains more than one element, they are plotted in the order they are provided, that is, the last one will always be in the foreground. Ignored if load.res is not NULL.}
\item{resolution}{
a character or character vector sepcifying which resolution(s) to use. Possible values are 'coarse' (1:110Mio), 'medium' (1:50Mio; default), and 'fine' (1:10Mio). Ignored if load.res is not NULL.
}
\item{lines.col}{
a colour or vector of colours to be used for any lines.
}
\item{lwd}{
a scalar or numeric vector specifying the line width.
}
\item{lty}{
a line type or vector of line types.
}
\item{fill.col}{
a colour or vector of colours to be used for filling polygons.
}
\item{fill.refine.boundary}{
a logical value or vector of logical values indicating whether or not to refine truncated polygons along curved plot boundaries (in polar projection).
}
\item{fill.refine.boundary.precision}{
a scalar or numeric vector specifying the precision (in degrees) for the refinement of truncated polygons along curved plot boundaries (in polar projection).
}
\item{polygon.borders}{
a logical value or vector of logical values indicating whether or not to plot lines along polygon edges.
}
\item{points.text}{
a logical value or vector of logical values indicating whether names associated with point objects shall be plotted.
}
\item{points.text.col}{
a colour or vector of colours to be used for text.
}
\item{points.text.cex}{
a scalar or numeric vector specifying the size scaling factor for text.
}
\item{points.text.adj}{
a numeric vector of length 2 with values in [0, 1] specifying the x and y adjustment of text.
}
\item{points.text.pos}{
a position specifier or vector of position specifiers for the text. If specified this overrides any \code{adj} value given. Values of 1, 2, 3 and 4, respectively indicate positions below, to the left of, above and to the right of the specified coordinates.
}
\item{points.text.offset}{
a scalar or numeric vector. When \code{points.text.pos} is specified, this value / these values give(s) the offset of the text from the specified coordinate in fractions of a character width.
}
\item{points.text.vfont}{
NULL for the current font family, or a character vector of length 2 for Hershey vector fonts. The first element of the vector selects a typeface and the second element selects a style.
}
\item{points.text.font}{
If \code{vfont = NULL}, the font to be used, possibly a vector. Defaults to the values of the global graphical parameters in \code{par()}.
}
\item{points.points}{
a logical value or vector of logical values indicating whether symbols shall be plotted at the locations of point objects.
}
\item{points.pch}{
a point 'character' (or vector thereof).
}
\item{points.col}{
a point colour (or vector thereof).
}
\item{points.cex}{
a point size scaling factor (or vector thereof).
}
\item{ignore.visibility}{
a logical value indicating whether or not objects shall be attempted to be drawn even if they are invisible, that is, outside the plot domain.
}
\item{naturalearth.dir}{
a character specifying the local Natural Earth data directory. If data are downloaded from the internet, they will be save to this directory; if it does not yet exist, it will be created.
}
\item{verbose}{
a logical value indicating whether or not to print more information.
}
}
\details{
This function, together with \code{sl.load.naturalearth()}, enables using the openly available and free-to-use Natural Earth data (http://www.naturalearthdata.com) - including coastlines, rivers, land and ocean polygons, and much more - in spheRlab.

If needed, this function invokes \code{sl.plot.naturalearth()} to load (and possibly download from the internet) Natural Earth data before plotting. In this case, the package rgdal is needed to read the shape file(s).
}
\value{
%%
}
\references{
http://www.naturalearthdata.com
}
\author{
Helge Goessling
}
\note{
%%
}

%% ~Make other sections like Warning with \section{Warning }{....} ~

\seealso{
\code{sl.load.naturalearth}
}
\examples{
# plot coastlines at coarse resolution:
pir = sl.plot.init()
sl.plot.naturalearth(pir,what="coastline",resolution="coarse")
sl.plot.end(pir)

# list all possible 'what' values for fine resolution:
sl.plot.naturalearth(what="list",resolution="fine")
}
% Add one or more standard keywords, see file 'KEYWORDS' in the
% R documentation directory.
%\keyword{ ~kwd1 }
%\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line

0 comments on commit fcf5561

Please sign in to comment.