ageBias {FSA}R Documentation

Compute and view possible differences between paired sets of ages.


Constructs age-agreement tables, statistical tests to detect differences, and plots to visualize potential differences in paired age estimates. Ages may be from, for example, two readers of the same structure, one reader at two times, two structures (e.g., scales, spines, otoliths), or one structure and known ages.


ageBias(formula, data, ref.lab = tmp$Enames, nref.lab = tmp$Rname,
  method = stats::p.adjust.methods, sig.level = 0.05, min.n.CI = 3)

## S3 method for class 'ageBias'
summary(object, what = c("table", "symmetry", "Bowker",
  "EvansHoenig", "McNemar", "bias", "diff.bias", "n"),
  flip.table = FALSE, zero.print = "-", digits = 3,
  cont.corr = c("none", "Yates", "Edwards"), ...)

## S3 method for class 'ageBias'
plot(x, xvals = c("reference", "mean"),
  xlab = ifelse(xvals == "reference", x$ref.lab, "Mean Age"),
  ylab = paste(x$nref.lab, "-", x$ref.lab), xlim = NULL, ylim = NULL,
  yaxt = graphics::par("yaxt"), xaxt = graphics::par("xaxt"),
  col.agree = "gray60", lwd.agree = lwd, lty.agree = 2, lwd = 1,
  sfrac = 0, show.pts = NULL, pch.pts = 20, cex.pts = ifelse(xHist
  | yHist, 1.5, 1), col.pts = "black", transparency = 1/10,
  show.CI = FALSE, col.CI = "black", col.CIsig = "red",
  lwd.CI = lwd, sfrac.CI = sfrac, show.range = NULL,
  col.range = ifelse(show.CI, "gray70", "black"), lwd.range = lwd,
  sfrac.range = sfrac, pch.mean = 19, pch.mean.sig = ifelse(show.CI |
  show.range, 21, 19), cex.mean = lwd, yHist = TRUE, xHist = NULL,
  hist.panel.size = 1/7, col.hist = "gray90", allowAdd = FALSE, ...)



A formula of the form nrefvar~refvar, where nrefvar and refvar generically represent variables that contain the paired “nonreference” and “reference” age estimates, respectively. See details.


A data.frame that minimally contains the paired age estimates given in formula.


A string label for the reference age estimates.


A string label for the nonreference age estimates.


A string for which method to use to adjust p-values for multiple comparisons. See ?p.adjust.methods.


A numeric value to determine whether a p-value indicates a significant result. The confidence level used in plot is 100*(1-sig.level).


A numeric value (default is 3) that is the smallest sample size for which a confidence interval will be computed.


A string that indicates what type of summary to print or plot to construct. See details.


A logical that indicates whether the age-agreement table should be ‘flipped’ (i.e., rows are reversed so that younger ages are at the bottom of the table). This makes the table more directly comparable to the age bias plot.


A string for what should be printed in place of the zeros on an age-agreement table. The default is to print a single dash.


A numeric for the minimum number of digits to print when showing what="bias" or what="diff.bias" in summary.


A string that indicates the continuity correction method to be used with (only) McNemar test. If "none" (default) then no continuity correction is used, if "Yates" then 0.5 is used, and if "Edwards" then 1 is used.


Additional arguments for methods.

x, object

An object of class ageBias, usually a result from ageBias.


A string for whether the x-axis values are reference ages or mean of the reference and nonreference ages.

xlab, ylab

A string label for the x-axis (reference) or y-axis (non-reference) age estimates, respectively.

xlim, ylim

A numeric vector of length 2 that contains the limits of the x-axis (reference ages) or y-axis (non-reference ages), respectively.

xaxt, yaxt

A string which specifies the x- and y-axis types. Specifying “n” suppresses plotting of the axis. See ?par.


A string or numeric for the color of the 1:1 or zero (if difference=TRUE) reference line.


A numeric for the line width of the 1:1 or zero (if difference=TRUE) reference line.


A numeric for the line type of the 1:1 or zero (if difference=TRUE) reference line.


A numeric that controls the separate ‘lwd’ argument (e.g., lwd.CI and lwd.range).


A numeric that controls the separate ‘sfrac’ arguments (e.g., sfrac.CI and sfrac.range). See sfrac in plotCI of plotrix.


A logical for whether or not the raw data points are plotted.


A numeric for the plotting character of the raw data points.


A character expansion value for the size of the symbols for pch.pts.


A string or numeric for the color of the raw data points. The default is to use black with the transparency found in transparency.


A numeric (between 0 and 1) for the level of transparency of the raw data points. This number of points plotted on top of each other will represent the color in col.pts.


A logical for whether confidence intervals should be plotted or not.


A string or numeric for the color of confidence interval bars that are considered non-significant.


A string or numeric for the color of confidence interval bars that are considered significant.


A numeric for the line width of the confidence interval bars.


A numeric for the size of the ends of the confidence interval bars. See sfrac in plotCI of plotrix.


A logical for whether or not vertical bars that represent the range of the data points are plotted.


A string or numeric for the color of the range intervals.


A numeric for the line width of the range intervals.


A numeric for the size of the ends of the range intervals. See sfrac in plotCI of plotrix.


A numeric for the plotting character used for the mean values when the means are considered insignificant.


A numeric for the plotting character for the mean values when the means are considered significant.


A character expansion value for the size of the mean symbol in pch.mean and pch.mean.sig.


A logical for whether a histogram of the y-axis variable should be added to the right margin of the age bias plot. See details.


A logical for whether a histogram of the x-axis variable should be added to the top margin of the age bias plot. See details.


A numeric between 0 and 1 that indicates the proportional size of histograms (relative to the entire plotting pane) in the plot margins (only used if xHist=TRUE or yHist=TRUE).


A string for the color of the bars in the marginal histograms (only used if xHist=TRUE or yHist=TRUE).


A logical that will allow the user to add items to the main (i.e., not the marginal histograms) plot panel (if TRUE). Defaults to FALSE.


Generally, one of the two age estimates will be identified as the “reference” set. In some cases this may be the true ages, the ages from the more experienced reader, the ages from the first reading, or the ages from the structure generally thought to provide the most accurate results. In other cases, such as when comparing two novice readers, the choice may be arbitrary. The reference ages will form the columns of the age-agreement table and will be the “constant” age used in the t-tests and age bias plots (i.e., the x-axis). See further details below.

The age-agreement table is constructed with what="table" in summary. The agreement table can be “flipped” (i.e., the rows in descending rather than ascending order) with flip.table=TRUE. By default, the tables are shown with zeros replaced by dashes. This behavior can be changed with zero.print.

Three statistical tests of symmetry for the age-agreement table can be computed with what= in summary. The “unpooled” or Bowker test as described in Hoenig et al. (1995) is constructed with what="Bowker", the “semi-pooled” or Evans-Hoenig test as described in Evans and Hoenig (1998) is constructed with what="EvansHoenig", and the “pooled” or McNemar test as described in Evans and Hoenig (1998) is constructed with what="McNemar". All three tests are computed with what="symmetry".

The age bias plot introduced by Campana et al. (1995) can be constructed with plotAB. Muir et al. (2008) modified the original age bias plot by plotting the difference between the two ages on the y-axis (still against a reference age on the x-axis). McBride (2015) introduced the Bland-Altman plot for comparing fish ages where the difference in ages is plotted on the y-axis versus the mean of the ages on the x-axis. Modifications of these plots are created with plot (rather than plotAB) using xvals= to control what is plotted on the x-axis (i.e., xvals="reference" uses the reference ages, whereas xvals="mean" uses the mean of the two ages for the x-axis). In both plots, a horizontal agreement line at a difference of zero is shown for comparative purposes. In addition, a histogram of the differences is shown in the right margin (can be excluded with yHist=FALSE.) A histogram of the reference ages is shown by default in the top margin for the modified age bias plot, but not for the modified Bland-Altman-like plot (the presence of this histogram is controlled with xHist=).

By default, the modified age bias plot shows the mean and range for the nonreference ages at each of the reference ages. Means shown with an open dot are mean age differences that are significantly different from zero. The ranges of differences in ages at each reference age can be removed with show.range=FALSE. A confidence interval for difference in ages can be added with show.CI=FALSE. Confidence intervals are only shown if the sample size is greater than the value in min.n.CI= (also from the original call to ageBias). Confidence intervals plotted in red with an open dot (by default; these can be changed with col.CIsig and pch.mean.sig, respectively) do not contain the reference age (see discussion of t-tests below). Individual points are plotted if show.pts=TRUE, where there color is controlled by col.pts= and transparency=. See examples for use of these arguments.

The main (i.e., not the marginal histograms) can be "added to" after the plot is constructed if allowAdd=TRUE is used. For example, the Bland-Altman-like plot can be augmented with a horizontal line at the mean difference in ages, a line for the regression between the differences and the means, or a generalized additive model that describes the relationship between the differences and the means. See the examples for use of allowAdd=TRUE. It is recommended to save the plotting parameters (e.g., op <- par(no.readonly=TRUE)) before using plot with allowAdd=TRUE so that the original parameters can be reset (e.g., par(op)); see the examples.

Individual t-tests to determine if the mean age of the nonreference set at a particular age of the reference set is equal to the reference age (e.g., is the mean age of the nonreference set at age-3 of the reference set statistically different from 3?) are shown with what="bias" in summary. The results provide a column that indicates whether the difference is significant or not as determined by adjusted p-values from the t-tests and using the significance level provided in sig.level (defaults to 0.05). Similar results for the difference in ages (e.g., is the mean reference age minus nonreference age at a nonreference age of 3 different from 0?) are constructed with what="diff.bias" in summary.

The sample size present in the age-agreement table is found with what="n".


ageBias returns a list with the following items:

summary returns the result if what= contains one item, otherwise it returns nothing. Nothing is returned by plot or plotAB, but see details for a description of the plot that is produced.


Tested all symmetry test results against results in Evans and Hoenig (2008), the McNemar and Evans-Hoenig results against results from compare2 in fishmethods, and all results using the AlewifeLH data set from FSAdata against results from the online resource at

IFAR Chapter

4-Age Comparisons. Note that plot has changed since IFAR was published. Some of the original functionality is in plotAB.


Derek H. Ogle,


Ogle, D.H. 2016. Introductory Fisheries Analyses with R. Chapman & Hall/CRC, Boca Raton, FL.

Campana, S.E., M.C. Annand, and J.I. McMillan. 1995. Graphical and statistical methods for determining the consistency of age determinations. Transactions of the American Fisheries Society 124:131-138. [Was (is?) available from]

Evans, G.T. and J.M. Hoenig. 1998. Testing and viewing symmetry in contingency tables, with application to readers of fish ages. Biometrics 54:620-629.

Hoenig, J.M., M.J. Morgan, and C.A. Brown. 1995. Analysing differences between two age determination methods by tests of symmetry. Canadian Journal of Fisheries and Aquatic Sciences 52:364-368.

McBride, R.S. 2015. Diagnosis of paired age agreement: A simulation approach of accuracy and precision effects. ICES Journal of Marine Science 72:2149-2167.

Muir, A.M., M.P. Ebener, J.X. He, and J.E. Johnson. 2008. A comparison of the scale and otolith methods of age estimation for lake whitefish in Lake Huron. North American Journal of Fisheries Management 28:625-635. [Was (is?) available from]

See Also

See agePrecision for measures of precision between pairs of age estimates. See compare2 in fishmethods for similar functionality. See plotAB for a more traditional age-bias plot.


ab1 <- ageBias(scaleC~otolithC,data=WhitefishLC,
               ref.lab="Otolith Age",nref.lab="Scale Age")
# flip table (easy to compare to age bias plot) and show zeroes (not dashes)

## Differences Plot (inspired by Muir et al. (2008))
# Default (ranges, open circles for sig diffs, marginal hists)
# Show CIs for means (with and without ranges)
# show points (with and without CIs)
# Use same symbols for all means (with ranges)
# Use same symbols/colors for all means/CIs (without ranges)
# Remove histograms
## Suppress confidence intervals for n < a certain value
##   must set this in the original ageBias() call
ab2 <- ageBias(scaleC~otolithC,data=WhitefishLC,min.n.CI=8,
               ref.lab="Otolith Age",nref.lab="Scale Age")

## Differences Plot ( inspired by Bland-Altman plots in McBride (2015))
## Modify axis limits
## Add and remove histograms

## Adding post hoc analyses to the main plot
# get original graphing parameters to be reset at the end
op <- par(no.readonly=TRUE)

# get raw data
tmp <- ab1$d

# Add mean difference (w/ approx. 95% CI)
bias <- mean(tmp$diff)+c(-1.96,0,1.96)*se(tmp$diff)

# Same as above, but without marginal histogram, and with
#   95% agreement lines as well (1.96SDs)
#   (this is nearly a replicate of a Bland-Altman plot)
bias <- mean(tmp$diff)+c(-1.96,0,1.96)*se(tmp$diff)
agline <- mean(tmp$diff)+c(-1.96,1.96)*sd(tmp$diff)

# Add linear regression line of differences on means (w/ approx. 95% CI)
lm1 <- lm(diff~mean,data=tmp)
xval <- seq(0,19,0.1)
pred1 <- predict(lm1,data.frame(mean=xval),interval="confidence")
bias1 <- data.frame(xval,pred1)

# Add loess of differences on means (w/ approx. 95% CI as a polygon)
lo2 <- loess(diff~mean,data=tmp)
xval <- seq(min(tmp$mean),max(tmp$mean),0.1)
pred2 <- predict(lo2,data.frame(mean=xval),se=TRUE)
bias2 <- data.frame(xval,pred2)
bias2$lwr <- bias2$fit-1.96*bias2$
bias2$upr <- bias2$fit+1.96*bias2$
# Same as above, but polygon and line behind the points

# Can also be made with the reference ages on the x-axis
lo3 <- loess(diff~otolithC,data=tmp)
xval <- seq(min(tmp$otolithC),max(tmp$otolithC),0.1)
pred3 <- predict(lo3,data.frame(otolithC=xval),se=TRUE)
bias3 <- data.frame(xval,pred3)
bias3$lwr <- bias3$fit-1.96*bias3$
bias3$upr <- bias3$fit+1.96*bias3$

[Package FSA version Index]