How to place an expression on top of another expression using plotmath - r

If I want to generate a multi-line expression I can do:
over = 'OVER'
below = 'BELOW'
x_lab_title = bquote(atop(.(over), .(below)))
ggplot(data.frame()) + xlab(x_lab_title)
However, I would like to make over and below expressions on their own, e.g.:
over = expression(X^2)
below = expression(Y^2)
but it does not work - renders a blank space instead (why is that?). In my scenario, the real expression is much more complicated, autogenerated, and changing between subsequent plots I generate, thus I cannot simply do:
x_lab_title = bquote(X^2, Y^2)
which would work in this particular case, but not for any other value of over and below.

The problem is that an expression() in R actually acts more like a container of expressions. What you really want is the language object inside the expression object. So you could either do
over = expression(X^2)
below = expression(Y^2)
x_lab_title = bquote(atop(.(over[[1]]), .(below[[1]])))
or, even better, skip the expression() and just use quote()
over = quote(X^2)
below = quote(Y^2)
x_lab_title = bquote(atop(.(over), .(below)))

After some hours of trial and error found a solution - this worked for me:
atop_string = paste0('bquote(atop(', toString(over), ',', toString(below), '))')
x_lab_title = eval(parse(text=atop_string))
This solution first assembles equivalent code representation and then parses it into an expression.
Even though I found a solution on my own, I am still curious why I cannot simply embed expressions in atop?

Related

Functions to format text for base R plotting

Specifying text in a base R plot() with formatting such as italics / bold font / newline usually involves one or more of the following functions:
paste()
expression()
atop()
substitute()
italic()
Is there an intuitive explanation for the differences between these functions and when best to apply them?
What you're referring to is the plotmath syntax.
To start off, let's make it clear that for a plotmath expression to be interpreted as such, you tell R it's an "expression" and that is why you need expression().
So any time you want to use special symbols or formatting, like italic() and atop(), it's actually a part of plotmath and so you need to wrap it in an expression. eg:
plot(0, main = expression(atop(over,italic(under))))
If you've tried out ?italic or ?atop, you've probably noticed it takes you straight to the plotmath manual page, where a bunch of other functions are listed.
What about substitute() ? Well in my previous example, you'll notice I used strings directly to write 'over' and 'under', without putting them within quotes. This is because of the special expression() environment.
So if you need to put whatever is inside a variable in your text (rather than the variable name) then you put your expression inside a substitute() and give it the arguments. eg:
plot(0, main = substitute(atop(oo,italic(under))), list(oo='over2')))
Note that we don't put substitute around the expression block but replace it entirely.
Finally, where does paste() come in all this ? Well, paste is the glue (pun intended) with any text not dealt with by plotmath.
So if you need text before or after math symbols (or formatted text), you paste() things together within the expression (or substitute) environment. eg :
plot(0, main = substitute(paste("b4", atop(oo,italic(under)), aft),
list(oo='over', aft = 'after3')))
As before, if you want to paste the content of a variable, you need substitute.
And Voilà that's most of the plotmath you'll ever need!
For any other symbols, or functions, have look at ?plotmath

Why does substitute change noquote text to a string in R?

I wanted to answer a question regarding plotmath but I failed to get my desired substitute output.
My desired output:paste("Hi", paste(italic(yes),"why not?"))
and what I get: paste("Hi", "paste(italic(yes),\"why not?\")")
text<-'paste(italic(yes),"why not?")'
text
[1] "paste(italic(yes),\"why not?\")"
noqoute_text<-noquote(text)
noqoute_text
[1] paste(italic(yes),"why not?")
sub<-substitute(paste("Hi",noqoute_text),
env=list(noqoute_text=noqoute_text))
sub
paste("Hi", "paste(italic(yes),\"why not?\")")
You're using the wrong function, use parse instead of noquote :
text<-'paste(italic(yes),"why not?")'
noquote_text <- parse(text=text)[[1]]
sub<- substitute(paste("Hi",noquote_text),env=list(noquote_text= noquote_text))
# paste("Hi", paste(italic(yes), "why not?"))
noquote just applies a class to an object of type character, with a specific print method not to show the quotes.
str(noquote("a"))
Class 'noquote' chr "a"
unclass(noquote("a"))
[1] "a"
Would you please elaborate on your answer?
In R you ought to be careful about the difference between what's in an object, and what is printed.
What noquote does is :
add "noquote" to the class attribute of the object
That's it
The code is :
function (obj)
{
if (!inherits(obj, "noquote"))
class(obj) <- c(attr(obj, "class"), "noquote")
obj
}
Then when you print it, the methods print.noquote :
Removes the class "noquote" from the object if it's there
calls print with the argument quote = FALSE
that's it
You can actually call print.noquote on a string too :
print.noquote("a")
[1] a
It does print in a similar fashion as quote(a) or substitute(a) would but it's a totally different beast.
In the code you tried, you've been substituting a string instead of a call.
For solving the question I think Moody_Mudskipperss answer works fine, but as you asked for some elaboration...
You need to be careful about different ways similar-looking things are actually stored in R, which means they behave differently.
Especially with the way plotmath handles labels, as they try to emulate the way character-strings are normally handled, but then applies its own rules. The 3 things you are mixing I think:
character() is the most familiar: just a string. Printing can be confusing when quotes etc. are escaped. The function noquote basically tells R to mark it's argument, so that quotes are not escaped.
calls are "unevaluated function-calls": it's an instruction as to what R should do, but it's not yet executed. Any errors in this call don't come up yet, and you can inspect it.
Note that a call does not have its own evironment given with it, which means a call can give different results if evaluated e.g. from within a function.
Expressions are like calls, but applied more generally, i.e. not always a function that needs to be executed. An expression can be a variable-name, but also a simple value such as "why not?". Also, expressions can consist of multiple units, like you would have with {
Different functions can convert between these classes, but sometimes functions (such as paste!) also convert unexpectedly:
noquote does not do that much useful, as Moody_Mudskipper already pointed out: it only changes the printing. But the object basically remains a character
substitute not only substitutes variables, but also converts its first argument into (most often) a call. Here, the print bites you, for when printing a call, there is no provision for special classes of its members. Try it: sub[[3]] from the question gives[1] paste(italic(yes),"why not?")
without any backslashes! Only when printing the full call the noquote-part is lost.
parse is used to transform a character to an expression. Nothing is evaluated yet, but some structure is introduced, so that you could manipulate the expression.
paste is often behaving annoyingly (although as documented), as it can only paste together character-strings. Therefore, if you feed it anything but a character, it firs calls as.character. So if you give it a call, you just get a text-line again. So in your question, even if you'd use parse, as soon as you start pasting thing together, you get the quotes again.
Finally, your problem is harder because it's using plotmaths internal logic.
That means that as soon as you try to evaluate your text, you'll probably get an error "could not find function italic" (or a more confusing error if there is a function italic defined elsewhere). When providing it in plotmath, it works because the call is only evaluated by plotmath, which will give it a nice environment, where italic works as expected.
This all means you need to treat it all as an expression or call. As long as evaluation cannot be done (as long as it's you that handles the expression, instead of plotmath) it all needs to remain an expression or call. Giving substitute a call works, but you can also emulate more closely what happens in R, with
call('paste', 'Hi', parse(text=text)[[1]])

Trouble interpolating column name for subset in R function

I have (fbodata) 'data.frame': 6181090 obs. of 41 variables:
I want to subset it and save the portion that pertains to a specific subset (like a zip). My approach seems to work when it is not in a function, but I ultimately want to use sapply.
nmakedir <- function(item, ccol) {
snipped a bunch of code that works
trim<- fbodata[ which(paste(ccol)==item),]
trim%>% drop_na(paste(ccol))
trim<- droplevels(trim
save(trim, file = paste(item, "rda", sep="."))
}
The line that doesn't work is one where I creating the subset with which. If i hardcode the line using fbodata$zip instead of paste(ccol) it works fine. Eventually, I plan to call it with something like:
sapply(unique(fbodata$zip),zip, FUN = nmakedir)
I appreciate any clues, I have been on this for a good long while.
A few things going on:
ccol is a string. paste(ccol) is the same string. You never need to call paste with only one argument. (You can use paste to coerce non-strings to strings, but in that case you should use as.character() to be clear.)
Keeping in mind that ccol is a string, what is fbodata$zip? It's a column! What is the equivalent using ccol and brackets? fbodata[[ccol]] or fbodata[, ccol]. You can use either of those interchangeably with fbodata$zip. So, this bad line
fbodata[ which(paste(ccol)==item),]
# should be this:
fbodata[which(fbodata[[ccol]] == item), ]
drop_na, like most dplyr functions, expects (quoting from the help) "bare variable names", not strings. Also from the help, "See Also: drop_na_ for a version that uses regular evaluation and is suitable for programming with". In this case, I don't think you need to do anything more than replace drop_na with drop_na_.
You are missing a right parenthesis on your droplevels command.
There might be more, but this is much as I can see without any sample data. Your sapply call looks funny to me because I thought zip is supposed to be a column name, but when you call sapply(unique(fbodata$zip),zip, FUN = nmakedir) it needs to be an object in your global environment. I would think sapply(unique(fbodata$zip), 'zip', FUN = nmakedir) makes more sense, but without a reproducile example there's no way to know.
It also seems like you're coding your own version of split. I would probably start this off with fbo_split = split(fbodata, fbodata$zip) and then use lapply to drop_na_, droplevels, and save, but maybe your snipped code makes that a less good idea.

How to add a space to an object name in R

Piston_Rings<-diameter[1:25,]
I want my quality control graph NOT to have the underscore in the object name.
At the moment there is an underscore (not a hyphen) in that object name. It is possible to construct objects whose names have spaces in them but in order to access them you will then always need to use backticks in order to get the interpreter to understand what you want:
> `Piston Rings` <- list(1,2)
> `Piston Rings`[[1]]
[1] 1
> `Piston Rings`[[2]]
[1] 2
The problem you incur is cluttering up your code, at least relative to obeying the usual conventions in R where a space is a token-ending marker to the parser. Hyphens (at least short-hyphens) are actually minus signs.
If on the other hand you only want to use a modified version of a name that contains an underscore as the title for a graph, then try something like this:
Piston_Rings <- list() # just for testing purposes so there will be an object.
plot( 1:10,10:1, main = sub("_", " ", quote(Piston_Rings)) )
#BondedDust's answer is correct, but (guessing, since you haven't been very specific) a simpler way to get what you want is just to specify xlab or ylab arguments to the plot() function. Let's say you have variables stuff (x) and Piston_Rings (y). If you just
plot(stuff,Piston_Rings)
then the plot will have "Piston_Rings" as the y-axis label. But if you
plot(stuff,Piston_Rings,ylab="Piston Rings")
you'll get the label you want. You can also include lots more information this way:
plot(stuff,Piston_Rings,
xlab="Important stuff (really)",
ylab="Piston Rings (number per segment)")
See ?plot.default for many more options.

How to display greater than or equal to sign using unicode \u2265

This is a follow up question to "Displaying a greater than or equal sign"
This is the text I wish to display as the y axis label:
Pr(Number of Invasions, X ≥ x)
This is the code:
expression(paste("Pr(Number of Invasions, ", italic('X'), "\u2265", italic('x'), ")"))
What I get is:
Pr(Number of Invasions, X = x)
This is the same result in the thread mentioned above. "\u2265" is supposed to overcome the issue, as suggested in the answers to the thread but it doesn't in my case.
When I run "\u2265" the result is:
"\u2265"
[1] "≥"
When I assign this to an object I get the same result:
symbol<-"\u2265"
symbol
[1] "≥"
However, in the Global Environment the object "symbol" contains "=".
Can anyone suggest how to display the symbol in the plot?
The answer isn't obvious to me.
I'm using RStudio, and OS system is Windows 7
By placing quotations marks around >= or \u2265 within paste within expression, it is was not able to produce the right symbol.
Even though I was formatting the Xs in italics, I should have just treated the code as if it was X>=x, which is what expression really wants to see, as MrFlick suggested... which makes sense now.
So:
expression(paste("Pr(Number of Invasions", italic('X')>=italic('x'), ")"))
Thanks MrFick!
You don't need paste. It's often clearer to use ~ and * as separators
plot(1,1, xlab=expression(Pr*'('*Number~of~Invasions~~ italic(X)*'\u2265'*italic(x)*")") )
That way it's easier to transition to the "full" plotmath version which gets a different spacing and looks better:
plot(1,1,
xlab=expression( Pr*'('*Number~of~Invasions~~ italic(X) >= italic(x)*")" )
)
If you had really wanted to have a named token hold the "≥" character, you can use the bquote and .( )-functions. The names inside the .( ) get evaluated (when the dot-function is within bquote):
symbol<-"\u2265"
plot(1,1,xlab=bquote(Pr*'('*Number~of~Invasions~~ italic(X) * .(symbol) * italic(x)*")") )

Resources