[Rd] "plot.ts" doesn't respect the value of "pch" (+ blocked from Bugzilla signups)

2016-08-24 Thread Gregory Werbin
I did a search on Bugzilla for "plot.ts" and didn't find anything on 
this issue. I tried to sign up for Bugzilla to report it, but my e-mail 
address didn't pass your "syntax checking" for a legal e-mail address.


The bug is easily reproducible on my machine as follows:

## start

# generate some data
y <- arima.sim(list(), 150)

# this will definitely dispatch to a ".ts" method
class(y)[1] == 'ts'

# compare and note that `cex = 0.5` has no effect
plot(y, type = 'b', pch = 16)
plot(y, type = 'b', pch = 16, cex = 0.5)

# it works if `y` is coerced back to a regular vector
plot(as.numeric(y), type = 'b', pch = 16, cex = 0.5)

# another way to see the issue
plot.ts(y, type = 'b', pch = 16, cex = 0.5)
plot.default(y, type = 'b', pch = 16, cex = 0.5)

## end

Skimming through source code for `plot.ts`, it seems like the `cex` 
argument is being "eaten" by a `...` somewhere without being properly 
passed to `plot.default`.


The output of `R.version` is:
platform   x86_64-apple-darwin15.5.0
arch   x86_64
os darwin15.5.0
system x86_64, darwin15.5.0
status
major  3
minor  3.1
year   2016
month  06
day21
svn rev70800
language   R
version.string R version 3.3.1 (2016-06-21)
nickname   Bug in Your Hair

Greg

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] "plot.ts" doesn't respect the value of "pch" (+ blocked from Bugzilla signups)

2016-08-25 Thread Gregory Werbin
I've had a chance to read the source more thoroughly. The chain of 
events is as follows:


1. Local function `plotts()` is defined with argument `cex` that 
defaults to `par("cex")`
2. `...` is passed to `plotts()`. If "cex" is an element in `...`, 
inside `plotts()` the variable `cex` is assigned thereby (overriding the 
default arg). Importantly, this means that the element "cex" is captured 
and _removed_ from `...`. `...` is eventually passed to `plot.window()`.

3.
  - In the univariate case (NCOL(x) == 1): When `lines.default()` is 
called to actually plot the data 
(https://github.com/wch/r-source/blob/trunk/src/library/stats/R/ts.R#L588 
and 
https://github.com/wch/r-source/blob/trunk/src/library/stats/R/ts.R#L597 
for reference), `cex` is not included in the call.
  - In the bivariate case (NCOL(x) > 1): Because "cex" was captured and 
removed from `...`, it is not passed to `plot.default` when it is called 
(https://github.com/wch/r-source/blob/trunk/src/library/stats/R/ts.R#L548).


It turns out that the "eating" is not being done by `...` but by the 
signature of `plotts`.


The documentation currently reads:

...: additional graphical arguments, see 'plot', 'plot.default' and 
'par'.


This, to me, suggests parity with the 'plot' function in how the 
arguments in '...' are handled. Therefore either the code is wrong or 
the documentation is incomplete and misleading.


I filed this is as a bug because it's undocumented, and inconsistent 
with how other arguments typically passed through `plot.default` are 
handled.


I'll be happy to do the patch myself -- I just need to know which thing 
to patch (the source or the docs).



Greg


On 2016-08-25 03:00, David Winsemius wrote:

On Aug 24, 2016, at 5:59 PM, Gregory Werbin 
 wrote:


I did a search on Bugzilla for "plot.ts" and didn't find anything on 
this issue. I tried to sign up for Bugzilla to report it, but my 
e-mail address didn't pass your "syntax checking" for a legal e-mail 
address.


The bug is easily reproducible on my machine as follows:

## start

# generate some data
y <- arima.sim(list(), 150)

# this will definitely dispatch to a ".ts" method
class(y)[1] == 'ts'

# compare and note that `cex = 0.5` has no effect
plot(y, type = 'b', pch = 16)
plot(y, type = 'b', pch = 16, cex = 0.5)

# it works if `y` is coerced back to a regular vector
plot(as.numeric(y), type = 'b', pch = 16, cex = 0.5)

# another way to see the issue
plot.ts(y, type = 'b', pch = 16, cex = 0.5)
plot.default(y, type = 'b', pch = 16, cex = 0.5)

## end

Skimming through source code for `plot.ts`, it seems like the `cex` 
argument is being "eaten" by a `...` somewhere without being properly 
passed to `plot.default`.


'...' does not "eat" parameters, it passes them on.

Looking at the very top of the body we see this in the definition of 
the internal `plotts` function:


cex = par("cex"), lty = par("lty"), lwd = par("lwd"),
axes = TRUE, frame.plot = axes, ann = par("ann"), cex.lab = 
par("cex.lab"),

col.lab = par("col.lab"), font.lab = par("font.lab"),
cex.axis = par("cex.axis"), col.axis = par("col.axis"),

And at the end of the body we se the call to plotts (including the 
"dots")


So I would suggest using par-settings.

par(cex=0.5)
plot(y, type = 'b', pch = 16)

(Question seems more appropriate for r-help.)

--
David.


The output of `R.version` is:
platform   x86_64-apple-darwin15.5.0
arch   x86_64
os darwin15.5.0
system x86_64, darwin15.5.0
status
major  3
minor  3.1
year   2016
month  06
day21
svn rev70800
language   R
version.string R version 3.3.1 (2016-06-21)
nickname   Bug in Your Hair

Greg

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


David Winsemius
Alameda, CA, USA


__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


[Rd] Why is as.function() slower than eval(call("function"())?

2017-08-04 Thread Gregory Werbin
(Apologies if this is better suited for R-help.)

On my system (macOS Sierra, late 2014 MacBook Pro; R 3.4.1, Homebrew build), I 
found that it is faster to construct a function using eval(call("function", 
...)) than using as.function(list(...)). Example:

make_fn_1 <- function(a, b) eval(call("function", a, b), env = 
parent.frame())
make_fn_2 <- function(a, b) as.function(c(a, list(b)), env = parent.frame())

a <- as.pairlist(alist(x = , y = ))
b <- quote(x + y)

library("microbenchmark")
microbenchmark(make_fn_1(a, b), make_fn_2(a, b))

# Unit: microseconds
# expr   min lqmean median uqmax neval cld
#  make_fn_1(a, b) 1.671 1.8855 2.13297  2.039 2.1950  9.852   100  a
#  make_fn_2(a, b) 3.541 3.7230 4.13400  3.906 4.1055 23.153   100   b

At first I thought the gap was due to the overhead of calling c(a, list(b)). 
But this turns out not to be the case:

make_fn_weird <- function(a, b) as.function(c(a, b), env = parent.frame())
b_wrapped <- list(b)

make_fn_weirder <- function(a_b) as.function(a_b, env = parent.frame())
a_b <- c(a, b_wrapped)

microbenchmark(make_fn_1(a, b), make_fn_2(a, b),
   make_fn_weird(a, b_wrapped), make_fn_weirder(a_b))

# Unit: microseconds
# expr   min lqmean median uqmax 
neval cld
#  make_fn_1(a, b) 1.718 1.8990 2.12119 1.9860 2.1605  8.057   
100 a
#  make_fn_2(a, b) 3.393 3.5865 4.03029 3.6655 3.9615 27.499   
100   c
#  make_fn_weird(a, b_wrapped) 3.354 3.5005 3.77190 3.6405 3.9425  6.839   
100   c
# make_fn_weirder(a_b) 2.488 2.6290 2.83352 2.7215 2.8800  7.007   
100  b

One IRC user pointed out that as.function() takes its own path through the 
code, namely do_asfunction() (in src/main/coerce.c). What is it about this code 
path that's 50% slower than whatever happens during eval(call("function", a, 
b))?

Obviously this is a trivial micro-optimization and it doesn't matter to 99% of 
users. Mostly asking out of curiosity, but also wondering if there's a more 
general lesson to be learned here.

Thanks!
__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel