Skip to content

Changing a plot

7 messages · R Help, Ben Bolker, Adaikalavan Ramasamy +2 more

#
Hello list,

I've been working on this problem for a while and I haven't been able
to come up with a solution.

I have a couple of functions that plot a bunch of data, then a single
point on top of it.  What I want is to be able to change the plot of
the point without replotting all the data.  Consider the following
example:

x = rnorm(100,1,0.5)
y = rnorm(100,1,0.5)
plot(x,y,pch=16)
points(x[35],y[35],pch=19,col=6,cex=3)

What I want to be able to do is to change the purple point to a
different value without replotting everything.

I know this seems like an odd suggestion, but it comes up a lot with
the work I'm doing.  I've prepared a package on CRAN called
ResearchMethods for a course I'm working on, and there are several
functions in there who's GUIs could work better if I could figure this
out.

If anyone has any ideas, or needs some further explanation, feel free
to contact me.

Thanks a lot,
Sam Stewart
#
R Help <rhelp.stats <at> gmail.com> writes:
R's default (base) graphics model is a 'canvas' -- things get
drawn, but nothing ever gets erased. (The cheap solution is
to overplot in the background color, but that 
won't work if there's stuff underneath the point
that you want to preserve.) You probably need to move
to the grid graphics package (hint: buy or borrow Paul Murrell's
book) to do something like this.

  Ben Bolker
#
One way is to keep a copy of the original and then return to it when you 
need it.

  x <- rnorm(100,1,0.5)
  y <- rnorm(100,1,0.5)
  plot(x,y,pch=16)
  original <- recordPlot()

  for( i in 1:10 ){
    points( x[i], y[i], pch=19, col="yellow", cex=3)
    points( x[i], y[i], pch=16)
    Sys.sleep(1)                  # slow the graphs a bit
    replayPlot(original)
  }

Regards, Adai
R Help wrote:
#
R Help wrote:
Hi Sam,
An interesting question. Here's a way to erase a point while redrawing 
any points within a certain proportion of the plot extent. It wouldn't 
be hard to extend this to draw a new point somewhere else if you wanted 
it all in one function.

erase.point<-function(x,y,pch=1,col=par("fg"),cex=1,tol=0.02*cex,
 erase.index,erase.pch=1,erase.col=par("bg"),erase.cex=1) {
 
 # erase the point
 points(x[erase.index],y[erase.index],pch=pch,col=erase.col,cex=1.1*erase.cex)
 # repeat the point parameters so that they can be indexed
 if(length(pch) < length(x)) pch<-rep(pch,length.out=length(x))
 if(length(col) < length(x)) col<-rep(col,length.out=length(x))
 if(length(cex) < length(x)) cex<-rep(cex,length.out=length(x))
 # work out the x and y differences within which the remaining points
 # will be redrawn
 xylim<-par("usr")
 xtol<-diff(xylim[1:2])*tol
 ytol<-diff(xylim[3:4])*tol
 for(i in 1:length(x)) {
  if(i != erase.index) {
   # if this point is within the specified tolerance, redraw it
   if(abs(x[i]-x[erase.index]) < xtol && abs(y[i]-y[erase.index]) < ytol)
    points(x[i],y[i],pch=pch[i],col=col[i],cex=cex[i])
  }
 }
}

x = rnorm(100,1,0.5)
y = rnorm(100,1,0.5)
plot(x,y,pch=16)
points(x[35],y[35],pch=19,col=6,cex=3)
erase.point(x,y,pch=19,erase.index=35,erase.pch=19,erase.col="white",erase.cex=3)

Jim
#
Thanks, I looked into the grid package.  The grid package does do a
better job of managing the plotting, but it's still re-plotting the
entire canvas whenever a modifcation is made to a plot.

I guess I should have been a little clearer with my question.  Here's
a sample function.

library(tcltk)
x = runif(10000)
y = runif(10000)
v1 <- viewport()
grid.rect(gp = gpar(lty = "dashed"))
pushViewport(plotViewport(c(5.1, 4.1, 4.1, 2.1)))
pushViewport(dataViewport(x, y))
grid.rect()
grid.xaxis()
grid.yaxis()
grid.points(x, y)
grid.text("1:10", x = unit(-3, "lines"), rot = 90)
v2 <- viewport()
push.viewport()
grid.points(x[1],y[1],pch=16,gp=gpar(col='green'),name='pts')
index = tclVar(1)
grid
refresh <- function(...){
  i <- as.numeric(tclvalue(index))
  grid.edit('pts',x=unit(x[i],'npc'),y=unit(y[i],'npc'))

}
m <- tktoplevel()
pScale <- tkscale(m,from=0,to=10000,orient='horiz',resolution=1,variable=index,command=refresh)
tkgrid(pScale)

The green point should change as the slider is moved, but there are so
many points in the background that replotting them confuses the
graphic.  What I want to be able to do is replt the green point
without removing the background.

Sam Stewart
On Wed, Sep 24, 2008 at 11:12 AM, Ben Bolker <bolker at ufl.edu> wrote:
#
R Help wrote:
OK, I see the issue but I don't at the moment see a way around it.
  The only R graphics device I know of that actually maintains the full
scene in the way that you want is rgl:


library(rgl)
rgl.bg(color="white")
rgl.points(runif(10000),runif(10000),0,col="black")
rgl.viewpoint(theta=0,phi=0,fov=1)
for (i in 5:995) {
  ##  rgl.points(i/1000,i/1000,0,col="green",alpha=0.5,size=20)
  rgl.spheres(i/1000,i/1000,0,col="green",alpha=1,radius=0.02)
  rgl.pop()
}

  This is kind of an ugly workaround, but maybe it will work for you.
(Really, the fundamental problem is that the plot is ALWAYS being
redrawn -- I think the issue is that rgl just redraws it much faster ...)

   I'm curious if anyone else has solutions.

  Ben Bolker
#
R Help wrote:
The TK canvas is rather good at replotting only what is necessary.
Unfortunately, it lacks functionality for a real graphics driver, but
you might want to look into demo(tkcanvas).