help with expression()

#1
Good day forum,

I would like to create an axis that will further my illustration of a plot on a logarithmic scale...
[TEX] 10^0, \qquad 10^1, \qquad 10^2, \qquad 10^3, \qquad \ldots [/TEX]

This I can achieve, statically, with :
Code:
axis(2,at=10^seq(0,3,1),labels=expression(10^0,10^1,10^2,10^3), las=1)
but, now I would like to create a function to specifically generate a certain style of plot and would like to dynamically generate the labels according to the range passed. My problem boils down to manipulating the input of the expression() function to achieve desired results. I believe that the input of expression() should be in the form of some sort of list?!?

I have tried, intuitively and naively, things such as expression(paste(10^seq(0,3,1), collapse=", ")), but to no avail. (the 0 and 3 in example will later be replaced with variables representing suitable upper and lower bounds)

Could someone please give me a nudge in the right direction with regards to my problem.

Thanks in advance

Chippy
 
Last edited:
#3
Hi Dason,

here's the "basic" thing I'm trying to accomplish
Code:
RngToPlot <- seq(1:1000)

plot(RngToPlot,RngToPlot ,log="y", ylim=range(RngToPlot),yaxt="n")
axis(2,at=10^seq(0,3,1),labels=expression(10^0,10^1,10^2,10^3), las=1)
and I would like to create a function that will do some of this automatically for me (For the moment I've removed other additional formatting that the function should do. I've also expanded some steps, just for improved readability)

Code:
log10PlotY <- function(x, y){
  rngY <- range(y)
  logm <- floor(log10(rngY[1]))
  logM <- ceiling(log10(rngY[2]))
  exponents <- seq(logm, logM, by=1)
  plot(x,y, ylim=range(10^logm,10^logM), log="y",yaxt="n")
  axis(2,at=10^seq(logm,logM,1),labels=expression(10^seq(logm,logM,1)), las=1)
}

log10PlotY(RngToPlot, RngToPlot)
my problem comes in with the expression() function. The axis function wants the length of "at=" and "labels=" to be the same length, but when I try to pass the labels as above (10^seq(logm,logM,1)), expression() sends back something of length 1 and I end up with the error :

'at' and 'labels' lengths differ, 4 != 1

So...I'm not certain what the correct method is to pass my variables to the "label=".
 

bryangoodrich

Probably A Mammal
#4
If I understand what you want, you want to be able to generate the expression command automatically from your data?

Here's an approach I toyed around with. First, you'll want to understand do.call. This is a command that executes a command and passes the arguments to that command as a list. Okay? So, what you want to feed it are character statements compiled in some way. We can create those strings with paste and convert it to a list with as.list, e.g.,

Code:
as.list(paste("10^", seq(10), sep = ""))
[[1]]
[1] "10^1"

[[2]]
[1] "10^2"

[[3]]
[1] "10^3"

[[4]]
[1] "10^4"

[[5]]
[1] "10^5"

[[6]]
[1] "10^6"

[[7]]
[1] "10^7"

[[8]]
[1] "10^8"

[[9]]
[1] "10^9"

[[10]]
[1] "10^10"
Each of these can then be fed directly into expression using do.call

Code:
do.call("expression", as.list(paste("10^", seq(10), sep = "")))
The expression above is exactly what you pass as the parameter "label = do.call(...)". I tested this out on some generic data and a BS sequence and it worked out fine. You'll have to customize it for your purposes, of course, and it didn't show me the first and last couple of marks.
 

Dason

Ambassador to the humans
#5
This is kind of kludgy but it gets the job done

Code:
log10PlotY <- function(x, y){
  rngY <- range(y)
  logm <- floor(log10(rngY[1]))
  logM <- ceiling(log10(rngY[2]))
  exponents <- seq(logm, logM, by=1)
  plot(x,y, ylim=range(10^logm,10^logM), log="y",yaxt="n") 

  vals <- paste("10^", seq(logm, logM, 1), sep = "", collapse = ", ")
  # Yucky but it'll do...
  expr <- eval(parse(text = paste("expression(", vals, ")")))

  axis(2,at=10^seq(logm,logM,1),labels = expr, las=1)
}
 

Dason

Ambassador to the humans
#6
The problem with that approach is that you construct
Code:
expression("10^0", "10^1", "10^2")
but that is different than
Code:
expression(10^0, 10^1, 10^2)
The former won't actually produce labels that have the proper superscripting - they'll just produce labels that look like 10^1 instead of \(10^1\). The latter will do what we want which is why I ended up having to go the eval(parse(...)) route.
 
#7
@bryangoodrich : Thank you very much for your code. It means a lot to get input from the experts. Thanks for telling me about do.call - I will definitely be reading up on that one! Your code works, but unfortunately it pastes "10^1" instead of [TEX] 10^1 [/TEX]. I'll keep playing with it until I get your solution working, because, intuitively, it looks like it MUST work. Also, it is your approach that I originally was aiming for. Thank you very much for your help.

@Dason : Thank you as well for your speedy response to my question. Your method works perfectly and I will be using this one as it provides labels as [TEX] 10^1 [/TEX]. Also thank you for adding to my tiny smorgasbord of functions - I will definitely be reading up on those as well. I also believe that your treatment of the problem can be applied successfully to a wide variety of situations - thanks for sharing this train of thought and method!!

All in all - thanks guys - MUCH appreciated!
 

Dason

Ambassador to the humans
#8
Here is an alternative way of doing it without resorting to eval(parse(...))

Code:
log10PlotY <- function(x, y){
  rngY <- range(y)
  logm <- floor(log10(rngY[1]))
  logM <- ceiling(log10(rngY[2]))
  exponents <- seq(logm, logM, by=1)
  plot(x,y, ylim=range(10^logm,10^logM), log="y",yaxt="n") 

  id <- seq(logm, logM, 1)
  expr <- do.call("c", lapply(id, function(x){substitute(expression(10^x), list(x=x))}))

  axis(2,at=10^seq(logm,logM,1),labels = expr, las=1)
}
It alternatively uses substitute and the fact that: c(expression(foo), expression(bar)) is the same as expression(foo, bar).

It could be refactored a little more by saving intermediate results so that it's more readable but this is how I wrote it so... yeah.