From maechler@stat.math.ethz.ch  Tue Jun 27 08:11:36 2000
From: maechler@stat.math.ethz.ch (maechler@stat.math.ethz.ch)
Date: Tue, 27 Jun 2000 09:11:36 +0200 (MET DST)
Subject: [Rd] par(lty = "1") -- lty storage-etc bug (PR#584)
Message-ID: <200006270711.JAA22047@pubhealth.ku.dk>

Bug report, rather than R-help;
This is at least since 1.0.0; didn't try even older versions ..

    Jim> Anon wrote:

    Anon> ...However, if I use Fred <- c(1,"33")...  Is this a
    Anon> bug, or am I missing something?

this made use it  essentially something like   
      par(lty = "1")

    Jim> This is an interesting problem.  It boils down to the fact that
    Jim> PostScript expects an array (even if it's empty) and an offset for
    Jim> "setdash".  Normally, a solid line is specified with an empty
    Jim> array and zero offset.  However, if R gets specs that convert to
    Jim> zero and puts a zero in the array, the PostScript interpreter will
    Jim> barf.  Zero can appear, but there must be at least one non-zero
    Jim> number in the array.  Hexadecimal strings supplied to lty are
    Jim> converted to array elements, but a single character "1" seems to
    Jim> produce "0.00".  Remember that the c() operater will coerce the
    Jim> number 1 to the string "1" when combining it with "33".  That is,
    Jim> it's probably a bad idea to mix the two methods of specifying line
    Jim> types with "lty".

I think there's at least another (maybe the only one) bug in main/graphics.c
which is not related to postscript at all, see below.

    Jim> A possible fix is to insert a test for zero in the function
    Jim> SetLineStyle() - devPS.c:

 >> static void SetLineStyle(int newlty, double newlwd, DevDesc *dd)
 >> {
 >>     PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;
 >>     int i, ltyarray[8];
 >>     int sum = 0;
 >>     if (pd->lty != newlty || pd->lwd != newlwd) {
 >>       pd->lwd = newlwd;
 >>       pd->lty = newlty;
 >>       PostScriptSetLineWidth(pd->psfp, dd->gp.lwd*0.75);
 >>       for(i = 0; i < 8 && newlty & 15 ; i++) {
 >>           ltyarray[i] = newlty & 15;
 >>           sum += ltyarray[i];
 >>           newlty = newlty >> 4;
 >>       }
 >>       if(!sum) i = 0;
 >>       PostScriptSetLineTexture(pd->psfp, ltyarray, i, dd->gp.lwd * 0.75);
 >>     }
 >> }

    Jim> producing a solid line when all elements of 'ltyarray' are zero.

yes, but I think this shouldn't be necessary.

The real bug is uglier:
If you use something like   par(lty="1")  
or any other one-letter (hex digit) string,
this leads to an invalid `code', and further, the storage location 
(such dd->lty in C) of that string somehow loses it's final string
terminator (\0 in C) and gets mangled.
I can reproduce this most easily with the following


for(i in seq(along=dev.list())) dev.off()
par(lty="1")
example(barplot) 
## (almost!) always ends in an error, see below,

## and then
for(i in 1:4) print(par("lty"))

--------

Note that in the Error message below,
    "invalid hex digit in color" 
has been changed in the very latest R-release sources to
    "invalid hex digit in color or lty" 
which is ``more helpful'' here :

> example(barplot) ## (almost!) always ends in an error, see below,

barplt> tN <- table(Ni <- rpois(100, lambda = 5))
barplt> r <- barplot(tN, col = "gray")

barplt> lines(r, tN, type = "h", col = "red", lwd = 2)
Error in plot.xy(xy.coords(x, y), type = type, col = col, lty = lty, ...) : 
	invalid hex digit in color

> traceback()
[1] "plot.xy(xy.coords(x, y), type = type, col = col, lty = lty, ...)"         
[2] "lines.default(r, tN, type = \"h\", col = \"red\", lwd = 2)"               
[3] "lines(r, tN, type = \"h\", col = \"red\", lwd = 2)"                       
[4] "eval.with.vis(expr, envir, enclos)"                                       
[5] "eval.with.vis(ei, envir)"                                                 
[6] "source(zfile, echo = echo, prompt.echo = prompt.echo, verbose = verbose, "
[7] "    max.deparse.length = 250)"                                            
[8] "example(barplot)"                                                         

> for(i in 1:4) print(par("lty"))
[1] "1r"
[1] "1S°I@}@gMG@\\}@\"J@}@U\\F@4}@?D@|@A@|@]G@|@(B@names"
[1] "1|@ult"
[1] "1"
> 

---------
Peter D., I'd like to learn how to use watchpoints to debug this...

Martin

-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
r-devel mailing list -- Read http://www.ci.tuwien.ac.at/~hornik/R/R-FAQ.html
Send "info", "help", or "[un]subscribe"
(in the "body", not the subject !)  To: r-devel-request@stat.math.ethz.ch
_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._


[Rd] par(lty = "1") -- lty storage-etc bug (PR#584)
maechler@stat.math.ethz.ch