Peter
Peter

Reputation: 35

Is it possible to do a common plot in parallel (with foreach)?

The problem in short: I have to visualise an optimisation process on a plot. On a pre-plotted device the new solutions (as points(x,y)) should appear as they are available. I have working sequential code by a nested loop, but it should possible to make it parallel. I gave a try with the foreach package (with the doParallel backend) but the spawned processes can not plot on the parent processe's device - obviously. Is it possible to overcome this maybe with another package or anyhow?

Upvotes: 3

Views: 725

Answers (2)

Steve Weston
Steve Weston

Reputation: 19667

I don't think it's possible to have one process plot to another process's graphics device in R. Instead, the processes need to send messages to a designated process that does all of the graphics operations. That would be rather difficult using parallel or foreach/doParallel, but it's relatively easy using foreach with a parallel backend that supports processing worker results on-the-fly, such as doMPI or doRedis. In that case, you can plot the points in the combine function as they are computed by the workers. Here's a simple example:

library(doMPI)
nworkers <- 4
cl <- startMPIcluster(nworkers)
comm <- cl$comm  # get communicator number
registerDoMPI(cl)
cap <- capabilities()
if (cap['aqua']) quartz() else if (cap['X11']) X11() else windows()
plot(integer(0), integer(0),
     main='Random points generated by doMPI workers',
     xlab='X', ylab='Y', xlim=c(1,100), ylim=c(1,100))
legend('topright', sprintf('worker %d', 1:nworkers), pch=1:nworkers)

# The argument "p" is a list of arguments to the function "points"
plotpoint <- function(x, p) {
  do.call('points', p)
  x
}

foreach(i=icount(100), .combine='plotpoint',
        .init=NULL, .inorder=FALSE) %dopar% {
  Sys.sleep(abs(rnorm(1, mean=3)))
  list(x=sample(100,1), y=sample(80,1), pch=mpi.comm.rank(comm))
}
text(50, 90, 'Finished')
Sys.sleep(10)

closeCluster(cl)
mpi.quit()

I'm throwing away the results since they are only used to call points, but you could modify plotpoint to save some part of the result in the first argument x. Just make sure that you modify the .init argument to the appropriate data structure.

Upvotes: 1

MentatOfDune
MentatOfDune

Reputation: 309

You might be able to try something like this:

foreach(i=1:10) %dopar% with(env.profile(.GlobalEnv), #Your Code#)

I'm not sure if this would work or not. You may be running into problems because of the sequential nature of plotting with base R graphics works. You might also try creating a list and just adding the results of each iteration to the list during the %dopar% call. After it's finished, you should be able to just use lapply(point.list, points).

Upvotes: 0

Related Questions