[R] Unintended behaviour (possibly bugs)

Martin Maechler m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Thu Jul 2 15:30:05 CEST 2020


>>>>> Alexey Shipunov 
>>>>>     on Wed, 1 Jul 2020 23:58:04 +0900 writes:

    > Dear colleagues,
    > There is a new problem with dotchart(), and it is very simple to reproduce.

    > Just run example(dotchart).

    > On R versions < 4, group labels ("Urban Female" and so on) were
    > visible. Now they are not visible.

    > If in the dotchart() code, we replace the string

    > ===

    > goffset <- (max(linch + offset, ginch, na.rm = TRUE) + 1/16)/lheight

    > ===

    > with the string

    > ===

    > goffset <- (max(linch + 0.2, ginch, na.rm = TRUE) + 1/16)/lheight

    > ===

 > everything start to be OK. Probably, the reason that in the code,
 > there is another "offset" object and they clash. So if we replace this
 > part of code

    > ===

    > offset <- cumsum(c(0, diff(as.numeric(groups)) != 0))
    > y <- seq_len(n) + 2 * offset

    > ===

    > with

    > ===

    > offset1 <- cumsum(c(0, diff(as.numeric(groups)) != 0))
    > y <- seq_len(n) + 2 * offset1

    > ===

    > everything will be well again.

Thank you.

I'll have a look *again*, and cautiously consider the above.
Indeed your second patch seems the correct one, distinguishing the
two different offsets that where conflated.
I will commit to R-devel and also to "R 4.0.2 patched" (but note
that no quick R 4.0.3 has been planned).

Note (Alexey knows, almost everbody else probably not):
This has come from another dotchart(* , ylab=.) glitch which
Alexey had reported in February and I had fixed early
March... evidently not fixed quite correctly... and yes, I'm
embarrased.
However I did mention here to have fixed it, on March 12
(--> https://stat.ethz.ch/pipermail/r-help/2020-March/465921.html )

It would have been really great if people would test such
changes, as they were in all pre-releases (R 4.0.0 alpha, beta,
RC), easily available ...  and we could have fixed this even
before R 4.0.0 was released more than a month later than my
e-mail above...

Martin


    > With best wishes,
    > Alexey Shipunov

    > пт, 13 мар. 2020 г. в 18:56, Alexey Shipunov <dactylorhiza using gmail.com>:
    >> 
    >> Dear Martin,
    >> 
    >> Great news, thanks!
    >> 
    >> If you wish, please also consider my initial note about help(hist),
    >> this is definitely worrying new R users.
    >> 
    >> With best wishes,
    >> 
    >> Alexey
    >> 
    >> пт, 13 мар. 2020 г. в 02:16, Martin Maechler <maechler using stat.math.ethz.ch>:
    >> >
    >> > >>>>> Alexey Shipunov
    >> > >>>>>     on Tue, 18 Feb 2020 14:34:48 +0900 writes:
    >> >
    >> >     > Thank you for the detailed explanation. I tend to agree. However, this
    >> >     > behavior is relatively easy to remediate:
    >> >
    >> >     > This is the piece of the current code:
    >> >
    >> >     > ===
    >> >     > if (!(is.null(labels) && is.null(glabels))) {
    >> >     >    nmai <- par("mai")
    >> >     >    nmai[2L] <- nmai[4L] + max(linch + goffset, ginch) + 0.1
    >> >     >    par(mai = nmai)
    >> >     > }
    >> >     > ===
    >> >
    >> >     > This is my proposal:
    >> >
    >> >     > ===
    >> >     > yinch <- if (!is.null(ylab)) 0.4 else 0
    >> >     > if (!(is.null(labels) && is.null(glabels))) {
    >> >     >    nmai <- par("mai")
    >> >     >    nm.2 <- nmai[4L] + max(if(is.null(ylab)) 0 else 0.4) + linch + goffset, ginch) + 0.1
    >> >     >    if (nmai[2L] < nm.2)
    >> >     >       nmai[2L] <- nm.2
    >> >     >    par(mai = nmai)
    >> >     > }
    >> >     > ===
    >> >
    >> >     > Then margins and y-axis labels start to work normally. I wonder if
    >> >     > this (or similar) is possible to introduce into the code?
    >> >
    >> >     > Alexey
    >> >
    >> > Well, I had looked at this back then (~Feb 18), and now had a
    >> > considerable longer look.
    >> >
    >> > Your suggestion makes sense,  but then it needs even more work
    >> > to ensure that the  'ylab'  y-axis label will be placed properly.
    >> >
    >> > Of course, Deepayan (author of grid-based 'lattice')  is right
    >> > that dotchart()s implementation is pretty hackish ... but then
    >> > still.
    >> >
    >> > I have (+-) fixed this in the sources of "R-devel" the
    >> > development version of R (which should become R 4.0.0  on April
    >> > 24 as was announced today).
    >> >
    >> > Now, things like this (extended) example work nicely :
    >> >
    >> > op <- par(xaxs = "i")  # 0 -- 100\%
    >> > dotchart(t(VADeaths), xlim = c(0,100), bg = "skyblue",
    >> >          main = "Death Rates in Virginia - 1940", xlab = "rate [ % ]",
    >> >          ylab = "Grouping:  Age  x   Urbanity . Gender")
    >> > par(op)
    >> >
    >> >
    >> > Thank you, Alexey, for your report and bug fix suggestion!
    >> >
    >> > Best regards,
    >> >
    >> > Martin Maechler
    >> > ETH Zurich and R Core team
    >> >
    >> >
    >> >
    >> >     > ........... 17:37, Deepayan Sarkar <deepayan.sarkar using gmail.com>:
    >> >     >>
    >> >     >> On Mon, Feb 17, 2020 at 10:24 AM Rui Barradas <ruipbarradas using sapo.pt> wrot=
    >> >     > e:
    >> >     >> >
    >> >     >> > Hello,
    >> >     >> >
    >> >     >> > Yes, this is definitely a bug.
    >> >     >>
    >> >     >> I would argue that the only bug here is that the documentation doesn't
    >> >     >> say that 'ylab' may not behave as expected.
    >> >     >>
    >> >     >> dotchart() is mainly designed for 2-way tables (see the VADeaths
    >> >     >> example), but it's implementation is really pretty hackish because it
    >> >     >> has to work within the limited traditional graphics framework. The
    >> >     >> main problem is that dot plots want to put horizontal y-axis labels
    >> >     >> (usually derived from factor levels), which are often longer than the
    >> >     >> default margins, so the margins are modified. Unfortunately they are
    >> >     >> only re-set on exit, and so the ylab that is plotted inside dotchart()
    >> >     >> may be clipped. Traditionally, Cleveland dot plots don't have a y-axis
    >> >     >> label; it's assumed that the factor levels are sufficient (and for
    >> >     >> 2-way tables, there would be two variables, so there is no sensible
    >> >     >> default).
    >> >     >>
    >> >     >> I doubt that dotchart() is worth fixing (except to maybe disallow
    >> >     >> ylab). If you want flexibility, use modern grid-based alternatives
    >> >     >> such as lattice::dotplot() or ggplot2.
    >> >     >>
    >> >     >> -Deepayan
    >> >     >>
    >> >     >> > Even the matrix plot is puzzling, with a "1" as top row sort-of-label
    >> >     >> > but no grid line. I'm trying to follow the source code of dotchart but
    >> >     >> > am yet to understand exactly what it does to decide the margins setting=
    >> >     > s.
    >> >     >> >
    >> >     >> >      if (!(is.null(labels) && is.null(glabels))) {
    >> >     >> >        nmai <- par("mai")
    >> >     >> >        nmai[2L] <- nmai[4L] + max(linch + goffset, ginch) +
    >> >     >> >          0.1
    >> >     >> >        par(mai = nmai)
    >> >     >> >      }
    >> >     >> >
    >> >     >> > This should be moved to r-devel?
    >> >     >> >
    >> >     >> > Rui Barradas
    >> >     >> >
    >> >     >> >  03:33 de 17/02/20, Alexey Shipunov escreveu:
    >> >     >> > > John and Rui, thanks!
    >> >     >> > >
    >> >     >> > > However, if we use the proper object, the problem still persists:
    >> >     >> > >
    >> >     >> > > dotchart(c("3"=1, "2"=2, "1"=3), ylab="Ylab") # ylab is invisible
    >> >     >> > > dotchart(c("aa"=1, "b"=2, "cc"=3), ylab="Ylab") # ylab is partly visible (!!!)
    >> >     >> > > dotchart(c("aaa"=1, "bbb"=2, "ccc"=3), ylab="Ylab") # ylab is well visible
    >> >     >> > >
    >> >     >> > > If the object is matrix, ylab is visible:
    >> >     >> > >
    >> >     >> > > dotchart(matrix(1:3, dimnames=list(c("aa","bb","cc"), NULL)), ylab="Ylab")
    >> >     >> > >
    >> >     >> > > But the ?dotchart explicitly says that "x: either a vector or matrix
    >> >     >> > > of numeric values" and then "labels: a vector of labels for each
    >> >     >> > > point.  For vectors the default is to use  "names(x) = ...".
    >> >     >> > >
    >> >     >> > > So this is likely a bug. Do you agree?
    >> >     >> > >
    >> >     >> > > Alexey
    >> >     >> > >
    >> >     >> > > ..... 01:55, Rui Barradas <ruipbarradas using sapo.pt>:
    >> >     >> > >>
    >> >     >> > >> Hello,
    >> >     >> > >>
    >> >     >> > >> I believe you are wrong, the error is not in dotchart, it's in your
    >> >     >> > >> code. You assume that to plot an object of class "table" is the same as
    >> >     >> > >> to plot an object of class "numeric".
    >> >     >> > >>
    >> >     >> > >> Inline.
    >> >     >> > >>
    >> >     >> > >> =C3=80s 12:21 de 16/02/20, Alexey Shipunov escreveu:
    >> >     >> > >>> Dear list,
    >> >     >> > >>>
    >> >     >> > >>> I have been advised to share these with R-help instead of filling the
    >> >     >> > >>> bug report:
    >> >     >> > >>>
    >> >     >> > >>> 1) dotchart() does not allow to see the left axis title ('ylab') and
    >> >     >> > >>> cannot change the left margin (outer margin 2) of the plot
    >> >     >> > >>>
    >> >     >> > >>> The code:
    >> >     >> > >>>
    >> >     >> > >>> aa <- table(c(1, 1, 1, 2, 2, 3))
    >> >     >> > >>> dotchart(aa, ylab="Ylab") # does not show 'ylab'
    >> >     >> > >>
    >> >     >> > >> You are right, it does *not* show 'ylab' but the user is warned.
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >> aa <- table(c(1, 1, 1, 2, 2, 3))
    >> >     >> > >> dotchart(aa, ylab = "Ylab") # does show 'ylab'
    >> >     >> > >> #Warning message:
    >> >     >> > >> #In dotchart(aa, ylab = "Ylab") :
    >> >     >> > >> #  'x' is neither a vector nor a matrix: using as.numeric(x)
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >> My code:
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >> (mar <- par("mar"))    # new R session
    >> >     >> > >> #[1] 5.1 4.1 4.1 2.1   # the left margin is 4.1
    >> >     >> > >>
    >> >     >> > >> aa <- as.numeric(table(c(1, 1, 1, 2, 2, 3)))
    >> >     >> > >>
    >> >     >> > >> dotchart(aa, ylab = "Ylab") # It does show 'ylab'
    >> >     >> > >> old.par <- par(mar = mar + c(0, 5, 0, 0))
    >> >     >> > >> par("mar")
    >> >     >> > >> #[1] 5.1 9.1 4.1 2.1
    >> >     >> > >>
    >> >     >> > >> dotchart(aa, ylab = "Ylab")  # The left margin is now 9.1, much bigger
    >> >     >> > >>
    >> >     >> > >> par(old.par)                 # It does change the left margin
    >> >     >> > >> dotchart(aa, ylab = "Ylab")  #  but only when a new graph is plotted.
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >>> old.par <- par(mar=c(1, 10, 1, 1)) ; dotchart(aa, ylab="Ylab") ;
    >> >     >> > >>> par(old.par) # does not change left margin
    >> >     >> > >>>
    >> >     >> > >>> Possible solution:
    >> >     >> > >>>
    >> >     >> > >>> I researched the problem and think that the dotchart() code will need
    >> >     >> > >>> few corrections. If there is an interest, I can post it here; or you
    >> >     >> > >>> can look at the code of shipunov::Dotchart1() function.
    >> >     >> > >>>
    >> >     >> > >>> 2) example(hist) includes two "wrong" and "extreme" examples which
    >> >     >> > >>> slow down and even crash R on some systems; this make it unsuitable
    >> >     >> > >>> for demonstration in the class and strikes beginners in R who just
    >> >     >> > >>> want to understand how hist() works. Actually, I did it last week (I
    >> >     >> > >>> was not aware of these examples), and in the class two computers hang,
    >> >     >> > >>> and many others were extremely slow.
    >> >     >> > >>>
    >> >     >> > >>> The code:
    >> >     >> > >>>
    >> >     >> > >>> example(hist)
    >> >     >> > >>>
    >> >     >> > >>> Possible solution:
    >> >     >> > >>>
    >> >     >> > >>> If R maintainers will enclose parts of "hist" example in \dontrun{},
    >> >     >> > >>> this will allow to see the code but in the same time will not strike
    >> >     >> > >>> beginners in R who just
    >> >     >> > >>> want to understand how hist() works. They will still be possible to
    >> >     >> > >>> run with example(..., run.dontrun=TRUE).
    >> >     >> > >>
    >> >     >> > >> Agree, it's annoying. Sometimes there's a Warning section after the
    >> >     >> > >> Details section. Maybe such a section could get users' attention to
    >> >     >> > >> those examples? At least it wouldn't hurt...
    >> >     >> > >>
    >> >     >> > >>
    >> >     >> > >> Hope this helps,
    >> >     >> > >>
    >> >     >> > >> Rui Barradas
    >> >     >> > >>
    >> >     >> > >>>
    >> >     >> > >>> With best wishes,
    >> >     >> > >>>
    >> >     >> > >>> Alexey Shipunov
    >> >     >> > >>> ______________________________________________



More information about the R-help mailing list