diff --git a/.Rbuildignore~ b/.Rbuildignore~ deleted file mode 100644 index 2f10473..0000000 --- a/.Rbuildignore~ +++ /dev/null @@ -1,10 +0,0 @@ -^check_package.R$ -.travis.yml -^.*\.Rproj$ -^\.Rproj\.user$ -create_data -_layouts -revdep -^cran-comments.md$ -^cran-comments\.md$ -^CRAN-SUBMISSION$ diff --git a/.gitignore b/.gitignore index e43b0f9..915b330 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +*~ + diff --git a/.gitignore~ b/.gitignore~ deleted file mode 100644 index bc34d43..0000000 --- a/.gitignore~ +++ /dev/null @@ -1,10 +0,0 @@ -plan.html -*~ -plan.pdf -.Rhistory -*swp -.Rproj.user -.Rapp.history -revdep -Rplots.pdf -docs diff --git a/R/AllClass.R~ b/R/AllClass.R~ deleted file mode 100644 index a54f173..0000000 --- a/R/AllClass.R~ +++ /dev/null @@ -1,57 +0,0 @@ -#' Base Class for plan Objects -#' @slot data A list containing variable contents. -#' @family classes provided by plan -#setClass("plan", representation(data="list"), prototype=list(data=list())) -setClass("plan", slots=c(data="list")) -setMethod("initialize", "plan", - function(.Object) { - .Object@data <- list() - .Object - }) - -#' Extract Something From a plan Object -#' -#' @description Extract something from a plan object, avoiding using the "slot" notation. -#' -#' @param x A [plan-class] object. -#' @param i The item to extract. -#' @param j Optional additional information on the `i` item. -#' @param ... Optional additional information (ignored). -setMethod(f="[[", - signature(x="plan", i="ANY", j="ANY"), - definition=function(x, i, j, ...) { - if (length(i) != 1L) - stop("length of 'i' must be 1") - if (i == "data") { - return(x@data) - } else { - return(x@data[[i]]) - } - }) - -#' @title Replace Parts of a plan Object -#' -#' @description Replace something within a plan object, avoiding using the "slot" notation. -#' -#' @param x A \code{plan} object, i.e. inheriting from \code{\link{plan-class}}. -#' @param i The item to replace. -#' @param j Optional additional information on the \code{i} item. -#' @param ... Optional additional information (ignored). -#' @param value The value to be placed into \code{x}, somewhere. -setMethod(f="[[<-", - signature(x="plan", i="ANY", j="ANY"), - function(x, i, j, ..., value) { # FIXME: use j for e.g. times - ## message("in base [[<-") - ## message("value: ", paste(value, collapse=" ")) - ## metadata must match exactly but data can be partially matched - if (length(i) != 1L) - stop("length of 'i' must be 1") - if (i %in% names(x@data)) { - x@data[[i]] <- value - return(x) - } else { - warning("there is no item named \"", i, "\" in this ", class(x), " object", call.=FALSE) - } - }) - - diff --git a/R/burndown.R~ b/R/burndown.R~ deleted file mode 100644 index 7b38dcf..0000000 --- a/R/burndown.R~ +++ /dev/null @@ -1,409 +0,0 @@ -#' Class to store burndown objects -#' @family things related to burndown data -setClass("burndown", contains="plan") - -setMethod(f="initialize", - signature="burndown", - definition=function(.Object) - { - return(.Object) - }) - - -#' Draw a burndown chart -#' -#' Plot a burndown chart. -#' -#' @param x A [burndown-class] object. -#' @param col list of colours for items, starting with the first key in the -#' file (which will be at the bottom of the chart). If not specified, the -#' [hcl()] scheme will be used, to generate colours that are -#' distinct, that show up reasonably well on a monitor. -#' @param draw.plan boolean, set to `TRUE` to draw the plan, as a -#' blue descending line with a horizontal intercept. -#' @param draw.regression boolean, set to `TRUE` to draw a red dashed -#' line indicating the overall progress, as determined by regression. -#' @param draw.lastupdate boolean, set to `TRUE` to draw the last update -#' (which otherwise requires a sharp eye). -#' @param t.stop a POSIX time, the maximum time for graph (defaults to deadline -#' if not given). -#' @param y.name character string, for labelling the vertical axis. -#' @param debug boolean, set to `TRUE` to monitor the work. -#' @param ... extra things handed down to plotting functions. -#' @author Dan Kelley -#' @family things related to burndown data -#' @references -#' \url{https://en.wikipedia.org/wiki/Burndown_chart} -#' @examples -#' library(plan) -#' data(burndown) -#' summary(burndown) -#' plot(burndown) -#' @aliases plot.burndown -#' @export -#' @importFrom stats lm -setMethod(f="plot", - signature=signature("burndown"), - definition=function(x, col=NULL, draw.plan=TRUE, - draw.regression=TRUE, - draw.lastupdate=FALSE, - t.stop="", - y.name="Remaining Effort", debug=FALSE, ...) - { - opar <- par(no.readonly = TRUE) - on.exit(opar) - num.items <- length(x[["tasks"]]$key) - num.progress <- length(x[["progress"]]$key) - if (is.null(col)) { - ##col <- heat.colors(num.items) - col <- hcl(h = 360*(1:num.items)/num.items, c=70,l=80) - } - if (debug) - cat("Progress:\n") - t <- x[["start"]] - effort.remaining <<- x[["tasks"]]$effort - e <- effort.remaining - if (debug) { - cat("TIME:");print(t);cat("\n") - cat("effort remaining:\n");print(effort.remaining);cat("\n") - cat(sprintf(" %5s\t%20s\t%15s\n","Key","Percent Complete","Time")) - } - num.progress <- length(x[["progress"]]$key) - for (i in 1:num.progress) { - if (debug) { - cat(sprintf(" %5s\t%20s ", x[["progress"]]$key[i], x[["progress"]]$progress[i])) - cat(format(x[["progress"]]$time[i])) - cat("\n") - } - t <- c(t, x[["progress"]]$time[i]) - k <- x[["progress"]]$key[i] - effort.remaining[k] <- x[["tasks"]]$effort[k] * (1 - x[["progress"]]$progress[i]/100) - if (debug) { - cat(paste("k=",k,"\n")) - cat("TIME:\n");print(x[["progress"]]$time[i]);cat("\n") - cat("effort remaining:\n");print(effort.remaining);cat("\n") - } - e <- c(e,effort.remaining) - } - e.matrix <- matrix(e,ncol=num.items,byrow=TRUE) - if (debug) - cat("BEFORE t.stop='", format(t.stop), "' (class ", paste(class(t.stop), collapse=","), ")\n", sep="") - time.max <- if (inherits(t.stop, "POSIXt")) { - t.stop - } else if (is.character(t.stop) && t.stop[1] != "") { - as.POSIXct(t.stop[1]) - } else { - x[["deadline"]][1] - } - if (debug) - cat("AFTER time.max='", format(time.max), "'\n", sep="") - time.range <- range(c(t[1], time.max)) - plot(time.range, range(c(0,sum(x[["tasks"]]$effort))),type='n', - xlab="", ylab=y.name, - xaxs="i") - xx <- c(t, rev(t)) - bottom <- rep(0,1+num.progress) - for (i in 1:num.items) { - y <- e.matrix[,i] + bottom - yy <- c(y, rev(bottom)) - bottom <- y - polygon(xx,yy,col=col[i]) - } - ## Indicate prediction (possibly with a regression line) - totalEffort <- c(); - for (i in 1:dim(e.matrix)[1]) - totalEffort <- c(totalEffort,sum(e.matrix[i,])) - effortAnomaly <- totalEffort - totalEffort[1] - tAnomaly <- t - t[1] - m <- lm(effortAnomaly ~ tAnomaly - 1) - slope <- m$coefficients[1][[1]] - intercept <- totalEffort[1] - slope * as.numeric(t[1]) - ##t.done <- floor(-intercept / slope) - if (draw.regression) - abline(a=intercept, b=slope, col=2,lwd=2,lty=2) - ##class(t.done) <- "POSIXct" - ##cat(paste("NOTE: predicted time of completion is", format(t.done))) - ## Indicate plan - if (draw.plan) { - lines(c(t[1],x[["deadline"]]),c(sum(x[["tasks"]]$effort),0),col=4,lwd=3) - abline(h=0,col=4,lwd=3) - } - final.effort <- sum(e.matrix[dim(e.matrix)[1],]) - if (draw.lastupdate) { - points(t[length(t)],final.effort,col="yellow",cex=2.5,pch=19) - points(t[length(t)],final.effort,col="blue",cex=2.6) - ##lines(c(t[length(t)],time.max),rep(final.effort,2),col=gray(0.9),lwd=3)#,col="red",lwd=3) - } - ## legend - cex <- if (length(x[["tasks"]]$description) < 5) 1 else 4/5 - legend("topright",legend=rev(x[["tasks"]]$description),fill=rev(col),cex=cex,y.intersp=1.5*cex) - mtext(paste(paste(format(time.range), collapse=" to "), - attr(x[["ts"]]$time[1], "tzone")), - side=3, cex=cex, adj=0) - invisible(x) - }) - - -#' Scan burndown data file -#' -#' Read a data file containing burndown information. -#' -#' Reads a burndown dataset. -#' -#' A strict format is required, in which the following items must be present, -#' in the stated order, and with nothing else in the file. An example is given -#' after the description. -#' -#' * Line 1: contains two comma-separated items: the string `Start`, -#' and a time expressed in ISO 8601 format (`YYYY-MM-DD` or -#' `YYY-MM-DD hh:mm:ss`). This line indicates the start of the project. -#' -#' * Line 2: as Line 1, but the string is to be `Start`, and the line -#' indicates the deadline for the project. -#' -#' * Line 3: a header line for a "tasks" list, comprising the following -#' three words separated by commas: `Key`, `Description`, and -#' `Effort`. -#' -#' * Lines 4 to N: data lines, each containing three items: a numeric index -#' "Key" for the task, a short "Description" of the task, and the estimated -#' "Effort" for this task, expressed as a number. The keys must be distinct, -#' and they must match the keys in the progress table (see below). The -#' description should be short enough to give a reasonable-size legend as -#' created by [plot,burndown-method()]. The effort may be expressed in any -#' convenient unit, e.g. the number of hours or days for the task, or as a -#' percentage of the overall task. -#' -#' * Line N+1: a header line for the "Progress" list, comprising the -#' following four words separated by commas: `Key`, `Done`, and -#' `Time`. -#' -#' * Line N+2 to end: data lines holding Progress items. Each "Key" must -#' match a key in the task list. The "Done" column holds the percentage of the -#' task that has been completed. The "Time" is in ISO 8601 format, as described -#' above. -#' -#' @section Sample data file: -#' \preformatted{ -#' Start, 2006-04-08 12:00:00 -#' Deadline, 2006-04-11 20:00:00 -#' Key, Description, Effort -#' 1, Code read.burndown(), 4 -#' 2, Code summary.burndown(), 1 -#' 3, Code plot.burndown(), 5 -#' 4, Create R package, 2 -#' 5, Write documentation, 2 -#' 6, Set up website, 1 -#' Key, Done, Time -#' 1, 5, 2006-04-08 13:00:00 -#' 2, 5, 2006-04-08 13:30:00 -#' 1, 10, 2006-04-08 14:00:00 -#' 2, 50, 2006-04-08 15:00:00 -#' 4, 5, 2006-04-08 19:30:00 -#' 5, 5, 2006-04-08 20:00:00 -#' 4, 100, 2006-04-08 21:16:00 -#' 1, 50, 2006-04-09 09:10:00 -#' 3, 5, 2006-04-09 09:41:00 -#' 3, 30, 2006-04-09 10:18:00 -#' 3, 80, 2006-04-09 11:00:00 -#' 2, 60, 2006-04-09 12:00:00 -#' 2, 100, 2006-04-09 12:10:00 -#' 1, 70, 2006-04-09 12:30:00 -#' 5, 30, 2006-04-09 13:50:00 -#' 5, 90, 2006-04-09 14:20:00 -#' 5, 100, 2006-04-09 14:30:00 -#' 1, 100, 2006-04-09 14:35:00 -#' 3, 100, 2006-04-09 14:40:00 -#' 6, 100, 2006-04-09 16:00:00 -#' } -#' -#' @param file a connection or a character string giving the name of the file -#' to load. -#' @param debug boolean, set to `TRUE` to print debugging information. -#' @return A burndown object. -#' @author Dan Kelley -#' @family things related to burndown data -#' @examples -#' library(plan) -#' filename <- system.file("extdata", "burndown.dat", package="plan") -#' b <- read.burndown(filename) -#' summary(b) -#' plot(b) -#' @export -read.burndown <- function(file, debug=FALSE) -{ - if (is.character(file)) { - file <- file(file, "r") - on.exit(close(file)) - } - if (!inherits(file, "connection")) stop("argument `file' must be a character string or connection") - if (!isOpen(file)) { - open(file, "r") - on.exit(close(file)) - } - quiet <- !debug - ## Start, ISdate - tokens <- trimws(scan(file, what='char', sep=",", nlines=1,quiet=quiet,blank.lines.skip=TRUE)) - name <- tokens[1] - if (name != "Start") stop("First line of file must be 'Start' followed by an ISO date but got '", - paste(tokens, collapse=",")) - start <- as.POSIXct(tokens[2]) - ## Deadline, ISOdate - tokens <- trimws(scan(file,what='char',sep=",",nlines=1,quiet=quiet,blank.lines.skip=TRUE)) - name <- tokens[1] - deadline <- as.POSIXct(tokens[2]) - if (name != "Deadline") stop("Second line of file must be 'Deadline' followed by an ISO date, but got '", - paste(tokens, collapse=","), "'") - ## Header - tokens <- trimws(scan(file,what='char',sep=',',nlines=1,quiet=quiet,blank.lines.skip=TRUE)) - check.tokens(tokens, c("Key", "Description", "Effort")) - task.key <- c() - task.description <- c() - task.effort <- c() - while (TRUE) { # TASK: key description effort - tokens <- trimws(scan(file, what=character(0),nlines=1,blank.lines.skip=FALSE,quiet=quiet,sep=",")) - if (tokens[1] == "Key") - break - if (3 == length(tokens)) { - task.key <- c(task.key, as.numeric(tokens[1])) - task.description <- c(task.description, tokens[2]) - task.effort <- c(task.effort, as.numeric(tokens[3])) - } - } - ## "Key, Progress, Time", followed by data lines - check.tokens(tokens, c("Key", "Done", "Time")) - progress.key <- progress.done <- progress.time <- NULL - while (TRUE) { - tokens <- trimws(scan(file, what=character(0),nlines=1,blank.lines.skip=FALSE,quiet=quiet, sep=",")) - if (is.na(tokens[1])) - break - key <- as.numeric(tokens[1]) - if (!(key %in% task.key)) { - msg <- paste("Progress key",key,"not in the list of task keys\n\tOffending line in data file follows\n\t",tokens[1]," ",tokens[2], " ", tokens[3]) - stop(msg) - } - done <- as.numeric(tokens[2]) - time <- as.POSIXct(tokens[3]) - progress.key <- c(progress.key, key) - progress.done <- c(progress.done, done) - progress.time <- c(progress.time, time) - } - # class(progress.time) <- "POSIXct" - progress.time <- as.POSIXct(progress.time, origin=as.POSIXct("1970-01-01 00:00.00", tz="UTC")) - ## BUG: should ensure item is in task - o <- order(progress.time) - progress.key <- progress.key[o] - progress.done <- progress.done[o] - progress.time <- progress.time[o] - rval <- new("burndown") - rval@data <- list(start=start, - deadline=deadline, - tasks=list(key=task.key, - description=task.description, - effort=task.effort), - progress=list(key=progress.key, - progress=progress.done, - time=progress.time)) - rval -} - - -#' Summarize a burndown object -#' -#' Print a summary of a burndown dataset. -#' -#' @param object A [burndown-class] object. -#' @param ... ignored. -#' @author Dan Kelley -#' @family things related to burndown data -#' @examples -#' library(plan) -#' data(burndown) -#' summary(burndown) -setMethod(f="summary", - signature="burndown", - definition=function(object, ...) { - cat(paste("Start, ", format(object[["start"]])), "\n") - cat(paste("Deadline,", format(object[["deadline"]])), "\n") - num.tasks <- length(object[["tasks"]]$key) - dspace <- max(nchar(object[["tasks"]]$description)) - cat(sprintf("Key, Description,%s %5s\n", - paste(rep(" ", dspace - nchar("Description")), collapse=""), - "Effort")) - for (i in 1:num.tasks) { - space <- paste(rep(" ", dspace - nchar(object[["tasks"]]$description[i])), collapse="") - cat(sprintf("%3s, %s,%s %s\n", - object[["tasks"]]$key[i], object[["tasks"]]$description[i], space, object[["tasks"]]$effort[i])) - } - cat("Key, Done, Time\n") - num.progress <- length(object[["progress"]]$key) - for (i in 1:num.progress) { - cat(sprintf("%3s, %5s, ", object[["progress"]]$key[i], object[["progress"]]$progress[i])) - cat(format((object[["progress"]]$time[i]))) - cat("\n") - } - invisible() - }) - -#' Create a burndown object -#' -#' Create a [burndown-class] object from the given data. -#' -#' Creates a [burndown-class] object from the given data; progress may be given in percentage or absolute values. -#' -#' @param start Start date -#' @param deadline Deadline (end date) -#' @param tasks Data frame containing the task IDs (may be alphanumeric), their description and effort -#' @param progress Data frame containing the progress values with task ID, timestamp and work done (either in percentage or absolute) -#' @param progressInPercent boolean; if set to `FALSE`, progress values are treated like absolute values and -#' converted to percentages -#' @return A burndown object. -#' @author Frank Schmitt -#' @family things related to burndown data -#' @examples -#' library(plan) -#' # same data as in tests/burndown.dat -#' start <- as.POSIXct(strptime("2006-04-08 12:00:00", "%Y-%m-%d %H:%M:%S")) -#' deadline <- as.POSIXct(strptime("2006-04-11 20:00:00", "%Y-%m-%d %H:%M:%S")) -#' tasks <- data.frame(key = c(1, 2, 3, 4, 5, 6), -#' description = c("code read.burndown()", "code summary.burndown()", -#' "code plot.burndown()", "create R package", -#' "write documentation", "set up website"), -#' effort = c(4, 1, 5, 2, 2, 1), -#' stringsAsFactors = FALSE) -#' progress <- data.frame(key = c(1, 2, 1, 2, 4, 5, 4, 1, 3, 3, 3, 2, 2, 1, 5, 5, 5, 1, 3, 6), -#' progress = c(5, 5, 10, 50, 5, 5, 100, 50, 5, 30, 80, 60, -#' 100, 70, 30, 90, 100, 100, 100, 100), -#' time = structure(c(1144494000, 1144495800, 1144497600, 1144501200, -#' 1144517400, 1144519200, 1144523760, 1144566600, -#' 1144568460, 1144570680, 1144573200, 1144576800, -#' 1144577400, 1144578600, 1144583400, 1144585200, -#' 1144585800, 1144586100, 1144586400, 1144591200), -#' class = "POSIXct"), -#' stringsAsFactors = FALSE -#' ) -#' b <- as.burndown(start, deadline, tasks, progress, progressInPercent = TRUE) -#' summary(b) -#' plot(b) -#' @export -as.burndown <- function(start, deadline, tasks, progress, progressInPercent=FALSE) -{ - progress_percentage <- progress - # if progress was given in absolute values: calculate percentage - if (!progressInPercent) { - progress_percentage$progress <- mapply( - function(itskey, itsprogress) { - itsprogress / subset(tasks, get("key", tasks) == itskey)$effort * 100 - }, - progress$key, - progress$progress - ) - } - rval <- new("burndown") - rval@data <- list( - start = start, - deadline = deadline, - tasks = tasks, - progress = progress_percentage) - rval -} diff --git a/R/gantt.R~ b/R/gantt.R~ deleted file mode 100644 index 96180c7..0000000 --- a/R/gantt.R~ +++ /dev/null @@ -1,677 +0,0 @@ -#' Class to store gantt objects -#' -#' These objects may be created with [as.gantt()] or [read.gantt()]. -#' @family things related to gantt data -#' @importFrom methods new -setClass("gantt", contains="plan") - -setMethod(f="initialize", - signature="gantt", - definition=function(.Object) { - .Object@data <- list(description=NULL, start=NULL, end=NULL, done=NULL, neededBy=NULL, key=NULL) - return(.Object) - }) - - -#' Draw a Gantt diagram -#' -#' Plot a gantt chart that shows the time allocated to a set of tasks, optionally -#' also with an indication of discrete events that occur as instants in time. -#' -#' Time is indicated along the x axis, and tasks are stacked along the y -#' axis, akin to progress bars. Colour-coding can be used to indicate the degree of -#' completion of each task. These codes can be set individually for individual -#' tasks. Progress bars can have arrows (on either end), suggesting tasks -#' with flexible start/end dates or overdue tasks. Vertical lines may -#' be drawn for discreet events. See \dQuote{Examples} for a few of the -#' possibilities. -#' -#' @param x A [gantt-class] object. -#' @param xlim optional range of time axis; if not provided, the range of times -#' in `x` will be used. -#' @param time.format format for dates on time axis; defaults to 3-letter -#' month. -#' @param time.labels.by suggested label increment on time axis, e.g. -#' `time.labels.by="2 months"` to get a two-month interval. If not -#' supplied, the axis will be generated automatically. -#' @param time.lines.by suggested interval between vertical grid lines on the -#' plot, e.g. `time.lines.by="1 week"` for weekly. If not supplied, the -#' grid will be generated automatically. -#' @param event.time vector of event times, e.g. conferences, whose time cannot -#' be altered. -#' @param event.label vector of character strings holding event names. -#' @param event.side side for event labels. -#' @param col.connector colour of (optional) connectors between items. -#' @param col.done colour of work that has been done already. This may be a -#' vector of colours, one for each item in the gantt table. -#' @param col.notdone colour of work that has not been done yet. This may be a -#' vector of colours, one for each item in the gantt table. -#' @param col.eventLine colour of event lines; may be a vector. -#' @param col.event colour of event labels; may be a vector. -#' @param cex.event expansion factor for event labels; may be a vector. -#' @param lty.eventLine line type for event lines; may be a vector. -#' @param lwd.eventLine line width for event lines; may be a vector. -#' @param font.event font for event labels; may be a vector. -#' @param bg background colour for plot. -#' @param grid.col colour for grid. -#' @param grid.lty line type for grid. -#' @param ylabels A [list] with elements `col` for colour, -#' `cex` for character-expansion factor, `font` for font, and `justification` -#' for the placement in the margin (`0` means left-justified, and `1` -#' means right-justified. (NOTE: left-justification works poorly in RStudio, but -#' properly in other systems.) -#' It usually makes sense for the elements in `ylabels` to be vectors of the same -#' length as the topic list. However, shorter vectors are permitted, and they lengthened by -#' copying the default values at the end (see Example 6). -#' @param arrows A vector of strings, one for each topic, indicating the nature of -#' the arrows that may be drawn at the ends of task bars. The individual values -#' may be `"left"`, `"right"`, `"both"` or `"neither"`. -#' Set `arrows=NULL`, the default, to avoid such arrows. -#' @param main character string to be used as chart title. -#' @param line.main line where title occurs. If `NA`, then the -#' title is placed in a default location; otherwise, it is `line.main` -#' lines above the top of the plot. -#' @param cex.main numeric, font-size factor for title. -#' @param mgp setting for [par]`(mgp)`, within-axis spacing. The -#' default value tightens axis spacing. -#' @param maiAdd inches to add to the auto-computed margins at the bottom, -#' left, top, and right margins. The values may be negative (to tighten -#' margins) but the sum will be truncated to remain positive. -#' @param axes logical, `TRUE` to draw the x axis. (Setting to -#' `FALSE` permits detailed axis tweaking.) -#' @param debug logical value, `TRUE` to monitor the work. -#' @param ... extra things handed down. -#' @author Dan Kelley -#' @family things related to gantt data -#' @references Gantt diagrams are described on wikipedia -#' `https://en.wikipedia.org/wiki/Gantt_Chart`. -#' -#' @examples -#' library(plan) -#' data(gantt) -#' summary(gantt) -#' -#' # 1. Simple plot -#' plot(gantt) -#' -#' # 2. Plot with two events -#' event.label <- c("Proposal", "AGU") -#' event.time <- c("2008-01-28", "2008-12-10") -#' plot(gantt, event.label=event.label,event.time=event.time) -#' -#' # 3. Control x axis (months, say) -#' plot(gantt,labels=paste("M",1:6,sep="")) -#' -#' # 4. Control task colours -#' plot(gantt, -#' col.done=c("black", "red", rep("black", 10)), -#' col.notdone=c("lightgray", "pink", rep("lightgray", 10))) -#' -#' # 5. Control event colours (garish, to illustrate) -#' plot(gantt, event.time=event.time, event.label=event.label, -#' lwd.eventLine=1:2, lty.eventLine=1:2, -#' col.eventLine=c("pink", "lightblue"), -#' col.event=c("red", "blue"), font.event=1:2, cex.event=1:2) -#' -#' # 6. Top task is in bold font and red colour -#' plot(gantt,ylabels=list(col="red",font=2)) -#' -#' # 7. Demonstrate zero-time item (which becomes a heading) -#' gantt[["description"]][1] <- "Preliminaries" -#' gantt[["end"]][1] <- gantt[["start"]][1] -#' plot(gantt, ylabel=list(font=2, justification=0)) -#' -#' # 8. Arrows at task ends -#' plot(gantt, arrows=c("right","left","left","right")) -#' @aliases plot.gantt -#' @importFrom grDevices gray hcl -#' @importFrom graphics abline axis axis.POSIXct box grconvertX legend lines mtext par points polygon rect rug strheight strwidth text -#' @export -setMethod(f="plot", - signature=signature("gantt"), - definition=function (x, xlim, - time.format=NULL, time.labels.by, time.lines.by, - event.time=NULL, event.label=NULL, event.side=3, - col.connector="black", - col.done=gray(0.3), col.notdone=gray(0.9), - col.eventLine=gray(0.1), col.event=par("fg"), - cex.event=par("cex"), font.event=par("font"), - lty.eventLine=par("lty"), lwd.eventLine=par("lwd"), - bg=par("bg"), grid.col="lightgray", grid.lty="dotted", - ylabels=list(col=1, cex=1, font=1, justification=1), - arrows=NULL, - main="", line.main=NA, cex.main=par("cex"), - mgp=c(2, 0.7, 0), maiAdd=rep(0, 4), - axes=TRUE, - debug=FALSE, ...) -{ - if (!inherits(x, "gantt")) stop("method is only for gantt objects") - opar <- par(no.readonly = TRUE) - half.height <- 0.33 - t0 <- as.POSIXct("1970-01-01 00:00:00") - ## Lengthen anything that can be a vector - ndescriptions <- length(x[["description"]]) - if (length(arrows) == 0L) - arrows <- rep("none", ndescriptions) - if (length(arrows) < ndescriptions) - arrows <- c(arrows, rep("none", ndescriptions-length(arrows))) - ## Twiddle the labels, including defaulting things that a user - ## need not define. - if (!("col" %in% names(ylabels))) - ylabels$col <- 1 - if (!("cex" %in% names(ylabels))) - ylabels$cex <- 1 - if (!("font" %in% names(ylabels))) - ylabels$font <- 1 - if (!("justification" %in% names(ylabels))) - ylabels$justification <- 1 - for (i in seq_along(ylabels)) { - len <- length(ylabels[[i]]) - if (len < ndescriptions) { - ylabels[[i]] <- c(ylabels[[i]], rep(1, ndescriptions-len)) - } - } - if (any(!(ylabels$justification %in% c(0, 1)))) - stop("ylabels$justification entries must be 0 or 1") - if (length(col.done) < ndescriptions) - col.done <- rep(col.done, length.out=ndescriptions) - if (length(col.notdone) < ndescriptions) - col.notdone <- rep(col.notdone, length.out=ndescriptions) - nevent <- length(event.time) - if (length(col.eventLine) < nevent) - col.eventLine <- rep(col.eventLine, length.out=nevent) - if (length(col.event) < nevent) - col.event <- rep(col.event, length.out=nevent) - if (length(cex.event) < nevent) - cex.event <- rep(cex.event, length.out=nevent) - if (length(font.event) < nevent) - font.event <- rep(font.event, length.out=nevent) - if (length(lty.eventLine) < nevent) - lty.eventLine <- rep(lty.eventLine, length.out=nevent) - if (length(lwd.eventLine) < nevent) - lwd.eventLine <- rep(lwd.eventLine, length.out=nevent) - - charheight <- strheight("M", units = "inches") - maxwidth <- max(strwidth(x[["description"]], units = "inches")) * 1.1 - - ## Get around some problems with autoscaling of POSIXt values - r <- if (missing(xlim)) range(x[["start"]], x[["end"]], na.rm=TRUE) else xlim - if (debug) {cat("range: ", as.character(r[1]), "to", as.character(r[2]), "\n")} - s <- as.numeric(difftime(r[2], r[1], units="days")) - r <- as.POSIXlt(r) - subTics <- NULL - if (s > 100) { - if (is.null(time.format)) time.format <- "%b %Y" # month/year - r[2] <- r[2] + 86400 - r[1:2]$hour <- r[1:2]$min <- r[1:2]$sec <- 0 - if (debug){cat("range: ", as.character(r[1]), "to", as.character(r[2]), "\n")} - ## monthly ticks - lhs <- as.POSIXlt(r[1]) - lhs$mon <- 0 - lhs$mday <- 1 - rhs <- as.POSIXlt(r[2]) - rhs$mon <- 11 - rhs$mday <- 31 - subTics <- seq(lhs, rhs, by="month") - } else { - if (s > 10) { - if (is.null(time.format)) time.format <- "%d/%b" # day/month - r[2] <- r[2] + 86400 - r[1:2]$hour <- r[1:2]$min <- r[1:2]$sec <- 0 - if(debug){cat("range: ", as.character(r[1]), "to", as.character(r[2]), "\n")} - } else { - if (s > 1) { - if (is.null(time.format)) time.format <- "%d/%b" # day/month - r[2] <- r[2] + 86400 - r[1:2]$hour <- r[1:2]$min <- r[1:2]$sec <- 0 - if(debug){cat("range: ", as.character(r[1]), "to", as.character(r[2]), "\n")} - } else { - if (is.null(time.format)) time.format <- "%d/%b" # day/month - } - } - } - bottom.margin <- 0.5 - if (is.na(line.main)) - line.main <- if (nevent==0) 0.5 else 0.5 + cex.event[1] - topSpace <- charheight * (2 + line.main) - mai <- maiAdd + c(bottom.margin, maxwidth, topSpace, 0.25) - mai <- ifelse(mai < 0, 0, mai) - opar <- par(no.readonly = TRUE) - par(mgp=mgp, mai=mai, omi=c(0.1, 0.1, 0.1, 0.1), bg=bg) - plot(c(r[1], r[2]), c(1,2*ndescriptions), - ylim=c(0.5, ndescriptions + 0.5), - xaxs="i", yaxs="i", - bg=bg, - main="", xlab="", ylab="", xaxs="r", type="n", axes=FALSE) - xlim <- as.POSIXct(par("usr")[1:2] + t0) - box() - if (nchar(main)) { - mtext(main, side=3, line=line.main, cex=cex.main) - } - if (axes) { - if (missing(time.labels.by)) { - ##xaxp <- par("xaxp") - lines.at.0 <- axis.POSIXct(1, - at=pretty(r, 10), #seq(xaxp[1], xaxp[2], length.out=xaxp[3]) + t0, - format=time.format, cex.axis=par("cex.axis"), ...) - } else { - lines.at.0 <- axis.POSIXct(1, - at=as.POSIXct(seq.POSIXt(as.POSIXct(xlim[1]), as.POSIXct(xlim[2]), by=time.labels.by)), - format=time.format, cex.axis=par("cex.axis"), ...) - } - } - if (axes) { - if (!is.null(subTics)) - rug(subTics, quiet=TRUE) - if (missing(time.lines.by)) { - abline(v=lines.at.0, col = grid.col, lty=grid.lty) - } else { - abline(v = seq.POSIXt(as.POSIXct(xlim[1]), as.POSIXct(xlim[2]), by=time.lines.by), col = grid.col, lty=grid.lty) - } - } - topdown <- seq(ndescriptions, 1) - font <- rep(1, ndescriptions) - font[2] <- 2 - axis(2, at=topdown, labels=rep("", ndescriptions), las=2, tick=FALSE, cex.axis=par("cex.axis")) - par(xpd=NA) - for (i in 1:ndescriptions) { - if (ylabels$justification[i] == 1) { - left <- par('usr')[1] - text(left, topdown[i], x[["description"]][i], pos=2, - col=ylabels$col[i], cex=ylabels$cex[i], font=ylabels$font[i]) - } else { - left <- grconvertX(0, 'device', 'user') - ## warning("In plot() method for gantt objects :\n justification=0 places labels poorly in RStudio, better in other systems", - ## call.=FALSE) - ## message(" left= ", left, " (the thick black line is there)") - ## message(" Q: why is this black line not at the left of the graph?") - text(left, topdown[i], x[["description"]][i], pos=4, - col=ylabels$col[i], cex=ylabels$cex[i], font=ylabels$font[i]) - ## abline(v=left, lwd=10, col='red') - } - } - par(xpd=FALSE) - - ## Connectors - for (t in 1:ndescriptions) { - nb <- x[["neededBy"]][t][[1]] - if (!is.na(nb)) { - source.y <- topdown[t] - source.t <- as.POSIXct(x[["end"]][t]) - for (nbi in 1:length(nb)) { - r <- as.numeric(nb[nbi]) - receiver.t <- as.POSIXct(x[["start"]][r]) - receiver.y <- topdown[r] - lines(c(source.t,receiver.t), c(source.y,receiver.y),col=col.connector) - } - } - } - ## Events - if (!is.null(event.time)) { - ne <- length(event.time) - for (e in 1:ne) { - t <- as.POSIXct(event.time[e]) - abline(v=t, col=col.event[e], lwd=lwd.eventLine[e], lty=lty.eventLine[e]) - mtext(event.label[e], side=event.side, at=t, - col=col.event[e], font=font.event[e], cex=cex.event[e]) - } - } - ## Description - for (i in 1:ndescriptions) { - if (!is.na(x[["start"]][i])) { - mid <- as.POSIXct(x[["start"]][i]) + - x[["done"]][i] * as.numeric(difftime(as.POSIXct(x[["end"]][i]), - as.POSIXct(x[["start"]][i]), - units="secs")) / 100 - if (debug) {cat(as.character(x[["description"]][i]),"takes", as.numeric(difftime(as.POSIXct(x[["end"]][i]), as.POSIXct(x[["start"]][i]), units="secs")), "s\n")} - - bottom <- topdown[i] - half.height - top <- topdown[i] + half.height - left <- as.POSIXct(x[["start"]][i]) - right <- as.POSIXct(x[["end"]][i]) - - if (debug){cat(as.character(x[["description"]][i]));cat(" done=",x[["done"]][i]," mid=");print(mid);cat(" left=");print(left);cat("right=");print(right);cat("\n")} - - if (right > left) { - arrow <- arrows[i] - rect(left, bottom, right, top, col = col.notdone[i], border = FALSE) - rect(left, bottom, mid, top, col = col.done[i], border = FALSE) - rect(left, bottom, right, top, col = "transparent", border = TRUE) - usr <- par('usr') - D <- (top - bottom) * (usr[2]-usr[1]) / (usr[4]-usr[3]) - D <- 0.02 * (usr[2] - usr[1]) - if (arrow == "left" || arrow == "both") { - colTriangle <- if (left == mid) col.notdone else col.done - polygon(c(left, left-D, left), c(bottom, 0.5*(bottom+top), top), - border=colTriangle[i], col=colTriangle[i]) - lines(c(left, left-D, left), c(bottom, 0.5*(bottom+top), top)) - } - if (arrow == "right" || arrow == "both") { - colTriangle <- if (right == mid) col.done else col.notdone - polygon(c(right, right+D, right), c(bottom, 0.5*(bottom+top), top), - border=colTriangle[i], col=colTriangle[i]) - lines(c(right, right+D, right), c(bottom, 0.5*(bottom+top), top)) - } - } - } - } - abline(h = (topdown[1:(ndescriptions - 1)] + topdown[2:ndescriptions])/2, col = grid.col, lty=grid.lty) - par(opar) - invisible(x) -}) - - -#' Summarize a gantt object -#' -#' Summarizes a gantt object. -#' -#' Prints a summary of a gantt dataset. -#' -#' @param object A [gantt-class] object. -#' @param ... ignored. -#' @author Dan Kelley -#' @family things related to gantt data -#' @references -#' `http://alistair.cockburn.us/crystal/articles/evabc/earnedvalueandburncharts.htm`. -#' @examples -#' library(plan) -#' data(gantt) -#' summary(gantt) -#' @export -setMethod(f="summary", - signature="gantt", - definition=function(object, ...) { - if (length(object@data[[1]])) { - max.description.width <- max(nchar(as.character(object[["description"]]))) - num.descriptions <- length(object[["description"]]) - cat("Key, Description,", paste(rep(" ", max.description.width-12), collapse=""), "Start, End, Done, NeededBy\n") - for (t in 1:num.descriptions) { - spacer <- paste(rep(" ", 1 + max.description.width - nchar(as.character(object[["description"]][t]))), - collapse="") - cat(paste(format(object[["key"]][t], width=3, justify="right"), ",", sep=""), - paste(as.character(object[["description"]][t]), ",", - spacer, - format(object[["start"]][t]), ", ", - object[["end"]][t], ", ", - format(object[["done"]][t], width=4, justify="right"), sep = "")) - nb <- object[["neededBy"]][t][[1]] - if (!is.null(nb) && !is.na(nb[1])) { - cat(", ") - for (nbi in 1:length(nb)) { - cat(object[["description"]][as.numeric(nb[nbi])], " ") - } - } - cat("\n") - } - } else { - cat("empty\n") - } - }) - - -#' Create a gantt object. -#' -#' This creates a [gantt-class] object. -#' -#' @param key integer key for task, normally 1 for the first task, 2 for the -#' second, etc. -#' @param description character string describing the task (brief) -#' @param start start date for task (POSIXt or character string that converts -#' to POSIXt with [as.POSIXct()] -#' @param end end date for task (POSIXt or character string that converts to -#' POSIXt with [as.POSIXct()]. -#' @param done percentage completion for the task -#' @param neededBy optional key for a dependent task -#' @return A [gantt-class] object; for details, see [read.gantt()]. -#' @author Dan Kelley -#' @family things related to gantt data -#' @examples -#' -#' library(plan) -#' arrive <- as.POSIXct("2012-09-05") -#' month <- 28 * 86400 -#' year <- 12 * month -#' leave <- arrive + 4 * year -#' startT1 <- arrive -#' endT1 <- startT1 + 4 * month -#' startT2 <- endT1 + 1 -#' endT2 <- startT2 + 4 * month -#' startQE <- arrive + 9 * month -#' endQE <- arrive + 12 * month -#' QEabsoluteEnd <- arrive + 15 * month -#' startProposal <- arrive + 15 * month # for example -#' endProposal <- arrive + 20 * month -#' startThesisWork <- arrive + 2 * month # assumes no thesis work until 2 months in -#' endThesisWork <- leave - 4 * month -#' startWriting <- leave - 36 * month -#' endWriting <- leave -#' g <- as.gantt(key=1:8, c("Academic", -#' "Term 1 classes", -#' "Term 2 classes", -#' "Qualifying Examination", -#' "Research", -#' "Proposal Defence", -#' "Thesis Work", -#' "Paper/Thesis Writing"), -#' c(startT1, startT1, startT2, startQE, startProposal, startProposal, -#' startThesisWork, startWriting), -#' c(startT1, endT1, endT2, endQE, startProposal, endProposal, -#' endThesisWork, endWriting), -#' done=rep(0, 7)) -#' plot(g, xlim=c(arrive, leave), -#' ylabel=list(font=c(2,rep(1,3),2), justification=c(0,rep(1,3),0))) -#' @export -as.gantt <- function(key, description, start, end, done, neededBy) -{ - if (missing(key)) - stop("must give 'key'") - if (missing(description)) - stop("must give 'description'") - if (missing(start)) - stop("must give 'start'") - if (missing(end)) - stop("must give 'end'") - n <- length(key) - if (missing(done)) - done <- rep(0, n) - if (missing(neededBy)) - neededBy <- rep(NA, n) - rval <- new("gantt") - rval@data <- list(key=key, - description=as.character(description), - start=as.POSIXct(start), - end=as.POSIXct(end), - done=done, - neededBy=neededBy) - rval -} - - - - - -#' Read a gantt data file -#' -#' Read a data file containing gantt information. -#' The data format is strict, and deviations from it may lead to error messages -#' that are difficult to understand; see \dQuote{Details}. -#' -#' The first line is a header, and must contain the words `Key`, -#' `Description`, `Start`, `End`, `Done`, and -#' `NeededBy`, written exactly in this way, with commas separating the -#' words. (Blanks are ignored in this line.) -#' -#' Additional lines indicate the details of each of several sub-projects, in -#' comma-separated items, as follows: -#' -#' * A key for the task. These must be distinct, and are -#' typically just the numbers 1, 2, 3, etc. -#' -#' * A description of the task. (This may not contain commas!) -#' -#' * The start time for the task, in ISO 8601 format (`YYYY-MM-DD` or -#' `YYYY-MM-DD hh:mm:ss`). -#' -#' * The end time for the task, in the same format as the starting time. If -#' an end time equals the corresponding start time, no rectangle will be drawn -#' for the activity, and this gives a way to make headings (see example 7 -#' for [plot,gantt-method()]). -#' -#' * A number indicating the percentage of this task that has been -#' completed to date. -#' -#' * A space-separated optional list of numbers that indicate the keys of -#' other tasks that depend on this one. This list is ignored in the present -#' version of [read.gantt()]. -#' -#' @section Sample data file: -#'``` -#' Key, Description, Start, End, Done, NeededBy -#' 1, Assemble equipment, 2008-01-01, 2008-03-28, 90 -#' 2, Test methods, 2008-02-28, 2008-03-28, 30 -#' 3, Field sampling, 2008-04-01, 2008-08-14, 0 -#' 4, Analyse field data, 2008-06-30, 2008-11-14, 0 -#' 5, Write methods chapter, 2008-08-14, 2008-11-14, 0 -#' 6, Write results chapter, 2008-10-14, 2009-01-15, 0 -#' 7, Write other chapters, 2008-12-10, 2009-02-28, 0 -#' 8, Committee reads thesis, 2009-02-28, 2009-03-14, 0 -#' 9, Revise thesis, 2009-03-15, 2009-03-30, 0 -#' 10, Thesis on display, 2009-04-01, 2009-04-15, 0 -#' 11, Defend thesis, 2009-04-16, 2009-04-17, 0 -#' 12, Finalize thesis, 2009-04-18, 2009-05-07, 0 -#'``` -#' -#' @param file a connection or a character string giving the name of the file -#' to load. -#' @param debug boolean, set to `TRUE` to print debugging information. -#' @return A [gantt-class] object, which is a data frame containing -#' `description` (a character description of the task), `"start"` -#' (the task's start time), `"end"` (the task's end time), -#' `"progress"` (a number giving the percent progress on this item, or -#' `NA` if none given), and `needed.by` (a number giving the -#' indices of other tasks that rely on this task, or `NA` if none given). -#' @author Dan Kelley -#' @family things related to gantt data -#' @examples -#' library(plan) -#' filename <- system.file("extdata", "gantt.dat", package="plan") -#' g <- read.gantt(filename) -#' summary(g) -#' plot(g) -#' -#' @export -read.gantt <- function(file, debug=FALSE) -{ - if (is.character(file)) { - file <- file(file, "r") - on.exit(close(file)) - } - if (!inherits(file, "connection")) stop("argument `file' must be a character string or connection") - if (!isOpen(file)) { - open(file, "r") - on.exit(close(file)) - } - quiet <- !debug - tokens <- trimws(scan(file,what='char',sep=",",nlines=1,quiet=quiet)) - check.tokens(tokens, c("Key", "Description", "Start", "End", "Done", "NeededBy")) - key <- description <- start <- end <- done <- neededBy <- c() - while (TRUE) { - tokens <- trimws(scan(file, what=character(0), nlines=1, - blank.lines.skip=FALSE, quiet=quiet, sep=",")) - ni <- length(tokens) - if (ni > 1) { - if (ni < 3) stop("need at least 3 items per line") - key <- c(key, as.numeric(tokens[1])) - description <- c(description, tokens[2]) - start <- c(start, tokens[3]) - end <- c(end, tokens[4]) - done <- c(done, if (ni >= 5) as.numeric(tokens[5]) else NA) - neededBy <- c(neededBy, if (ni >= 6) as.numeric(tokens[6:ni]) else NA) - } else { - break - } - } - as.gantt(key=key, - description=as.character(description), - start=as.POSIXct(start), - end=as.POSIXct(end), - done=done, - neededBy=neededBy) -} - -#' Add a task to a gantt object -#' -#' This can be a simpler method than using [as.gantt()], because -#' tasks can be added one at a time. -#' -#' @param g A [gantt-class] object. -#' @param description A character string describing the task. -#' @param start A character string indicating the task start time, in a format understood by [as.POSIXct()]. -#' Set to `""` (the default) to indicate that `description` is a heading, with no start and end time. -#' @param end A character string indicating the end time, in a format understood by [as.POSIXct()]. -#' @param done A numerical value indicating the fraction done. -#' @param neededBy An integer indicating a task that depends on the completion of this task. If this is -#' `NA`, then the task is not needed by any other task. -#' @param key An optional value indicating the desired key value. If not given, this will default to -#' one beyond the highest key in `g`. Otherwise, if `key` is an integer matching -#' a task that is already in `g`, then that task is replaced; otherwise, the new task -#' is placed between the tasks with integral keys on either side of the task. For example, setting -#' `key=4.5` places this between existing keys 4 and 5 (and then renumbers all keys -#' to be integers); see \dQuote{Examples}. -#' -#' @examples -#' library("plan") -#' g <- new("gantt") -#' g <- ganttAddTask(g, "Courses") # no times, so a heading -#' g <- ganttAddTask(g, "Physical Oceanography", "2016-09-03", "2016-12-05") -#' g <- ganttAddTask(g, "Chemistry Oceanography", "2016-09-03", "2016-12-05") -#' g <- ganttAddTask(g, "Fluid Dynamics", "2016-09-03", "2016-12-05") -#' g <- ganttAddTask(g, "Biological Oceanography", "2017-01-03", "2017-04-05") -#' g <- ganttAddTask(g, "Geological Oceanography", "2017-01-03", "2017-04-05") -#' g <- ganttAddTask(g, "Time-series Analysis", "2017-01-03", "2017-04-05") -#' g <- ganttAddTask(g, "Research") # no times, so a heading -#' g <- ganttAddTask(g, "Literature review", "2016-09-03", "2017-04-05") -#' g <- ganttAddTask(g, "Develop analysis skills", "2016-09-03", "2017-08-01") -#' g <- ganttAddTask(g, "Thesis work", "2017-01-01", "2018-04-01") -#' g <- ganttAddTask(g, "Defend thesis proposal", "2017-05-01", "2017-06-01") -#' g <- ganttAddTask(g, "Write papers & thesis", "2017-05-01", "2018-04-01") -#' g <- ganttAddTask(g, "Defend thesis", "2018-05-01", "2018-05-15") -#' # Set 'font' for bold-faced headings -#' font <- ifelse(is.na(g[["start"]]), 2, 1) -#' plot(g, ylabel=list(font=font)) -#' -#' @family things related to gantt data -#' @export -ganttAddTask <- function(g, description="", start=NA, end=NA, done=0, neededBy=NA, key) -{ - if (!inherits(g, "gantt")) stop("method only applies to gantt objects") - if (nchar(description) < 1) { - warning("empty description") - } else { - nkey <- if (length(g[["key"]])) max(g[["key"]]) else 0 - if (missing(key)) - key <- 1 + nkey - if (key < 1) - stop("cannot have a key less than 1") - if (key==as.integer(key)) { - g[["description"]][key] <- description - g[["start"]][key] <- start - g[["end"]][key] <- end - g[["done"]][key] <- done - g[["neededBy"]][key] <- neededBy - g[["key"]][key] <- key - } else { - before <- seq.int(1, floor(key)) - after <- seq.int(floor(key) + 1, nkey) - message("nkey: ", nkey, ", key: ", key, ", before: ", paste(before, collapse=" "), ", after: ", paste(after, collapse=" ")) - g[["description"]] <- c(g[["description"]][before], description, g[["description"]][after]) - g[["start"]] <- c(g[["start"]][before], start, g[["start"]][after]) - g[["end"]] <- c(g[["end"]][before], end, g[["end"]][after]) - g[["done"]] <- c(g[["done"]][before], done, g[["done"]][after]) - g[["neededBy"]] <- c(g[["neededBy"]][before], neededBy, g[["neededBy"]][after]) - g[["key"]] <- c(g[["key"]][before], key, g[["key"]][after]) - } - } - g[["key"]] <- seq_along(g[["key"]]) - g -} diff --git a/R/misc.R~ b/R/misc.R~ deleted file mode 100644 index f38c88d..0000000 --- a/R/misc.R~ +++ /dev/null @@ -1,10 +0,0 @@ -check.tokens <- function(tokens, expected) -{ - nt <- length(tokens) - ne <- length(expected) - if (nt != ne) stop("wrong number of words on line; got", nt, "but need", ne) - for (i in 1:nt) { - if (tokens[i] != expected[i]) stop("expecting word", expected[i], "but got", tokens[i]) - } -} - diff --git a/R/plan-package.R~ b/R/plan-package.R~ deleted file mode 100644 index b04577a..0000000 --- a/R/plan-package.R~ +++ /dev/null @@ -1,35 +0,0 @@ -#' Sample burndown dataset -#' -#' This is sample burndown dataset provided for testing. -#' -#' @name burndown -#' @docType data -#' @author Dan Kelley -#' @family things related to burndown data -#' @family data sets provided with plan -NULL - - -#' Sample gantt dataset -#' -#' This is sample gantt dataset provided for testing. -#' -#' @name gantt -#' @docType data -#' @author Dan Kelley -#' @family things related to gantt data -#' @family data sets provided with plan -NULL - - -#' Plan, a package for project planning -#' -#' This package provides tools for project planning, e.g. burndown charts, -#' gantt diagrams, etc.; see [burndown-class] and -#' \code{\link{gantt-class}} for entries to the documentation. -#' -#' @name plan -#' @docType package -#' @author Dan Kelley -NULL - diff --git a/_pkgdown.yml~ b/_pkgdown.yml~ deleted file mode 100644 index db461be..0000000 --- a/_pkgdown.yml~ +++ /dev/null @@ -1,11 +0,0 @@ -url: https://dankelley.github.io/plan/ -destination: docs - -template: - bootstrap: 5 - -reference: -- title: All functions -- contents: - - matches(".*") - diff --git a/tests/testthat.R~ b/tests/testthat.R~ deleted file mode 100644 index 01feea2..0000000 --- a/tests/testthat.R~ +++ /dev/null @@ -1,2 +0,0 @@ -library(plan) -test_check("plan") diff --git a/tests/testthat/test_burndown.R~ b/tests/testthat/test_burndown.R~ deleted file mode 100644 index c6e8707..0000000 --- a/tests/testthat/test_burndown.R~ +++ /dev/null @@ -1,32 +0,0 @@ -# vim:textwidth=80:expandtab:shiftwidth=2:softtabstop=2 -library(plan) -filename <- system.file("extdata", "burndown.dat", package="plan") -b <- read.burndown(filename) # make it available for other tests -test_that("can read burndown.dat file", { - expect_silent(b <- read.burndown(filename)) -}) - -test_that("summary works for burndown objects", { - expect_output(summary(b), "Start,") -}) - -test_that("plot works for burndown objects", { - expect_silent(plot(b)) -}) - -test_that("plot.burndown() handles POSIX t.stop correctly (issue 23)", { - t.stop <- as.POSIXct(strptime("2006-04-15", "%Y-%m-%d")) - expect_silent(plot(b, t.stop=t.stop)) -}) - -test_that("plot.burndown() handles POSIX t.stop correctly (issue 23)", { - t.stop <- "2006-04-15" - expect_silent(plot(b, t.stop=t.stop)) -}) - -test_that("as.burndown() creates same object as read.burndown", { - b2 = as.burndown(b@data$start, b@data$deadline, - b@data$tasks, b@data$progress) - expect_equivalent(b, b2) -}) - diff --git a/tests/testthat/test_gantt.R~ b/tests/testthat/test_gantt.R~ deleted file mode 100644 index 55480e0..0000000 --- a/tests/testthat/test_gantt.R~ +++ /dev/null @@ -1,17 +0,0 @@ -# vim:textwidth=80:expandtab:shiftwidth=2:softtabstop=2 -library(plan) -filename <- system.file("extdata", "gantt.dat", package="plan") -g <- read.gantt(filename) # make it available for other tests - -test_that("can read gantt.dat file", { - expect_silent(b <- read.gannt(filename)) -}) - -test_that("summary works for gantt objects", { - expect_output(summary(g), "Key, Description,") -}) - -test_that("plot works for gantt objects", { - expect_silent(plot(g)) -}) - diff --git a/vignettes/plan.Rmd~ b/vignettes/plan.Rmd~ deleted file mode 100644 index 3b634a4..0000000 --- a/vignettes/plan.Rmd~ +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: "The plan package" -author: "Dan Kelley" -date: "`r Sys.Date()`" -output: - rmarkdown::html_vignette: - toc: true - number_sections: true - fig_caption: yes - fig_width: 5 - fig_height: 5 - dpi: 72 - dev.args: list(pointsize=11) - -vignette: > - %\VignetteIndexEntry{The plan package} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - - - - -```{r, echo = FALSE} -knitr::opts_chunk$set(collapse = TRUE, comment = "#>") -``` - -**Abstract.** The `plan` package provides functions for planning and -describing projects and monitoring the progress towards completions of -individual tasks within projects. - -# Introduction - -This package provides (mainly graphical) tools for the planning of projects. -This is an early version of the package, providing support for burn-down -charts and Gantt diagrams. - - -# Burn-down charts - -Burndown charts^[https://en.wikipedia.org/wiki/Burndown_chart] are used to -display a time series of the progress towards the goals of a project. The -format is simple. The x axis represents time, ranging from the onset of the -project to the deadline for completion. The y axis represents the remaining -effort that is require to accomplish the work. As the work is carried out, the -chart provides a running summary of progress towards the deadline. If work is -proceeding smoothly according to schedule, the chart takes the form of a -triangle, with the remaining effort falling from its initial value to zero at -the deadline. For guidance, a gray line is drawn to indicate this ideal -situation. If work is being accomplished faster than expected, the data will -lie below this gray line. However, if the project is falling behind schedule, -the data line will lie above the ideal line. Thus, a glance at the chart -indicates whether the deadline can be met. In most cases, the work is divided -into sub-tasks, and the remaining effort in each task is shown with a different -colour in the chart. This is helpful in identifying tasks that may need more -attention. - -The following plots a sample burndown chart -```{r} -library("plan") -data(burndown) -plot(burndown) -``` - -To work with your own files, use `read.burndown()` to create the burndown -object. - -# Gantt charts - -Gantt diagrams^[https://en.wikipedia.org/wiki/Gantt_Chart] indicate a timetable -for completion of the components of a project. The sample dataset `gantt` is a -hypothetical research plan for an MSc project; you can see how it is graphed -with `example(plot.gantt)`, or by entering the following code. -```{r fig.height=4, fig.width=6, dev.args=list(pointsize=10)} -library("plan") -data(gantt) -plot(gantt) -``` - -Moving beyond this built-in dataset, note that there are 3 main ways to create -`gantt-class` objects: (a) write information in a text file and use -`read.gantt()`, (b) use `as.gantt()` to assemble the object in one (somewhat -complicated) step, or (c) use `new()` to create an object and then -`ganttAddTask()` to add tasks one by one. The third approach may be the easiest -for beginners, so it is illustrated below, with a sketch of a typical -oceanography MSc program. Note that a legend is added, along with an indication -of the time at which the graph was prepared. - - -```{r fig.height=4, fig.width=6, dev.args=list(pointsize=10)} -library("plan") -g <- new("gantt") -g <- ganttAddTask(g, "Courses") # no times, so a heading -g <- ganttAddTask(g, "Physical Oceanography", "2016-09-03", "2016-12-05", done=100) -g <- ganttAddTask(g, "Chemistry Oceanography", "2016-09-03", "2016-12-05", done=100) -g <- ganttAddTask(g, "Fluid Dynamics", "2016-09-03", "2016-12-05", done=100) -g <- ganttAddTask(g, "Biological Oceanography", "2017-01-03", "2017-04-05") -g <- ganttAddTask(g, "Geological Oceanography", "2017-01-03", "2017-04-05") -g <- ganttAddTask(g, "Time-series Analysis", "2017-01-03", "2017-04-05") -g <- ganttAddTask(g, "Research") # no times, so a heading -g <- ganttAddTask(g, "Literature review", "2016-09-03", "2017-02-01", done=20) -g <- ganttAddTask(g, "Develop analysis skills", "2016-09-03", "2017-08-01", done=30) -g <- ganttAddTask(g, "Thesis work", "2016-10-01", "2018-04-01") -g <- ganttAddTask(g, "Defend thesis proposal", "2017-05-01", "2017-06-01") -g <- ganttAddTask(g, "Write papers & thesis", "2017-03-01", "2018-04-01") -g <- ganttAddTask(g, "Defend thesis", "2018-05-01", "2018-05-15") -font <- ifelse(is.na(g[["start"]]), 2, 1) -plot(g, ylabel=list(font=font), - event.time="2017-01-01", event.label="Report Date") -par(lend="square") # default is round -legend("topright", pch=22, pt.cex=2, pt.bg=gray(c(0.3, 0.9)), - border="black", xpd=NA, - legend=c("Completed", "Not Yet Done"), title="MSc plan", bg="white") -``` -