I have an R routine which creates a number of plots from a large set of data. Each plot is labeled with a titles describing the details of the set of points plotted. Unfortunately, I have not been able to use subscripts in the text if I am using paste to combine a complex label. The result is ugly. This is a simplified version of the code using data from R. The title shows the technique I am currently using, without subscripts. The attempt at an improved version is placed either on the x axis or on the plot.
library(ggplot2)
x1 = 1
x2 = 2
list <- c(1:4)
tle <- paste("VGM = ", as.character(list[1]),
"V, VDM = ", as.character(list[2]),
"V, VGF = ", as.character(list[3]),
"V, VDF = ", as.character(list[4]),
"V", sep="")
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
labs(title=tle) +
geom_point()
p
p + xlab(expression(V[DM])) #works fine
p + xlab(expression(paste(V[DM], "= 3"))) # works fine
# now we would like to use a variable to provide the number
p + xlab(expression(paste(V[DM], "=", x1))) # Just displays "x1", not value of x1
p + xlab(expression(paste(V[DM], "=",
as.character(x1)))) # NO
p + xlab(expression(paste(V[DM], "=",
as.character(as.number(x1))))) # NO
my.xlab1 <- bquote(V[DM] == .(x1))
p + xlab(my.xlab1) # We can see the success here
# A single variable at the end of the expression works
# What if you wanted to display two variables?
my.xlab2 <- bquote(V[GM] == .(x2))
my.xlab3 <- paste(my.xlab1, my.xlab2)
p + xlab(my.xlab3) # doesn't work
# Apparently the expressions cannot be pasted together. Try another approach.
# Place the two expressions separately on the plot. They no longer need to be
# pasted together. It would look better, anyway. Would it work?
p + annotate("text", x=4, y=30, label="Annotate_text", parse=TRUE)
# This is the idea
# p + annotate("text", x=4, y=30, label=bquote(V[DM] == .(x1)), parse=TRUE)
# This is a disaster
# RStudio stops the process with a question mark placed on the console. Appears that
# more input is being requested?
p + geom_text(x=4, y=30, label="Geom_text") # works
p + geom_text(x=4, y=30, label=my.xlab1) # does not accept variables.
I have included comments which describe the problems raised by each attempt. Ideally, the information should probably be placed as an annotation on the plot rather than as a title, but I cannot find a way to do this. Using a subscript turns a character into an expression, and it seems that there is a long list of functions which handle characters but not expressions.
If you want to "paste" two expressions together, you need to have some "operator" join them. There really isn't a paste method for expressions, but there are ways to put them together. First, obviously you could use one bquote() to put both variables together. Either
my.xlab3 <- bquote(V[DM] == .(x1)~ V[GM] == .(x2))
my.xlab3 <- bquote(list(V[DM] == .(x1), V[GM] == .(x2)))
would work. The first puts a space between them, the second puts a comma between them. But if you want to build them separately, you can combine them with another round of bquote. So the equivalent building method for the two above expressions is
my.xlab3 <- bquote(.(my.xlab1) ~ .(my.xlab2))
my.xlab3 <- bquote(list(.(my.xlab1), .(my.xlab2)))
All of those should work to set your xlab() value.
Now, if you also want to get annotate to work, you can "un-parse" your expression and then have R "re-parse" it for you and you should be all set. Observe
p + annotate("text", x=4, y=30, label=deparse(my.xlab3), parse=TRUE)
Related
so I am struggling to get a plot working like I want. I have a facet_grid where the variables facetted is determined dynamically in a shiny app...
facet_grid(facetFormula, labeller = label_both)
where...
facetFormula <- as.formula(paste(input$filter2Var, "~", input$filter1Var))
this works fine, except that i'd rather a linebreak as the variable "name: value" separator instead of the colon. i've poked around with other arguments (multi_line, sep), using label_both() or label_wrap_gen() or labeller() instead of label_both no parenthesis... and am getting no where, probably stumbling over the already complex issue of dynamic variables to be facetted by. i've tried treating arguments to these various functions with !!sym() or as.formula(), but i really don't know what i am doing and probably messing up several things in trying to just add some simple text wrapping to my facet labels. any help is much appreciated!
UPDATE...
cases <- c("case1_has_long_name", "case2_long_too", "case3_long_as_well", "case4_also_long", "case5_long")
the_first_variable <- cases[round(runif(100,1,3))]
variable_number_two <- cases[round(runif(100,1,5))]
var1 <- "the_first_variable"
var2 <- "variable_number_two"
facetFormula <- as.formula(paste(var1, "~", var2))
myX <- runif(100,0,10)
myY <- runif(100,-5,5)
myData <- data.frame(myX, myY, the_first_variable, variable_number_two)
ggplot(myData, aes(x = myX, y = myY)) +
geom_point(alpha = .5) +
facet_grid(facetFormula,
labeller = label_both)
this generates a plot with my issue, where the facet labels are too big. i just want to learn how to make the labels wrap. was thinking as a simple start, instead of ":" as the separator between variable name and variable value, i could use "\n" as the seperator. the awkwardness of specifying my facet variables as variable themselves comes from them being dynamically defined in a shiny app.
Wrapping the facet labels could be achieved like so:
A labeller takes as its first argument a df with the variable names and labels. In your case a df with one column. The column contains the labels, the column name is the var name.
To wrap the labels I use a wrapper function around label_both where I first wrap the labels before passing the manipulated df to label_both. To make the wrapping work I replaced all underscores by spaces.
library(ggplot2)
my_label <- function(x) {
# Wrap var names
names(x)[[1]] <- stringr::str_wrap(gsub("_", " ", names(x)[[1]]), 10)
# Wrap value labels
x[[1]] <- stringr::str_wrap(gsub("_", " ", x[[1]]), 10)
# Call label both with sep "\n"
label_both(x, sep = "\n")
}
ggplot(myData, aes(x = myX, y = myY)) +
geom_point(alpha = .5) +
facet_grid(facetFormula, labeller = my_label)
I am trying to loop a ggplot2 plot with a linear regression line over it. It works when I type the y column name manually, but the loop method I am trying does not work. It is definitely not a dataset issue.
I've tried many solutions from various websites on how to loop a ggplot and the one I've attempted is the simplest I could find that almost does the job.
The code that works is the following:
plots <- ggplot(Everything.any, mapping = aes(x = stock_VWRETD, y = stock_10065)) +
geom_point() +
labs(x = 'Market Returns', y = 'Stock Returns', title ='Stock vs Market Returns') +
geom_smooth(method='lm',formula=y~x)
But I do not want to do this another 40 times (and then 5 times more for other reasons). The code that I've found on-line and have tried to modify it for my means is the following:
plotRegression <- function(z,na.rm=TRUE,...){
nm <- colnames(z)
for (i in seq_along(nm)){
plots <- ggplot(z, mapping = aes(x = stock_VWRETD, y = nm[i])) +
geom_point() +
labs(x = 'Market Returns', y = 'Stock Returns', title ='Stock vs Market Returns') +
geom_smooth(method='lm',formula=y~x)
ggsave(plots,filename=paste("regression1",nm[i],".png",sep=" "))
}
}
plotRegression(Everything.any)
I expect it to be the nice graph that I'd expect to get, a Stock returns vs Market returns graph, but instead on the y-axis, I get one value which is the name of the respective column, and the Market value plotted as normally, but as if on a straight number-line across the one y-axis value. Please let me know what I am doing wrong.
Desired Plot:
Actual Plot:
Sample Data is available on Google Drive here:
https://drive.google.com/open?id=1Xa1RQQaDm0pGSf3Y-h5ZR0uTWE-NqHtt
The problem is that when you assign variables to aesthetics in aes, you mix bare names and strings. In this example, both X and Y are supposed to be variables in z:
aes(x = stock_VWRETD, y = nm[i])
You refer to stock_VWRETD using a bare name (as required with aes), however for y=, you provide the name as a character vector produced by colnames. See what happens when we replicate this with the iris dataset:
ggplot(iris, aes(Petal.Length, 'Sepal.Length')) + geom_point()
Since aes expects variable names to be given as bare names, it doesn't interpret 'Sepal.Length' as a variable in iris but as a separate vector (consisting of a single character value) which holds the y-values for each point.
What can you do? Here are 2 options that both give the proper plot
1) Use aes_string and change both variable names to character:
ggplot(iris, aes_string('Petal.Length', 'Sepal.Length')) + geom_point()
2) Use square bracket subsetting to manually extract the appropriate variable:
ggplot(iris, aes(Petal.Length, .data[['Sepal.Length']])) + geom_point()
you need to use aes_string instead of aes, and double-quotes around your x variable, and then you can directly use your i variable. You can also simplify your for loop call. Here is an example using iris.
library(ggplot2)
plotRegression <- function(z,na.rm=TRUE,...){
nm <- colnames(z)
for (i in nm){
plots <- ggplot(z, mapping = aes_string(x = "Sepal.Length", y = i)) +
geom_point()+
geom_smooth(method='lm',formula=y~x)
ggsave(plots,filename=paste("regression1_",i,".png",sep=""))
}
}
myiris<-iris
plotRegression(myiris)
I have searched here for a while and my question was partially answered by previous questions/answers. I am learning R, coming from Matlab. As the title says, I have a question about plot annotations. In Matlab it was fairly straightforward to have plot annotations that contained all sorts of data formats, and I am looking for something similar in R. I have already discovered paste and managed to put text and numbers into one annotation and I also figured out (to a degree...) what parse does, for example when displaying an r squared. My question is, how do I combine the two annotations in the code snippet into one annotation without R yelling at me? My solution with two annotations works for what I need, but I simply would like to know how to do it...
a <- 30 # some coefficients
b <- 70
r2 <- 0.87
anno1 <- paste("y = ",b,"ln(x) + ",a) # first annotation with a random equation
anno2 <- paste("r^2 == ", r2) # second annotation with a random r squared
Pdata <- data.frame("X" = 1:10, "Y" = 1:10) # some data
ggplot(Pdata,aes(x=Pdata$X,y=Pdata$Y)) +
geom_point() +
annotate("text", x=2, y=8, label=anno1, parse=FALSE) +
annotate("text", x=2, y=7, label=anno2, parse=TRUE)
Thanks y'all!
It took a while for me to figure this out (for my own projects), but here's a solution:
anno3 <- paste("'y ='~",b,"~'ln(x) +'~",a,"~r^2==~", r2)
Add it to your plot using + annotate("text", x=2, y=6, label=anno3, parse=TRUE)
The single quote identifies text to not evaluate. Combined, the pasted result should be written like an expression.
Here is one way to do the requested operation by using bquote
ggplot() +
geom_point(aes(x = 1:4, y = 1:4)) +
annotate("text", x=2, y=3,
label = deparse(bquote(~y ==~ .(b) ~ln(x)~ + .(a) ~r^2 ==~ .(r2))),
parse = T)
bquote quotes its argument except the terms wrapped in .() which are evaluated
annotate does not support expressions, one trick to get it to work is to deparse it and then parse it again
I need to label my y axis so that it displays first the word "Power" followed by an expression in square brackets: [micro Volt squared].
I can produce single parts of the overall label that I want, but I run into problems when I want to combine them:
x <- 1:10; y <- 10:1; z <- data.frame(x,y)
g <- ggplot(z, aes(x,y) + geom_bar(stat='identity')
g + ylab('Power') # No problem
g + ylab(paste('Power [', ']')) #No problem
g + ylab(expression(mu)) # No problem
g + ylab(expression(V^2)) # No problem
However, this seems not to be possible:
g + ylab(paste('Power [', expression(mu), expression(V^2), ']'))
The output does not evalute the expressions (mu and V^2):
Where am I going wrong? Is the paste() command the wrong approach in general? I have also had a look at unicode characters (Unicode Characters in ggplot2 PDF Output) ... but that would still leave me with the question how I adequately combine all the single terms.
Your help is much appreciated!
You need to put everything inside the expression.
You can use an asterisk for separation, the tilde is for space. So this should be right.
g + ylab(expression("Power"~"["*mu*V^2*"]"))
A single expression seems to do the trick:
g + ylab(expression(paste("Power [",mu, V^2,"]")))
Say I have a dataframe:
df <- data.frame(x=1:10, y=4:13)
p <- ggplot(df,aes(x,y)) + geom_point()
Now I want to add many things to this graph, so I use a big paste function and print the output. Just as an example, say I wanted to add the word 'bananas' inside the x axis label.
x <- "bananas"
print(paste0("+ xlab('Price of", x[1], "')"), quote=F)
If I try:
p + print(paste0("+ xlab('Price of", x[1], "')"), quote=F)
then it obviously does not work. But is there a way of adding the output of this function to the ggplot object 'p' without cutting/pasting from the console?
i.e. so we automatically can execute:
p + xlab('Price ofbananas')
If you want to add Price of bananas as the x label, then:
p + xlab(paste0("Price of ", x[1]))
Remember you're adding the xlab, so that should be your outside function. Inside it, you add/create the label you want. No need to print.
Update:
I think what you want is eval(parse(text=xxx)). For example:
add <- paste0("xlab('Price of ", x[1], "')")
p + eval(parse(text=add))
Note that I removed the + from the text, because you need it next to p to connect with eval.
I'm not sure why you would do this, but it works.