Skip to content

Commit c9a8d30

Browse files
committed
Merge pull request #255 from lindsaycarr/master
wip for legend refactor (part 2)
2 parents 97a5617 + 96cd65f commit c9a8d30

24 files changed

+299
-152
lines changed

R/abline.R

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
#' \item{\code{h}} {the y-value specifying a horizontal line}
1212
#' \item{\code{v}} {the x-value specifying a vertical line}
1313
#' \item{\code{col, lty, lwd}} {parameters describing the color, type, and width of the line, respectively}
14-
#' \item{\code{legend.name}} {name that appears the legend, see \code{\link{legend}}}
15-
#' }
14+
#' \item{\code{legend.name}} {name that appears in the legend, see \code{\link{legend}} for more legend parameters}
15+
#' }
16+
#'
1617
#'
1718
#' @export
1819
#' @examples
@@ -28,5 +29,7 @@ abline <- function(object, ...) {
2829

2930

3031
abline.gsplot <- function(object, ..., legend.name=NULL, side=c(1,2)){
31-
set_window_args(object, fun.name='abline', ..., legend.name=legend.name, side=side, def.funs=c(graphics::abline, graphics::plot.xy))
32+
fun.name <- 'abline'
33+
object <- set_window_args(object, fun.name=fun.name, ..., legend.name=legend.name, side=side, def.funs=c(graphics::abline, graphics::plot.xy))
34+
object <- set_legend_args(object, fun.name=fun.name, ..., legend.name=legend.name)
3235
}

R/arrows.R

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#' \item{\code{x0, y0}} {position of the arrow tail}
1111
#' \item{\code{x, y}} {position of the arrow head}
1212
#' \item{\code{col, lty, lwd}} {parameters describing the color, type, and width of the arrow, respectively}
13+
#' \item{\code{legend.name}} {name that appears in the legend, see \code{\link{legend}} for more legend parameters}
1314
#' }
1415
#'
1516
#' @export
@@ -33,5 +34,7 @@ arrows <- function(object, ...) {
3334

3435

3536
arrows.gsplot <- function(object, ..., legend.name=NULL, side=c(1,2)){
36-
set_window_args(object, fun.name='arrows', ..., legend.name=legend.name, side=side, def.funs=graphics::arrows)
37+
fun.name <- 'arrows'
38+
object <- set_window_args(object, fun.name=fun.name, ..., legend.name=legend.name, side=side, def.funs=graphics::arrows)
39+
object <- set_legend_args(object, fun.name=fun.name, ..., legend.name=legend.name)
3740
}

R/curve.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#' \item{\code{col}} {line color}
2020
#' \item{\code{lty}} {line type}
2121
#' \item{\code{lwd}} {line width}
22+
#' \item{\code{legend.name}} {name that appears in the legend, see \code{\link{legend}} for more legend parameters}
2223
#' }
2324
#'
2425
#' @rdname curve
@@ -56,6 +57,9 @@ curve.gsplot <- function(object, expr, ..., legend.name=NULL, side=c(1,2)){
5657
setNames('lines')
5758

5859
object <- gsplot(append(object, to.gsplot))
60+
61+
fun.name <- 'lines'
62+
object <- set_legend_args(object, fun.name=fun.name, ..., legend.name=legend.name)
5963

6064
return(object)
6165
}

R/error_bars.R

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@
44
#'
55
#' @param object gsplot object
66
#' @param \dots Further graphical parameters may also be supplied as arguments. See 'Details'.
7+
#'
8+
#' @details Additional graphical parameter inputs:
9+
#' \itemize{
10+
#' \item{\code{x, y}} {location of error_bar origin}
11+
#' \item{\code{y.high, y.low}} {the y-value specifying the error above the point (high) and below the point (low)}
12+
#' \item{\code{x.high, x.low}} {the x-value specifying the error above the point (high) and below the point (low)}
13+
#' \item{\code{epsilon}} {width of the end of the error bar (in inches)}
14+
#' \item{\code{col, lty, lwd}} {parameters describing the color, type, and width of the line, respectively}
15+
#' \item{\code{legend.name}} {name that appears in the legend, see \code{\link{legend}} for more legend parameters}
16+
#' }
717
#'
818
#' @rdname error_bar
919
#' @export
@@ -49,7 +59,8 @@ error_bar.gsplot <- function(object, x, y, y.high=0, y.low=0, x.high=0, x.low=0,
4959
y.low.coord <- y.low.coord[errorIndex]
5060
y.error <- y[errorIndex]
5161
x.error <- x[errorIndex]
52-
object <- arrows(object, x0=x.error, y0=y.error, x1=x.error, y1=y.low.coord, length=epsilon, angle=90, ...)
62+
object <- arrows(object, x0=x.error, y0=y.error, x1=x.error, y1=y.low.coord,
63+
length=epsilon, angle=90, ..., legend.name=legend.name)
5364
}
5465

5566
if(!all(y.high == 0)){
@@ -58,7 +69,8 @@ error_bar.gsplot <- function(object, x, y, y.high=0, y.low=0, x.high=0, x.low=0,
5869
y.high.coord <- y.high.coord[errorIndex]
5970
y.error <- y[errorIndex]
6071
x.error <- x[errorIndex]
61-
object <- arrows(object, x0=x.error, y0=y.error, x1=x.error, y1=y.high.coord, length=epsilon, angle=90, ...)
72+
object <- arrows(object, x0=x.error, y0=y.error, x1=x.error, y1=y.high.coord, length=epsilon,
73+
angle=90, ..., legend.name=check_legend_name(legend.name, y.low))
6274
}
6375

6476
if(!all(x.low == 0)){
@@ -67,7 +79,8 @@ error_bar.gsplot <- function(object, x, y, y.high=0, y.low=0, x.high=0, x.low=0,
6779
x.low.coord <- x.low.coord[errorIndex]
6880
x.error <- x[errorIndex]
6981
y.error <- y[errorIndex]
70-
object <- arrows(object, x0=x.error, y0=y.error, x1=x.low.coord, y1=y.error, length=epsilon, angle=90, ...)
82+
object <- arrows(object, x0=x.error, y0=y.error, x1=x.low.coord, y1=y.error, length=epsilon,
83+
angle=90, ..., legend.name=check_legend_name(legend.name, c(y.low, y.high)))
7184
}
7285

7386
if(!all(x.high == 0)){
@@ -76,7 +89,8 @@ error_bar.gsplot <- function(object, x, y, y.high=0, y.low=0, x.high=0, x.low=0,
7689
x.high.coord <- x.high.coord[errorIndex]
7790
x.error <- x[errorIndex]
7891
y.error <- y[errorIndex]
79-
object <- arrows(object, x0=x.error, y0=y.error, x1=x.high.coord, y1=y.error, length=epsilon, angle=90, ...)
92+
object <- arrows(object, x0=x.error, y0=y.error, x1=x.high.coord, y1=y.error, length=epsilon,
93+
angle=90, ..., legend.name=check_legend_name(legend.name, c(y.low, y.high, x.low)))
8094
}
8195

8296
return(object)
@@ -87,4 +101,8 @@ error_bar.default <- function(x, y, y.high, y.low, x.high, x.low, epsilon=0.1, .
87101
return()
88102
}
89103

90-
104+
#don't use legend.name more than once
105+
check_legend_name <- function(legend.name, prev_calls){
106+
if(!is.null(legend.name) && sum(prev_calls != 0)){ legend.name <- NULL }
107+
return(legend.name)
108+
}

R/legend.R

Lines changed: 90 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,22 @@
44
#' for legends. See \code{\link[graphics]{legend}} for more details.
55
#'
66
#' @param object gsplot object
7-
#' @param \dots Further graphical parameters may also be supplied as arguments. See 'Details'.
7+
#' @param \dots Overall legend parameters may also be supplied as arguments. See 'Details'.
88
#'
9-
#' @details Additional graphical parameter inputs:
10-
#' \itemize{
11-
#' \item{\code{location}} {position of the legend, specified by x- and y-coordinates or by keyword ("bottomright", "bottom", "bottomleft", "left", "topleft", "top", "topright", "right", or "center")}
12-
#' \item{\code{title}} {character string indicating the legend title}
13-
#' }
9+
#' @details
10+
#' Overall legend inputs:
11+
#'
12+
#' \code{x, y} coordinates OR use \code{location} which is a character string indicating the legend location: above, toright, toleft, or below (see \code{\link[graphics]{legend}} for more)
13+
#'
14+
#' \code{bty, bg, box.lty, box.lwd, box.col, cex, xjust, yjust
15+
#' x.intersp, y.intersp, adj, text.width, merge, trace,
16+
#' plot, ncol, horiz, title, inset, xpd, title.col
17+
#' title.adj, seg.len}
18+
#'
19+
#' Parameter inputs for each graphics call (use inside of lines, points, curve, etc):
20+
#'
21+
#' \code{legend.name, fill, col, border, lty, lwd, pch, angle,
22+
#' density, pt.bg, pt.cex, pt.lwd, text.col, text.font}
1423
#'
1524
#' @export
1625
#' @importFrom graphics par
@@ -51,44 +60,19 @@ legend <- function(object, ...){
5160
}
5261

5362

54-
legend.gsplot <- function(object, ..., location="topright", title="EXPLANATION", legend_offset=0.3) {
63+
legend.gsplot <- function(object, ..., location="topright", legend_offset=0.3) {
5564
arguments <- list(...)
5665

57-
# current_list <- config("legend") # grabbing yaml defaults
58-
# title <- current_list$title
59-
# location <- current_list$location
66+
gsConfig <- list(location = location, legend_offset = legend_offset, ...)
6067

6168
if("x" %in% names(arguments)){
62-
location <- arguments$x
69+
gsConfig$location <- gsConfig$x
70+
gsConfig$x <- NULL
6371
}
6472

65-
gsConfig <- list(location = location, legend_offset = legend_offset, title = title)
66-
67-
arguments <- appendLegendPositionConfiguration(location, gsConfig, arguments)
68-
arguments <- append(arguments, list(title=title))
69-
70-
object <- append(object, list(legend = list(arguments = arguments, gs.config = gsConfig)))
71-
72-
return(gsplot(object))
73-
}
74-
75-
appendLegendPositionConfiguration <- function(location, gsConfig, arguments) {
76-
#TODO support explicit x/y coords
77-
legend_offset <- gsConfig$legend_offset
73+
object[['legend']] <- append(object[['legend']], list(gs.config = gsConfig))
7874

79-
if(location == "below") {
80-
return(append(arguments, list(x = "bottom", y = NULL, inset=c(0, -legend_offset), bty="n")))
81-
} else if(location == "above") {
82-
return(append(arguments, list(x = "top", y = NULL, inset=c(0, -legend_offset), bty="n")))
83-
} else if(location == "toright") {
84-
return(append(arguments, list(x = "right", y = NULL, inset=c(-legend_offset, 0), bty="n")))
85-
} else if(location == "toleft") {
86-
return(append(arguments, list(x = "left", y = NULL, inset=c(-legend_offset, 0), bty="n")))
87-
} else if("x" %in% names(arguments)){
88-
return(arguments)
89-
} else {
90-
return(append(arguments, list(x = location)))
91-
}
75+
return(object)
9276
}
9377

9478
#' gsplot draw_legend
@@ -100,98 +84,90 @@ appendLegendPositionConfiguration <- function(location, gsConfig, arguments) {
10084

10185
draw_legend <- function(gsplot) {
10286

87+
if (all(!names(gsplot[['legend']]) %in% "gs.config")){
88+
return()
89+
}
90+
10391
oldXPD <- par()$xpd
92+
oldBg <- par('bg')
10493

105-
for(index in which(names(gsplot) %in% "legend")){
106-
107-
legendParams <- gsplot[[index]][['arguments']]
94+
for(index in which(names(gsplot[['legend']]) %in% "gs.config")){
10895

10996
par(xpd=TRUE)
11097

111-
if(!("legend" %in% names(legendParams))){
98+
if (any(names(gsplot[['legend']]) == "legend.args")) {
99+
100+
default.args <- formals(graphics::legend)
101+
overall.legend <- c("x", "y", "bty", "bg", "box.lty", "box.lwd", "box.col", "cex",
102+
"xjust", "yjust", "x.intersp", "y.intersp", "adj", "text.width",
103+
"merge", "trace", "plot", "ncol", "horiz", "title", "inset",
104+
"xpd", "title.col", "title.adj", "seg.len")
105+
not.overall <- default.args[which(!names(default.args) %in% overall.legend)]
106+
legendParamsALL <- vector("list", length(not.overall))
107+
names(legendParamsALL) <- names(not.overall)
112108

113-
if(!is.null(legendParams)) {
114-
115-
smartLegend <- data.frame(row.names=names(formals(graphics::legend)), stringsAsFactors = FALSE)
116-
views = views(gsplot)
117-
for (v in seq_len(length(views))){
118-
for (i in seq_len(length(names(views[[v]])))) {
119-
120-
plotElement <- names(views[[v]][i])
121-
122-
params <- c('legend'=views[[v]][[i]][['legend.name']])
123-
if (is.null(params)) {next}
124-
125-
params <- append(params, views[[v]][[i]][which(names(views[[v]][[i]]) %in% names(formals(graphics::legend))[-c(1,2)])])
126-
type <- views[[v]][[i]][['arguments$type']]
127-
128-
if (plotElement == "points") {
129-
names(params)[which(names(params) %in% "bg")] <- 'pt.bg'
130-
names(params)[which(names(params) %in% "cex")] <- 'pt.cex'
131-
names(params)[which(names(params) %in% "lwd")] <- 'pt.lwd'
132-
if (!is.null(type) && type %in% c("l", "o", "b", "c", "s", "S", "h")) {
133-
if (all(!names(params) %in% c("lty"))) {params <- append(params, list(lty=par("lty")))}
134-
}
135-
}
136-
if (plotElement == "lines" && !is.null(type) && type %in% c("p", "o", "b", "c")) {
137-
if (all(!names(params) %in% c("pch"))) {params <- append(params, list(pch=par("pch")))}
138-
params <- append(params, list(pt.lwd=params$lwd))
139-
if (type == "p") {params <- params[-which(names(params) %in% c('lty', 'lwd'))]}
140-
names(params)[which(names(params) %in% "bg")] <- 'pt.bg'
141-
names(params)[which(names(params) %in% "cex")] <- 'pt.cex'
142-
}
143-
if (plotElement %in% c("rect", "polygon")) {
144-
names(params)[which(names(params) %in% "col")] <- 'fill'
145-
}
146-
147-
ifelse(length(smartLegend) == 0, smartLegendNames <- row.names(smartLegend), smartLegendNames <- names(smartLegend))
148-
newsmartLegend <- match(smartLegendNames, names(params))
149-
newsmartLegend[which(!is.na(newsmartLegend))] <- params[newsmartLegend[which(!is.na(newsmartLegend))]]
150-
names(newsmartLegend) <- smartLegendNames
151-
152-
smartLegend <- rbind(smartLegend, as.data.frame(newsmartLegend, stringsAsFactors = FALSE))
153-
154-
}
155-
}
156-
157-
158-
159-
#take out any calls with all NA, and add overall legend calls from legendParams
160-
indices <- unlist(sapply(seq_len(length(smartLegend)), function(x) {!all(is.na(smartLegend[[x]]))}))
161-
legendParams <- append(legendParams, smartLegend[indices])
162-
163-
# change any numeric linetypes to character
164-
lineTypes <- c("blank", "solid", "dashed", "dotted", "dotdash", "longdash", "twodash")
165-
if (any(legendParams$lty %in% c(as.character(1:6)))) {
166-
ltyIndices <- which(legendParams$lty %in% c(as.character(1:6)))
167-
legendParams$lty[ltyIndices] <- sapply(as.numeric(legendParams$lty[ltyIndices]), function(x) lineTypes[x+1])
109+
for(i in which(names(gsplot[['legend']]) %in% 'legend.args')) {
110+
orderedParams <- gsplot[['legend']][[i]][match(names(legendParamsALL), names(gsplot[['legend']][[i]]))]
111+
for (j in seq_along(legendParamsALL)) {
112+
legendParamsALL[[j]] <- c(legendParamsALL[[j]], orderedParams[[j]])
168113
}
169-
170-
#if density is specified, default should be "NULL"
171-
#if (!is.null(legendParams$density)) {legendParams$density[which(is.na(legendParams$density))] <- par("bg")}
172-
173-
#for above/below, dynamically set the number of columns
174-
location <- gsplot[['legend']][['gs.config']][['location']]
175-
if(location == "below" || location == "above") {
176-
itemsPerCol <- 3 #TODO load this from config
177-
cols <- NROW(smartLegend) %/% 3;
178-
if(NROW(smartLegend) %% 3 > 0) {
179-
cols <- cols + 1
180-
}
181-
legendParams <- append(legendParams, list(ncol=cols))
114+
}
115+
116+
#for above/below, dynamically set the number of columns
117+
location <- gsplot[['legend']][['gs.config']][['location']]
118+
if(location == "below" || location == "above") {
119+
itemsPerCol <- 3 #TODO load this from config
120+
cols <- length(legendParamsALL$legend) %/% 3;
121+
if(length(legendParamsALL$legend) %% 3 > 0) {
122+
cols <- cols + 1
182123
}
183-
184-
legend(legendParams)
185-
124+
legendParamsALL <- append(legendParamsALL, list(ncol=cols))
125+
}
126+
127+
overallLegendArgs <- appendLegendPositionConfiguration(gsplot[['legend']][['gs.config']])
128+
legendParamsALL <- append(legendParamsALL, overallLegendArgs)
129+
legendOrdered <- legendParamsALL[na.omit(match(names(default.args), names(legendParamsALL)))]
130+
131+
#set bg so that fill/border/etc args are correct, then evaluate any quoted list items
132+
if(any(names(overallLegendArgs) %in% c("bg"))) {
133+
par(bg=overallLegendArgs$bg)
186134
}
135+
legendComplete <- lapply(legendOrdered, function(x) {unname(sapply(x, function(x) {eval(x)}))})
136+
187137
} else {
188-
legend(legendParams)
138+
legendComplete <- appendLegendPositionConfiguration(gsplot[['legend']][[index]])
189139
}
140+
141+
legend(legendComplete)
142+
par(xpd=oldXPD)
143+
par(bg=oldBg)
190144
}
145+
146+
}
147+
148+
appendLegendPositionConfiguration <- function(gsConfig) {
149+
#TODO support explicit x/y coords
150+
legend_offset <- gsConfig$legend_offset
151+
location <- gsConfig$location
152+
gsConfig$legend_offset <- NULL
153+
gsConfig$location <- NULL
191154

192-
par(xpd=oldXPD)
155+
if(location == "below") {
156+
return(append(gsConfig, list(x = "bottom", y = NULL, inset=c(0, -legend_offset), bty="n")))
157+
} else if(location == "above") {
158+
return(append(gsConfig, list(x = "top", y = NULL, inset=c(0, -legend_offset), bty="n")))
159+
} else if(location == "toright") {
160+
return(append(gsConfig, list(x = "right", y = NULL, inset=c(-legend_offset, 0), bty="n")))
161+
} else if(location == "toleft") {
162+
return(append(gsConfig, list(x = "left", y = NULL, inset=c(-legend_offset, 0), bty="n")))
163+
} else if("x" %in% names(gsConfig)){
164+
return(gsConfig)
165+
} else {
166+
return(append(gsConfig, list(x = location)))
167+
}
193168
}
194169

170+
# What is this for?
195171
legend_adjusted_margins <- function(gsPlot) {
196172
defaults <- config("plot")
197173
defaultMargins <- c(3, 3, 3, 3) #default margins should come from config

R/lines.R

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
#' \itemize{
1010
#' \item{\code{x}} {vector of x-coordinates for points that make up the line}
1111
#' \item{\code{y}} {vector of y-coordinates for points that make up the line}
12-
#' \item{\code{legend.name}} {a character vector of length one to be used in the legend}
1312
#' \item{\code{side}} {vector specifying the side(s) to use for axes (1,2,3,4 for sides, or 5,6,7,8 for outward offsets of those)}
13+
#' \item{\code{legend.name}} {name that appears in the legend, see \code{\link{legend}} for more legend parameters}
1414
#' \item{\code{error_bar}} {add error bars to the defined line, see \code{\link{error_bar}}
1515
#' for arguments, must add arguments as a list}
1616
#' \item{\code{callouts}} {add callouts and text to the defined line, see \code{\link{callouts}}
@@ -43,5 +43,8 @@ lines <- function(object, ...) {
4343

4444

4545
lines.gsplot <- function(object, ..., legend.name=NULL, side=c(1,2)){
46-
set_window_args(object, fun.name='lines', ..., legend.name=legend.name, side=side, def.funs=c(graphics::plot.xy, graphics::lines.default))
47-
}
46+
fun.name <- 'lines'
47+
object <- set_window_args(object, fun.name=fun.name, ..., legend.name=legend.name, side=side, def.funs=c(graphics::plot.xy, graphics::lines.default))
48+
object <- set_legend_args(object, fun.name=fun.name, ..., legend.name=legend.name)
49+
}
50+

0 commit comments

Comments
 (0)