diff --git a/.Rbuildignore b/.Rbuildignore index cd5f26a..5b94133 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -2,6 +2,8 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^/lib/$ +^lib\$ .Rprofile ^README\.Rmd$ -^README\*.png$ \ No newline at end of file +^README\*.png$ +^lib$ diff --git a/.gitignore b/.gitignore index cc40004..12ff8b4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ inst/doc -/lib/ \ No newline at end of file +/lib/ +/README/cache/ diff --git a/DESCRIPTION b/DESCRIPTION index 97d38fd..581e686 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,24 +1,26 @@ Package: splot Type: Package -Title: splot - Stefan's plotting package +Title: splot! - Stefan's plot library of tricks +URL: https://github.com/stefanedwards/splot +BugReports: https://github.com/stefanedwards/splot/issues Version: 0.2.0 -Author: Stefan McKinnon Edwards +Author@R: person(c('Stefan','McKinnon'), 'Edwards', email='sme@iysik.com', + role=c('aut','ctb','cre')) +Author: Stefan McKinnon Edwards [aut, ctb, cre] Maintainer: Stefan McKinnon Edwards Description: Yet another ggplot2 and knitr extension package. -Imports: - ggplot2, - grid, - gridExtra, - gtable, - RCurl + Includes functions for manipulating ggplot2 legends, + axis lines, and a bit of knitr magic. Depends: - ggplot2, + R (>= 3.1.0) +Imports: + ggplot2 (>= 2.2.0), grid, gridExtra, gtable, -Enhances: ggplot2, - knitr -License: GPL-3 + RCurl, + knitr (>= 1.12) +License: GPL-3 + file LICENSE Encoding: UTF-8 LazyData: true RoxygenNote: 5.0.1 @@ -28,10 +30,11 @@ Collate: 'coord-capped.r' 'coord-flex.r' 'facet-rep-lab.r' + 'facet-wrap.r' 'knit_print.r' 'legends.r' 'splot.r' Suggests: - knitr, - rmarkdown + rmarkdown, + stringr VignetteBuilder: knitr diff --git a/NAMESPACE b/NAMESPACE index 704b335..5aa78df 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -28,17 +28,5 @@ import(grid) import(gridExtra) import(gtable) import(knitr) -importFrom(ggplot2,CoordCartesian) -importFrom(ggplot2,CoordFixed) -importFrom(ggplot2,CoordFlip) -importFrom(ggplot2,FacetGrid) -importFrom(ggplot2,FacetWrap) importFrom(ggplot2,ggproto) importFrom(grid,unit) -importFrom(gtable,gtable_add_cols) -importFrom(gtable,gtable_add_grob) -importFrom(gtable,gtable_add_rows) -importFrom(gtable,gtable_col) -importFrom(gtable,gtable_height) -importFrom(gtable,gtable_row) -importFrom(gtable,gtable_width) diff --git a/R/brackets.R b/R/brackets.R index 1dea1ad..284668e 100644 --- a/R/brackets.R +++ b/R/brackets.R @@ -25,6 +25,7 @@ NULL #' If \code{waiver()} (default), use \code{axis.ticks.length} from \code{\link{theme}}. #' #' @examples +#' library(ggplot2) #' p <- ggplot(mpg, aes(as.factor(cyl), hwy, colour=class)) + #' geom_point(position=position_jitter(width=0.3)) + #' theme_bw() + @@ -39,7 +40,8 @@ NULL #' # A further adjustment, #' p + theme(panel.grid.major.x = element_blank()) #' @import grid -#' @importFrom gtable gtable_col gtable_row gtable_width gtable_height +#' @import ggplot2 +#' @import gtable brackets_horisontal <- function(direction = c('up','down'), length = unit(0.05, 'native'), tick.length = waiver()) { @@ -71,12 +73,12 @@ brackets_horisontal <- function(direction = c('up','down'), labels <- agrob$children[[ind.notline]]$grobs[[ind.text]] gt <- switch(position, - top = gtable_col('axis', + top = gtable::gtable_col('axis', grobs = list(labels, brackets), width = unit(1, 'npc'), heights = unit.c(grobHeight(labels), tick.length) ), - bottom = gtable_col('axis', + bottom = gtable::gtable_col('axis', grobs = list(brackets, labels), width = unit(1, 'npc'), heights = unit.c(tick.length, grobHeight(labels)) @@ -89,8 +91,8 @@ brackets_horisontal <- function(direction = c('up','down'), ggplot2:::absoluteGrob( gList(gt), - width = gtable_width(gt), - height = gtable_height(gt), + width = gtable::gtable_width(gt), + height = gtable::gtable_height(gt), vp = justvp ) } @@ -132,12 +134,12 @@ brackets_vertical <- function(direction = c('left','right'), labels <- agrob$children[[ind.notline]]$grobs[[ind.text]] gt <- switch(position, - left = gtable_row('axis', + left = gtable::gtable_row('axis', grobs = list(labels, brackets), height = unit(1, 'npc'), widths = unit.c(grobWidth(labels), tick.length) ), - right = gtable_row('axis', + right = gtable::gtable_row('axis', grobs = list(brackets, labels), height = unit(1, 'npc'), widths = unit.c(tick.length, grobWidth(labels)) @@ -150,8 +152,8 @@ brackets_vertical <- function(direction = c('left','right'), ggplot2:::absoluteGrob( gList(gt), - width = gtable_width(gt), - height = gtable_height(gt), + width = gtable::gtable_width(gt), + height = gtable::gtable_height(gt), vp = justvp ) } diff --git a/R/coord-capped.r b/R/coord-capped.r index 60ec279..6eb4f38 100644 --- a/R/coord-capped.r +++ b/R/coord-capped.r @@ -33,6 +33,7 @@ NULL #' @rdname coord_capped #' @export #' @examples +#' library(ggplot2) #' # Notice how the axis lines of the following plot meet in the lower-left corner. #' p <- ggplot(mtcars, aes(x = mpg)) + geom_dotplot() + #' theme_bw() + diff --git a/R/coord-flex.r b/R/coord-flex.r index 243baa9..3be6d08 100644 --- a/R/coord-flex.r +++ b/R/coord-flex.r @@ -40,7 +40,7 @@ NULL #' limits are taken exactly from the data or \code{xlim}/\code{ylim}. #' @export #' @examples -#' +#' library(ggplot2) #' # A standard plot #' p <- ggplot(mtcars, aes(disp, wt)) + #' geom_point() + @@ -66,7 +66,8 @@ NULL #' #' # Also works with secondary axes: #' p + scale_y_continuous(sec.axis=sec_axis(~5*., name='wt times 5')) + -#' coord_flex_cart(left=brackets_vertical(), bottom=capped_horisontal('right'), right=capped_vertical('both', gap=0.02)) +#' coord_flex_cart(left=brackets_vertical(), bottom=capped_horisontal('right'), +#' right=capped_vertical('both', gap=0.02)) #' #' #' # Supports the usual 'coord_fixed': @@ -165,32 +166,35 @@ flex_render_axis_v <- function(self, scale_details, theme) { # ggproto objects ------------------------------------------------------------- -#' @rdname ggplot2-ggproto +#' @rdname splot-ggproto +#' @keywords internal #' @format NULL #' @usage NULL #' @export -#' @importFrom ggplot2 CoordCartesian ggproto +#' @import ggplot2 CoordFlexCartesian <- ggplot2::ggproto('CoordFlexCartesian', `_inherit` = ggplot2::CoordCartesian, render_axis_h = flex_render_axis_h, render_axis_v = flex_render_axis_v ) -#' @rdname ggplot2-ggproto +#' @rdname splot-ggproto +#' @keywords internal #' @format NULL #' @usage NULL #' @export -#' @importFrom ggplot2 CoordFlip ggproto +#' @import ggplot2 CoordFlexFlipped <- ggplot2::ggproto('CoordFlexFlipped', `_inherit` = ggplot2::CoordFlip, render_axis_h = flex_render_axis_h, render_axis_v = flex_render_axis_v ) -#' @rdname ggplot2-ggproto +#' @rdname splot-ggproto +#' @keywords internal #' @format NULL #' @usage NULL #' @export -#' @importFrom ggplot2 CoordFixed ggproto +#' @import ggplot2 CoordFlexFixed <- ggplot2::ggproto('CoordFlexFlipped', `_inherit` = ggplot2::CoordFixed, render_axis_h = flex_render_axis_h, render_axis_v = flex_render_axis_v diff --git a/R/facet-rep-lab.r b/R/facet-rep-lab.r index f293cbe..abd5158 100644 --- a/R/facet-rep-lab.r +++ b/R/facet-rep-lab.r @@ -1,77 +1,29 @@ #' @include ggplot2.r NULL -# facet_rep_grid ------------------------ -NULL - -#' Lay out panels in a grid with axes replicated across all panels. -#' -#' \strong{Documentation is straight from \code{\link[ggplot2]{facet_grid}}.} -#' Only addition is this function \emph{copies the axis across all panels}. -#' \code{repeat.tick.labels=FALSE} removes the labels (numbering) on an axis. +#' Repeat axis lines and labels across all facet panels #' -#' \code{facet_grid} forms a matrix of panels defined by row and column -#' facetting variables. It is most useful when you have two discrete -#' variables, and all combinations of the variables exist in the data. +#' \code{\link[ggplot2]{facet_grid}} and \code{\link[ggplot2]{facet_wrap}}, but +#' with axis lines and labels preserved on all panels. #' -#' @param facets a formula with the rows (of the tabular display) on the LHS -#' and the columns (of the tabular display) on the RHS; the dot in the -#' formula is used to indicate there should be no faceting on this dimension -#' (either row or column). The formula can also be provided as a string -#' instead of a classical formula object -#' @param margins either a logical value or a character -#' vector. Margins are additional facets which contain all the data -#' for each of the possible values of the faceting variables. If -#' \code{FALSE}, no additional facets are included (the -#' default). If \code{TRUE}, margins are included for all faceting -#' variables. If specified as a character vector, it is the names of -#' variables for which margins are to be created. -#' @param scales Are scales shared across all facets (the default, -#' \code{"fixed"}), or do they vary across rows (\code{"free_x"}), -#' columns (\code{"free_y"}), or both rows and columns (\code{"free"}) -#' @param space If \code{"fixed"}, the default, all panels have the same size. -#' If \code{"free_y"} their height will be proportional to the length of the -#' y scale; if \code{"free_x"} their width will be proportional to the -#' length of the x scale; or if \code{"free"} both height and width will -#' vary. This setting has no effect unless the appropriate scales also vary. -#' @param labeller A function that takes one data frame of labels and -#' returns a list or data frame of character vectors. Each input -#' column corresponds to one factor. Thus there will be more than -#' one with formulae of the type \code{~cyl + am}. Each output -#' column gets displayed as one separate line in the strip -#' label. This function should inherit from the "labeller" S3 class -#' for compatibility with \code{\link{labeller}()}. See -#' \code{\link{label_value}} for more details and pointers to other -#' options. -#' @param as.table If \code{TRUE}, the default, the facets are laid out like -#' a table with highest values at the bottom-right. If \code{FALSE}, the -#' facets are laid out like a plot with the highest value at the top-right. -#' @param switch By default, the labels are displayed on the top and -#' right of the plot. If \code{"x"}, the top labels will be -#' displayed to the bottom. If \code{"y"}, the right-hand side -#' labels will be displayed to the left. Can also be set to -#' \code{"both"}. -#' @param shrink If \code{TRUE}, will shrink scales to fit output of -#' statistics, not raw data. If \code{FALSE}, will be range of raw data -#' before statistical summary. -#' @param drop If \code{TRUE}, the default, all factor levels not used in the -#' data will automatically be dropped. If \code{FALSE}, all factor levels -#' will be shown, regardless of whether or not they appear in the data. -#' @param repeat.tick.labels Logical, removes the labels (numbering) on an axis when \code{FALSE}. -#' @importFrom ggplot2 ggproto +#' @param ... Arguments used for \code{\link[ggplot2]{facet_grid}} or +#' \code{\link[ggplot2]{facet_wrap}}. +#' @param repeat.tick.labels Logical, removes the labels (numbering) on an inner +#' axes when \code{FALSE}. +#' @rdname facet_rep #' @export -facet_rep_grid <- function(facets, shrink=TRUE, repeat.tick.labels=FALSE, .debug=FALSE, ...) { - f <- facet_grid(facets, shrink=shrink, ...) - params <- append(f$params, list(repeat.tick.labels=repeat.tick.labels, .debug=.debug)) - ggproto(NULL, FacetGridRepeatLabels, - shrink=shrink, +facet_rep_grid <- function(..., repeat.tick.labels=FALSE) { + f <- ggplot2::facet_grid(...) + params <- append(f$params, list(repeat.tick.labels=repeat.tick.labels)) + ggplot2::ggproto(NULL, FacetGridRepeatLabels, + shrink=f$shrink, params=params) } #' Removes labels from axis grobs. -#' +#' #' Called from FacetGridRepeatLabels. -#' +#' #' @param axisgrob Grob with an axis. #' @keywords interal remove_labels_from_axis <- function(axisgrob) { @@ -87,43 +39,43 @@ remove_labels_from_axis <- function(axisgrob) { axisgrob } -#' @rdname ggplot2-ggproto +#' @rdname splot-ggproto +#' @keywords internal #' @format NULL #' @usage NULL #' @export -#' @importFrom ggplot2 FacetGrid ggproto -#' @importFrom gtable gtable_add_cols gtable_add_grob gtable_add_rows -FacetGridRepeatLabels <- ggplot2::ggproto('FacetGridRepeatLabels', `_inherit`=ggplot2::FacetGrid, +#' @import ggplot2 +#' @import gtable +FacetGridRepeatLabels <- ggplot2::ggproto('FacetGridRepeatLabels', + `_inherit`=ggplot2::FacetGrid, draw_panels = function(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { - table <- FacetGrid$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) - if (params$.debug) { saveRDS(table, file='table.rds')} - + table <- ggplot2::FacetGrid$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) + # Add axes across all panels panels <- table$layout[grepl("^panel", table$layout$name), , drop = FALSE] - #cord <- do.call(rbind, strsplit(panels$name, split='-', fixed = TRUE)) - panels$col <- as.integer(as.factor(panels$l))# as.integer(cord[,3]) - panels$row <- as.integer(as.factor(panels$t))#as.integer(cord[,2]) - + panels$col <- as.integer(as.factor(panels$l)) + panels$row <- as.integer(as.factor(panels$t)) + axis_b <- table$grobs[grepl('axis-b-[[:digit:]]+', table$layout$name)] axis_l <- table$grobs[grepl('axis-l-[[:digit:]]+', table$layout$name)] axis_t <- table$grobs[grepl('axis-t-[[:digit:]]+', table$layout$name)] axis_r <- table$grobs[grepl('axis-r-[[:digit:]]+', table$layout$name)] - + if (params$repeat.tick.labels == FALSE) { axis_b <- lapply(axis_b, remove_labels_from_axis) axis_l <- lapply(axis_l, remove_labels_from_axis) axis_t <- lapply(axis_t, remove_labels_from_axis) axis_r <- lapply(axis_r, remove_labels_from_axis) } - + panel_range <- find_panel(table) panel_range[,c('col','row')] <- c(max(panels$col), max(panels$row)) - + l_axis_column_added <- logical(panel_range$col) r_axis_column_added <- logical(panel_range$col) t_axis_row_added <- logical(panel_range$row) b_axis_row_added <- logical(panel_range$row) - + for (i in nrow(panels):1) { p <- panels[i,] # Bottom @@ -131,19 +83,19 @@ FacetGridRepeatLabels <- ggplot2::ggproto('FacetGridRepeatLabels', `_inherit`=gg coord <- table$layout[table$layout$name == p$name, ] if (b_axis_row_added[p$row] == FALSE) { b_axis_row_added[p$row] <- TRUE - table <- gtable_add_rows(table, max_height(axis_b), coord$b) + table <- gtable::gtable_add_rows(table, max_height(axis_b), coord$b) } - table <- gtable_add_grob(table, axis_b[[p$col]], t=coord$b+1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-b-%d-%d', p$col, p$row)) + table <- gtable::gtable_add_grob(table, axis_b[[p$col]], t=coord$b+1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-b-%d-%d', p$col, p$row)) } # Left if (p$col > 1 & !inherits(axis_l[[p$row]], 'zeroGrob')) { # panel is not left-most column, (add column), add axis coord <- table$layout[table$layout$name == p$name, ] if (l_axis_column_added[p$col] == FALSE) { l_axis_column_added[p$col] <- TRUE - table <- gtable_add_cols(table, max_width(axis_l), coord$l-1) - table <- gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) + table <- gtable::gtable_add_cols(table, max_width(axis_l), coord$l-1) + table <- gtable::gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) } else { - table <- gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l-1, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) + table <- gtable::gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l-1, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) } } # Top @@ -151,148 +103,26 @@ FacetGridRepeatLabels <- ggplot2::ggproto('FacetGridRepeatLabels', `_inherit`=gg coord <- table$layout[table$layout$name == p$name, ] if (t_axis_row_added[p$row] == FALSE) { t_axis_row_added[p$row] <- TRUE - table <- gtable_add_rows(table, max_height(axis_t), coord$t-1) - table <- gtable_add_grob(table, axis_t[[p$col]], t=coord$t, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) + table <- gtable::gtable_add_rows(table, max_height(axis_t), coord$t-1) + table <- gtable::gtable_add_grob(table, axis_t[[p$col]], t=coord$t, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) } else { - table <- gtable_add_grob(table, axis_t[[p$col]], t=coord$t-1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) + table <- gtable::gtable_add_grob(table, axis_t[[p$col]], t=coord$t-1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) } - + } # Right if (p$col != panel_range$col & !inherits(axis_l[[p$row]], 'zeroGrob')) { # panel is not right-most, (add colun), add axis coord <- table$layout[table$layout$name == p$name, ] if (r_axis_column_added[p$col] == FALSE) { r_axis_column_added[p$col] <- TRUE - table <- gtable_add_cols(table, max_width(axis_r), coord$r) + table <- gtable::gtable_add_cols(table, max_width(axis_r), coord$r) } - table <- gtable_add_grob(table, axis_r[[p$row]], t=coord$t, b=coord$b, l=coord$r+1, clip='off', name=sprintf('axis-r-%d-%d', p$row, p$col)) + table <- gtable::gtable_add_grob(table, axis_r[[p$row]], t=coord$t, b=coord$b, l=coord$r+1, clip='off', name=sprintf('axis-r-%d-%d', p$row, p$col)) } - + } - + table } ) -# facet_wrap --------------- -NULL - -#' Wrap a 1d ribbon of panels into 2d -#' -#' \code{facet_wrap} wraps a 1d sequence of panels into 2d. This is generally -#' a better use of screen space than \code{\link{facet_grid}} because most -#' displays are roughly rectangular. -#' -#' @param facets Either a formula or character vector. Use either a -#' one sided formula, \code{~a + b}, or a character vector, \code{c("a", "b")}. -#' @param nrow,ncol Number of rows and columns. -#' @param scales should Scales be fixed (\code{"fixed"}, the default), -#' free (\code{"free"}), or free in one dimension (\code{"free_x"}, -#' \code{"free_y"}). -#' @param strip.position By default, the labels are displayed on the top of -#' the plot. Using \code{strip.position} it is possible to place the labels on -#' either of the four sides by setting \code{strip.position = c("top", -#' "bottom", "left", "right")} -#' @param dir Direction: either "h" for horizontal, the default, or "v", for -#' vertical. -#' @inheritParams facet_rep_grid -#' @export -facet_rep_wrap <- function(facets, shrink=TRUE, repeat.tick.labels=FALSE, .debug=FALSE, ...) { - f <- facet_wrap(facets, shrink=shrink, ...) - params <- append(f$params, list(repeat.tick.labels=repeat.tick.labels, .debug=.debug)) - ggproto(NULL, FacetWrapRepeatLabels, - shrink=shrink, - params=params) -} - -#' @rdname ggplot2-ggproto -#' @format NULL -#' @usage NULL -#' @export -#' @importFrom ggplot2 FacetWrap ggproto -#' @importFrom gtable gtable_add_cols gtable_add_grob gtable_add_rows -FacetWrapRepeatLabels <- ggplot2::ggproto('FacetWrapRepeatLabels', `_inherit`=ggplot2::FacetWrap, - draw_panels = function(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { - table <- FacetWrap$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) - if (params$.debug) { saveRDS(table, file='table.rds')} - - # Add axes across all panels - panels <- table$layout[grepl("^panel", table$layout$name), , drop = FALSE] - #cord <- do.call(rbind, strsplit(panels$name, split='-', fixed = TRUE)) - panels$col <- as.integer(as.factor(panels$l))# as.integer(cord[,3]) - panels$row <- as.integer(as.factor(panels$t))#as.integer(cord[,2]) - - # axes are placed on all four sides of **all** panels, but are in most cases zeroGrobs. - # - - axis_b <- table$grobs[grepl('axis-b-[[:digit:]]+', table$layout$name)] - axis_l <- table$grobs[grepl('axis-l-[[:digit:]]+', table$layout$name)] - axis_t <- table$grobs[grepl('axis-t-[[:digit:]]+', table$layout$name)] - axis_r <- table$grobs[grepl('axis-r-[[:digit:]]+', table$layout$name)] - - if (params$repeat.tick.labels == FALSE) { - axis_b <- lapply(axis_b, remove_labels_from_axis) - axis_l <- lapply(axis_l, remove_labels_from_axis) - axis_t <- lapply(axis_t, remove_labels_from_axis) - axis_r <- lapply(axis_r, remove_labels_from_axis) - } - - # panel_range <- ggplot2:::find_panel(table) - # panel_range[,c('col','row')] <- c(max(panels$col), max(panels$row)) - # - # l_axis_column_added <- logical(panel_range$col) - # r_axis_column_added <- logical(panel_range$col) - # t_axis_row_added <- logical(panel_range$row) - # b_axis_row_added <- logical(panel_range$row) - - - - for (i in nrow(panels):1) { - p <- panels[i,] - # Bottom - if (p$row != panel_range$row & !inherits(axis_b[[p$col]], 'zeroGrob')) { # panel not in bottom row, (add row), add axis - coord <- table$layout[table$layout$name == p$name, ] - if (b_axis_row_added[p$row] == FALSE) { - b_axis_row_added[p$row] <- TRUE - table <- gtable_add_rows(table, max_height(axis_b), coord$b) - } - table <- gtable_add_grob(table, axis_b[[p$col]], t=coord$b+1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-b-%d-%d', p$col, p$row)) - } - # Left - if (p$col > 1 & !inherits(axis_l[[p$row]], 'zeroGrob')) { # panel is not left-most column, (add column), add axis - coord <- table$layout[table$layout$name == p$name, ] - if (l_axis_column_added[p$col] == FALSE) { - l_axis_column_added[p$col] <- TRUE - table <- gtable_add_cols(table, max_width(axis_l), coord$l-1) - table <- gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) - } else { - table <- gtable_add_grob(table, axis_l[[p$row]], t=coord$t, b=coord$b, l=coord$l-1, clip='off', name=sprintf('axis-l-%d-%d', p$row, p$col)) - } - } - # Top - if (p$row > 1 & !inherits(axis_t[[p$col]], 'zeroGrob')) { # panel not in top row, (add row), add axis - coord <- table$layout[table$layout$name == p$name, ] - if (t_axis_row_added[p$row] == FALSE) { - t_axis_row_added[p$row] <- TRUE - table <- gtable_add_rows(table, max_height(axis_t), coord$t-1) - table <- gtable_add_grob(table, axis_t[[p$col]], t=coord$t, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) - } else { - table <- gtable_add_grob(table, axis_t[[p$col]], t=coord$t-1, l=coord$l, r=coord$r, clip='off', name=sprintf('axis-t-%d-%d', p$col, p$row)) - } - - } - # Right - if (p$col != panel_range$col & !inherits(axis_l[[p$row]], 'zeroGrob')) { # panel is not right-most, (add colun), add axis - coord <- table$layout[table$layout$name == p$name, ] - if (r_axis_column_added[p$col] == FALSE) { - r_axis_column_added[p$col] <- TRUE - table <- gtable_add_cols(table, max_width(axis_r), coord$r) - } - table <- gtable_add_grob(table, axis_r[[p$row]], t=coord$t, b=coord$b, l=coord$r+1, clip='off', name=sprintf('axis-r-%d-%d', p$row, p$col)) - } - - } - - table - } -) \ No newline at end of file diff --git a/R/facet-wrap.r b/R/facet-wrap.r new file mode 100644 index 0000000..1379472 --- /dev/null +++ b/R/facet-wrap.r @@ -0,0 +1,185 @@ +#' @include ggplot2.r +NULL + +#' @rdname facet_rep +#' @inheritParams facet_rep_grid +#' @import ggplot2 +#' @export +facet_rep_wrap <- function(..., repeat.tick.labels=FALSE) { + f <- facet_wrap(...) + params <- append(f$params, list(repeat.tick.labels=repeat.tick.labels)) + ggplot2::ggproto(NULL, FacetWrapRepeatLabels, + shrink=f$shrink, + params=params) +} + + +#' @rdname splot-ggproto +#' @keywords internal +#' @format NULL +#' @usage NULL +#' @export +#' @import ggplot2 +#' @import gtable +FacetWrapRepeatLabels <- ggplot2::ggproto('FacetWrapRepeatLabels', + `_inherit`=ggplot2::FacetWrap, + draw_panels = function(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { + # If coord is non-cartesian and (x is free or y is free) + # then throw error + if ((!inherits(coord, "CoordCartesian")) && (params$free$x || params$free$y)) { + stop("ggplot2 does not currently support free scales with a non-cartesian coord", call. = FALSE) + } + if (inherits(coord, "CoordFlip")) { + if (params$free$x) { + layout$SCALE_X <- seq_len(nrow(layout)) + } else { + layout$SCALE_X <- 1L + } + if (params$free$y) { + layout$SCALE_Y <- seq_len(nrow(layout)) + } else { + layout$SCALE_Y <- 1L + } + } + + ncol <- max(layout$COL) + nrow <- max(layout$ROW) + n <- nrow(layout) + panel_order <- order(layout$ROW, layout$COL) + layout <- layout[panel_order, ] + panels <- panels[panel_order] + panel_pos <- ggplot2:::convertInd(layout$ROW, layout$COL, nrow) + + axes <- ggplot2:::render_axes(ranges, ranges, coord, theme, transpose = TRUE) + + labels_df <- layout[names(params$facets)] + attr(labels_df, "facet") <- "wrap" + strips <- ggplot2::render_strips( + structure(labels_df, type = "rows"), + structure(labels_df, type = "cols"), + params$labeller, theme) + + # If user hasn't set aspect ratio, and we have fixed scales, then + # ask the coordinate system if it wants to specify one + aspect_ratio <- theme$aspect.ratio + if (is.null(aspect_ratio) && !params$free$x && !params$free$y) { + aspect_ratio <- coord$aspect(ranges[[1]]) + } + + if (is.null(aspect_ratio)) { + aspect_ratio <- 1 + respect <- FALSE + } else { + respect <- TRUE + } + + empty_table <- matrix(list(ggplot2::zeroGrob()), nrow = nrow, ncol = ncol) + panel_table <- empty_table + panel_table[panel_pos] <- panels + empties <- apply(panel_table, c(1,2), function(x) ggplot2:::is.zero(x[[1]])) + panel_table <- gtable_matrix("layout", panel_table, + widths = unit(rep(1, ncol), "null"), + heights = unit(rep(aspect_ratio, nrow), "null"), respect = respect, clip = "on", z = matrix(1, ncol = ncol, nrow = nrow)) + panel_table$layout$name <- paste0('panel-', rep(seq_len(ncol), nrow), '-', rep(seq_len(nrow), each = ncol)) + + panel_table <- gtable::gtable_add_col_space(panel_table, + theme$panel.spacing.x %||% theme$panel.spacing) + panel_table <- gtable::gtable_add_row_space(panel_table, + theme$panel.spacing.y %||% theme$panel.spacing) + + # Add axes + axis_mat_x_top <- empty_table + axis_mat_x_top[panel_pos] <- axes$x$top[layout$SCALE_X] + axis_mat_x_bottom <- empty_table + axis_mat_x_bottom[panel_pos] <- axes$x$bottom[layout$SCALE_X] + axis_mat_y_left <- empty_table + axis_mat_y_left[panel_pos] <- axes$y$left[layout$SCALE_Y] + axis_mat_y_right <- empty_table + axis_mat_y_right[panel_pos] <- axes$y$right[layout$SCALE_Y] + #if (!params$free$x) { + # axis_mat_x_top[-1,]<- list(zeroGrob()) + # axis_mat_x_bottom[-nrow,]<- list(zeroGrob()) + #} + #if (!params$free$y) { + # axis_mat_y_left[, -1] <- list(zeroGrob()) + # axis_mat_y_right[, -ncol] <- list(zeroGrob()) + #} + if (!params$repeat.tick.labels) { + axis_mat_x_top[-1,] <- lapply(axis_mat_x_top[-1,], remove_labels_from_axis) + axis_mat_x_bottom[-nrow,] <- lapply(axis_mat_x_bottom[-nrow,], remove_labels_from_axis) + axis_mat_y_left[,-1] <- lapply(axis_mat_y_left[,-1], remove_labels_from_axis) + axis_mat_y_right[, -ncol] <- lapply(axis_mat_y_right[, -ncol], remove_labels_from_axis) + } + axis_height_top <- unit(apply(axis_mat_x_top, 1, max_height), "cm") + axis_height_bottom <- unit(apply(axis_mat_x_bottom, 1, max_height), "cm") + axis_width_left <- unit(apply(axis_mat_y_left, 2, max_width), "cm") + axis_width_right <- unit(apply(axis_mat_y_right, 2, max_width), "cm") + # Add back missing axes + if (any(empties)) { + first_row <- which(apply(empties, 1, any))[1] - 1 + first_col <- which(apply(empties, 2, any))[1] - 1 + row_panels <- which(layout$ROW == first_row & layout$COL > first_col) + row_pos <- ggplot2:::convertInd(layout$ROW[row_panels], layout$COL[row_panels], nrow) + row_axes <- axes$x$bottom[layout$SCALE_X[row_panels]] + col_panels <- which(layout$ROW > first_row & layout$COL == first_col) + col_pos <- ggplot2:::convertInd(layout$ROW[col_panels], layout$COL[col_panels], nrow) + col_axes <- axes$y$right[layout$SCALE_Y[col_panels]] + if (params$strip.position == "bottom" && + theme$strip.placement != "inside" && + any(!vapply(row_axes, is.zero, logical(length(row_axes))))) { + warning("Suppressing axis rendering when strip.position = 'bottom' and strip.placement == 'outside'", call. = FALSE) + } else { + axis_mat_x_bottom[row_pos] <- row_axes + } + if (params$strip.position == "right" && + theme$strip.placement != "inside" && + any(!vapply(col_axes, is.zero, logical(length(col_axes))))) { + warning("Suppressing axis rendering when strip.position = 'right' and strip.placement == 'outside'", call. = FALSE) + } else { + axis_mat_y_right[col_pos] <- col_axes + } + } + panel_table <- ggplot2:::weave_tables_row(panel_table, axis_mat_x_top, -1, axis_height_top, "axis-t", 3) + panel_table <- ggplot2:::weave_tables_row(panel_table, axis_mat_x_bottom, 0, axis_height_bottom, "axis-b", 3) + panel_table <- ggplot2:::weave_tables_col(panel_table, axis_mat_y_left, -1, axis_width_left, "axis-l", 3) + panel_table <- ggplot2:::weave_tables_col(panel_table, axis_mat_y_right, 0, axis_width_right, "axis-r", 3) + + strip_padding <- convertUnit(theme$strip.switch.pad.wrap, "cm") + strip_name <- paste0("strip-", substr(params$strip.position, 1, 1)) + strip_mat <- empty_table + strip_mat[panel_pos] <- unlist(unname(strips), recursive = FALSE)[[params$strip.position]] + if (params$strip.position %in% c("top", "bottom")) { + inside <- (theme$strip.placement.x %||% theme$strip.placement %||% "inside") == "inside" + if (params$strip.position == "top") { + placement <- if (inside) -1 else -2 + strip_pad <- axis_height_top + } else { + placement <- if (inside) 0 else 1 + strip_pad <- axis_height_bottom + } + strip_height <- unit(apply(strip_mat, 1, max_height), "cm") + panel_table <- ggplot2:::weave_tables_row(panel_table, strip_mat, placement, strip_height, strip_name, 2, "on") + if (!inside) { + strip_pad[unclass(strip_pad) != 0] <- strip_padding + panel_table <- ggplot2:::weave_tables_row(panel_table, row_shift = placement, row_height = strip_pad) + } + } else { + inside <- (theme$strip.placement.y %||% theme$strip.placement %||% "inside") == "inside" + if (params$strip.position == "left") { + placement <- if (inside) -1 else -2 + strip_pad <- axis_width_left + } else { + placement <- if (inside) 0 else 1 + strip_pad <- axis_width_right + } + strip_pad[unclass(strip_pad) != 0] <- strip_padding + strip_width <- unit(apply(strip_mat, 2, max_width), "cm") + panel_table <- ggplot2:::weave_tables_col(panel_table, strip_mat, placement, strip_width, strip_name, 2, "on") + if (!inside) { + strip_pad[unclass(strip_pad) != 0] <- strip_padding + panel_table <- ggplot2:::weave_tables_col(panel_table, col_shift = placement, col_width = strip_pad) + } + } + panel_table + } +) diff --git a/R/ggplot2.r b/R/ggplot2.r index a182388..d90c54e 100644 --- a/R/ggplot2.r +++ b/R/ggplot2.r @@ -5,16 +5,15 @@ #' @import gtable NULL -#' Base ggproto classes for ggplot2 +#' ggproto classes used in splot! #' #' If you are creating a new geom, stat, position, or scale in another package, #' you'll need to extend from \code{ggplot2::Geom}, \code{ggplot2::Stat}, #' \code{ggplot2::Position}, or \code{ggplot2::Scale}. -#' -# -#' @seealso \code{\link[ggplot2]{ggproto}} +#' +#' @seealso \code{\link[ggplot2]{ggproto}}, \code{\link[ggplot2]{ggplot2-ggproto}} #' @keywords internal -#' @name ggplot2-ggproto +#' @name splot-ggproto NULL #' A waiver object. @@ -26,18 +25,19 @@ NULL #' #' Code taken from \file{ggplot2/R/utilities.r}. #' +#' @seealso \code{\link[ggplot2]{waiver}} #' @references ggplot2 -#' @rdname waiver +#' @rdname splot-waiver #' @keywords internal waiver <- function() structure(list(), class = "waiver") #' @param x The object to inquery is a \code{waiver}. -#' @rdname waiver +#' @rdname splot-waiver #' @keywords internal is.waive <- function(x) inherits(x, "waiver") -#' @rdname waiver +#' @rdname splot-waiver #' @keywords internal "%|W|%" <- function(a, b) { if (!is.waive(a)) a else b diff --git a/R/knit_print.r b/R/knit_print.r index 0ad7139..ce6d8ff 100644 --- a/R/knit_print.r +++ b/R/knit_print.r @@ -31,11 +31,11 @@ #' @import knitr knit_print.data.frame = function(x, options, ...) { if (getOption('knit_print', default=TRUE) == FALSE) - return(normal_print(x, options, ...)) + return(knitr::normal_print(x, options, ...)) opts <- options$`kable.opts` if (is.null(opts)) opts <- NULL opts <- RCurl::merge.list(list(x=x, digits=2), opts) - res = paste(c("","", do.call(kable, opts)), collapse="\n") + res = paste(c("","", do.call(knitr::kable, opts)), collapse="\n") asis_output(res) } diff --git a/R/legends.r b/R/legends.r index eeb3838..3405b5e 100644 --- a/R/legends.r +++ b/R/legends.r @@ -16,6 +16,8 @@ NULL #' @import ggplot2 #' @seealso \code{\link{grid_arrange_shared_legend}}, \code{\link{reposition_legend}} #' @examples +#' library(ggplot2) +#' library(grid) #' dsamp <- diamonds[sample(nrow(diamonds), 1000), ] #' (d <- ggplot(dsamp, aes(carat, price)) + #' geom_point(aes(colour = clarity))) @@ -54,6 +56,7 @@ g_legend<-function(a.gplot){ #' @export #' @seealso \code{\link{g_legend}}, \code{\link{reposition_legend}} #' @examples +#' library(ggplot2) #' dsamp <- diamonds[sample(nrow(diamonds), 1000), ] #' p1 <- qplot(carat, price, data = dsamp, colour = clarity) #' p2 <- qplot(cut, price, data = dsamp, colour = clarity) @@ -112,7 +115,7 @@ grid_arrange_shared_legend <- function(..., #' \preformatted{ #' ggplot_gtable(ggplot_build(aplot)) #' } -#' to build a \code{\link[ggplot2]{gtable}} object, and print it to look at the +#' to build a \code{\link[gtable]{gtable}} object, and print it to look at the #' names. #' #' @param aplot a ggplot2 or gtable object. @@ -136,6 +139,7 @@ grid_arrange_shared_legend <- function(..., #' @seealso \code{\link{g_legend}}, \code{\link{grid_arrange_shared_legend}} #' @export #' @examples +#' library(ggplot2) #' dsamp <- diamonds[sample(nrow(diamonds), 1000), ] #' (d <- ggplot(dsamp, aes(carat, price)) + #' geom_point(aes(colour = clarity))) diff --git a/R/splot.r b/R/splot.r index 61e5634..ba9a903 100644 --- a/R/splot.r +++ b/R/splot.r @@ -1,22 +1,36 @@ -#' Stefan's plot package +#' splot! - Stefan's plot library of tricks #' #' Just another ggplot2 extension. -#' +#' #' @section Functions for axis: -#' -#' See \code{\link{coord_capped_cart}} and \code{\link{coord_flex_cart}}. -#' The latter is a shorthand version of the former. -#' It automatically uses \code{\link{capped_horisontal}} and -#' \code{\link{capped_vertical}}, but both accepts these as well as +#' +#' See \code{\link{coord_capped_cart}} and \code{\link{coord_flex_cart}}. +#' The latter is a shorthand version of the former. +#' It automatically uses \code{\link{capped_horisontal}} and +#' \code{\link{capped_vertical}}, but both accepts these as well as #' \code{\link{brackets_horisontal}} and \code{\link{brackets_vertical}}. -#' -#' +#' +#' @section Legends: +#' +#' \describe{ +#' \item{Extract legend}{\code{\link{g_legend}}} +#' \item{Many plots, one legend}{\code{\link{grid_arrange_shared_legend}}} +#' \item{Place legend exactly on plot}{\code{\link{reposition_legend}}} +#' } +#' +#' @section Facets: +#' +#' \code{\link{facet_rep_grid}} and \code{\link{facet_rep_wrap}} are extensions +#' to the wellknown \code{\link[ggplot2]{facet_grid}} and +#' \code{\link[ggplot2]{facet_wrap}} where axis lines and labels are drawn on +#' all panels. +#' #' @section Extending knitr: -#' -#' We automatically load knitr's \code{\link[knitr]{knit_print}} for +#' +#' We automatically load knitr's \code{\link[knitr]{knit_print}} for #' data frames and dplyr tables to provide automatic pretty printing of #' data frame using \code{\link[knitr]{kable}}. -#' +#' #' See \code{\link{knit_print.data.frame}}. #' #' @docType package diff --git a/README.Rmd b/README.Rmd index 0ded495..f56ccae 100644 --- a/README.Rmd +++ b/README.Rmd @@ -8,15 +8,48 @@ output: github_document knitr::opts_chunk$set( collapse = TRUE, comment = "#>", - fig.path = "README/" + fig.path = "README/", + cache.path = "README/cache/", + cache = TRUE, + autodep=TRUE ) ``` -# splot - Stefan's plotting package +# splot! --- Stefan's plot library of tricks Just another [ggplot2](http://ggplot2.tidyverse.org) and [knitr](https://yihui.name/knitr/) extension package. +This package contains functions primarily in these domains of ggplot2: + +```{r domain_axis_lines,include=FALSE,fig.height=0.5,fig.width=0.5} +library(ggplot2) +library(splot) +ggplot(mtcars, aes(x=cyl, y=mpg)) + + geom_point(size=0.1) + + coord_capped_cart(bottom=brackets_horisontal(), left='both') + + theme_light() + + theme(panel.border=element_blank(), axis.line = element_line(), + axis.title=element_blank(), axis.text=element_blank(), + panel.grid=element_blank(), axis.ticks.x = element_line(colour='black')) +``` +```{r domain_facets,include=FALSE,fig.height=0.5, fig.width=0.5} +ggplot(mtcars, aes(x=cyl, y=mpg)) + + geom_point(size=0.1) + + coord_capped_cart(bottom='both', left='both') + + facet_rep_wrap(~carb) + + theme_light() + + theme(panel.border=element_blank(), axis.line = element_line(), + axis.title=element_blank(), axis.text=element_blank(), + panel.grid=element_blank(), axis.ticks = element_blank(), + axis.ticks.length = unit(0, 'npc'), panel.spacing=unit(1, 'mm'), + strip.background=element_blank(), strip.text=element_blank()) +``` + +* ![Axis lines miniature](README/domain_axis_lines-1.png) Axis lines +* ![Facets miniature](README/domain_facets-1.png) Repeated axis lines on facets. +* Legends +* knitr ## Installation @@ -32,7 +65,7 @@ devtools::install_github("stefanedwards/splot") -## Usage +## Axis lines We can display a limit on the axes range. ```{r usage1} @@ -47,25 +80,51 @@ ggplot(mtcars, aes(x=cyl, y=mpg)) + We could also show that the x-axis is categorical (or ordinal): ```{r brackets_demo} -ggplot(mtcars, aes(x=as.factor(cyl), y=mpg)) + +(p <- ggplot(mtcars, aes(x=as.factor(cyl), y=mpg)) + geom_point(position=position_jitter(width=0.1)) + - coord_flex_cart(bottom=brackets_horisontal(), left=capped_vertical('none')) + + coord_flex_cart(bottom=brackets_horisontal(), left=capped_vertical('both')) + theme_light() + theme(panel.border=element_blank(), axis.line = element_line()) +) ``` +When capping the axis lines, they are never capped further inwards than the ticks! +Look up + +* `coord_capped_cart`, `coord_capped_flip` +* `coord_flex_cart`, `coord_flex_flip`, `coord_flex_fixed` +* `brackets_horisontal`, `brackets_vertical` +* `capped_horisontal`, `capped_vertical` + +## Facets + +Having produced such wonderous axes, it is a pity they are not plotted around +all panels when using faceting. +We have extended both `facet_grid` and `facet_wrap` to produce axis, ticks, and +labels on _all_ panels: + +```{r facets} +p + facet_rep_wrap(~gear, ncol=2, label=label_both) +``` + +They work just like the normal ones; look up `facet_rep_grid` and `facet_rep_wrap`. ## Legends +Reposition the legend onto the plot. Exactly where you want it: +```{r reposition_legend,fig.cap='The legend repositioned onto the top left corner of the panel.'} +dsamp <- diamonds[sample(nrow(diamonds), 1000), ] +d <- ggplot(dsamp, aes(carat, price)) + + geom_point(aes(colour = clarity)) +reposition_legend(d, 'top left') +``` + Scavenging the Internet, we have found some functions that help work with legends. Frequently appearing on [Stack Overflow](http://stackoverflow.com), we bring you `g_legend`: -```{r g_legend} -dsamp <- diamonds[sample(nrow(diamonds), 1000), ] -(d <- ggplot(dsamp, aes(carat, price)) + -geom_point(aes(colour = clarity))) - +```{r g_legend,fig.height=3,fig.width=2,fig.cap='The legend grob, by itself.'} +library(grid) legend <- g_legend(d) grid.newpage() grid.draw(legend) @@ -78,7 +137,7 @@ brought us the ([original](https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs)). We put it in a package. -```{r grid_arrange_shared_legend} +```{r grid_arrange_shared_legend,fig.cap='Four plots that share the same legend.'} dsamp <- diamonds[sample(nrow(diamonds), 1000), ] p1 <- qplot(carat, price, data = dsamp, colour = clarity) p2 <- qplot(cut, price, data = dsamp, colour = clarity) @@ -116,7 +175,6 @@ See `knit_print.data.frame`. ## To do: -* Implement `facet` objects that repeat axes * Describe coord objects in capped-axes vignette. * Add `.dot` functions to knitr. * Describe facets in this file. diff --git a/README.md b/README.md index 4a98607..d55cc5d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,17 @@ -splot - Stefan's plotting package -================================= +splot! - Stefan's plot library of tricks +======================================== Just another [ggplot2](http://ggplot2.tidyverse.org) and [knitr](https://yihui.name/knitr/) extension package. +This package contains functions primarily in these domains of ggplot2: + +- ![Axis lines miniature](README/domain_axis_lines-1.png) Axis lines +- ![Facets miniature](README/domain_facets-1.png) Repeated axis lines on facets. +- Legends +- knitr + Installation ------------ @@ -25,10 +32,6 @@ We can display a limit on the axes range. ``` r library(splot) -#> Loading required package: ggplot2 -#> Loading required package: grid -#> Loading required package: gridExtra -#> Loading required package: gtable ggplot(mtcars, aes(x=cyl, y=mpg)) + geom_point() + coord_capped_cart(bottom='both', left='none') + @@ -53,26 +56,29 @@ ggplot(mtcars, aes(x=as.factor(cyl), y=mpg)) + Legends ------- -Scavenging the Internet, we have found some functions that help work with legends. - -Frequently appearing on [Stack Overflow](http://stackoverflow.com), we bring you `g_legend`: +Reposition the legend onto the plot. Exactly where you want it: ``` r dsamp <- diamonds[sample(nrow(diamonds), 1000), ] -(d <- ggplot(dsamp, aes(carat, price)) + -geom_point(aes(colour = clarity))) +d <- ggplot(dsamp, aes(carat, price)) + + geom_point(aes(colour = clarity)) +reposition_legend(d, 'top left') ``` -![](README/g_legend-1.png) +![The legend repositioned onto the top left corner of the panel.](README/reposition_legend-1.png) -``` r +Scavenging the Internet, we have found some functions that help work with legends. +Frequently appearing on [Stack Overflow](http://stackoverflow.com), we bring you `g_legend`: + +``` r +library(grid) legend <- g_legend(d) grid.newpage() grid.draw(legend) ``` -![](README/g_legend-2.png) +![The legend grob, by itself.](README/g_legend-1.png) [Shaun Jackman](http://rpubs.com/sjackman) [originally](%5Bhttp://rpubs.com/sjackman/grid_arrange_shared_legend) brought us the `grid_arrange_shared_legend`, which was furhter refined by `baptiste` ([original](https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs)). We put it in a package. @@ -85,7 +91,7 @@ p4 <- qplot(depth, price, data = dsamp, colour = clarity) grid_arrange_shared_legend(p1, p2, p3, p4, ncol = 2, nrow = 2) ``` -![](README/grid_arrange_shared_legend-1.png) +![Four plots that share the same legend.](README/grid_arrange_shared_legend-1.png) Extensions to knitr ------------------- @@ -126,5 +132,4 @@ See `knit_print.data.frame`. To do: ------ -- Implement `facet` objects that repeat axes - Describe coord objects in capped-axes vignette. diff --git a/README/domain_axis_lines-1.png b/README/domain_axis_lines-1.png new file mode 100644 index 0000000..45f8f74 Binary files /dev/null and b/README/domain_axis_lines-1.png differ diff --git a/README/domain_facets-1.png b/README/domain_facets-1.png new file mode 100644 index 0000000..bf28306 Binary files /dev/null and b/README/domain_facets-1.png differ diff --git a/README/g_legend-1.png b/README/g_legend-1.png index a7cbfa9..e932760 100644 Binary files a/README/g_legend-1.png and b/README/g_legend-1.png differ diff --git a/README/reposition_legend-1.png b/README/reposition_legend-1.png new file mode 100644 index 0000000..bd5dc8f Binary files /dev/null and b/README/reposition_legend-1.png differ diff --git a/README/reposition_legend-2.png b/README/reposition_legend-2.png new file mode 100644 index 0000000..bd5dc8f Binary files /dev/null and b/README/reposition_legend-2.png differ diff --git a/man/brackets.Rd b/man/brackets.Rd index 3ce94a3..f4af419 100644 --- a/man/brackets.Rd +++ b/man/brackets.Rd @@ -37,6 +37,7 @@ It does not re-calculate tick marks, but lets \code{scale_x_*} and \code{scale_y calculate and draw ticks and labels, and then modifies the ticks with brackets. } \examples{ +library(ggplot2) p <- ggplot(mpg, aes(as.factor(cyl), hwy, colour=class)) + geom_point(position=position_jitter(width=0.3)) + theme_bw() + @@ -51,4 +52,3 @@ p # A further adjustment, p + theme(panel.grid.major.x = element_blank()) } - diff --git a/man/coord_capped.Rd b/man/coord_capped.Rd index 21e83ee..eb44e52 100644 --- a/man/coord_capped.Rd +++ b/man/coord_capped.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/coord-capped.r \name{coord_capped_cart} -\alias{capped_horisontal} -\alias{capped_vertical} \alias{coord_capped_cart} \alias{coord_capped_flip} +\alias{capped_horisontal} +\alias{capped_vertical} \title{Cartesian coordinates with capped axis lines.} \usage{ coord_capped_cart(xlim = NULL, ylim = NULL, expand = TRUE, @@ -53,6 +53,7 @@ To ensure the modified axis lines are visible, use \code{theme(panel.border=element_blank(), axis.lines=element_line())}. } \examples{ +library(ggplot2) # Notice how the axis lines of the following plot meet in the lower-left corner. p <- ggplot(mtcars, aes(x = mpg)) + geom_dotplot() + theme_bw() + @@ -77,4 +78,3 @@ p + coord_capped_cart(bottom='none', left='none', right='both', top=brackets_horisontal()) # Although we cannot recommend the above madness. } - diff --git a/man/coord_flex.Rd b/man/coord_flex.Rd index 4f3b124..4d9114e 100644 --- a/man/coord_flex.Rd +++ b/man/coord_flex.Rd @@ -2,8 +2,8 @@ % Please edit documentation in R/coord-flex.r \name{coord_flex_cart} \alias{coord_flex_cart} -\alias{coord_flex_fixed} \alias{coord_flex_flip} +\alias{coord_flex_fixed} \title{Cartesian coordinates with flexible options for drawing axes} \usage{ coord_flex_cart(xlim = NULL, ylim = NULL, expand = TRUE, top = waiver(), @@ -51,8 +51,9 @@ and the function should return an \code{\link{absoluteGrob}} object. For examples of modifying the drawn object, see e.g. \code{\link{capped_horisontal}} or \code{\link{brackets_horisontal}}. } -\examples{ +\examples{ +library(ggplot2) # A standard plot p <- ggplot(mtcars, aes(disp, wt)) + geom_point() + @@ -78,7 +79,8 @@ p + coord_flex_cart(left=brackets_vertical(), bottom=capped_horisontal('left')) # Also works with secondary axes: p + scale_y_continuous(sec.axis=sec_axis(~5*., name='wt times 5')) + - coord_flex_cart(left=brackets_vertical(), bottom=capped_horisontal('right'), right=capped_vertical('both', gap=0.02)) + coord_flex_cart(left=brackets_vertical(), bottom=capped_horisontal('right'), + right=capped_vertical('both', gap=0.02)) # Supports the usual 'coord_fixed': @@ -87,4 +89,3 @@ p + coord_flex_fixed(ratio=1.2, bottom=capped_horisontal('right')) # and coord_flip: p + coord_flex_flip(ylim=c(2,5), bottom=capped_horisontal('right')) } - diff --git a/man/facet_rep.Rd b/man/facet_rep.Rd new file mode 100644 index 0000000..3a6ef05 --- /dev/null +++ b/man/facet_rep.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/facet-rep-lab.r, R/facet-wrap.r +\name{facet_rep_grid} +\alias{facet_rep_grid} +\alias{facet_rep_wrap} +\title{Repeat axis lines and labels across all facet panels} +\usage{ +facet_rep_grid(..., repeat.tick.labels = FALSE) + +facet_rep_wrap(..., repeat.tick.labels = FALSE) +} +\arguments{ +\item{...}{Arguments used for \code{\link[ggplot2]{facet_grid}} or +\code{\link[ggplot2]{facet_wrap}}.} + +\item{repeat.tick.labels}{Logical, removes the labels (numbering) on an inner +axes when \code{FALSE}.} +} +\description{ +\code{\link[ggplot2]{facet_grid}} and \code{\link[ggplot2]{facet_wrap}}, but +with axis lines and labels preserved on all panels. +} diff --git a/man/facet_rep_grid.Rd b/man/facet_rep_grid.Rd deleted file mode 100644 index 4b3fd5e..0000000 --- a/man/facet_rep_grid.Rd +++ /dev/null @@ -1,75 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/facet-rep-lab.r -\name{facet_rep_grid} -\alias{facet_rep_grid} -\title{Lay out panels in a grid with axes replicated across all panels.} -\usage{ -facet_rep_grid(facets, shrink = TRUE, repeat.tick.labels = FALSE, - .debug = FALSE, ...) -} -\arguments{ -\item{facets}{a formula with the rows (of the tabular display) on the LHS -and the columns (of the tabular display) on the RHS; the dot in the -formula is used to indicate there should be no faceting on this dimension -(either row or column). The formula can also be provided as a string -instead of a classical formula object} - -\item{shrink}{If \code{TRUE}, will shrink scales to fit output of -statistics, not raw data. If \code{FALSE}, will be range of raw data -before statistical summary.} - -\item{repeat.tick.labels}{Logical, removes the labels (numbering) on an axis when \code{FALSE}.} - -\item{margins}{either a logical value or a character -vector. Margins are additional facets which contain all the data -for each of the possible values of the faceting variables. If -\code{FALSE}, no additional facets are included (the -default). If \code{TRUE}, margins are included for all faceting -variables. If specified as a character vector, it is the names of -variables for which margins are to be created.} - -\item{scales}{Are scales shared across all facets (the default, -\code{"fixed"}), or do they vary across rows (\code{"free_x"}), -columns (\code{"free_y"}), or both rows and columns (\code{"free"})} - -\item{space}{If \code{"fixed"}, the default, all panels have the same size. - If \code{"free_y"} their height will be proportional to the length of the - y scale; if \code{"free_x"} their width will be proportional to the -length of the x scale; or if \code{"free"} both height and width will -vary. This setting has no effect unless the appropriate scales also vary.} - -\item{labeller}{A function that takes one data frame of labels and -returns a list or data frame of character vectors. Each input -column corresponds to one factor. Thus there will be more than -one with formulae of the type \code{~cyl + am}. Each output -column gets displayed as one separate line in the strip -label. This function should inherit from the "labeller" S3 class -for compatibility with \code{\link{labeller}()}. See -\code{\link{label_value}} for more details and pointers to other -options.} - -\item{as.table}{If \code{TRUE}, the default, the facets are laid out like -a table with highest values at the bottom-right. If \code{FALSE}, the -facets are laid out like a plot with the highest value at the top-right.} - -\item{switch}{By default, the labels are displayed on the top and -right of the plot. If \code{"x"}, the top labels will be -displayed to the bottom. If \code{"y"}, the right-hand side -labels will be displayed to the left. Can also be set to -\code{"both"}.} - -\item{drop}{If \code{TRUE}, the default, all factor levels not used in the -data will automatically be dropped. If \code{FALSE}, all factor levels -will be shown, regardless of whether or not they appear in the data.} -} -\description{ -\strong{Documentation is straight from \code{\link[ggplot2]{facet_grid}}.} -Only addition is this function \emph{copies the axis across all panels}. -\code{repeat.tick.labels=FALSE} removes the labels (numbering) on an axis. -} -\details{ -\code{facet_grid} forms a matrix of panels defined by row and column -facetting variables. It is most useful when you have two discrete -variables, and all combinations of the variables exist in the data. -} - diff --git a/man/facet_rep_wrap.Rd b/man/facet_rep_wrap.Rd deleted file mode 100644 index a5479f1..0000000 --- a/man/facet_rep_wrap.Rd +++ /dev/null @@ -1,39 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/facet-rep-lab.r -\name{facet_rep_wrap} -\alias{facet_rep_wrap} -\title{Wrap a 1d ribbon of panels into 2d} -\usage{ -facet_rep_wrap(facets, shrink = TRUE, repeat.tick.labels = FALSE, - .debug = FALSE, ...) -} -\arguments{ -\item{facets}{Either a formula or character vector. Use either a -one sided formula, \code{~a + b}, or a character vector, \code{c("a", "b")}.} - -\item{shrink}{If \code{TRUE}, will shrink scales to fit output of -statistics, not raw data. If \code{FALSE}, will be range of raw data -before statistical summary.} - -\item{repeat.tick.labels}{Logical, removes the labels (numbering) on an axis when \code{FALSE}.} - -\item{nrow, ncol}{Number of rows and columns.} - -\item{scales}{should Scales be fixed (\code{"fixed"}, the default), -free (\code{"free"}), or free in one dimension (\code{"free_x"}, -\code{"free_y"}).} - -\item{strip.position}{By default, the labels are displayed on the top of -the plot. Using \code{strip.position} it is possible to place the labels on -either of the four sides by setting \code{strip.position = c("top", -"bottom", "left", "right")}} - -\item{dir}{Direction: either "h" for horizontal, the default, or "v", for -vertical.} -} -\description{ -\code{facet_wrap} wraps a 1d sequence of panels into 2d. This is generally -a better use of screen space than \code{\link{facet_grid}} because most -displays are roughly rectangular. -} - diff --git a/man/g_legend.Rd b/man/g_legend.Rd index 01dfbe0..b85971d 100644 --- a/man/g_legend.Rd +++ b/man/g_legend.Rd @@ -21,6 +21,8 @@ applied. Modifying the legend is easiest by applying themes etc. to the ggplot2 object, before calling \code{g_legend}. } \examples{ +library(ggplot2) +library(grid) dsamp <- diamonds[sample(nrow(diamonds), 1000), ] (d <- ggplot(dsamp, aes(carat, price)) + geom_point(aes(colour = clarity))) @@ -29,10 +31,9 @@ legend <- g_legend(d) grid.newpage() grid.draw(legend) } -\author{ -Stack Overflow -} \seealso{ \code{\link{grid_arrange_shared_legend}}, \code{\link{reposition_legend}} } - +\author{ +Stack Overflow +} diff --git a/man/grid_arrange_shared_legend.Rd b/man/grid_arrange_shared_legend.Rd index 07538bb..6bf7f46 100644 --- a/man/grid_arrange_shared_legend.Rd +++ b/man/grid_arrange_shared_legend.Rd @@ -34,6 +34,7 @@ Extract legend, combines plots using \code{\link[gridExtra]{arrangeGrob}}, and places legend underneath. } \examples{ +library(ggplot2) dsamp <- diamonds[sample(nrow(diamonds), 1000), ] p1 <- qplot(carat, price, data = dsamp, colour = clarity) p2 <- qplot(cut, price, data = dsamp, colour = clarity) @@ -45,4 +46,3 @@ grid_arrange_shared_legend(p1, p2, p3, p4, ncol = 2, nrow = 2) \seealso{ \code{\link{g_legend}}, \code{\link{reposition_legend}} } - diff --git a/man/if-not-null.Rd b/man/if-not-null.Rd index 286c121..6038838 100644 --- a/man/if-not-null.Rd +++ b/man/if-not-null.Rd @@ -1,8 +1,8 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/ggplot2.r \name{if-not-null} -\alias{\%||\%} \alias{if-not-null} +\alias{\%||\%} \title{Return if not null} \usage{ a \%||\% b @@ -14,4 +14,3 @@ Returns second argument if first argument is \code{NULL}. Code taken from \file{ggplot2/R/utilities.r}. } \keyword{internal} - diff --git a/man/knit_print.Rd b/man/knit_print.Rd index 2bb08ca..f34aca8 100644 --- a/man/knit_print.Rd +++ b/man/knit_print.Rd @@ -2,8 +2,8 @@ % Please edit documentation in R/knit_print.r \name{knit_print.data.frame} \alias{knit_print.data.frame} -\alias{knit_print.grouped_df} \alias{knit_print.tbl_df} +\alias{knit_print.grouped_df} \title{knitr extension: Always use `kable` for data frames.} \usage{ \method{knit_print}{data.frame}(x, options, ...) @@ -42,4 +42,3 @@ data.frame \code{\link[knitr]{knit_print}}, \code{\link[knitr]{kable}} } \keyword{print} - diff --git a/man/remove_labels_from_axis.Rd b/man/remove_labels_from_axis.Rd index f12a3af..bcd3cf7 100644 --- a/man/remove_labels_from_axis.Rd +++ b/man/remove_labels_from_axis.Rd @@ -13,4 +13,3 @@ remove_labels_from_axis(axisgrob) Called from FacetGridRepeatLabels. } \keyword{interal} - diff --git a/man/reposition_legend.Rd b/man/reposition_legend.Rd index df9ab34..40aab8b 100644 --- a/man/reposition_legend.Rd +++ b/man/reposition_legend.Rd @@ -47,10 +47,11 @@ form \code{panel-{col}-{row}}. Use \preformatted{ ggplot_gtable(ggplot_build(aplot)) } -to build a \code{\link[ggplot2]{gtable}} object, and print it to look at the +to build a \code{\link[gtable]{gtable}} object, and print it to look at the names. } \examples{ +library(ggplot2) dsamp <- diamonds[sample(nrow(diamonds), 1000), ] (d <- ggplot(dsamp, aes(carat, price)) + geom_point(aes(colour = clarity))) @@ -66,10 +67,9 @@ reposition_legend(d + theme(legend.position='bottom'), x=0.3, y=0, just=c(0, -0. # For using with facets: reposition_legend(d + facet_grid(.~cut), 'top left', panel = 'panel-3-1') } -\author{ -Stefan McKinnon Edwards -} \seealso{ \code{\link{g_legend}}, \code{\link{grid_arrange_shared_legend}} } - +\author{ +Stefan McKinnon Edwards +} diff --git a/man/ggplot2-ggproto.Rd b/man/splot-ggproto.Rd similarity index 73% rename from man/ggplot2-ggproto.Rd rename to man/splot-ggproto.Rd index 8bc054b..9824412 100644 --- a/man/ggplot2-ggproto.Rd +++ b/man/splot-ggproto.Rd @@ -1,22 +1,21 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/ggplot2.r, R/coord-flex.r, R/facet-rep-lab.r +% Please edit documentation in R/ggplot2.r, R/coord-flex.r, R/facet-rep-lab.r, R/facet-wrap.r \docType{data} -\name{ggplot2-ggproto} +\name{splot-ggproto} \alias{CoordFlexCartesian} \alias{CoordFlexFixed} \alias{CoordFlexFlipped} \alias{FacetGridRepeatLabels} \alias{FacetWrapRepeatLabels} -\alias{ggplot2-ggproto} -\title{Base ggproto classes for ggplot2} +\alias{splot-ggproto} +\title{ggproto classes used in splot!} \description{ If you are creating a new geom, stat, position, or scale in another package, you'll need to extend from \code{ggplot2::Geom}, \code{ggplot2::Stat}, \code{ggplot2::Position}, or \code{ggplot2::Scale}. } \seealso{ -\code{\link[ggplot2]{ggproto}} +\code{\link[ggplot2]{ggproto}}, \code{\link[ggplot2]{ggplot2-ggproto}} } -\keyword{datasets} \keyword{internal} diff --git a/man/waiver.Rd b/man/splot-waiver.Rd similarity index 94% rename from man/waiver.Rd rename to man/splot-waiver.Rd index 1713264..96511ea 100644 --- a/man/waiver.Rd +++ b/man/splot-waiver.Rd @@ -27,5 +27,8 @@ Code taken from \file{ggplot2/R/utilities.r}. \references{ ggplot2 } +\seealso{ +\code{\link[ggplot2]{waiver}} +} \keyword{internal} diff --git a/man/splot.Rd b/man/splot.Rd index 72d7ac9..3060761 100644 --- a/man/splot.Rd +++ b/man/splot.Rd @@ -4,7 +4,7 @@ \name{splot} \alias{splot} \alias{splot-package} -\title{Stefan's plot package} +\title{splot! - Stefan's plot library of tricks} \source{ \url{https://github.com/stefanedwards/splot} } @@ -14,17 +14,36 @@ Just another ggplot2 extension. \section{Functions for axis}{ -See \code{\link{coord_capped_cart}} and \code{\link{coord_flex_cart}}. -The latter is a shorthand version of the former. -It automatically uses \code{\link{capped_horisontal}} and -\code{\link{capped_vertical}}, but both accepts these as well as +See \code{\link{coord_capped_cart}} and \code{\link{coord_flex_cart}}. +The latter is a shorthand version of the former. +It automatically uses \code{\link{capped_horisontal}} and +\code{\link{capped_vertical}}, but both accepts these as well as \code{\link{brackets_horisontal}} and \code{\link{brackets_vertical}}. } +\section{Legends}{ + + +\describe{ + \item{Extract legend}{\code{\link{g_legend}}} + \item{Many plots, one legend}{\code{\link{grid_arrange_shared_legend}}} + \item{Place legend exactly on plot}{\code{\link{reposition_legend}}} +} +} + +\section{Facets}{ + + +\code{\link{facet_rep_grid}} and \code{\link{facet_rep_wrap}} are extensions +to the wellknown \code{\link[ggplot2]{facet_grid}} and +\code{\link[ggplot2]{facet_wrap}} where axis lines and labels are drawn on +all panels. +} + \section{Extending knitr}{ -We automatically load knitr's \code{\link[knitr]{knit_print}} for +We automatically load knitr's \code{\link[knitr]{knit_print}} for data frames and dplyr tables to provide automatic pretty printing of data frame using \code{\link[knitr]{kable}}. diff --git a/vignettes/capped-axes.Rmd b/vignettes/capped-axes.Rmd index df90d37..dfb5ace 100644 --- a/vignettes/capped-axes.Rmd +++ b/vignettes/capped-axes.Rmd @@ -24,7 +24,7 @@ A quick demonstration of capping the lines. First, load the package, generate a dataset and display it. ```{r load_pkg_and_data,fig.cap='Default ggplot2 plotting.'} -#library(ggplot2) +library(ggplot2) library(splot) dat1 <- data.frame( @@ -77,25 +77,116 @@ ggplot(dat1, aes(gp, y)) + geom_point(position=position_jitter(width=0.2, height ## The `coord` objects +ggplot2's Cartesian coordinates systems, `coord_cartesian`, have been extended +to allow for flexible specification of how axes are drawn. +You've seen them above. +The following table summarises the connection between ggplot2's coord functions +and those of splot!. + + ggplot2 | splot's flexible | splot's short hand +------------------|--------------------|-------------------- +`coord_cartesian` | `coord_flex_cart` | `coord_capped_cart` +`coord_flip` | `coord_flex_flip` | `coord_capped_flip` +`coord_fixed` | `coord_flex_fixed` | -- + +The short hand functions in the table's right column simply are almost identical +to those in the middle column. +If one of the side arguments are specified with a character value, the +relevant axis drawing function is used. You can however choose to use e.g. +`brackets_horisontal` in place. + +### The axis drawing functions + +The functions `capped_horisontal` or `brackets_vertical` returns a function +that is called when ggplot2 prints the plot. It is called with the arguments + + scale_details, axis, scale, position, theme + +and the function should return a grob. +Some pointers to how it is used can be found in ggplot2's help pages; just run +`?"ggplot2-ggproto"`. +In this package, we use ggplot2 to build the axes, then modify in place the +return grobs. + +### Brackets + +The brackets comes in two orientations: +`brackets_horisontal` and `brackets_vertical`. +If you attempt to use a vertical bracket on a horisontal axis, it will fail with +a undescriptive error. + +The bracket functions accept a `direction` argument, which can be used to control +which direction the end-points are pointing: + +```{r brackets} +p <- ggplot(mpg, aes(cyl, hwy, colour=class)) + + geom_point(position=position_jitter(width=0.3)) + + scale_x_continuous(breaks=c(4,5,6,8), sec.axis=dup_axis()) + + scale_y_continuous(sec.axis=dup_axis()) + + coord_flex_cart(bottom=brackets_horisontal(), + top=brackets_horisontal(direction='down'), + left=brackets_vertical(), + right=brackets_vertical(direction='right')) + + my.theme +p +``` + +The look of the brackets are controlled via `theme(axis.ticks)`. +The length of the end-point are controlled via the theme +`theme(axis.ticks.length)`. If these needs to be specified for each margin, +use the argument `tick.length`: + +```{r} +p <- ggplot(mpg, aes(cyl, hwy, colour=class)) + + geom_point(position=position_jitter(width=0.3)) + + coord_flex_cart(bottom=brackets_horisontal(tick.length=unit(0, 'cm')), + left=brackets_vertical(tick.length = unit(1, 'cm'))) + + my.theme +p +``` +As shown above, using `tick.length=unit(0, 'cm')` results in a flat line. ## Facets -```{r eval=FALSE} +Having produced such wonderous axes, it is a pity they are not plotted around +all panels when using faceting. -# Facet grid ----------------- -ggplot(dat1, aes(gp, y)) + geom_point() + - coord_capped_flip(bottom = 'left', left='none') + - theme(axis.title=element_blank(), plot.title=element_text(size=rel(1))) + - facet_rep_grid(~cl) +```{r} +dsamp <- diamonds[sample(nrow(diamonds), 1000), ] +(d <- ggplot(dsamp, aes(carat, price)) + + geom_point(aes(colour = clarity)) + + coord_capped_cart(bottom='none', left='bottom') + + facet_grid(.~cut) + my.theme +) +``` -dat2 <- rbind(dat1, data.frame(gp=letters[1:3], y=rnorm(3, 2), cl=3, cl2='b')) -ggplot(dat2, aes(gp, y)) + geom_point() + - coord_capped_flip(bottom = 'left', left='none') + - theme(axis.title=element_blank(), plot.title=element_text(size=rel(1))) + - facet_rep_grid(.~cl, scales='free_y') +`facet_grid` and `facet_wrap` have been implemented in versions that display +the axis lines (and labels) on all panels. They work exactly like ggplot2's +functions, and are named with `_rep_`: +```{r} +d + facet_rep_grid(.~cut) +``` + +If we want the labels shown as well, use the argument: +```{r} +d + facet_rep_grid(.~cut, repeat.tick.labels = TRUE) +``` +It also works for `facet_wrap`: +```{r} +(d2 <- d + facet_rep_wrap(~cut, ncol=2)) +``` +Finally, the legend can be repositioned to fit in a panel by using +`reposition_legend`. +See the vignette `legend`. +The addition of `theme(legend.background)` is merely to provide a border around +the legend. +```{r} +d2 <- d2 + guides(colour=guide_legend(ncol=2)) + + theme(legend.background = element_rect(colour='grey')) +reposition_legend(d2, position='center', panel='panel-2-3') ``` Also a quote using `>`: diff --git a/vignettes/legends.Rmd b/vignettes/legends.Rmd index 93e9da8..b41fac3 100644 --- a/vignettes/legends.Rmd +++ b/vignettes/legends.Rmd @@ -32,17 +32,31 @@ in relative measures on the entire plot: ```{r} library(ggplot2) +library(grid) dsamp <- diamonds[sample(nrow(diamonds), 1000), ] (d <- ggplot(dsamp, aes(carat, price)) + geom_point(aes(colour = clarity)) + - theme(legend.position = c(0.1, 0.7)) + theme(legend.position = c(0.06, 0.75)) ) ``` -This is however prone to badly positioning, if e.g. the plot is resized: +This is however prone to badly positioning, if e.g. the plot is resized or +font size changed: + +```{r echo=FALSE,fig.cap='**Left:** Base font size set to 22 pt. **Right:** Zoom on plot that is plotted at 150% size.'} + + +vp1 <- viewport(x=0, y=0, width=unit(0.5, 'npc'), just=c(0,0)) +vp2 <- viewport(x=0.5, y=1, width=unit(1.5, 'npc'), height=unit(1.5, 'npc'), just=c(0,1)) +grid.newpage() +vp0 <- current.viewport() +pushViewport(vp1) +g <- ggplotGrob(d + theme_gray(base_size=26) + theme(legend.position = c(0.06, 0.75))) +grid.draw(g) +popViewport() +pushViewport(vp2) +grid.draw(ggplotGrob(d)) -```{r echo=FALSE,fig.height=3, fig.width=3} -d ``` With our function, we can specify exactly how we want it in the plotting area: @@ -51,11 +65,25 @@ library(splot) reposition_legend(d, 'top left') ``` -And it stays there. -```{r reposition_legend_small,eval=FALSE,fig.height=2, fig.width=2} -reposition_legend(d, 'top left') +And it stays there. Most of the time. +```{r echo=FALSE,fig.cap='**Left:** Base font size set to 22 pt. **Right:** Zoom on plot that is plotted at 150% size.'} + + +vp1 <- viewport(x=0, y=0, width=unit(0.5, 'npc'), just=c(0,0)) +vp2 <- viewport(x=0.5, y=1, width=unit(1.5, 'npc'), height=unit(1.5, 'npc'), just=c(0,1)) +grid.newpage() +vp0 <- current.viewport() +pushViewport(vp1) +grid.draw(reposition_legend(d + theme_gray(base_size=26) + theme(legend.position = 'left'), 'top left', plot=FALSE)) +grid.draw(g) +popViewport() +pushViewport(vp2) +grid.draw(reposition_legend(d, 'top left', plot=FALSE)) + ``` +The left plot is printed in full at the end of this document. + ### Facets The above demonstration finds the panel named `panel`. This is default. @@ -96,3 +124,16 @@ which was furhter refined by `baptiste` at [ggplot2's wiki](https://github.com/tidyverse/ggplot2/wiki/Share-a-legend-between-two-ggplot2-graphs). `reposition_legend` was coded by [Stefan McKinnon Edwards](http://www.iysik.com/)/ + +## Footnotes + +Example with `reposition_legend` that didn't quite work: +```{r} +dsamp <- diamonds[sample(nrow(diamonds), 1000), ] +d <- ggplot(dsamp, aes(carat, price)) + + geom_point(aes(colour = clarity)) +reposition_legend(d + theme_gray(base_size=26), 'top left') +``` + + +