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
personyears and transitions with events or rates.
Usage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56  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("\n(",")") 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, ... )

Arguments
txt 
Text to be placed inside the box. 
x 
xcoordinate of center of box. 
y 
ycoordinate 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,

b2 
Coordinates of the "to" box; like 
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 For 
boxpos 
If 
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 personyears and transitions be put in the plot.
Ignored if 
show.Y 
If logical: Should personyears be put in the boxes. If numeric: Numbers to put in boxes. 
scale.Y 
What scale should be used for annotation of personyears. 
digits.Y 
How many digits after the decimal point should be used for the personyears. 
show.BE 
Logical. Should number of persons beginning resp. ending follow up in each state be shown? If given as charcater "nz" or "noz" the numbers will be shown, but zeros omitted. 
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 
scale.D 
Synonumous with 
digits.D 
Synonumous with 
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 
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 
col.arr 
Color of the arrows between boxes. A vector of character strings, the arrows are referred to as the rowwise sequence of nonNA 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 twoway 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 
xcoordinate of the starting point. 
y1 
ycoordinate of the starting point. 
x2 
xcoordinate of the end point. 
y2 
ycoordinate 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 
angle 
What angle should the arrowhead have? 
length 
Length of the arrow head in inches. Defaults to 1/30 of the physical width of the plot. 
Details
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
personyears, and offdiagnonal elements as number of transitions.
This also works for boxes.matrix
.
Optionally returns the Rcode 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
redraws 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 arrowheads; called
by boxarr
.
Value
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.
Author(s)
Bendix Carstensen
See Also
tmat.Lexis
Examples
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69  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=dodmdobth, DMdur=0 ),
exit=list(Per=dox),
exit.status=factor(!is.na(dodth),labels=c("DM","Dead")),
data=DMlate[1:1000,] )
# Cut followup 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 twoway 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 )
