A couple of weeks ago I posted a trick in R-help on improving Quartz
behaviour in the command line version of R:
http://tolstoy.newcastle.edu.au/R/e6/help/09/04/12948.html .

Works with Aqua Tcl/Tk 8.5 too, but I discovered one annoying
side-effect. After having a Tk dialog open (and using it) for a while,
the R process starts eating more than 50% cpu on my PPC G4, using
either the 8.4 or the 8.5 Tcl/Tk libraries. (I'm currently running R
2.8.1 .)

This does NOT happen when running the exact same code in the same
commandline R version with the 8.4 X11 Tcl/Tk libraries, nor when I
run the Quartz version in R-GUI.

For completeness, here's the Tcl/Tk function:

dialog.test <- function(wait=FALSE)
{
        with3 <- function( data1, data2=.GlobalEnv, expr )
        {
                attach(data1)
                attach(data2)
                on.exit( detach(data1), add= FALSE )
                on.exit( detach(data2), add= TRUE )
        
                try( eval( substitute(expr), parent.frame() ) )
        }

        require(tcltk) || stop("tcltk support is absent")

        tt <- tktoplevel()
        tkwm.title(tt,"VG1 tests")
        tt.done <- tclVar("0")

        name <- paste('dialog.test',as.character(tt$ID), sep='')
        assign( name, tt, env=tdialog.env )

        dialogVals<-get("dialogVals", env=RJVB.env)
        data<-tclVar(dialogVals[1])
        crit<-tclVar(dialogVals[2])
        eval1st<-tclVar(dialogVals[9])
        func<-tclVar(dialogVals[3])
        args<-tclVar(dialogVals[4])
        args2<-tclVar(dialogVals[5])
        acomm<-tclVar(dialogVals[8])
        sumvar <- tclVar(dialogVals[7])
        done <- tclVar(0)
        savecmd<-tclVar(dialogVals[6]);
        devvar <- tclVar( dev.cur() )
        theData <- ""

        reset <- function()
        {
                tclvalue(data)<-""
                tclvalue(crit)<-""
                tclvalue(eval1st)<-""
                tclvalue(func)<-""
                tclvalue(args)<-""
                tclvalue(args2)<-""
                tclvalue(acomm)<-""
                tclvalue(sumvar)<-"0"
        }

        doSource <- function()
        {
                fileN <- tclvalue( tkgetOpenFile() )
                if( fileN != "" ){
                        try( source(fileN) )
                }
        }

        dfInfo <- function(fnc)
        {
        ## notice that tclvalue() is correct here, since it is the
        ## string representation of xvar and yvar that is being
        ## displayed in the entry fields

                dataf  <- tclvalue(data)
                crit  <- tclvalue(crit)
                eval1st  <- tclvalue(eval1st)

                if( is.null(crit) | !strlen(crit) ){
                        theData <- paste( dataf )
                        assign( "Selected.Cases", "", env=RJVB.env )
                }
                else{
                        theData <- paste( "SelectCases(", dataf, ",\"", crit, 
"\")" )
                }
                cmd<-paste( fnc, "( ", theData, " )" )
                try(
                        cmd<-parse( text=cmd )
                );
                print( paste( "###", cmd ) )
                print( try( eval(cmd, envir=.GlobalEnv) ) )
                cmd
        }

        build <- function()
        {
        ## notice that tclvalue() is correct here, since it is the
        ## string representation of xvar and yvar that is being
        ## displayed in the entry fields

                dataf  <- tclvalue(data)
                crit  <- tclvalue(crit)
                eval1st  <- tclvalue(eval1st)
                func  <- tclvalue(func)
                args  <- tclvalue(args)
                args2  <- tclvalue(args2)
                acomm  <- tclvalue(acomm)
                summ <- as.logical(tclObj(sumvar))

                assign( "dialogVals",
c(dataf,crit,func,args,args2,dialogVals[6],tclvalue(sumvar), acomm,
eval1st ), env=RJVB.env )

                if( is.null(crit) | !strlen(crit) ){
                        theData <- paste( dataf )
                        assign( "Selected.Cases", "", env=RJVB.env )
                }
                else{
                        theData <- paste( "SelectCases(", dataf, ",\"", crit, 
"\")" )
                }
                if( is.null(acomm) | is.na(acomm) | !strlen(acomm) ){
                        acomm <- ""
                }
                else{
                        acomm <- paste( ", add.comment=\"", acomm, "\"" )
                }
                if( summ ){
                        cmd<-paste( "with3( ", theData, ", tkdial.env, summary(
last.dialog.result<-", func, "(", args, ",", args2, acomm, ") ) )" )
#                       cmd<-paste( "with2( ", theData, ", summary(
last.dialog.result<-", func, "(", args, ",", args2, acomm, ") ) )" )
                }
                else{
                        cmd<-paste( "with3( ", theData, ", tkdial.env,
last.dialog.result<-", func, "(", args, ",", args2, acomm, ") )" )
#                       cmd<-paste( "with2( ", theData, ", 
last.dialog.result<-", func,
"(", args, ",", args2, acomm, ") )" )
                }
                assign( "Selected.Data", theData, env=RJVB.env )
                try(
                        cmd<-parse( text=cmd )
                );
                cmd
        }

        saveIt <- function()
        {
                cmd<-savecmd  <- tclvalue(savecmd)

                assign( "dialogVals",
c(dialogVals[1],dialogVals[2],dialogVals[3],dialogVals[4],dialogVals[5],cmd,dialogVals[7],
dialogVals[9]), env=RJVB.env )
                try(
                        cmd<-parse( text=savecmd )
                );
                cmd
        }

        doIt <- function(cmd="")
        {
                orgDev <- dev.cur()
                try( dev.set( tclvalue(devvar) ) )
                func  <- tclvalue(func)
                eval1st  <- tclvalue(eval1st)

                eval( parse( text="tkdial.env <- new.env()"), env=.GlobalEnv )

                if( !is.null(eval1st) & strlen(eval1st) ){
                        try(
                                eval1st <- parse( text=eval1st )
                        );
                        cat(deparse(eval1st,width=500),sep="\n")
                        print(
                                try( eval(eval1st, env=tkdial.env) )
                        );
                        ls( env=tkdial.env )
                }

                cat("### Command executed via Tk ###\n")
                cat(deparse(cmd,width=500),sep="\n")
                cat("### Output:\n")
                dialogVals<-get("dialogVals", env=RJVB.env)
                print( system.time( print( try( res<-eval(cmd, 
envir=.GlobalEnv) ) ) ) )
                if( func == 'aov' | func == 'aov.VG1' ){
                        cat('\n')
                        try( print( TukeyHSD(res, ordered=TRUE) ), silent=TRUE)
                }
                cat( paste( "### ----------- (", 
deparse(tclvalue(data),width=132),
") ----------- ###\n", sep="" ) )

                try( dev.set(orgDev) )

                eval( parse( text="rm(tkdial.env)" ), env=.GlobalEnv )
        }

        doQuit <- function()
        {
                dQ <- function()
                {
                        tclvalue(done)<-"cancel"
                        tkdestroy(tt)
                        tt.done<-"1"
                }

                 # if the window is referenced in the windowlist environment, 
remove
the reference and then close
                if( exists(name, env=tdialog.env) ){
                        w <- get(name, env=tdialog.env)
                        if( !is.null(w) && class(w) == "tkwin" ){
                                try( assign( name, NULL, env=tdialog.env ) )
                                try( rm( list=name, envir=tdialog.env ) )
                                dQ()
                        }
                }
                else{
                 # if not, close too. Probably means that dQ() can sstill be 
called
recursively...
                        dQ()
                }
                return(0)
        }

        data.entry <- tkentry(tt, textvariable=data, width=100)
        crit.entry <- tkentry(tt, textvariable=crit, width=100)
        eval1st.entry <- tkentry(tt, textvariable=eval1st, width=100)
        func.entry <- tkentry(tt, textvariable=func, width=100)
        args.entry <- tkentry(tt, textvariable=args, width=100)
        args2.entry <- tkentry(tt, textvariable=args2, width=100)
        acomm.entry <- tkentry(tt, textvariable=acomm, width=100)
        dev.entry <- tkentry(tt, textvariable=devvar, width=2)

        summ.cbut <- tkcheckbutton(tt,text="Print summary()", variable=sumvar)

        submit.but <- tkbutton(tt, text="submit",
                                 command=function()doIt(build()) )

        savecmd.entry <- tkentry(tt, textvariable=savecmd, width=100)
        save.but <- tkbutton(tt, text="save",
                                command=function()doIt(saveIt()) )

        reset.but <- tkbutton(tt, text="Reset", command=reset)
        source.but <- tkbutton(tt, text="Source", command=function()doSource() )
        cancel.but <- tkbutton(tt, text="Cancel", command=doQuit )
        
        names.but <- tkbutton(tt, text="names", 
command=function()dfInfo("names") )
        summary.but <- tkbutton(tt, text="summary",
command=function()dfInfo("summary") )

        tkgrid(tklabel(tt,text="Dataframe"), data.entry, names.but, 
columnspan=3 )
        tkgrid(tklabel(tt,text="Sel.Crit"), crit.entry, summary.but, 
columnspan=3 )
        tkgrid(tklabel(tt,text="Eval.1st"), eval1st.entry, columnspan=3 )
        tkgrid(tklabel(tt,text="Analysis"), func.entry, columnspan=3 )
        tkgrid(tklabel(tt,text="Variables"), args.entry, columnspan=3 )
        tkgrid(tklabel(tt,text="Options"), args2.entry, columnspan=3 )
        tkgrid(tklabel(tt,text="Comment"), acomm.entry, columnspan=3 )
        tkgrid(summ.cbut, tklabel(tt,text="Device"), dev.entry, sticky="e" ,
columnspan=3 )
        tkgrid(tklabel(tt,text="Save cmd"), savecmd.entry, columnspan=3 )
        tkgrid(submit.but, save.but, reset.but, source.but, cancel.but,
columnspan=2, sticky="w")

## capture destroy (e.g. from window controls
## otherwise the tkwait hangs with nowhere to go)
#       tkbind(tt, "<Destroy>", function()tclvalue(done)<-"quit")
        tkbind(tt, "<Destroy>", function()doQuit())
        tkbind(tt, "<Return>", function()doIt(build()) )
        tkbind(tt, "<Control-s>", function()doIt(saveIt()) )
        tkbind(tt, "<Control-S>", function()doSource() )

        .Tcl("update idletasks")

        if( wait ){
                while( tclvalue(done) != "cancel" ){
                        tkwait.variable(done)
                        doQuit()
                }
        }
#       else{
#               return(tt)
#       }

## not necessary: button handlers do all the work, until tkdestroy().
#       tkwait.variable(done)
#
#       while( tclvalue(done)!= "cancel" ){
#               if(tclvalue(done)=="quit") stop("aborted")
#
#               if( tclvalue(done)=="save"){
#                       cmd <- saveIt()
#               }
#               else{
#                       cmd <- build()
#               }
#               cat("### Command executed via Tk ###\n")
#               cat(deparse(cmd,width=132),sep="\n")
#               cat("### Output:\n")
#               dialogVals<-get("dialogVals", env=RJVB.env)
#               print( try( eval.parent(cmd) ) )
#               cat("### ----------------------- ###\n")
#
#               tkwait.variable(done)
#       }

#       return(NULL)

}

On 2009-04-28, René J.V. Bertin <rjvber...@gmail.com> wrote:

>  mkApp /Library/Frameworks/R.framework/Resources/bin/exec/R
<snip>
>  improves the behaviour of Quartz graphics windows, and of dialogs made
>  with TclTk (Aqua version 8.4), which for me now behave like under X11.
>  (i.e. as if controlled by a separate thread while the prompt remains
>  usable.)

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to