Julio Sergio
2013-Apr-12 03:15 UTC
[R] A strange behaviour in the graphical function "curve"
I thought the curve function was a very flexible way to draw functions. So I
could plot funtions like the following:
# I created a function to produce functions, for instance:
fp <- function(m,b) function(x) sin(x) + m*x + b
# So I can produce a function like this
ff <- fp(-0.08, 0.2)
ff(1.5)
# Is the same as executing
sin(1.5) - 0.08*1.5 + 0.2
# Let's plot this
plot(fp(0.1,0.1),xlim=c(-2*pi,2*pi),col="red")
curve(fp(0,0)(x),add=T)
curve(ff(x),add=T,col="blue")
When I get to plot some more complex functions, "curve", instead of
taking
the argument function as a black-box, i.e., something that takes an argument
(the x) and returns a value (the y), seems to inspect the inner code of the
argument function in a way that even R itself doesn't do. See what I'm
talking about:
# A function that returns a 2-element vector, given a
# single argument
zetas <- function(alpha) {z <- qnorm(alpha/2); c(z,-z)}
# A transformation function - it can take a vector as
# its z argument
Tzx <- function(z, sigma_p, mu_p) sigma_p*z + mu_p
# Another transformation function similar to the
# previous one - it can take a vector as its x argument
Txz <- function(x, sigma_p, mu_p) (x - mu_p)/sigma_p
# The general function with several arguments
BetaG <- function(mu, alpha, n, sigma, mu_0) {
lasZ <- zetas(alpha) # It is a vector
sigma_M <- sigma/sqrt(n)
lasX <- Tzx(lasZ, sigma_M, mu_0) # Another vector(transf. from lasZ)
NewZ <- Txz(lasX, sigma_M, mu) # A new vector:transf. from lasX
# And the result is a single value:
pnorm(NewZ[2]) - pnorm(NewZ[1])
}
# Now, let's have a function of a single argument, giving
# particular values to all other arguments; so miBeta depends
# only on the value of the argument 'mu'
miBeta <- function(mu) BetaG(mu, 0.05, 36, 48, 400)
# I can call this function with 420 and it works
miBeta(420)
# But when the time comes to plot the function, it doesn't work
curve(miBeta,xlim=c(370,430), xlab="mu", ylab="L(mu)")
When I called miBeta with any value the R interpreter didn't complain.
However, "curve" seems to go deeper than the R interpreter and issues
several error messages:
Error en curve(miBeta, xlim = c(370, 430), xlab = "mu", ylab =
"L(mu)") :
'expr' did not evaluate to an object of length 'n'
Adem?s: Mensajes de aviso perdidos
In x - mu_p :
longitud de objeto mayor no es m?ltiplo de la longitud de uno menor
Do you have any idea on why "curve" behaves this way?
Thanks,
-Sergio.
Berend Hasselman
2013-Apr-12 05:37 UTC
[R] A strange behaviour in the graphical function "curve"
On 12-04-2013, at 05:15, Julio Sergio <juliosergio at gmail.com> wrote:> I thought the curve function was a very flexible way to draw functions. So I > could plot funtions like the following: > > # I created a function to produce functions, for instance: > fp <- function(m,b) function(x) sin(x) + m*x + b > # So I can produce a function like this > ff <- fp(-0.08, 0.2) > ff(1.5) > # Is the same as executing > sin(1.5) - 0.08*1.5 + 0.2 > # Let's plot this > plot(fp(0.1,0.1),xlim=c(-2*pi,2*pi),col="red") > curve(fp(0,0)(x),add=T) > curve(ff(x),add=T,col="blue") > > When I get to plot some more complex functions, "curve", instead of taking > the argument function as a black-box, i.e., something that takes an argument > (the x) and returns a value (the y), seems to inspect the inner code of the > argument function in a way that even R itself doesn't do. See what I'm > talking about: > > # A function that returns a 2-element vector, given a > # single argument > zetas <- function(alpha) {z <- qnorm(alpha/2); c(z,-z)} > > # A transformation function - it can take a vector as > # its z argument > Tzx <- function(z, sigma_p, mu_p) sigma_p*z + mu_p > > # Another transformation function similar to the > # previous one - it can take a vector as its x argument > Txz <- function(x, sigma_p, mu_p) (x - mu_p)/sigma_p > > # The general function with several arguments > BetaG <- function(mu, alpha, n, sigma, mu_0) { > lasZ <- zetas(alpha) # It is a vector > sigma_M <- sigma/sqrt(n) > lasX <- Tzx(lasZ, sigma_M, mu_0) # Another vector(transf. from lasZ) > NewZ <- Txz(lasX, sigma_M, mu) # A new vector:transf. from lasX > # And the result is a single value: > pnorm(NewZ[2]) - pnorm(NewZ[1]) > } > > # Now, let's have a function of a single argument, giving > # particular values to all other arguments; so miBeta depends > # only on the value of the argument 'mu' > miBeta <- function(mu) BetaG(mu, 0.05, 36, 48, 400) > > # I can call this function with 420 and it works > miBeta(420) > > # But when the time comes to plot the function, it doesn't work > curve(miBeta,xlim=c(370,430), xlab="mu", ylab="L(mu)") > > > When I called miBeta with any value the R interpreter didn't complain. > However, "curve" seems to go deeper than the R interpreter and issues > several error messages: > > Error en curve(miBeta, xlim = c(370, 430), xlab = "mu", ylab = "L(mu)") : > 'expr' did not evaluate to an object of length 'n' > Adem?s: Mensajes de aviso perdidos > In x - mu_p : > longitud de objeto mayor no es m?ltiplo de la longitud de uno menor > > Do you have any idea on why "curve" behaves this way?Yes. curve expects the function you give it to return a vector if the input argument is a vector. This is clearly documented for the argument "expr" of curve. Your function miBeta returns a scalar when the argument mu is a vector. Use Vectorize to vectorize it. Like this VmiBeta <- Vectorize(miBeta,vectorize.args=c("mu")) VmiBeta(c(420,440)) and draw the curve with this curve(VmiBeta,xlim=c(370,430), xlab="mu", ylab="L(mu)") Berend