[R] split.screen problem and segments in figure margin

Marc Schwartz MSchwartz at medanalytics.com
Sun Sep 7 05:06:37 CEST 2003


Many thanks to Uwe and Thomas for their off-list clarifications.

To quote my daughter, who recently said with a slip of the tongue: "Dad,
you are not being very observative". 

I apologize for my oversight on this one.

As a result of focusing on the initial function sequence that Thomas
posted, where 'dat' was assigned after the call to plot(dat, ...) and
then reviewing the bug report, I was led to focus on any changes in
certain graphic parameters as per my reply. I however missed the now
obvious error in the way that the points are being plotted outside of
the expected ranges.

I suppose that this is a good example of "Be careful of what ye seek..."

That all being said, I have spent much of the day trying to track this
one down, albeit without definitive success at this point.

After reviewing the code for split.screen, screen and erase.screen, I
have noted that there is a probability that at least part of the problem
is embedded in how the device parameters for each individual screen are
being saved and restored as one changes from screen to screen. There is
an explicit list of parameters (defined in split.screen) that are being
saved and manipulated in the Global Environment and my suspicion at this
point is that there is a mis-match of some sort in that process.

The particular pars that are being saved and restored are:

c("adj", "bty", "cex", "col", "crt", "err", "font", "lab", "las", "lty",
"lwd", "mar", "mex", "mfg", "mgp", "pch", "pty", "smo", "srt", "tck",
"usr", "xaxp", "xaxs", "xaxt", "xpd", "yaxp", "yaxs", "yaxt", "fig")


One can run the following code with proper results:

graphics.off()
x11()
split.screen(c(3, 1))
split.screen(c(2, 1), 1)

dat <- rnorm(1000)

screen(3)
plot(dat, type = "n")
par3 <- par(no.readonly = TRUE)

screen(4)
plot(dat, type = "n")
par4 <- par(no.readonly = TRUE)

screen(2)
plot(dat, type = "n")
par2 <- par(no.readonly = TRUE)

# In lieu of screen(3)
par(fig = par3$fig)
par(usr = par3$usr)
points(dat)

# In lieu of screen(4)
par(xpd = TRUE)
par(fig = par4$fig)
par(usr = par4$usr)
points(dat)

# In lieu of screen(2)
par(xpd = FALSE)
par(fig = par2$fig)
par(usr = par2$usr)
points(dat)

close.screen(all = TRUE)


Note that I explicitly save the non-readonly pars after each plot() call
so that I can restore specific pars prior to calling points().

Rather than using screen() to select the screen to place the set of
points, I am explicitly setting par("fig") and par("usr"), which
essentially accomplishes the same thing as screen(), although there is a
lot of additional code and other pars that get saved and restored, in
that function of course.

What is curious however, is the need to set par(xpd = TRUE) for the
second call to points(). If I do not, then no points are drawn after the
first set. Note that I have to re-set par(xpd = FALSE) for the third set
of points, or they do not plot. This gets curiouser and curiouser...

What is also interesting, is that the default arguments to screen() not
only include the screen number, but 'new' which is set to TRUE by
default. The effect of this argument is to call erase.screen(). However,
the default background color is 'transparent'. Thus if one calls
screen() as Thomas did in the original code, there is no visible screen
clearing effect. If one however sets par(bg = "white") before calling
the screen() calls, the individual screens are indeed cleared. This
behavior is referenced in the help 'warning' section for these screen
related functions.. 

Thus, in the situation Thomas is trying to get to work (go back to a
plot and add to it), in reality each call to screen should be of the
form screen(n, new = FALSE).

Now, with that in place, using the following section of code in place of
the second series of calls above:

screen(3, new = FALSE)
points(dat)

screen(4, new = FALSE)
points(dat)

screen(2, new = FALSE)
points(dat)

close.screen(all = TRUE)


One actually gets the first set of points properly plotted. However the
second and third sets do not. This brings us back to par("xpd"), yet
with a curious result. If I try to take the approach that I did above:

screen(3, new = FALSE)
points(dat)

screen(4, new = FALSE)
par(xpd = TRUE)
points(dat)

screen(2, new = FALSE)
par(xpd = FALSE)
points(dat)

close.screen(all = TRUE)

This results in a proper first set of points in the lower screen, but
the other two, which have a proper x axis range, are improperly plotted
on the y axis.

At this point, after looking at the code, I am losing my
"observativeness" and cannot seem to identify what is causing the
problems as Thomas first noted today.  Perhaps someone with a clear set
of eyes can see something here. I hope that this may be of help in
providing some sense of direction here. If there is something obvious, I
am just not seeing it at this point, but then again, my eyes are pretty
glazed over...

Marc




More information about the R-help mailing list