Learn R Programming

Epi (version 1.1.7)

boxes.MS: Draw boxes and arrows for illustration of multistate models.

Description

Boxes can be drawn with text (tbox) or a cross (dbox), and arrows pointing between the boxes (boxarr) can be drawn automatically not overlapping the boxes. The boxes method for Lexis objects generates displays of states with person-years and transitions with events or rates.

Usage

tbox( txt, x, y, wd, ht,
         font=2, lwd=2,
         col.txt=par("fg"),
         col.border=par("fg"),
         col.bg="transparent" )
   dbox( x, y, wd, ht=wd,
         font=2, lwd=2, cwd=5,
         col.cross=par("fg"),
         col.border=par("fg"),
         col.bg="transparent"  )
   boxarr( b1, b2, offset=FALSE, pos=0.45, ... )
## S3 method for class 'Lexis':
boxes( obj,
                    boxpos = FALSE,
                     wmult = 1.15,
                     hmult = 1.15,
                       cex = 1.45,
                    show   = inherits( obj, "Lexis" ),
                    show.Y = show,
                   scale.Y = 1,
                  digits.Y = 1,
                   show.BE = FALSE,
                    BE.sep = c("","","          ",""),
                    show.D = show,
                   scale.D = FALSE,
                  digits.D = as.numeric(as.logical(scale.D)),
                    show.R = is.numeric(scale.R),
                   scale.R = 1,
                  digits.R = as.numeric(as.logical(scale.R)),
                    DR.sep = if( show.D ) c("(",")") else c("",""),
                     eq.wd = TRUE,
                     eq.ht = TRUE,
                        wd,
                        ht,
                    subset = NULL,
                   exclude = NULL,
                      font = 2,
                       lwd = 2,
                   col.txt = par("fg"),
                col.border = col.txt,
                    col.bg = "transparent",
                   col.arr = par("fg"),
                   lwd.arr = 2,
                  font.arr = 2,
                   pos.arr = 0.45,
                   txt.arr = NULL,
               col.txt.arr = col.arr,
                offset.arr = 2,
                             ... )
## S3 method for class 'matrix':
boxes( obj, ... )
## S3 method for class 'MS':
boxes( obj, sub.st, sub.tr, cex=1.5, ... )
   fillarr( x1, y1, x2, y2, gap=2, fr=0.8,
            angle=17, lwd=2, length=par("pin")[1]/30, ... )
txt{Text to be placed inside the box.}
  x{x-coordinate of center of box.}
  y{y-coordinate of center of box.}
  wd{width of boxes in percentage of the plot width.}
  ht{height of boxes in percentage of the plot height.}
  font{Font for the text. Defaults to 2 (=bold).}
  lwd{Line width of the boxborders.}
  col.txt{Color for the text in boxes.}
  col.border{Color of the box border.}
  col.bg{Background color for the interior of the box.}
  ...{Arguments to be passed on to the call of other functions.}
  cwd{Width of the lines in the cross.}
  col.cross{Color of the cross.}
  b1{Coordinates of the "from" box. A vector with 4 components,
            x, y, w, h.}
  b2{Coordinates of the "to" box; like b1.}
  offset{Logical. Should the arrow be offset a bit to the left.}
  pos{Numerical between 0 and 1, determines the position of the point
    on the arrow which is returned.}
  obj{A Lexis object or a transition matrix; that
    is a square matrix indexed by state in both dimensions, and the
    $(i,j)$th entry different from NA if a transition $i$
    to $j$ can occur. If show.D=TRUE, the arrows between
    states are annotated by these numbers. If show.Y=TRUE, the
    boxes representing states are annotated by the numbers in the
    diagonal of obj.

    For boxes.matrix obj is a matrix and for
    boxes.MS, obj is an MS.boxes object (see below).}
  boxpos{If TRUE the boxes are positioned  equidistantly on a
                circle, if FALSE (the default) you are queried to
                click on the screen for the positions. This argument can also
                be a named list with elements x and
                y, both numerical vectors, giving the centers of
                the boxes.}
  wmult{Multiplier for the width of the box relative to the width of the
               text in the box.}
  hmult{Multiplier for the height of the box relative to the height of the
               text in the box.}
  cex{Character expansion for text in the box.}
  show{Should person-years and transitions be put in the plot.
              Ignored if obj is not a Lexis object.}
  show.Y{If logical: Should person-years be put in the boxes.
              If numeric: Numbers to put in boxes.}
  scale.Y{What scale should be used for annotation of person-years.}
  digits.Y{How many digits after the decimal point should be used for the
                  person-years.}
  show.BE{Logical. Should number of persons beginning
    resp. ending follow up in each state be shown?}
  BE.sep{Character vector of length 4, used for annotation of the
    number of persons beginning and ending in each state: 1st elemet
    precedes no. beginning, 2nd trails it, 3rd precedes the no. ending
    (defaults to 8 spaces), and the 4th trails the no. ending.}
  show.D{Should no. transitions be put alongside the arrows.
                Ignored if obj is not a Lexis object.}
  scale.D{Synonumous with scale.R, retained for compatability.}
  digits.D{Synonumous with digits.R, retained for compatability.}
  show.R{Should the transition rates be shown on the arrows?}
  scale.R{If this a scalar, rates instead of no. transitions are printed
                 at the arrows, scaled by scale.R.}
  digits.R{How many digits after the decimal point should be used for the
                  rates.}
  DR.sep{Character vector of length 2. If rates are shown, the
    first element is inserted before and the second after the rate.}
  eq.wd{Should boxes all have the same width?}
  eq.ht{Should boxes all have the same height?}
  subset{Draw only boxes and arrows for a subset of the states.
                Can be given either as a numerical vector or character
                vector state names.}
  exclude{Exclude states from the plot. The complementary of subset.
    Ignored if subset is given.}
  col.arr{Color of the arrows between boxes.
    A vector of character strings, the arrows are referred to as the
    row-wise sequence of non-NA elements of the transition matrix.
    Thus the first ones refer to the transitions out of state 1, in
    order of states.}
  lwd.arr{Line withs of the arrows.}
  font.arr{Font of the text annotation the arrows.}
  pos.arr{Numerical between 0 and 1, determines the position on
    the arrows where the text is written.}
  txt.arr{Text put on the arrows.}
  col.txt.arr{Colors for text on the arrows.}
  offset.arr{The amount offset between arrows representing
    two-way transitions, that is where there are arrows both ways
    between two boxes.}
  sub.st{Subset of the states to be drawn.}
  sub.tr{Subset of the transitions to be drawn.}
  x1{x-coordinate of the starting point.}
  y1{y-coordinate of the starting point.}
  x2{x-coordinate of the end point.}
  y2{y-coordinate of the end point.}
  gap{Length of the gap between the box and the ends of the arrows.}
  fr{Length of the arrow as the fraction of the distance between the
            boxes. Ignored unless given explicitly, in which case any value
            given for gap is ignored.}
  angle{What angle should the arrow-head have?}
  length{Length of the arrow head in inches. Defaults to 1/30 of the
                physical width of the plot.}
  
These functions are designed to facilitate the drawing of multistate models, mainly by automatic calculation of the arrows between boxes. tbox draws a box with centered text, and returns a vector of location, height and width of the box. This is used when drawing arrows between boxes. dbox draws a box with a cross, symbolizing a death state. boxarr draws an arrow between two boxes, making sure it does not intersect the boxes. Only straight lines are drawn. boxes.Lexis takes as input a Lexis object sets up an empty plot area (with axes 0 to 100 in both directions) and if boxpos=FALSE (the default) prompts you to click on the locations for the state boxes, and then draws arrows implied by the actual transitions in the Lexis object. The default is to annotate the transitions with the number of transitions. A transition matrix can also be supplied, in which case the row/column names are used as state names, diagnonal elements taken as person-years, and off-diagnonal elements as number of transitions. This also works for boxes.matrix. Optionally returns the R-code reproducing the plot in a file, which can be useful if you want to produce exactly the same plot with differing arrow colors etc. boxarr draws an arrow between two boxes, on the line connecting the two box centers. The offset argument is used to offset the arrow a bit to the left (as seen in the direction of the arrow) on order to accommodate arrows both ways between boxes. boxarr returns a named list with elements x, y and d, where the two former give the location of a point on the arrow used for printing (see argument pos) and the latter is a unit vector in the direction of the arrow, which is used by boxes.Lexis to position the annotation of arrows with the number of transitions. boxes.MS re-draws what boxes.Lexis has done based on the object of class MS produced by boxes.Lexis. The point being that the MS object is easily modifiable, and thus it is a machinery to make variations of the plot with different color annotations etc. fill.arr is just a utility drawing nicer arrows than the default arrows command, basically by using filled arrow-heads; called by boxarr.
The functions tbox and dbox return the location and dimension of the boxes, c(x,y,w,h), which are designed to be used as input to the boxarr function. The boxarr function returns the coordinates (as a named list with names x and y) of a point on the arrow, designated to be used for annotation of the arrow. The function boxes.Lexis returns an MS object, a list with five elements: 1) Boxes - a dataframe with one row per box and columns xx, yy, wd, ht, font, lwd, col.txt, col.border and col.bg, 2) an object State.names with names of states (possibly an expression, hence not possible to include as a column in Boxes), 3) a matrix Tmat, the transition matrix, 4) a data frame, Arrows with one row per transition and columns: lwd.arr, col.arr, pos.arr, col.txt.arr, font.arr and offset.arr and 5) an object Arrowtext with names of states (possibly an expression, hence not possible to include as a column in Arrows) An MS object is used as input to boxes.MS, the primary use is to modify selected entries in the MS object first, e.g. colors, or supply subsetting arguments in order to produce displays that have the same structure, but with different colors etc. [object Object] par( mar=c(0,0,0,0), cex=1.5 ) plot( NA, bty="n", xlim=0:1*100, ylim=0:1*100, xaxt="n", yaxt="n", xlab="", ylab="" ) bw <- tbox( "Well" , 10, 60, 22, 10, col.txt="blue" ) bo <- tbox( "other Ca", 45, 80, 22, 10, col.txt="gray" ) bc <- tbox( "Ca" , 45, 60, 22, 10, col.txt="red" ) bd <- tbox( "DM" , 45, 40, 22, 10, col.txt="blue" ) bcd <- tbox( "Ca + DM" , 80, 60, 22, 10, col.txt="gray" ) bdc <- tbox( "DM + Ca" , 80, 40, 22, 10, col.txt="red" ) boxarr( bw, bo , col=gray(0.7), lwd=3 ) # Note the argument adj= can takes values outside (0,1) text( boxarr( bw, bc , col="blue", lwd=3 ), expression( lambda[Well] ), col="blue", adj=c(1,-0.2), cex=0.8 ) boxarr( bw, bd , col=gray(0.7) , lwd=3 ) boxarr( bc, bcd, col=gray(0.7) , lwd=3 ) text( boxarr( bd, bdc, col="blue", lwd=3 ), expression( lambda[DM] ), col="blue", adj=c(1.1,-0.2), cex=0.8 ) # Set up a transition matrix allowing recovery tm <- rbind( c(NA,1,1), c(1,NA,1), c(NA,NA,NA) ) rownames(tm) <- colnames(tm) <- c("Cancer","Recurrence","Dead") tm boxes.matrix( tm, boxpos=TRUE ) # Illustrate texting of arrows boxes.Lexis( tm, boxpos=TRUE, txt.arr=c("en","to","tre","fire") ) zz <- boxes( tm, boxpos=TRUE, txt.arr=c(expression(lambda[C]), expression(mu[C]), "recovery", expression(mu[R]) ) ) # Change color of a box zz$Boxes[3,c("col.bg","col.border")] <- "green" boxes( zz ) # Set up a Lexis object data(DMlate) str(DMlate) dml <- Lexis( entry=list(Per=dodm, Age=dodm-dobth, DMdur=0 ), exit=list(Per=dox), exit.status=factor(!is.na(dodth),labels=c("DM","Dead")), data=DMlate[1:1000,] ) # Cut follow-up at Insulin dmi <- cutLexis( dml, cut=dml$doins, new.state="Ins", pre="DM" ) summary( dmi ) boxes( dmi, boxpos=TRUE ) boxes( dmi, boxpos=TRUE, show.BE=TRUE ) boxes( dmi, boxpos=TRUE, show.BE="nz" ) boxes( dmi, boxpos=TRUE, show.BE="nz", BE.sep=c("In:"," Out:","") ) # Set up a bogus recovery date just to illustrate two-way transitions dmi$dorec <- dmi$doins + runif(nrow(dmi),0.5,10) dmi$dorec[dmi$dorec>dmi$dox] <- NA dmR <- cutLexis( dmi, cut=dmi$dorec, new.state="DM", pre="Ins" ) summary( dmR ) boxes( dmR, boxpos=TRUE ) boxes( dmR, boxpos=TRUE, show.D=FALSE ) boxes( dmR, boxpos=TRUE, show.D=FALSE, show.Y=FALSE ) boxes( dmR, boxpos=TRUE, scale.R=1000 ) MSobj <- boxes( dmR, boxpos=TRUE, scale.R=1000, show.D=FALSE ) MSobj <- boxes( dmR, boxpos=TRUE, scale.R=1000, DR.sep=c(" (",")") ) class( MSobj ) boxes( MSobj ) MSobj$Boxes[1,c("col.txt","col.border")] <- "red" MSobj$Arrows[1:2,"col.arr"] <- "red" boxes( MSobj ) tmat.Lexis survival hplot iplot

Arguments