Michael Friendly
2009-Aug-17 19:53 UTC
[R] help simplifying complex graphic arguments to a function
I'm working on a package to produce graphic displays of 2- and 3-way tables
and need some help/advice on how to simplify the specification of a complex
argument that gives the drawing details for each cell of the table.
Prototypes of two functions, 'tableplot' and 'cellgram' are
given below.
The essential idea is that for a given table ('values'), the cells can
be
be of different 'types' (integers: 1, 2, ..., max(types)). An argument
'patterns' is a list of max(types) lists, where patterns[[k]] is
presently
a list of 10 graphic parameters specifying shapes, colors, fill,
background color,
etc. that are passed as arguments to the cellgram function.
The difficulty is that it's too hard to remember the order and meaning
of the cellgram arguments to be passed in the patterns argument to
tableplot,
and often quite a few of these will take their default values, but-- as
presently written-- all must be specified.
The actual implementation of these functions use grid graphics, and I know
from other grid-based packages that use named specifications like
gp = gpar(shape=1, shape.col="black", shape.lty=2, ...)
are commonly used, but I'm unable to see how to re-write these functions to
take advantage of that form. To be specific, I need to re-write cellgram
to take two arguments
cellgram(cell.values, cell.pattern)
and then be able to extract the current arguments from cell.pattern within
this function.
tableplot <- function(
values, # Matrix of values to plot; can be a matrix,
or an array of 3 dimensions.
types, # Matrix of pattern designations (i.e., what pattern
for each cell).
# patterns, # List of lists; each list specifies one pattern.
patterns = list(list(0, "black", 1, "white",
"white", 0, 0.5,
"grey80", "no", 1)),
...){
#
#---Draw cellgrams.
for (i in 1:dim(values)[1]){
for (j in 1:dim(values)[2]){
pattern = patterns[[types[i,j]]]
cellgram(cell = values[i,j,],
shape = pattern[[1]],
shape.col = pattern[[2]],
shape.lty = pattern[[3]],
cell.fill = pattern[[4]],
back.fill = pattern[[5]],
label = pattern[[6]],
label.size= pattern[[7]],
ref.col = pattern[[8]],
ref.grid = pattern[[9]],
scale.max = pattern[[10]]
)
}
}
}
cellgram = function(
#-- Arguments that may be vectorized:
cell, #-- cell value(s)
shape=0, #-- shape of cell value(s); 0=circle,
1=diamond, 2=square, 3=cross
shape.col="black", #-- color of shape(s), outline only
shape.lty=1, #-- line type used for shape(s)
#-- Arguments that can not be vectorized:
scale.max=1,
shape.lwd=1, #-- line width of shape(s)
cell.fill="white", #-- inside color of smallest shape in a cell
back.fill="white", #-- background color of cell
label=0, #-- how many cell values will be printed; max is 4
label.size=0.7, #-- size of text labels
ref.col="grey80", #-- color for ref lines
ref.grid=TRUE, #-- to draw ref lines or not
neg.col="white", #-- fill color for negative cell value
frame.col="black", #-- color of frame around cell
frame.lwd="0.5" #-- line width of frame around cell
t.col="black", #-- color of cell labels [[ should be:
label.col]]
)
{
# ...
}
--
Michael Friendly Email: friendly AT yorku DOT ca
Professor, Psychology Dept.
York University Voice: 416 736-5115 x66249 Fax: 416 736-5814
4700 Keele Street http://www.math.yorku.ca/SCS/friendly.html
Toronto, ONT M3J 1P3 CANADA
baptiste auguie
2009-Aug-18 14:19 UTC
[R] help simplifying complex graphic arguments to a function
I'm facing a similar challenge with a grid.table function (see example
below). I envisaged two routes,
1- rather than assigning a list of properties for each cell, I would
define a matrix for each property. For instance, the default could be,
fill = matrix("grey90", nrow(values), ncol(values)) # or an array if
more than 2D
col = matrix("red", nrow(values), ncol(values))
col.text = matrix("black", nrow(values), ncol(values))
The drawing of each cell would look like,
for( ii in 1:nrow){
for (jj in 1:ncol){
grid.rect(gp=gpar(fill = fill[ii, jj], col = col[ii, jj]))
grid.text(values[ii, jj], gp = gpar(col= col.text[ii, jj]))
# or whatever grid function you need
}
}
2- Create the table with default values, but give a name to each grob
and allow for subsequent editing of individual gpar() properties.
(as suggested in sec. 7.3.10 "avoiding argument explosion" of Paul
Murrell's R graphics book)
Perhaps a structure like a gTree can help (in my case I wanted the
table header to have different settings than the rest of the table).
Best,
baptiste
source("http://gridextra.googlecode.com/svn/trunk/R/tableGrob.r")
tc = textConnection("
carat VeryLongWordIndeed color clarity depth
14513 1.35 Ideal J VS2 61.4
28685 0.30 Good G VVS1 64.0
50368 0.75 Ideal F SI2 59.2")
d = read.table(tc,head=T)
close(tc)
grid.newpage()
g = grid.table(d)
grid.ls(g) # not much of a clue which is which... let's edit a random
one (numbers probably session-dependent)
grid.edit("GRID.tableGrob.556::table.header.left::GRID.cellGrob.718::GRID.rect.717",
gp=gpar(fill="red"))
2009/8/17 Michael Friendly <friendly at yorku.ca>:> I'm working on a package to produce graphic displays of 2- and 3-way
tables
> and need some help/advice on how to simplify the specification of a complex
> argument that gives the drawing details for each cell of the table.
> Prototypes of two functions, 'tableplot' and 'cellgram' are
given below.
>
> The essential idea is that for a given table ('values'), the cells
can be
> be of different 'types' (integers: 1, 2, ..., max(types)). ?An
argument
> 'patterns' is a list of max(types) lists, where patterns[[k]] is
presently
> a list of 10 graphic parameters specifying shapes, colors, fill, background
> color,
> etc. that are passed as arguments to the cellgram function.
>
> The difficulty is that it's too hard to remember the order and meaning
> of the cellgram arguments to be passed in the patterns argument to
> tableplot,
> and often quite a few of these will take their default values, but-- as
> presently written-- all must be specified.
>
> The actual implementation of these functions use grid graphics, and I know
> from other grid-based packages that use named specifications like
>
> gp = gpar(shape=1, shape.col="black", shape.lty=2, ...)
>
> are commonly used, but I'm unable to see how to re-write these
functions to
> take advantage of that form. ?To be specific, I need to re-write cellgram
> to take two arguments
>
> cellgram(cell.values, cell.pattern)
>
> and then be able to extract the current arguments from cell.pattern within
> this function.
>
>
> tableplot <- function(
>
> ? values, ? ? ? ? ? ? ? # Matrix of values to plot; can be a matrix, or an
> array of 3 dimensions.
> ? types, ? ? ? ? ?# Matrix of pattern designations (i.e., what pattern for
> each cell).
> # ? ?patterns, ? ? ? ? ? ? # List of lists; each list specifies one
pattern.
> ? patterns = list(list(0, "black", 1, "white",
"white", 0, 0.5, "grey80",
> "no", 1)),
> ? ...){
>
> #
> ? #---Draw cellgrams.
>
> ? for (i in 1:dim(values)[1]){
> ? ? ? for (j in 1:dim(values)[2]){
>
> ? ? ? ? ? pattern = patterns[[types[i,j]]]
> ? ? ? ? ? cellgram(cell ? ? ? = values[i,j,],
> ? ? ? ? ? ? ? ? ?shape ? ? ?= pattern[[1]],
> ? ? ? ? ? ? ? ? ?shape.col = pattern[[2]],
> ? ? ? ? ? ? ? ? ?shape.lty = pattern[[3]],
> ? ? ? ? ? ? ? ? ?cell.fill = pattern[[4]],
> ? ? ? ? ? ? ? ? ?back.fill = pattern[[5]],
> ? ? ? ? ? ? ? ? ?label ? ? = pattern[[6]],
> ? ? ? ? ? ? ? ? ?label.size= pattern[[7]],
> ? ? ? ? ? ? ? ? ?ref.col ? ? = pattern[[8]],
> ? ? ? ? ? ? ? ? ?ref.grid ? ? = pattern[[9]],
> ? ? ? ? ? ? ? ? ?scale.max = pattern[[10]]
> ? ? ? ? ? ? ? ? ?)
> ? ? ? ? ? }
> ? ? ? }
>
> }
>
> cellgram = function(
>
> ? #-- Arguments that may be vectorized:
>
> ? cell, ? ? ? ? ? ? ? ? ? #-- cell value(s)
> ? shape=0, ? ? ? ? ? ? ? #-- shape of cell value(s); 0=circle, 1=diamond,
> 2=square, 3=cross
> ? shape.col="black", #-- color of shape(s), outline only
> ? shape.lty=1, ? ? ? ? #-- line type used for shape(s)
>
> ? #-- Arguments that can not be vectorized:
>
> ? scale.max=1, ? ? shape.lwd=1, ? ? ? #-- line width of shape(s)
> ? cell.fill="white", #-- inside color of smallest shape in a cell
> ? back.fill="white", #-- background color of cell
> ? label=0, ? ? ? ? ? #-- how many cell values will be printed; max is 4
> ? label.size=0.7, ? ?#-- size of text labels
> ? ref.col="grey80", ?#-- color for ref lines
> ? ref.grid=TRUE, ? ? #-- to draw ref lines or not
> ? neg.col="white", ? #-- fill color for negative cell value
> ? frame.col="black", #-- color of frame around cell
> ? frame.lwd="0.5" ? ?#-- line width of frame around cell
> ? t.col="black", ? ? #-- color of cell labels ?[[ should be:
label.col]]
> ? )
> {
> # ...
> }
>
>
> --
> Michael Friendly ? ? Email: friendly AT yorku DOT ca Professor, Psychology
> Dept.
> York University ? ? ?Voice: 416 736-5115 x66249 Fax: 416 736-5814
> 4700 Keele Street ? ?http://www.math.yorku.ca/SCS/friendly.html
> Toronto, ONT ?M3J 1P3 CANADA
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide
http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>
--
_____________________________
Baptiste Augui?
School of Physics
University of Exeter
Stocker Road,
Exeter, Devon,
EX4 4QL, UK
http://newton.ex.ac.uk/research/emag