knitr::opts_chunk$set(echo = TRUE) require(prepplot) require(ggplot2) require(grid) require(gridBase)
Base R graphics are very powerful, but the many different possibilities and graphical parameters can be overwhelming. Package prepplot has been developed for making it easier to customize figure regions for base R graphics. The concept is to prepare the figure region with prepplot
, and to then add further graphical elements as desired; this can be done with any function that allows adding to an existing plot.
Inspired by Rahlf (2017), the default choice consists of a lightly colored background, and axis lines, tick marks and boxes are avoided. Orientation in the plot region can be supported by grid lines or background stripes with reasonable defaults regarding line type and color; customization is straightforward and, for example, allows to modify defaults such that a ggplot2-like look is obtained. Figure \@ref(fig:ggplot) shows a scatter plot on default prepplot
background with grid lines and on a prepplot
customization similar to the ggplot
default, and compares it to a default ggplot
scatter plot. The code for this figure is shown in the examples section.
par(mfrow=c(1, 3), mgp=c(2,0.2,0), mar=c(3.1,4.1,4.1,1.6)) ## prepplot grid default prepplot(swiss$Education, swiss$Fertility, ## manage grid gridx=TRUE, gridy=TRUE, ## annotation xlab="Education", ylab="Fertility", main="prepplot default grid") points(Fertility ~ Education, swiss, pch=16, col="grey20", cex=1.3) ## prepplot ggplot like prepplot(swiss$Education, swiss$Fertility, ## background color (like in version 0.7 of prepplot) bg = "grey92", ## manage grid gridx=TRUE, gridy=TRUE, col.grid="white", lty.grid="solid", ## manage axis annotation cex=0.75, cex.lab=1.35, col.axis="black", xlab="Education", ylab="Fertility", ## manage title main="prepplot ggplot like", cex.main=1.75, font.main=1, col.main="black") points(Fertility ~ Education, swiss, pch=16, cex=1.3) ## add the default ggplot plot ## following the answer in StackOverflow question # https://stackoverflow.com/questions/14124373/ # combine-base-and-ggplot-graphics-in-r-figure-window plot.new() vps <- baseViewports() pushViewport(vps$figure) ## in the third plot region vp1 <-plotViewport(c(0,0.5,1,0.25)) ## create new vp with margins p <- ggplot(swiss, aes(Education, Fertility)) + geom_point() + labs(title="ggplot default") print(p, vp = vp1)
prepplot consists of only two user-visible functions, prepplot
and stripes
. Function prepplot
creates a plotting region for an x range and a y range, taking care of background color, and optionally specifying various further design and annotation elements of the figure region.
Function prepplot
has many arguments, most of which have reasonable defaults and are thus optional. The documentation groups related arguments together in order to support locating arguments. While it is possible and convenient to specify most plot annotations within function prepplot
, it is also possible to use prepplot
for background color and stripes only and to do all further annotation with functions like mtext
, title
, axis
, stripes
(from prepplot) or abline
.
The only compulsory arguments xlim
and ylim
specify the data limits for the two axes. They can either contain numeric vectors of length two like usual, or longer numeric vectors from which the length two vectors are calculated by function range
. Depending on the choices of the arguments xaxs
and yaxs
(or their values in the graphics state, as set/queried by the par
function), the plot region in the respective direction is 4% larger than specified by these limits (setting "r"
) or exactly matches these limits (setting "i"
).
prepplot
requires numeric xlim
and ylim
specifications; it currently does not work with logarithmic axes. For a date, time or date-time axis, the user has to take care of conversion to numeric values before using prepplot
(see the last example in the examples section). Axes with character-valued ticks are always based on numeric tick position specifications; see e.g. Figure \@ref(fig:barplots) for a barplot example.
The code below creates a default plot region with the default choice for xaxs
and yaxs
(assuming that the default has not been changed in par
) and both choices modified to exact axis limits. The result is shown in Figure \@ref(fig:default); the bottom margin has been reduced, because it would produce a lot of empty space between the figure and its caption.
x <- 0:10 y <- -5:5 par(mfrow=c(1,2), mar=c(2.1, 4.1, 4.1, 2.1)) prepplot(x, y, main='default axis extension', bg="grey92", cex.axis=0.8, mgpx=c(2,0.25,0)) points(x,y, pch=16) mtext('xaxs="r"', line=0.25, family="mono") prepplot(x, y, xaxs="i", yaxs="i", main='limits match axis extent', bg="grey92", cex.axis=0.8, mgpx=c(2,0.25,0)) points(x,y, pch=16, xpd=TRUE) mtext('xaxs="i"', line=0.25, family="mono")
prepplot
obeys to most general graphical parameters as set with function par
(see ?par
), e.g. mar
. Where further graphical parameters can be modified from within prepplot
(bg
, xaxs
, yaxs
, xaxt
, yaxt
, cex
), they default to the current par
settings; this is partly also true for parameters that are set for specific components, like mgp
, lwd
or col
; las
is an exception: it is per default 1 in prepplot
, regardless of par("las")
. prepplot
does not actively change the graphics state (as queried by par()
).
For default plot regions,
las=1
), i.e., easily readable from the reader's perspective (the y axis label, if specified, is parallel to the y axis),grey20
),lwd.axis=0
),lwd.axis
to a positive value, the default border color becomes the annotation color specified with col.axis
), xlab
and ylab
are NULL
),Default plot regions are therefore very unobtrusive: they are neither highlighted by a background color nor bounded by a border line nor indicated by visible axis lines or tick marks. In most cases, one will want to activate one or more structural elements:
gridx
, gridy
), possibly major and minor;bg
(e.g. to "grey92", which used to be its default in version~0.7 of the package): bg
in prepplot
affects the plot region only, which is the usr
area calculated by R from the axis limits by extending them by 4% (arguments xaxs
and/or yaxs
equal to "r"
or NULL
, assuming unchanged par
specifications) or not at all (arguments xaxs
and/or yaxs
equal to "i"
);stripex
, stripey
) as an alternative to grid lines;prepplot
by setting positive lwd.axis
(box and axis lines and ticks) or with subsequent axis
and/or box
statements.xaxs
and yaxs
) and the background areaIf xaxs="r"
, the horizontal extent of the plot region is 4% larger than the range obtained from the xlim
specification; if xaxs="i"
, the x extent of the plot region exactly coincides with range(xlim)
. If xaxs=NULL
, xaxs
is determined from the current graphics state par("xaxs")
. yaxs
behaves analogously for the vertical extent of the plot region.
The background color colors the plot region, whose coordinates can also be queried by par("usr")
, and the plot region is framed by the color specified with the border
argument. If an axis line is not requested (default, lwd.axis=0
), the default border color equals the background color; otherwise, the default border color equals the axis color.
Note that xaxs="i"
or yaxs="i"
should usually not be specified, if data values equal to one of the axis limits exist (see Figure \@ref(fig:default)). On the other hand, if the axis ranges have been chosen liberally, they may be a good choice, because the orientation marks often look more beautiful.
prepplot
offers stripes and / or grid lines. Respective arguments are handled separately for x and y axes (e.g., gridx
, stripesx
).
Stripes and grid lines cannot be simultaneously requested for the same axis within function prepplot
; if both are desired, stripes should be done with prepplot
, and subsequently grid lines can be added with function abline
. The simplest use is to activate grid lines or stripes by, e.g., gridx=TRUE
or stripesy=TRUE
; in that case, axis tick positions define the locations of grid lines or stripes. For stripes, swapping the colors between bg
and col.stripes
can make a big difference, as can be seen in Figure \@ref(fig:orient) by comparing the top and bottom chart in the middle column.
If grid lines are activated (gridx
and/or gridy
set to TRUE
), these are dotted, whenever there are no minor grid lines and solid otherwise. Their default color is darker than the default background color but lighter than the default axis and annotation (grey75
). Per default, if activated, minor grid lines are half as wide as major grid lines, whose width is governed by par("lwd")
per default.
If stripes are activated without specifying specific stripes boundaries (stripesx
and/or stripesy
set to TRUE
), the background is interrupted by stripes (default color light grey, grey90
) between tick positions. Depending on the device's default background color, this default may or may not be adequate.
Apart from using stripes or grid lines for orientation w.r.t. the axis scale, they can also be used for displaying information independent of the tick positions, e.g. grid lines for time points of interest or upper limits of harmful substances, or stripes for indicating time periods of interest in time series presentations (see, e.g., the last example). Such stripes or grid lines can be requested with function prepplot
, or subsequently with functions abline
or stripes
.
Per default, prepplot
displays tick position labelings without ticks, and~\textendash~if axis labels are given~\textendash~axis labels. Axis annotation color is controlled by col.axis
, which defaults to grey20
, i.e. a dark grey. Tick position labels default to tick positions, but can be modified by xticklabs
/yticklabs
, e.g. for character or date values.
If default tick positions from R's calculations are not appropriate, xticks
can be used for specifying custom tick positions for the horizontal axis. If xticks
is not given (i.e. remains NULL
), a vector-valued gridx
or (if that is not available either) stripesx
determines the x tick positions; default R tick positions are only calculated if neither of these is given. By giving both xticks
and one of gridx
or stripesx
, stripes or lines corresponding to the horizontal axis can be specified independent of tick mark positions, as mentioned before. yticks
and friends are completely analogous.
The distance of the tick position labels and axis labels from the plot region (i.e. the colored background, which coincides with the rectangle specified by par("usr")
coordinates) is controlled by the mgp
graphical parameter, a three-element vector (default c(3, 1, 0)
), which gives the number of lines the axis label, the tick mark labels and the axis line are outside the usr
rectangle (the specified line refers to the closest position, wide tick position labels will extend into the margin much more than the specified value). Options mgpx
and mgpy
can be used to control these positionings independent of the current par("mgp")
setting and separately for the two axes; both default to par("mgp")
, and mgpy
defaults to mgpx
, if that is specified. One should always think about mgp
in relation to the margin settings (par("mar")
); in the author's opinion, both mgp
and mar
settings are often too large, and occasionally much too narrow (e.g. for the left margin of horizontal barplots). Whether or not the margin size is appropriate also depends on whether or not non-NULL axis labels (xlab
and ylab
) are specified.
Per default, there is no axis line and ticks at the tick positions are not drawn. If lwd.axis
is set to a positive value, a typical R axis is drawn, per default with a same color border around the plot region, and the axis observes parameter settings like par("tcl")
; the ...
argument of function prepplot
can also be used for specifying such parameters, e.g. tcl=-0.2
specifies shorter tick marks on the outside of the usr
area than the R default (effective only for positive lwd.axis
).
Suppressing axes can also be useful, e.g. when subsequently using functions for which it is difficult to suppress axes; an example of this is given in Section 3.3.
The \dots argument of prepplot
allows to specify a title and / or sub title (with main
and / or sub
), and further arguments like col.main
or font.main
can be used for their formatting. Alternatively and even additionally, subsequent annotation with axis
, mtext
or title
can be used.
prepplot
allows to add arrows to the plot region: option axis.arrow
takes care of that. The default axes can be provided with an arrow by setting axis.arrow
to TRUE
; this draws axes with width equal to 1.5*lwd.grid
, i.e. lwd.axis=0
does not prevent axis arrows from being drawn. With axis.arrow=TRUE
, it is usually advisable to keep the respective xaxs
or yaxs
at its default "r"
(or NULL
).
A two-element numeric vector axis.arrow
(instead of a logical) requests axes with arrows in positions given by the two vector elements. prepplot
keeps axis annotation at the margin of the plot region (oberving mgp
specification), regardless where axis arrows are placed. An example with default axes with arrows is in the prepplot
help, and Section 3.5 of this vignette has an example with a differently placed axis arrow.
The examples in this section illustrate a few uses of function prepplot
.
The following simple example uses major and minor grid lines on white background. The result is shown in Figure \@ref(fig:majorminor).
par(mar=par("mar")-1, mgp=c(2,0.3,0)) prepplot(c(0,10), c(25,30), yticks=25:30, bg="white", lwd.grid.minor=1, gridyminor=4, gridx=TRUE, xlab="x axis label", ylab="y axis label", main="Major/minor grid on white background")
The overview section already showed the default gridlines and customized gridlines mimicking ggplot
style (Figure \@ref(fig:ggplot)). The code for that example is shown below; note that it uses package gridBase for placing the grid-based ggplot
figure in the third position of the base graphics layout.
It will often be of interest to adapt some par
settings before calling function prepplot
, e.g. mar
, mgp
, tcl
, xaxs
, yaxs
, ... The following code exemplifies such parameter settings, together with a selection of layouts; the results are shown in Figure \@ref(fig:parandmore).
par(mfrow=c(2,2), mar=c(3.1, 4.1, 3.1, 2.1), mgp=c(2,0.5,0), xaxs="i", yaxs="i") prepplot(xlim=c(0,9), ylim=c(0,12), bg="grey92", col.grid="grey98", lty.grid=1, lwd.grid=1.5, gridx=0:9, gridy=seq(0,12,2), xlab="x", ylab="y", cex = 0.7, mgpx=c(1.5,0.25,0), mgpy=c(1.75,0.5,0), main="ggplot style") prepplot(xlim=c(0,9), ylim=c(0,12), gridx=0:9, gridy=seq(0,12,2), xlab="x", ylab="y", cex = 0.7, main="default grid lines") prepplot(xlim=c(0,9), ylim=c(0,12), gridx=0:9, gridy=seq(0,12,2), xlab="x", ylab="y", cex = 0.7, lty.grid="solid", mgpx=c(2,0.5,0), main="default solid grid lines") prepplot(ylim=c(0,12), xlim=c(0,9), stripesx=0:9, xlab="x", yaxt="n", cex = 0.7, mgpx=c(2,0.5,0), main="default vertical stripes, no y axis")
The following code creates barplots with transparent bars on striped background. Function prepplot
provides the plot region and the x axis annotation, while the vertical axis annotation comes from function barplot
, which is called with the add=TRUE
argument. Figure \@ref(fig:barplots) shows the result.
tab <- c(one=10, two=5, three=8, four=7, five=12, six=10, seven=9) par(mfrow=c(1,2), mar=c(3.1, 4.1, 3.1, 2.1)) prepplot(ylim=c(0,8.5), xlim=c(-0.2,13), yaxs="i", stripesx=seq(0,12,2), xlab="Frequency", yaxt="n", cex = 0.8, mgpx=c(2,0.5,0), main="Default colors", cex.main=1.2) barplot(tab, col=rgb(0.5, 0.5, 0.5, 0.7), border=FALSE, add=TRUE, xaxt="n",las=2, horiz=TRUE, cex.names=0.8) hks51 <- rgb(0, 152/256, 161/256) prepplot(ylim=c(0,8.5), xlim=c(-0.2,13), yaxs="i", xticks=seq(0,12,2), stripesx=TRUE, xlab="Frequency", bg=rgb(235/256, 246/256, 246/256), col.stripes = rgb(190/256, 226/256, 226/256, 0.4), col.axis=hks51, cex=0.8, col.main=hks51, yaxt="n", tcl=-0.2, mgpx=c(2,0.5,0), main="Beuth colors", cex.main=1.2, col.main=hks51) barplot(tab, col=rgb(0,152/256,161/256,0.7), border=FALSE, add=TRUE, xaxt="n",las=2, horiz=TRUE, cex.names=0.8, col.axis=rgb(0,152/256,161/256))
The following code creates scatter plots on various backgrounds, illustrating various orientation strategies, which are on offer for function prepplot
. The result is shown in Figure \@ref(fig:orient). Note: The charts use the default axis extent (ranges of Education
and Fertility
, extended by 4\%); a custom axis with well-chosen limits and suppressing extension by 4\% could yield constant widths for all stripes, also the outer ones. Also remember the previous remark on the effect of swapping bg
and col.stripes
.
par(mfrow=c(2,3), oma=c(2,0,0,0), mgp=c(2.25,0.5,0), mar=c(3.1, 4.1, 3.1, 2.1)) ## default axis system with grid lines prepplot(xlim=swiss$Education, ylim=swiss$Fertility, mgpy=c(2.5,0.5,0), xlab="Education", ylab="Fertility", gridx=TRUE, gridy=TRUE, cex=0.8, main="grid lines") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") ## stripes and grid lines prepplot(xlim=swiss$Education, ylim=swiss$Fertility, mgpy=c(2.5,0.5,0), xlab="Education", ylab="Fertility", stripesx=seq(-5,60,5), gridy=seq(30,100,10), cex=0.8, xticks=seq(0,50,10), yticks = seq(40,90,10), main="stripes and grid lines") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") prepplot(xlim=range(swiss$Education), ylim=range(swiss$Fertility), mgpy=c(2.5,0.5,0), xlab="Education", ylab="Fertility", gridx=seq(0,60,10), stripesy=seq(30,100,5), cex=0.8, xticks=seq(0,50,10), yticks = seq(40,90,10), main="stripes and grid lines") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") ## stripes only prepplot(xlim=range(swiss$Education), ylim=range(swiss$Fertility), mgpy=c(2.5,0.5,0), bg="grey90", col.stripes = "white", xlab="Education", ylab="Fertility", stripesx=seq(-5,60,5), stripesy=seq(30,100,5), cex=0.8, xticks=seq(0,50,10), yticks = seq(40,90,10), main="crossing stripes") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") prepplot(xlim=range(swiss$Education), ylim=range(swiss$Fertility), mgpy=c(2.5,0.5,0), xlab="Education", ylab="Fertility", stripesx=seq(-5,60,5), cex=0.8, xticks=seq(0,50,10), yticks = seq(40,90,10), main="only vertical stripes", bg="grey90", col.stripes = "white") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") prepplot(xlim=range(swiss$Education), ylim=range(swiss$Fertility), mgpy=c(2.5,0.5,0), xlab="Education", ylab="Fertility", stripesy=seq(30,100,5), cex=0.8, yticks = seq(40,90,10), xticks=seq(0,50,10), main="only horizontal stripes") points(swiss$Education, swiss$Fertility, pch=16, col="grey20") mtext(side=1, line=0.5, 'Some strategies are better than others ...', cex=0.8, outer=TRUE, col="grey20")
This section exemplifies axis arrows (first example, Figure \@ref(fig:stripes)), simultaneous use of stripes and grid lines on the same dimension and a date-time axis (second example, Figure \@ref(fig:datetime)).
prepplot(0:10, -5:5, yticks=seq(-5,5,5), stripesy=-5:5, xlab="x", ylab="y", main="with stripes and arrow axis", cex=0.8, cex.main=1.2, axis.arrow = c(0,NA),arrow.length = 0.5,arrow.width = 0.5, lwd=2)
It sometimes make sense to combine stripes and grid lines for the same dimension, e.g. on a time axis. For example, think of some technical equipment with down times shown as stripes and days separated by grid lines. Such an application is exemplified below.
par(mar=c(1.5, 3, 3, 1), mgp=c(3,0.2,0)) xlim <- as.numeric(as.POSIXlt(c("2017-12-28 18:09:46","2018-01-02 09:15:22"))) stripelims <- as.numeric(as.POSIXlt( c("2017-12-29 10:30:00","2017-12-29 12:00:00", "2017-12-30 10:00:00","2017-12-30 12:30:00", "2017-12-31 10:00:00","2017-12-31 12:30:00", "2018-01-01 10:30:00","2018-01-01 11:30:00", "2018-01-01 16:30:00","2018-01-01 17:45:00"))) griddatts <- as.POSIXlt(c( "2017-12-29 00:00:00", "2017-12-30 00:00:00", "2017-12-31 00:00:00", "2018-01-01 00:00:00", "2018-01-02 00:00:00")) gridposs <- as.numeric(griddatts) tickposs <- gridposs + 12*3600 tickposs <- tickposs[tickposs < xlim[2]] prepplot(xlim=xlim, ylim=c(-5,10), stripesx=stripelims, xaxt="n", cex=0.7, gridy=TRUE, gridyminor=4, main="Date-time data with stripes and grid lines on same axis") abline(v=gridposs, col="grey20") axis(side=1, at=tickposs, labels=as.Date(as.POSIXlt(tickposs, origin="1970-01-01 00:00.00 UTC")), lwd=0, cex.axis=0.7)
Murrell, P. (2011). R graphics. CRC, Boca Raton. \url{https://www.stat.auckland.ac.nz/~paul/RG2e/}
Rahlf, T. (2017). Data visualisation with R. Springer, New York.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.