Search code examples
roopreference-class

Output to pdf not working with ReferenceClasses methods in R?


Output to pdf not working with ReferenceClasses methods in R?

This is an example taken from the ReferenceClasses R doc, with some minor modification:

mEdit = setRefClass("mEdit", fields = list(data="matrix", edits="list"))
mEdit$methods(
    edit = function(i, j, value) {
        backup = list(i, j, data[i, j])
        data[i, j] <<- value
        edits <<- c(edits, list(backup))
        invisible(value)
    }
)
mEdit$methods(
undo = function() {
    prev = edits
    if(length(prev)) {
        prev = prev[[length(prev)]]
    }
    else {
        stop("No more edits to undo!")
    }
    edit(prev[[1]], prev[[2]], prev[[3]])
    length(edits) <<- length(edits) - 2
    invisible(prev)
}
)
mEdit$methods(
    show = function() {
        message("ClassName: ", classLabel(class(.self)))
        message("Data:")
        methods::show(data)
        message("Undo list length: ", length(edits))
    }
)
mEdit$methods(
    .DollarNames.mEdit = function(x, pattern) {
        grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
    }
)

x = matrix(1:24, 3, 8)
xx = mEdit(data=x)
xx$edit(2,2,0)
xx$show()
xx$edit(3, 5, 1)
xx$show()
xx$undo()
xx$show()

mv = setRefClass(
"matrixViewer",
fields=c("viewerDevice", "viewerFile"),
contains="mEdit"
                 )
mv$methods(
    .DollarNames.mEdit = function(x, pattern) {
        grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
    }
)

mv$methods(
    view = function() {
        ## dd = dev.cur();
        ## dev.set(viewerDevice)
        ## devAskNewPage(FALSE)
        image(
            data,
            main=paste("After", length(edits), "edits")
        )
        ## dev.set(dd)
    }
)
mv$methods(
    edit = function(i,j, value) {
        callSuper(i,j, value)
        view()
    }
)
mv$methods(
    initialize = function(file="./mv.pdf", ...) {
        viewerFile <<- file
        ## pdf(viewerFile)
        ## viewerDevice <<- dev.cur()
        ## dev.set(dev.prev())
        callSuper(...)
    }
)
mv$methods(
    finalize = function() {
        dev.off(viewerDevice)
    }
)


x = matrix(rnorm(64, 0, 34), 8, 8)
xx = mv(file="/tmp/x.pdf", data=x)
xx$edit(2,2,0)
xx$edit(3, 5, 1)
xx$edit(4, 4, 2.3)
xx$undo()
xx$view()

Note that I have commented out those lines concerning switch of output devices, so it uses the default device all through, otherwise when the view method is called, the plot is not written to the pdf file at all. Any idea why this is happening?


Solution

  • Call rm on xx and then call garbage collection. finalize will then be called which will invoke dev.off and the pdf will be written. This assumes everything is uncommented.

    rm(xx)
    gc()
    

    Also your .DollarNames should be

    .DollarNames.mEdit = function(x, pattern) {
        grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
    }
    
    .DollarNames.matrixViewer = function(x, pattern) {
        grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
    }
    

    and are not methods of the Reference class. They are external functions seperate to the Reference classes.

    So the main takeaway here is that finalize is not called until the object is garbage collected.