addScales {addScales} | R Documentation |
Add Scaling Information to Panels in Multi-Panel Trellis Plots
Description
Adds a midline and upper and lower horizontal and/or vertical scale lines
or shaded regions to all panels. Mostly useful when the
relation = "free"
option is used in the
scales
list to avoid loss of detail in plots from data that vary in
location and scale from panel to panel.
Usage
addScales(obj, ...)
## S3 method for class 'trellis'
addScales(obj,
scaleline = list(h = TRUE, v = FALSE),
legend = list(h = TRUE, v = TRUE),
ndig.legend = c(h = 2, v = 2),
legend.aes = list(),
legend.loc = c("top","bottom","right","left"),
panelFUN = panel.addScales,
...)
Arguments
obj |
Object on which method dispatch is carried out. Currently only a |
scaleline |
A two component list with component names "h" and "v". The
"h" component is for (h)orizontal scale lines/regions and "v" is
for(v)ertical. Each of these must be a single logical or numeric value
(and can be mixed in the list, of course). Note: Scale lines/regions are only meaningful for |
legend |
A two component list as in |
ndig.legend |
Named or unnamed pair of integer arguments, or a single integer that will be replicated. The names must be (and are assumed to be if unnamed) "h" and "v" in that order and give the number of significant digits to show in the default legend for the corresponding scale lines/region. Non-integer values are rounded to integer, and values outside the range of 0 to 15 digits are converted to 2. |
legend.aes |
List of aesthetics of the legend text: |
legend.loc |
One of |
panelFUN |
The function used to add scaling details to the panels. Should use standard trellis/grid functionality. |
... |
Further arguments, controlling aesthetics of the lines, labels, and/or
fill regions such as color, line width, color palette, line type, etc., passed down to the
|
Details
As a convenience, abbreviated versions of scaleline
and
legend
logical arguments can be used instead of the full versions
described above.The abbreviated versions will be translated into the full
versions for use by other functions such as scaleline
and
update.scaledTrellis
.
Specifically, a single value of TRUE
or FALSE
is replicated to
both components of the argument. Thus scaleline = FALSE
aborts the
function, since it says not to add scales in either direction.
legend = FALSE
is fine, because it specifies only that legends be omitted.
See the Legend Specification Details section below for why this might be useful.
If an unnamed list with two components (of the correct form) are given, they are
assumed to be in the order c("h","v")
. If a single named component with
name "h" or "v" is given, the missing component is assumed
to be FALSE
. Thus, list(v = TRUE), list(FALSE, TRUE)
, and
list(h = FALSE, v = TRUE)
are all equivalent. A list with a single
unnamed component raises an error.
The default scaleline
calculation assures that all lines/regions fall within the
axis limits of all panels. A (typically user-supplied) scaleline
that fails this criterion will raise a warning and result in some
panels with missing scale lines when scaleType = "line"
.
Value
An object of class c("scaledTrellis","trellis")
if successful.
Because it inherits from class "trellis"
, it can be saved
and/or (automatically) plotted as usual.
NULL
invisibly if an error occurs.
The scaledTrellis
object is the original trellis
object list
with its panel
and legend
components modified to add the
scaling information. A new addScales
component is also added
that is itself a list with (at least) two components named "orig" and "args".
The first of these contains the original
panel
and legend
components of obj
. The second
contains either the names and values of the arguments in the call or the computed
values of those arguments. The most important of these is the scaleline
value, which can be extracted using the scaleline
function by users
who wish to construct their own scale line legends.The remaining values are used
by the update method for scaledTrellis
objects.
Legend Specification Details
The default legend is meant to be simple but serviceable. If there are scale lines
in both directions, it will space them horizontally for "top"
and
"bottom"
locations and vertically for "right"
and "left"
to
minimize the space they occupy.
A user-supplied legend component can be given in two forms: either as a (quoted)
UTF-8 character string, like this: "Scale lines are at ±10° ";
or as a so-called language
object. The latter allows the legend to use the
(shortened to the ndig.legend
number of digits) scaleline
value.
The former does not.
A detailed discussion of language
objects is beyond the scope of this Help
page, but a simple example provides a template that should usually suffice. Suppose,
instead of the default, the desired legend is:
Scale lines are at
± xxx
°,
where the scaleline
value computed by addScales
is to be substituted
for the xxx. If xxx were available in the environment of the call
(the addScales
invocation), then one could use something like
(as in the previous paragraph):
paste0("Scale lines are at
±
",xxx,"
° ")
as the legend
argument. But xxx is not known, because addScales
hasn't calculated it yet. So instead, wrap the paste0 call by the
quote
function like this:
quote(paste0("Scale lines are at
±
",sl,"
° "))
‘sl’ (unquoted) must be used to replace the not-yet-known
scaleline
value. The quote
function will pass the whole unevaluated
paste0
expression into addScales
where the scaleline
value will be calculated and substituted for
sl
and the whole expression then evaluated.
Of course, any R expression instead of paste0...
can
be used as long as sl
is substituted wherever the actual scaleline
value is wanted.
Another, perhaps slightly clumsier, way to do this – but which generalizes to
arbitrary scaleline
displays as text or graphical objects (so-called
grobs) of any kind – is simply to run
addScales
with legend = FALSE
and extract the
scaleline
value(s) from the resulting object with the scaleline()
function. The value(s) can then be used in any construction the user wishes to create.
Author(s)
Bert Gunter bgunter.4567@gmail.com
See Also
xyplot
,
panel.refline
,
panel.text
,
scaleline
,
panel.addScales
Examples
###### Artificial example to show why addScales() might be useful and
###### how it works
##
###### Create a data set whose panels have different
###### centers and scales for y
x <- rep(0:10, 4)
scaling <- rep(c(1, 2, 5, 10), e = 11)
y <- sin(pi*x/10)*scaling + scaling ## add some structure
f <- factor(rep(LETTERS[1:4], e = 11))
## Now add noise proportional to data mean (= constant CV)
set.seed(91834)
y <- y + rnorm(44,sd = scaling/3)
## Plot this with the default "same" scaling and a loess curve
xyplot(y ~ x| f, layout = c(4,1), col = "darkblue",
scales = list(alternating = 1, tck = c(1,0)),
panel = function(...){
panel.points(...)
panel.loess(..., span = .6, col.line = "blue")
})
##
## Because of the different scaling, it's somewhat difficult to
## see the common panel data behavior. With relation = "free", it
## becomes clearer:
##
trellis.par.set(plot.symbol = list(col = "darkblue"),
plot.line = list(col = "darkblue"))
xyplot(y ~ x| f, layout = c(4,1),
scales = list(alternating = 1, tck = c(1,0),
y = list(relation = "free")),
panel = function(...){
panel.points(...)
panel.loess(..., span = .6, col.line = "blue")
})
##
## Unfortunately, the y-scales take up a lot of space and are
## difficult to read. With more panels, they would completely
## mess things up. To avoid this, don't draw them and use addScales
## to layer visual scaling onto the panels.
##
freeplot <- xyplot(y ~ x| f, layout = c(4,1),
scales = list(alternating = 1, tck = c(1,0),
y = list(relation = "free", draw = FALSE)),
panel = function(...){
panel.points(...)
panel.loess(..., span = .6, col.line = "blue")
})
addScales(freeplot) ## using defaults
##
## The labeled midline allows location comparison among the panels.
## The fixed distance from the dashed scale lines to the midline are given
## by the legend at top. This allows scaling among the panels to be
## compared, because the more y varies within a panel, the closer together
## these fixed scale lines become.
##
## NOTE:
## The addScales object inherits from class "trellis", so can be
## saved and plotted in the same way as 'freeplot' was. That is, the
## following also works:
##
enhanced <- addScales(freeplot)
enhanced
## Further panel options, which we use the update() method to change,
## allow for color coded scale regions and midlines:
##
#### Warning: Nothing may display if your graphics device does not support
## alpha transparency
update(enhanced, scaleType = "region", colCode = "r")
##
## cleanup
rm(scaling, x, y, f, freeplot, enhanced)
##
######## Some real examples #############
############################################
## Historical daily temperatures for Chicago, New York, and San Francisco.
data(CHITemps, NYCTemps, SFTemps)
preprocess.temps <- function(d){
meanTemp <- with(d, (TMAX + TMIN)/2)
Month <- months(as.Date(d$DATE))
z<- aggregate(meanTemp, list(
Month = factor(Month, levels = unique(Month)),
Year = as.numeric(substring(d$DATE,1,4))
), FUN = mean)
names(z)[3] <- "meanTemp"
z
}
## Create a list containing the preprocessed data for all 3 cities
plotdat <- lapply(
list(CHI = CHITemps, NYC = NYCTemps, SF = SFTemps),
preprocess.temps)
## Consider NYC. Because of monthly temperature variation, monthly temperature
## histories are mostly whitespace with the default relation = "same".
## Note also the use of the prepanel.trim function with defaults to remove
## extreme y values.
##
## Consider New York City
nyctemps <-
xyplot(meanTemp ~ Year|Month, type = "l", layout = c(3,4),
data = plotdat[[2]],
as.table = TRUE,
between = list(x=1, y=0),
## reduce strip size
par.strip.text = list(lines = .8, cex = .7),
## remove blank space for top axis
par.settings = list(layout.heights = list(axis.top = 0)),
prepanel = prepanel.trim, ## to remove possible extreme values
panel = function(...){
panel.grid(v = -1, h = 0, col = "gray70")
panel.xyplot(...)
panel.loess(..., span = .5, col = "darkred",
lwd = 1.5)
},
scales = list(axs = "i", alternating = 1, tck = c(1,0)),
xlab = "Year",
ylab = "Average Temperature (\u00B0F)",
main = "Mean Monthly Historical Temperatures in NYC"
)
nyctemps
## Now try it with y-scale = "free' and addScales
##
nyctemps <- update(nyctemps,
scales = list(axs = "i", alternating = 1,
tck = c(1,0),y = list(relation = "free", draw = FALSE)))
addScales(nyctemps)
## The historical temperature trend as the city
## built up and modernized (more concrete and asphalt,people,
## heat sources, etc.) is clearer and quantified by the
## legend and scale lines; and the scale lines also show
## that winter temperatures are clearly more variable than summer.
## This was almost undetectable in the previous plot.
## The same plot using region shading instead of scale lines.
## Warning: May not display if your graphics device does not support
## alpha transparency
addScales(nyctemps, scaleType = "region")
## ... and using color coding for midlines and regions to better visually
## distinguish their values...
##
addScales(nyctemps, scaleType = "region", colCode = "r")
## You can repeat the exercise with the other two cities if you like.
## cleanup
rm(nyctemps, preprocess.temps, plotdat)
####### Historical Crime Data #####
data(USAcrime)
## We explore the relationship beween property and violent crime over time.
## Point transparency via the 'alpha' setting is used to code year
## and the violent vs. property crime relationship is trellised by state
## for a selection of states.
##
## First with scales = "same", the default..
state.smpl <- c("CA","TX","GA","CO","VA","FL","NY","OH","MO","UT","MA","TN")
wh <- USAcrime$State %in% state.smpl
pcols <- hcl.colors(55, rev = TRUE)
crm <-xyplot(allViolent ~ allProperty|State, data = USAcrime[wh,],
subscripts = TRUE, as.table = TRUE,
layout = c(4,3), type = c("p", "g"),
cex= .75, pch = 19,
col = pcols[USAcrime[wh,'Year'] -1959],
par.strip.text = list(lines = .8, cex = .7),
between = list(x = 1),
scales = list(axs="i",alternating =1, tck = c(1,0)),
xlab = "Property Crime Rate (incidents/100,000 population)",
ylab = "Violent Crime Rate (incidents/100,000 population)",
main = paste0("Violent vs. Property Crime Rates from 1960-2014 For 12 States"),
sub = "Point Darkness Codes Years: Darker = Later Years",
panel = function(subscripts,col,...)
panel.xyplot(col = col[subscripts],...)
)
crm
## remove the grid and update with
## "free" scales and no axes for both x and y
crm2 <- update(crm, type = "p",
scales = list(axs="i", relation = "free", draw = FALSE))
## Add scales for both x and y and color code midlines
addScales(crm2, scaleline = TRUE, colCode = "m")
## Some features to note:
## 1. As one might expect, violent and property crime rates are
## correlated.
##
## 2. Crime rates first increased, peaked, and then decreased over time.
##
## 3. For most states there appears to be a kind of 'hysteresis':
## the trajectory of the crime decrease is shifted up (higher violent
## crime rate for the same property rate) from when it increased.
## This could have been due to a change in reporting procedures,
## over time, for example.
##
## 4. The midline colors and labels show that NY has the highest
## violent crime rate, but a modest property crime rate: Tennessee
## has a middling violent crime rate but the lowest (with VA) property
## crime rate.
##
## cleanup
rm( state.smpl, wh, pcols, crm, crm2)