I want to use a Shiny input as a name in my shiny plot.
Here is my code:
ggplot() +
...
geom_point(data=data.frame(), aes(x=x, y=y, color=paste(input$name)),
size = 3) +
scale_color_manual(values=c("df1"="blue", "df2"="blue",
paste(input$name)="red"))
It doesn't recognize paste(input$name) as a string. Here is the error message:
1512: scale_color_manual(values=c("df1"="blue", "df2"="blue",
1513: paste(input$name)=
^
Anyone know how to properly structure this?
You can't intermix strings and symbols and expressions like you are doing. If you want to use a string in an aes() mapping, use aes_ or aes_string (no need for paste)
aes_string(x="x", y="y", color=input$name)
And you can't put an expression on the left of = in a named vector. Use something like setNames() instead.
values = setNames(c("blue", "blue", "red"), c("df1", "df2", input$name))
As requested above, it would be easier in the future if you include a reproducible example so that possible solutions can be properly tested. This isn't at all Shiny related. This is just how ggplot and R work.
Related
If I want to use paste0 inside expression to label the x-axis, it's not working as intended. But paste works.
library(ggplot2)
ggplot(mtcars, aes(mpg, disp)) +
geom_point() +
labs(
x = expression(paste0("It's","mpg")^("paste0 is not working")),
y = expression(paste("It's ", "disp")^("paste is working")), # had to give extra space
)
Please Note that
I have used paste0 in x-axis, which is not showing as intended
used paste in y-axis which is working, but had to give extra space to separate It's and disp, which should be the default behavior of paste (AFAIK). But that default behavior is not working inside the expression.
Also same happens with base-plot
plot(mtcars$disp ~ mtcars$mpg,
xlab = expression(paste0("mpg")^("paste0 is not working")),
ylab = expression(paste("disp")^("paste is working"))
)
Can anyone please break this out for me,
why paste0 is not working?
and also why pastes default behavior is not preserved here??
What's going on here?
Thanks.
It seems you can only use the operations listed in ?plotmath.
https://stat.ethz.ch/R-manual/R-devel/library/grDevices/html/plotmath.html
paste is there, but paste0 is not.
Also, the function features are not equivalent to the R's functions of the same name.
I'm trying to copy a ggplot object and then change some properties of the new copied object as, for instance, the colour line to red.
Assume this code:
df = data.frame(cbind(x=1:10, y=1:10))
a = ggplot(df, aes(x=x, y=y)) + geom_line()
b = a
Then, if I change the colour of line of variable a
a$layers[[1]]$geom_params$colour = "red"
it also changes the colour of b
> b$layers[[1]]$geom_params$colour
[1] "red" # why it is not "black"?
I wish I could have two different objects a and b with different characteristics. So, in order to do this in the correct way, I would need to call the plot again for b using b = ggplot(df, aes(xy, y=z)) + geom_line(). However, at this time in the algorithm, there is no way to know the plot command ggplot(df, aes(x=x, y=y)) + geom_line()
Do you know what's wrong with this? Is ggplot objects treated in a different manner?
Thanks!
The issue here is that ggplot uses the proto library to mimic OO-style objects. The proto library relies on environments to collect variables for objects. Environments are passed by reference which is why you are seeing the behavior you are (and also a reason no one would probably recommend changing the properties of a layer that way).
Anyway, adapting an example from the proto documentaiton, we can try to make a deep copy of the laters of the ggplot object. This should "disconnect" them. Here's such a helper function
duplicate.ggplot<-function(x) {
require(proto)
r<-x
r$layers <- lapply(r$layers, function(x) {
as.proto(as.list(x), parent=x)
})
r
}
so if we run
df = data.frame(cbind(x=1:10, y=1:10))
a = ggplot(df, aes(x=x, y=y)) + geom_line()
b = a
c = duplicate.ggplot(a)
a$layers[[1]]$geom_params$colour = "red"
then plot all three, we get
which shows we can change "c" independently from "a"
Ignoring the specifics of ggplot, there's a simple trick to make a deep copy of (almost) any object in R:
obj_copy <- unserialize(serialize(obj, NULL))
This serializes the object to a binary representation suitable for writing to disk and then reconstructs the object from that representation. It's equivalent to saving the object to a file and then loading it again (i.e. saveRDS followed by readRDS), only it never actually saves to a file. It's probably not the most efficient solution, but it should work for just about any object that can be saved to a file.
You can define a deepcopy function using this trick:
deepcopy <- function(p) {
unserialize(serialize(p, NULL))
}
This seems to successfully break the links between related ggplots.
Obviously, this will not work for objects that cannot be serialized, such as big matrices from the bigmemory package.
I need to wrap ggplot2 into another function, and want to be able to parse variables in the same manner that they are accepted, can someone steer me in the correct direction.
Lets say for example, we consider the below MWE.
#Load Required libraries.
library(ggplot2)
##My Wrapper Function.
mywrapper <- function(data,xcol,ycol,colorVar){
writeLines("This is my wrapper")
plot <- ggplot(data=data,aes(x=xcol,y=ycol,color=colorVar)) + geom_point()
print(plot)
return(plot)
}
Dummy Data:
##Demo Data
myData <- data.frame(x=0,y=0,c="Color Series")
Existing Usage which executes without hassle:
##Example of Original Function Usage, which executes as expected
plot <- ggplot(data=myData,aes(x=x,y=y,color=c)) + geom_point()
print(plot)
Objective usage syntax:
##Example of Intended Usage, which Throws Error ----- "object 'xcol' not found"
mywrapper(data=myData,xcol=x,ycol=y,colorVar=c)
The above gives an example of the 'original' usage by the ggplot2 package, and, how I would like to wrap it up in another function. The wrapper however, throws an error.
I am sure this applies to many other applications, and it has probably been answered a thousand times, however, I am not sure what this subject is 'called' within R.
The problem here is that ggplot looks for a column named xcol in the data object. I would recommend to switch to using aes_string and passing the column names you want to map using a string, e.g.:
mywrapper(data = myData, xcol = "x", ycol = "y", colorVar = "c")
And modify your wrapper accordingly:
mywrapper <- function(data, xcol, ycol, colorVar) {
writeLines("This is my wrapper")
plot <- ggplot(data = data, aes_string(x = xcol, y = ycol, color = colorVar)) + geom_point()
print(plot)
return(plot)
}
Some remarks:
Personal preference, I use a lot of spaces around e.g. x = 1, for me this greatly improves the readability. Without spaces the code looks like a big block.
If you return the plot to outside the function, I would not print it inside the function, but just outside the function.
This is just an addition to the original answer, and I do know that this is quite an old post, but just as an addition:
The original answer provides the following code to execute the wrapper:
mywrapper(data = "myData", xcol = "x", ycol = "y", colorVar = "c")
Here, data is provided as a character string. To my knowledge this will not execute correctly. Only the variables within the aes_string are provided as character strings, while the data object is passed to the wrapper as an object.
I've been trying to draw two plots using R's ggplot library in RStudio. Problem is, when I draw two within one function, only the last one displays (in RStudio's "plots" view) and the first one disappears. Even worse, when I run ggsave() after each plot - which saves them to a file - neither of them appear (but the files save as expected). However, I want to view what I've saved in the plots as I was able to before.
Is there a way I can both display what I'll be plotting in RStudio's plots view and also save them? Moreover, when the plots are not being saved, why does the display problem happen when there's more than one plot? (i.e. why does it show the last one but not the ones before?)
The code with the plotting parts are below. I've removed some parts because they seem unnecessary (but can add them if they are indeed relevant).
HHIplot = ggplot(pergame)
# some ggplot geoms and misc. here
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
HHIAvePlot = ggplot(AveHHI, aes(x = AveHHI$n_brokers))
# some ggplot geoms and misc. here
ggsave(paste("Average HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I've already taken a look here and here but neither have helped. Adding a print(HHIplot) or print(HHIAvePlot) after the ggsave() lines has not displayed the plot.
Many thanks in advance.
Update 1: The solution suggested below didn't work, although it works for the answer's sample code. I passed the ggplot objects to .Globalenv and print() gives me an empty gray box on the plot area (which I imagine is an empty ggplot object with no layers). I think the issue might lie in some of the layers or manipulators I have used, so I've brought the full code for one ggplot object below. Any thoughts? (Note: I've tried putting the assign() line in all possible locations in relation to ggsave() and ggplot().)
HHIplot = ggplot(pergame)
HHIplot +
geom_point(aes(x = pergame$n_brokers, y = pergame$HHI)) +
scale_y_continuous(limits = c(0,10000)) +
scale_x_discrete(breaks = gameSizes) +
labs(title = paste("HHI Index of all games,",year,"Finals"),
x = "Game Size", y = "Herfindahl-Hirschman Index") +
theme(text = element_text(size=15),axis.text.x = element_text(angle = 0, hjust = 1))
assign("HHIplot",HHIplot, envir = .GlobalEnv)
ggsave(paste("HHI Index of all games,",year,"Finals.png"),
path = plotpath, width = 6, height = 4)
I'll preface this by saying that the following is bad practice. It's considered bad practice to break a programming language's scoping rules for something as trivial as this, but here's how it's done anyway.
So within the body of your function you'll create both plots and put them into variables. Then you'll use ggsave() to write them out. Finally, you'll use assign() to push the variables to the global scope.
library(ggplot2)
myFun <- function() {
#some sample data that you should be passing into the function via arguments
df <- data.frame(x=1:10, y1=1:10, y2=10:1)
p1 <- ggplot(df, aes(x=x, y=y1))+geom_point()
p2 <- ggplot(df, aes(x=x, y=y2))+geom_point()
ggsave('p1.jpg', p1)
ggsave('p2.jpg', p2)
assign('p1', p1, envir=.GlobalEnv)
assign('p2', p2, envir=.GlobalEnv)
return()
}
Now, when you run myFun() it will write out your two plots to .jpg files, and also drop the plots into your global environment so that you can just run p1 or p2 on the console and they'll appear in RStudio's Plot pane.
ONCE AGAIN, THIS IS BAD PRACTICE
Good practice would be to not worry about the fact that they're not popping up in RStudio. They wrote out to files, and you know they did, so go look at them there.
I am going to plot a boxplot from a 4-column matrix pl1 using ggplot with dots on each box. The instruction for plotting is like this:
p1 <- ggplot(pl1, aes(x=factor(Edge_n), y=get(make.names(y_label)), ymax=max(get(make.names(y_label)))*1.05))+
geom_boxplot(aes(fill=method), outlier.shape= NA)+
theme(text = element_text(size=20), aspect.ratio=1)+
xlab("Number of edges")+
ylab(y_label)+
scale_fill_manual(values=color_box)+
geom_point(aes(x=factor(Edge_n), y=get(make.names(true_des)), ymax=max(get(make.names(true_des)))*1.05, color=method),
position = position_dodge(width=0.75))+
scale_color_manual(values=color_pnt)
Then, I use print(p1) to print it on an opened pdf. However, this does not work for me and I get the below error:
Error in make.names(true_des) : object 'true_des' not found
Does anyone can help?
Your example is not very clear because you give a call but you don't show the values of your variables so it's really hard to figure out what you're trying to do (for instance, is method the name of a column in the data frame pl1, or is it a variable (and if it's a variable, what is its type? string? name?)).
Nonetheless, here's an example that should help set you on the way to doing what you want:
Try something like this:
pl1 <- data.frame(Edge_n = sample(5, 20, TRUE), foo = rnorm(20), bar = rnorm(20))
y_label <- 'foo'
ax <- do.call(aes, list(
x=quote(factor(Edge_n)),
y=as.name(y_label),
ymax = substitute(max(y)*1.05, list(y=as.name(y_label)))))
p1 <- ggplot(pl1) + geom_boxplot(ax)
print(p1)
This should get you started to figuring out the rest of what you're trying to do.
Alternately (a different interpretation of your question) is that you may be running into a problem with the environment in which aes evaluates its arguments. See https://github.com/hadley/ggplot2/issues/743 for details. If this is the issue, then the answer might to override the default value of the environment argument to aes, for instance: aes(x=factor(Edge_n), y=get(make.names(y_label)), ymax=max(get(make.names(y_label)))*1.05, environment=environment())