Open chrisadolph opened 12 years ago
So this isn't exactly what is suggested in this issue, but I've been playing with making a more generalized sorting function that users could use to reorder a variety of object types they might chose to plot with a rope ladder, as I know I've often been building a ropeladder plot from something other than a raw simcf simulation output. You can see limits of my R programming sophistication (for example, I couldn't figure out how a tidy function to evaluate whether a list is a list of all vectors, so please let me know if there's an alternative to my mean(sapply...) hack job below).
Also, I suspect this whole thing is redundant to other functions out there, but I don't know what they are, and this might be handy for the non-R savvy target audience of the friendlier simcf/tile. (Really all this does is saves other users knowing that they need to and doing the work to generate a dataframe and then order it).
Comments? Right now this is fully stand alone, but should hopefully provide a decent base to start from to fit in with the automated cf/tile work.
ladderSort <- function(x, sort.by=NULL, ascending=TRUE, labels=NULL){
# transform list of vectors (i.e. yhyp output from linearsimev)
if (is.list(x) && mean(sapply(x,is.vector,simplify=TRUE))==1) {
x <- as.data.frame(x)
}
#placeholder for code to transform yhyp or full cf list once Issue 15 is addressed
#if (is.cf(x)){
# x <- as.data.frame(x$yhyp)
# }
#generic for any other matrix
if (is.matrix(x)==TRUE) {x <- as.data.frame(x)}
#check that dataframe (to use order), add labels if necessary
if (is.data.frame(x)!=TRUE) {stop("Input must be matrix, dataframe, list of vectors, or cf object with point estimates")}
if (is.null(labels)) cat("Including a column or vector of labels is recommended to make it easier to see what's what after sorting.\n")
if (!is.null(labels)) {rownames(x) <- labels}
#sort dataframe by specified sort.by, or default 'pe'
if (is.null(sort.by)) {
if(is.null(x$pe)) stop("Input must include vector named 'pe', otherwise specify a vector with sort.by")
else {
sort.by <- x$pe # if an error here, report that input dataframe must have column named 'pe' for default,
# or else user must specify a vector with length = nrow(input dataframe) to sort by (may
# be a specified column of input matrix or dataframe)
}
}
if (ascending) {x.sort <- x[order(sort.by),]}
else x.sort <- x[order(-sort.by),]
x.sort
}
On the name of the function: sort()
responds to the type of object given, and looks for a sort.obj()
function for objects of type obj
. So the function should be sort.ropeladder()
, and have inputs compatible with sort()
.
On the inputs: To fit with other sort()
functions, the first input should be x
, the second should be decreasing=FALSE
(the logic is that you ignore this unless you want and set decreasing=TRUE
), and then you can add any other new inputs.
On sorting by another object: The object "sorted by" should be the same kind of object as the one we are creating, ie, another ropeladder object. Also, I would recommend by
instead of sort.by
.
Next steps: The real trick is getting this to sort any and all inputs as needed. Ropeladder can take lots of inputs; these may be vector, with one element matching each scenario, or scalar. Most of the vector elements need to be sorted as well. (This gets tricky, as the vectors can be shorter than x and the get "repeated" to the length of x). You might find it easiest to have the sort.ropeladder()
function fill out all the default values for all possible inputs, which tile()
does on a trace-by-trace basis using ropeladderTileTraceDefaults()
followed by ropeladderTileTraceFillout()
. Then you could sort every input after it has been "stretched out" into the appropriate length.
sort.cf()
would be an object-oriented function that reorders scenarios from smallest to largest point estimate. This would be after running linearsimev, etc., and would require implementation of Issue 15 above.We would also make this an input option in all our simulation functions, with default
sort=FALSE
. Sorting is often best done by the user, though this function will make it much easier. We also want to be able to sort one cf object based on the order of another, so maybe we also wantorder.cf()