Giter VIP home page Giter VIP logo

gsplot's Introduction

gsplot

The goal of this package is to simplify base-R plotting.

Package Status

status

This package is considered a 'support' package. For more information, see: https://owi.usgs.gov/R/packages.html#support

This package is still very much in development, so the API may change at any time.

Windows Linix Test Coverage
Build status travis Coverage Status

Reporting bugs

Please consider reporting bugs and asking questions on the Issues page: https://github.com/USGS-R/gsplot/issues

Follow @USGS_R on Twitter for updates on USGS R packages:

Twitter Follow

Package Support

The Water Mission Area of the USGS has supported the development and maintenance of the gsplot R-package. Resources are available primarily for maintenance. Priorities on the development are determined by the gsplot development team.

USGS

Installation

Currently only available via github. Easiest way to install is to use the devtools package:

devtools::install_github("USGS-R/gsplot")

Overview

The goal of this package is to simplify plotting in R. This includes improving the basic workflow and using defaults that tend to adhear to USGS style guidelines. Extra features and functions are included that are not available in base for common USGS elements (error bars, callouts, reverse y axes, etc.). This is intended to make the plotting code more concise and easier to interpret for the sake of reproducibility.

Feature Description
Piping and plots as objects Easily add features to your plot.
Automatic legend For each plot feature, a corresponding legend name can be specified. Eliminates the need to duplicate par arguments.
Automatic limits Automatically regenerate limits of plot when new features are added.
Error bars Apply error bars to points by specifying the upper and lower offsets.
Callouts Add a line and label in one call.
Axes reversal Reverse the axis by specifying one argument to axis().
Embedded functions Add extra plot features within a points call (no duplication of x/y values)
Change rendering order Manipulate what order plot features are rendered by specifying the argument where
Compatibility with base Can start a plot using gsplot, and add base R features afterwards.

Piping and plot objects

With the magrittr pipe (%>%) and the gsplot object, you can easily add features to your plot without needing repeat code.

# base:
plot(1:3, 2:4)
lines(1:5, 5:1)

# add blue points after the initial plot
plot(1:3, 2:4)
lines(1:5, 5:1)
points(4,3, col="blue")
myplot <- gsplot() %>% 
  points(1:3, 2:4) %>%
  lines(1:5, 5:1)

# add blue points after the initial plot
myplot <- myplot %>% points(4,3,col="blue")
myplot

Automatic legend

For each plot feature, the argument legend.name can be included in it's function call. Then, the legend() function is used to add the legend to your plot object. This creates a legend that inherits par specifications from the function calls, so that you do not have to also include it in the legend call.

# base:
plot(1:3, 1:3, col = "green", pch = 8) 
points(1:3, 3:1, col = "red", pch = 20)
lines(1:3, 1:3, lty = 2) 
rect(1.15,2,1.25,2.5, col = "blue", density = 15, angle = 45)
legend(x = "topright", legend = c("my points", "some other points", "some line", "box"),
       col = c("green", "red", "black", "blue"), 
       pch = c(8,20,NA,NA), 
       lty = c(NA,NA,2,NA), 
       density = c(NA,NA,NA,15), 
       angle = c(NA,NA,NA,45), 
       fill = c("white","white","white","blue"), 
       border = c(NA,NA,NA,"black"))
myplot <- gsplot() %>% 
  points(1:3, 1:3, col = "green", pch = 8, legend.name = "my points") %>% 
  points(1:3, 3:1, col = "red", pch = 20, legend.name = "some other points") %>% 
  lines(1:3, 1:3, lty = 2, legend.name = "some line") %>% 
  rect(1.15,2,1.25,2.5, col = "blue", density = 15, angle = 45, legend.name = "box") %>% 
  legend()
myplot

Automatic limits

gsplot automatically regenerates plot limits when new features are added, so that the user does not need to explicity do so.

# base:
plot(1:3,1:3)
points(5:6,5:6)

#cuts it off, so you need to re-plot with different limits
plot(1:3,1:3, ylim = c(1,6), xlim = c(1,6))
points(5:6,5:6)
limitsplot <- gsplot() %>% 
  points(1:3,1:3) %>% 
  points(5:6,5:6)
limitsplot

Error bars

Apply error bars to points by specifying the upper and lower offsets. Horizontal and vertical error bars can be completed in the same call to error_bar. Error bar values are incorporated into the automatic limit calculations.

# base:
plot(1:7, 1:7, ylim=c(0, 8)) 
arrows(x0 = 1:7, x1 = 1:7, 
       y0 = 1:7, y1 = 2:8, 
       angle = 90, length = 0.1)
arrows(x0 = 1:7, x1 = 1:7, 
       y0 = 1:7, y1 = 0:6, 
       angle = 90, length = 0.1)
errorbarplot <- gsplot() %>% 
  points(1:7, 1:7) %>% 
  error_bar(x = 1:7, y = 1:7, offset.up = 1, offset.down = 1)
errorbarplot

Callouts

Add a line and label in one call, rather than making a call to segments and text. This function automatically determines if the callout line will be outside of the plot limits, and changes the angle accordingly.

# base:
plot(1:3,1:3)
segments(x0 = 1:2, y0 = 1:2, x1 = c(1.25,2.25), y1 = c(1.25,2.25))
text(x = c(1.25,2.25), y = c(1.25,2.25), 
     labels = paste("point", 1:2), pos = 4)
segments(x0 = 3, y0 = 3, x1 = 2.75, y1 = 2.75)
text(x = 2.75, y = 2.75, labels = paste("point 3"), pos = 2)
calloutsplot <- gsplot() %>% 
  points(1:3,1:3) %>% 
  callouts(1:3, 1:3, labels = paste("point", 1:3))
calloutsplot

Axis reversal

If the axis needs to be reversed, you can add the argument reverse = TRUE to the function call. The order of your data does not need to change, and you can easily revert the axis flip.

# base:
data_y <- c(1,7,23,47,31)
plot(1:5, rev(data_y)) 
data_y <- c(1,7,23,47,31)
reverseplot <- gsplot() %>% 
  points(1:5, data_y) %>% 
  axis(side = 2, reverse = TRUE)
reverseplot

Embedded functions

Add features that apply to points within the points call, so that it inherits those values. Reduces the amount of code because you are not repeating the points values.

# base:
plot(1:5, 1:5) 
arrows(x0 = 1:5, x1 = 1:5, 
       y0 = 1:5, y1 = 2:6, 
       angle = 90, length = 0.1)
arrows(x0 = 1:5, x1 = 1:5, 
       y0 = 1:5, y1 = 0.5:4.5, 
       angle = 90, length = 0.1)
segments(x0 = 1:5, y0 = 1:5, x1 = 1.25:5.25, y1 = 1.25:5.25)
text(x = 1.25:5.25, y = 1.25:5.25, 
     labels = paste("pt", 1:5), pos = 4)
embedplot <- gsplot() %>% 
  points(1:5, 1:5, 
         error_bar(offset.up = 1, offset.down = 0.5),
         callouts(labels = paste("pt", 1:5))) 
embedplot

Change rendering order

For each plot feature that is added (points, lines, callouts, etc), you can specify if it should render in it's current position (after everything above it) or whether it should go before everything else. Simply add the argument where = 'first' or leave the default where = "last".

renderorderplot <- gsplot() %>% 
  points(1:5, 1:5, col = "blue", legend.name = "data pts") %>% 
  callouts(2,2, labels = "my note") %>% 
  legend(location = "topleft", legend_offset=0.5)
renderorderplot

Say we have the plot above, but would like to add two red points.

renderorderplot_add <- renderorderplot %>% 
  points(c(2.5,3), c(2,3), pch = 18, cex = 3, legend.name = "additional pts") 
renderorderplot_add

Easy to do with gsplot, but now the two red points are covering up features in the original plot. We can easily change this by using the where argument when adding to the plot. Specifying where will also update the order of the legend.

renderorderplot_order <- renderorderplot %>% 
  points(c(2.5,3), c(2,3), pch = 18, cex = 3, legend.name = "additional pts", where = "first") 
renderorderplot_order

Compatibility with base plotting

If you need to use a feature that gsplot has yet to implement, you can always start with gsplot and add on using base R. The reverse is (starting with base and then using gsplot) is not supported.

date_vector <- seq(as.Date("2010-10-01"), as.Date("2011-09-30"), by="months")
gs <- gsplot() %>% 
  points(date_vector, 1:12)
gs

points(as.Date("2011-01-15"),2.5, col="blue", pch=20)

Improved workflow examples

demoPlot <- gsplot() %>%
  points(y=c(3,1,2), x=1:3, xlim=c(0,NA),ylim=c(0,NA),
         col="blue", pch=18, legend.name="Points", xlab="Index", 
         error_bar(offset.up = c(0.5,0.25,1), offset.down = 0.1,
                   offset.left=0.2, offset.right=0.2, col="red", lwd=2)) %>%
  lines(c(3,4,3), c(2,4,6), legend.name="Lines", ylab=expression(paste("Data [ft"^"3","/s]"))) %>%
  abline(b=1, a=0, legend.name="1:1") %>%
  axis(side=c(3,4), labels=FALSE) %>%
  legend(location="topleft",title="Awesome!") %>%
  grid() %>%
  callouts(x=1, y=2.8, lwd=2, angle=250, labels="Weird data") %>%
  title("Graphing Fun")
demoPlot

gs <- gsplot(mgp=c(1.4,0.8,0)) %>%
  points(y=c(3,1,2,4,5), x=c(1:3,8,80), 
         col="blue", pch=18, legend.name="Points", tcl=-0.38) %>%
  lines(c(3,4,3), c(2,4,6), legend.name="Lines", 
        ylab="logged y axis", xlab="logged x axis", log='xy') %>%
  callouts(x=8, y=4, lwd=2, angle=45, labels="Not sure about this one") %>%
  title("logged axes") %>%
  axis(side=c(3,4), labels=FALSE, n.minor=4) %>%
  axis(side=c(1,2), n.minor=4)
gs

usrDef <- gsplot(mar=c(4,4,4,4), xaxs='r', yaxs='r') %>% 
     points(x=1, y=2, side=c(3,2), legend.name="Points 1", cex=3, xlab='cat') %>% 
     points(x=3, y=4, side=c(1,4), legend.name="Points 2", pch=5, col="red", ylab=expression(paste("Discharge in ",ft^3/s))) %>% 
     lines(x=c(3,4,3), y=c(2,4,6), legend.name="Lines 1", lty=5, col="orange") %>%
     lines(x=c(1,2,5), y=c(1,8,5), legend.name="Lines 2", lwd=3, ylab='Science!', xlab='dogs') %>%  
     legend(x=1.5,y=4)
usrDef

Multiple plots in one figure

What if you wanted to see if there was any relationship between the pH and water temperature? Consider the following three graphs: pH vs water temperature, pH timeseries, water temperature timeseries. To view these three plots at one time, use layout to "append" the three different plots.

MaumeeDV <- MaumeeDV
site <- '04193490'

Maumee_1 <- MaumeeDV[MaumeeDV$site_no == site,]

plot1 <- gsplot() %>% 
  points(Maumee_1$Wtemp, Maumee_1$pH_Median, col="black", pch=20)%>%
  title(main=paste("Site", site), xlab="Water Temperature (deg C)", ylab="pH")
plot2 <- gsplot() %>% 
  lines(Maumee_1$Date, Maumee_1$pH_Median, col="seagreen")%>%
  title(main="", xlab="time", ylab="pH")
plot3 <- gsplot() %>% 
  lines(Maumee_1$Date, Maumee_1$Wtemp, col="orangered")%>%
  title(main="", xlab="time", ylab="Water Temperature (deg C)")

layout(matrix(c(1,2,3), byrow=TRUE, nrow=3))
plot1
plot2
plot3

Inset

Base:

#Base:

set.seed(1)
x <- rnorm(100)  
y <- rnorm(100)  


par(mfcol=c(1,2)) #Let's look at base next to gsplot

plot(x, pch=18, col="red", main="Base defaults")
u <- par("usr")
mar.par <- par()$mar
p <- c(.75, .75, 1, 1) #xbot, ybot, xhigh, yhigh
v <- c(grconvertX(p[c(1,3)], "npc", "ndc"),
       grconvertY(p[c(2,4)], "npc", "ndc"))
user <- c(grconvertX(p[c(1,3)], "npc", "user"),
       grconvertY(p[c(2,4)], "npc", "user")) 
rect(user[1], user[3], user[2], user[4], col="white")
par(new=TRUE, mar=c(0,0,0,0), fig=v)
plot(y, axes=FALSE, xlab="",ylab="", pch=20, cex=0.5)

#gsplot:
gs_main <- gsplot() %>%
  points(x, pch=18) %>%
  title(main="gsplot defaults")
gs_inset <- gsplot() %>%
  points(y, axes=FALSE, xlab="", ylab="", pch=20, cex=0.5, col="black") %>%
  background_color(col="white") 

par(new=TRUE, fig=c(0.5,1,0,1), mar=mar.par) #step into gsplot
gs_main
par(new=TRUE, mar=c(0,0,0,0), fig=v+ c(0.5,0.5,0,0))
gs_inset

Config and Theme

A "config" file is used to set defaults for functions. You can see the default in the file "default.yaml" in the inst/extdata folder. To see the full path:

system.file("extdata", "default.yaml", package = "gsplot")

It is possible to change the global default.

TODO: MORE TEXT NEEDED!!!!!!

It is also possible to load a temporary config file into a single gsplot object:

line_scatter_config <- system.file("extdata", "lineScatter.yaml", package = "gsplot")

g1 <- gsplot(config.file = line_scatter_config) %>% 
  points(1:10, 1:10, pch=20, legend.name="first points") %>% 
  lines(4:1, 4:1, legend.name="first line") %>% 
  points(c(3,7,4), c(9,3,6), pch=20, col="black", legend.name="second points") %>% 
  legend()
g1

Finally, a theme can call a config file to load up defaults, but also makes particular calls as a default. There are a few themes pre-loaded into the gsplot package

gs_packers <- gsplot(theme = theme.packers) %>%
  points(1:10, 1:10)
gs_packers

Code of Conduct

We want to encourage a warm, welcoming, and safe environment for contributing to this project. See the code of conduct for more information.

Disclaimer

This software is in the public domain because it contains materials that originally came from the U.S. Geological Survey, an agency of the United States Department of Interior. For more information, see the official USGS copyright policy

Although this software program has been used by the U.S. Geological Survey (USGS), no warranty, expressed or implied, is made by the USGS or the U.S. Government as to the accuracy and functioning of the program and related program material nor shall the fact of distribution constitute any such warranty, and no responsibility is assumed by the USGS in connection therewith.

This software is provided "AS IS."

CC0

gsplot's People

Contributors

aappling-usgs avatar jesse-ross avatar jiwalker-usgs avatar ldecicco-usgs avatar mhines-usgs avatar thongsav-usgs avatar wdwatkins avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gsplot's Issues

example data

I'll put in some Maumee data unless someone else has favorite data

smart axes

for starters, we'll do this:

figure <- as.gsplot() %>%
   points(x, y, legend.name="First dater", side=4) %>%
   lines(x, y2, legend.name="Second dater", side=c(5,8), ylab="Stuff") 

Discussed, but didn't like:

figure <- as.gsplot() %>%
   points(x, y, name="First dater", axes=c("PT","Jordan")) %>%
   lines(x, y2, name="Second dater", axes="Laura") %>%
   axis("PT", side=2, offset=-1) %>%
   axis("Laura", side=4) %>%
   axis("Jordan", side=3)

Null legend

Need a way to specify that a data set (line, points, abline) doesn't show up in the legend. For example, maybe a user want's to put a 1:1 line and not have it show up in the legend. So:

gsNew <- gsplot(list())
gsNew <- points(gsNew, y=1, x=2, col="blue", pch=18, legend.name="Points")
gsNew <- lines(gsNew, c(3,4,3), c(2,4,6),legend.name="Lines")
gsNew <- abline(gsNew, v=3, lty=1,legend.name=NULL)
gsNew

Currently the default is "Plotted Line"...do we want that to be the default, and specifying NULL to drop that legend info? Or, default means no legend (for that data set)?

smart legend method

This will track inputs of appended objects and make them available for adding a legend to plot

basic functionality to support

Need to support soon

  • rending external devices (pdf,png)
  • smart limits
  • grids and ticks
  • data call-outs
  • log and linear formatting
  • error bars
  • points, lines
  • smart legends (inputs are tracked with the appended objects)
  • builder plot workflow (i.e., appending components before rendering)
  • power-user specificity (someone well-versed in base can fully customize)

Need to support eventually

  • rending external devices (svg)
  • multi-panel plots
  • insert/overlay
  • looks nice within R/Rstudio
  • variety of date formatting
  • boxplot, bar, fills, contour, etc
  • smarter legend

Nice to support

  • map rendering
  • USGS style compliance
  • censored data
  • interactive plot outputs
  • smartest legends

create gsplot class

decision to make S3 or S4, then implement.

Advantage of S3 is more flexibility (and sloppiness), easier debugging, faster coding. Can do
points.gsplot(x,y,...) to create the method for points(gsplot,x,y,...)

Advantage of S4 is more explicit code and rigidity in structure, and supports multiple arg dispatch.

Axis warning.

"object" is not a graphical parameter

get rid of axis warning.

Populate vignette

Try to show all functionality with the Maumee dataset (or whatever).

Figure out what's going on here:

#' gsNew <- gsplot(list())
#' gsNew <- lines(gsNew, c(1,2), c(2,5))
#' gsNew <- lines(gsNew, c(3,4,3), c(2,4,6), pch=6)
#' gsNew <- points(gsNew, c(8,4,1.2), c(2,4.7,6), side=c(3,2))
#' gsNew

vs

#' gs <- gsplot(list())
#' gsNew <- lines(gs, c(1,2), c(2,5))
#' gsNew <- lines(gsNew, c(3,4,3), c(2,4,6), pch=6)
#' gsNew <- points(gsNew, c(8,4,1.2), c(2,4.7,6), side=c(3,2))
#' gsNew

strip out or compartmentalize non-standard args for graphics overrides

such as:

points.gsplot <- function(object, legend.name=NULL, side=c(1,2), ...)
Warning messages:
1: "side" is not a graphical parameter

option to do this (or something):

points.gsplot <- function(object, legend.name=NULL, side=c(1,2), ...){

  object <- append(object, list(points = list(...), 
          legend = list(legend.name = legend.name), 
          axis = list(side = side))))
  return(gsplot(object))
}

User defined legend

#' usrDef <- gsplot(list()) %>% 
#'  points(x=1, y=2, side=c(3,2), legend.name="Example Points 1", pch=1, col="blue") %>% 
#'  points(x=3, y=4, side=c(1,4), legend.name="Example Points 2", pch=5, col="red") %>% 
#'  lines(x=c(3,4,3), y=c(2,4,6), legend.name="Example Lines 1", lty=5, col="orange") %>%
#'  lines(x=c(1,2,5), y=c(1,8,5), legend.name="Example Lines 2", lty=5, col="green") %>%  
#'  legend(x=3,y=4)
#' usrDef

implement `show(gsplot)` method

this is the render command for the contents of the gsplot object. Must be able to call from within a function and/or loop.

Print just axis

Current example errors:

gs <- gsplot(list())
gsNew <- axis(gs, side=1)
gsNew <- axis(gsNew, side=2)
gsNew

I just took off the last line to remove the error ...but I'm trying to figure out if we had that there for a reason. Like, would someone want to just specify a bunch of axes with no data:

gs <- gsplot(list()) %>%
   axis(side=1, xlim=c(0,10)) %>%
   axis(side=2, ylim=c(0,10)) %>%
   axis(side=3, xlim=c(10,100), log="y") %>%
   axis(side=4, ylim=c(1,2), ylab="Something?") %>%
   axis(side=5, xlim=c(0.0001,0.1), xlab="Alternative") %>%
   axis(side=6, ylim=c(1,10)) %>%
gs

?

calc_views sensitive to any items in gsplot with an "arguments" or "gs.config" attribute.

calc_views keys off points$arguments, points$gs.config, lines$arguments, and lines$gs.config.

I attempted to structure the legend data into legend$arguments and legend$gs.config. This resulted in calc_views throwing errors. Changing to legend$legend.arguments and legend$legend.gs.config got around the problem, but calc_views should probably be updated to avoid that sensitivity (by being more explicit in pulling point/line attributes).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.