Interactive Graphics with tkrplot

The R code for this example is a little longer than that of the simpler examples. The basic idea is that we put a scatter plot in a Tk window, using the tkrplot package by Luke Tierney. We then allow the user to click on (or near) one of the plotted points in order to attach a label to that point (and replot the graph).

The hardest part is mapping between image (Tk widget) coordinates and R plot coordinates, which is done in the function OnLeftClick.

Running the code below gives the following graph window:


Clicking on the upper-left point gives the following message box :


After answering "Yes" to the message box question, the graph is updated. Note the label, "A" above the point that was clicked on.


After labeling all of the points, the graph looks like this :


R Code for Interactive tkrplot Example

xCoords<-(-12:13)
yCoords<-xCoords*xCoords
labelsVec <- LETTERS
require(tcltk)
require(tkrplot)
indexLabeled<-c()
labeledPoints <- list()
tt <- tktoplevel()
tkwm.title(tt,"Click on a point to label it")
parPlotSize <- c()
usrCoords <- c()

plotFunction <- function()
{
  params <- par(bg="white")
  plot(xCoords,yCoords,main="Click on a point to label it")
  if (length(indexLabeled)>0)
    for (i in (1:length(indexLabeled)))
    {
      indexClosest <- indexLabeled[i]
      text(xCoords[indexClosest],yCoords[indexClosest],
           labels=labelsVec[indexClosest],pos=3)
    }
  parPlotSize <<- par("plt")
  usrCoords   <<- par("usr")
  par(params)
}

img <- tkrplot(tt,fun=plotFunction,hscale=1.5,vscale=1.5)
tkgrid(img)

labelClosestPoint <- function(xClick,yClick,imgXcoords,imgYcoords)
{
  squared.Distance <- (xClick-imgXcoords)^2 + (yClick-imgYcoords)^2
  indexClosest <- which.min(squared.Distance)
  indexLabeled <<- c(indexLabeled,indexClosest)
  tkrreplot(img)
}

OnLeftClick <- function(x,y)
{
  xClick <- x
  yClick <- y
  require(tcltk)
  width  <- as.numeric(tclvalue(tkwinfo("reqwidth",img)))
  height <- as.numeric(tclvalue(tkwinfo("reqheight",img)))

  xMin <- parPlotSize[1] * width
  xMax <- parPlotSize[2] * width
  yMin <- parPlotSize[3] * height
  yMax <- parPlotSize[4] * height

  rangeX <- usrCoords[2] - usrCoords[1]
  rangeY <- usrCoords[4] - usrCoords[3]

  imgXcoords <- (xCoords-usrCoords[1])*(xMax-xMin)/rangeX + xMin
  imgYcoords <- (yCoords-usrCoords[3])*(yMax-yMin)/rangeY + yMin

  xClick <- as.numeric(xClick)+0.5
  yClick <- as.numeric(yClick)+0.5
  yClick <- height - yClick

  xPlotCoord <- usrCoords[1]+(xClick-xMin)*rangeX/(xMax-xMin)
  yPlotCoord <- usrCoords[3]+(yClick-yMin)*rangeY/(yMax-yMin)

  msg <- paste("Label the point closest to these approximate plot coordinates: \n",
               "x =",format(xPlotCoord,digits=2),",y =",format(yPlotCoord,digits=2),"?")
  mbval<- tkmessageBox(title="Label Point Closest to These Approximate Plot Coordinates",
                       message=msg,type="yesno",icon="question")

  if (tclvalue(mbval)=="yes")
    labelClosestPoint(xClick,yClick,imgXcoords,imgYcoords)
}

tkbind(img, "<Button-1>",OnLeftClick)
tkconfigure(img,cursor="hand2")