Jason Fisher blog
Early in my science career I believed that any good piece of software included a graphical user interface (GUI). That was many years ago, and during that time I delved deep into the art of Tcl/Tk programming; using the tcltk package to create GUI’s in R. Countless hours were spent struggling over the R-Tcl/Tk interface and educating myself on the best practices and principles for GUI design. After a few years of toil, I finally started feeling proficient with GUI construction. It was around this time that I also became aware of the importance of reproducible research; thanks to the many discussions on the topic within the R community. Rather quickly my GUI development ceased, and all of the GUI-based applications I relied so heavily on for my research (such as Excel, ArcGIS, and Illustrator) were no longer relevant. Scripting has become the essential ingredient for making my research reproducible, and I believe my work has benefited immensely from taking this approach.
More recently I’ve become a bit of a zealot about preaching the importance of reproducibility to my fellow scientists. These are career researchers in the earth sciences, typically with little to no programming experience—smart individuals on a strictly GUI-based diet. I’m disappointed to report that my efforts have resulted in very few converts. My colleagues have gone through a couple of R-training workshops, been made aware of countless online materials for learning to code, and are still having difficulties crossing over. The biggest complaint I hear is that the learning curve is just too steep. And I get it, learning your first programming language can be extremely difficult, especially when you’re trying to meet publication deadlines.
This may come as blasphemy to some, but perhaps the best way to reach out to these folks is through R-GUI applications (such as R Commander). Start them with the familiar and let these gateway applications slowly get them hooked on R. Reasoning such as this has spurred me to dust off one of my old R GUI’s, RSurvey, a cross-platform geographic information system (GIS) application. Perhaps not as feature rich as other GIS applications (such as QGIS), but completely written in R and fairly simple to use. The package repository is located on GitHub.
To install the stable version of RSurvey from CRAN, open an R session and type the following command
If you’re running into difficulties with package installation, see the package README file for possible solutions. To load the package and launch the main GUI, use the command
If any of the suggested packages are missing, you will be prompted to install them when it first starts up. The main GUI should look something like this
No manual currently exists for the RSurvey package; its absence is mainly attributed to the author’s laziness; but also from a sense that the software should reach a certain level of maturity before embarking on such an endeavor, thus avoiding endless document revisions. That said, please keep in mind that considerable effort was put into making the user interface easy enough to use without instruction.
In the remainder of this post, windows are shown for a typical RSurvey session that includes data import, data wrangling, and data visualization. This example session illustrates only a small fraction of the package’s functionality. You’ll need to explore the package on your own to discover its full potential. Any comments/guidance would be greatly appreciated, you can contact me via email. Bug reports and feature requests can be submitted on the GitHub Issues page.
And let’s not forget the R session information.
devtools::session_info() ## Session info ------------------------------------ ## setting value ## version R version 3.3.2 (2016-10-31) ## system x86_64, mingw32 ## ui Rgui ## language (EN) ## collate English_United States.1252 ## tz America/Los_Angeles ## date 2017-02-24 ## ## Packages ---------------------------------------- ## package * version date source ## devtools 1.12.0 2016-06-24 CRAN (R 3.3.2) ## digest 0.6.12 2017-01-27 CRAN (R 3.3.2) ## htmltools 0.3.5 2016-03-21 CRAN (R 3.3.2) ## htmlwidgets 0.8 2016-11-09 CRAN (R 3.3.2) ## httpuv 1.3.3 2015-08-04 CRAN (R 3.3.2) ## jsonlite 1.2 2016-12-31 CRAN (R 3.3.2) ## knitr 1.15.1 2016-11-22 CRAN (R 3.3.2) ## magrittr 1.5 2014-11-22 CRAN (R 3.3.2) ## memoise 1.0.0 2016-01-29 CRAN (R 3.3.2) ## mime 0.5 2016-07-07 CRAN (R 3.3.2) ## R6 2.2.0 2016-10-05 CRAN (R 3.3.2) ## Rcpp 0.12.9 2017-01-14 CRAN (R 3.3.2) ## rgl 0.97.0 2017-01-10 CRAN (R 3.3.2) ## RSurvey * 0.9.1 2017-02-24 CRAN (R 3.3.2) ## shiny 1.0.0 2017-01-12 CRAN (R 3.3.2) ## withr 1.0.2 2016-06-20 CRAN (R 3.3.2) ## XML 3.98-1.5 2016-11-10 CRAN (R 3.3.2) ## xtable 1.8-2 2016-02-05 CRAN (R 3.3.2)
The U.S. Geological Survey (USGS) recently published a report describing a groundwater-flow model of the Wood River Valley (WRV) aquifer system. What makes this report unique (at least in my opinion) was the authors’ desire to make their work as reproducible as possible under budgetary constraints. The collection of raw data, source code, and processing instructions used to build and analyze the model was placed in an non-general-use R package named wrv. The package repository can be found on the Gelogical Survey R Archive Network (GRAN). Commands for installing the package are as follows:
repos <- c("https://owi.usgs.gov/R", "https://cloud.r-project.org/") install.packages("wrv", repos = repos, dependencies = TRUE) # about 100 MB, so be patient
Report documentation was included in the wrv package as vignettes; these files are also available from the USGS Publications Warehouse. For a general overview of the project, I’ll recommend my useR! 2016 talk:
I’d like to introduce you to the Grid2Polygons function; an R function for converting sp spatial objects from class SpatialGridDataFrame to SpatialPolygonsDataFrame. The significance of this conversion is that spatial polygons can be transformed to a different projection or datum with the spTransform function in package rgdal. Postscript files created with spatial polygons are reduced in size and result in a much “cleaner” version of your image. Disadvantages of the conversion include long computational times and irreversible leveling, partitioning the range of z values. A general explanation of the algorithm is provided here; inspiration provided here.
See help documentation for argument descriptions:
The following examples highlight the functions usefulness:
Construct a simple spatial grid data frame.
z <- c(1.1, 1.5, 4.2, 4.1, 4.3, 4.7, 1.2, 1.4, 4.8, 4.8, NA, 4.1, 1.7, 4.2, 1.4, 4.8, 4.0, 4.4, 1.1, 1.3, 1.2, 4.8, 1.6, NA, 3.3, 2.9, NA, 4.1, 1.0, 4.0) m <- 5 n <- 6 x <- rep(0:n, m + 1) y <- rep(0:m, each = n + 1) xc <- c(rep(seq(0.5, n - 0.5, by = 1), m)) yc <- rep(rev(seq(0.5, m - 0.5, by = 1)), each = n) grd <- data.frame(z = z, xc = xc, yc = yc) sp::coordinates(grd) <- ~ xc + yc sp::gridded(grd) <- TRUE grd <- as(grd, "SpatialGridDataFrame")
Plot the grid using a gray scale to indicate values of z (fig. 1).
image(grd, col = gray.colors(30), axes = TRUE) grid(col = "black", lty = 1) points(x = x, y = y, pch = 16) text(cbind(xc, yc), labels = z) text(cbind(x = x + 0.1, y = rev(y + 0.1)), labels = 1:((m + 1) * (n + 1)), cex = 0.6)
Figure 1: Simple spatial grid data frame.
Convert the grid to spatial polygons and overlay in plot (fig. 2). Leveling is specified with cut locations at 1, 2, 3, 4, and 5, and z-values set equal to the midpoint between breakpoints. A “winding rule” is used to determine if a polygon ring is filled (island) or is a hole in another polygon.
at <- 1:ceiling(max(z, na.rm = TRUE)) plys <- Grid2Polygons(grd, level = TRUE, at = at) cols <- rainbow(length(plys), alpha = 0.3) sp::plot(plys, add = TRUE, col = cols) zz <- plys[] legend("top", legend = zz, fill = cols, bty = "n", xpd = TRUE, inset = c(0, -0.1), ncol = length(plys))
Figure 2: Simple gridded data represented with spatial polygons.
Apply the conversion function to the meuse data set, included in the sp package. The effect of leveling is shown in figure 3.
data(meuse.grid, package = "sp") sp::coordinates(meuse.grid) <- ~ x + y sp::gridded(meuse.grid) <- TRUE meuse.grid <- as(meuse.grid, "SpatialGridDataFrame") meuse.plys <- Grid2Polygons(meuse.grid, "dist", level = FALSE) op <- par(mfrow = c(1, 2), oma = rep(0, 4), mar = rep(0, 4)) sp::plot(meuse.plys, col = heat.colors(length(meuse.plys))) title("level = FALSE", line = -7) meuse.plys.lev <- Grid2Polygons(meuse.grid, "dist", level = TRUE) sp::plot(meuse.plys.lev, col = heat.colors(length(meuse.plys.lev))) title("level = TRUE", line = -7) par(op)