I wrote this function to plot the city and income. The plotting code works perfectly fine when it is not inside the function. However, when I called it with the function, no graph showed up. Please help! Thanks.
graph <- function(x, y) {
df %>%
filter(city == "x", year == y) %>%
ggplot(aes(log(income))) +
geom_histogram()
}
I tried to assign the plot to p and then add print(p), but nothing showed up.
you take x as a param, but dont use it in your function; you use a hardcoded x to check against city; its likely you get nothing, and so plot empty charts
besides from that, I can set up an analogous construction and see charts just fine; so theres not inherent reason that the plot wouldnt be seen from inside a function like this
Related
I'm creating a set of functions for enciphering data plots as a hook for data literacy lessons.
For example, this function performs an alphabetic shift of +/- X for any string input
enciphR<-function(x,alg,key=F){
x.vec<-tolower(unlist(strsplit(x,fixed=T,split="")))#all lower case as vector
#define new alphabet
alphabet<-1:26+alg
alphabet.shifted.idx<-sapply(alphabet,function(x) {if(x>26){x-26}else{ if(x<1){x+26}else{x}}})
alphabet.shifted<-letters[alphabet.shifted.idx]
keyMat=cbind(IN=letters,OUT=alphabet.shifted)
#encipher
x1.1<-as.vector(sapply(x.vec,function(s) {
if(!s%in%letters){s}else{#If nonletter, leave it alone, else...
keyMat[match(s,keyMat[,"IN"]),"OUT"]
}},USE.NAMES = F))
x2<-paste0(x1.1,collapse="")
if(key){
out<-list(IN=x,OUT=x2,KEY=keyMat)}
else{
out<-x2
}
return(out)
}
enciphR(letters,+1) yields "bcdefghijklmnopqrstuvwxyza"
I want to feed a ggplot object into another function ggEnciphR(), which uses the enciphR() helper to encode all text elements of that object, according to the supplied cipher algorithm.
So, start with a figure:
data("AirPassengers")
require(ggplot2);require(reshape2)
df <- data.frame(Passengers=as.numeric(AirPassengers), year = as.factor(trunc(time(AirPassengers))), mnth = month.abb[cycle(AirPassengers)])
(gg<-qplot(mnth,Passengers,aes(col=year),data=df)+geom_line(aes(group=year,col=year)))
now I define the ggCiphR function:
ggCiphR<-function(ggGraph,alg){
g<-ggGraph
pass2enciphR=function(x){enciphR(x,alg=alg)}
#process all labels
g$labels<-lapply(g$labels,pass2enciphR)
#process custom legend if present (sometimes works, depending on ggplot object)
try(if(length(g$scales$scales)>0){
for(i in 1:length(g$scales$scales)){
g$scales$scales[[i]]$name=enciphR(g$scales$scales[[i]],alg=alg)
}
})
g
}
ggCiphR(gg,+1)
Yields:
This is getting there. Axis labels and legend title have been enciphered, but not tick values. Also, if my factor was Airline, instead of Year, I'd like that to be sent through enciphR, as well.
I've searched high and wide and cannot for the life of me figure out how to modify x- and y-axis values and factor levels from the gg object. I don't want to have to recast the dataframe and regenerate the ggplot... ideally I can do this programmatically using the gg object. And also, it would (ideally) be flexible enough to work with different classes of data in X & Y. Thoughts?
I believe the answer to this is that I cannot, but rather than give in utterly to depraved desperation, I will turn to this lovely community.
How can I add points (or any additional layer) to a ggplot after already plotting it? Generally I would save the plot to a variable and then just tack on + geom_point(...), but I am trying to include this in a function I am writing. I would like the function to make a new plot if plot=T, and add points to the existing plot if plot=F. I can do this with the basic plotting package:
fun <- function(df,plot=TRUE,...) {
...
if (!plot) { points(dYdX~Time.Dec,data=df2,col=col) }
else { plot(dYdX~Time.Dec,data=df2,...) }}
I would like to run this function numerous times with different dataframes, resulting in a plot with multiple series plotted.
For example,
fun(df.a,plot=T)
fun(df.b,plot=F)
fun(df.c,plot=F)
fun(df.d,plot=F)
The problem is that because functions in R don't have side-effects, I cannot access the plot made in the first command. I cannot save the plot to -> p, and then recall p in the later functions. At least, I don't think I can.
have a ggplot plot object be returned from your function that you can feed to your next function call like this:
ggfun = function(df, oldplot, plot=T){
...
if(plot){
outplot = ggplot(df, ...) + geom_point(df, ...)
}else{
outplot = oldplot + geom_point(data=df, ...)
}
print(outplot)
return(outplot)
}
remember to assign the plot object returned to a variable:
cur.plot = ggfun(...)
Basically, i have a dataframe with 3 numeric vectors(x,y,z), and lets say i wanna make a scatter plot of x,y colored by z. I want to transform the colorscale with a squareroot that respects sign, so i made my own with trans_new. Here is a simple dataset, but with the actual transform.
library(ggplot2)
library(scales)
set.seed(1)
plot<-data.frame(x=rnorm(100),y=rnorm(100),z=rnorm(100))
super_trans <- function(){
trans_new('super', function(X) sapply(X,function(x) {if(x>0){x^0.5} else{-(- x)^0.5}}), function(X) sapply(X,function(x){ if(x>0){x^2} else{-x^2}}))
}
ggplot(plot,aes(x,y))+geom_point(aes(colour=z))+scale_colour_gradient(trans="super")
It gives an error,
Error in if (x > 0) { : missing value where TRUE/FALSE needed
I don't understand it. I tried to backtrack the mistake, and my guess is that the error happens when trans_new tries to make breaks.
However, i do not understand how the "breaks" parameter works in trans_new.
Is there a ggplot2/Scales hero out there, that can help me transform my color-scale correctly?
It may be relevant that only some datasets gives errors.
There is a vectorized if, called ifelse. It also seems you are missing an extra minus.
super_trans <- function() {
trans_new('super',
function(x) ifelse(x>0, x^0.5, -(-x)^0.5),
function(x) ifelse(x>0, x^2, -(-x)^2))
}
Is there a way to get the plot function to generate equal xlimand ylimautomatically?
I do not want to define a fix range beforehand, but I want the plot function to decide about the range itself. However, I expect it to pick the same range for x and y.
A possible solution is to define a wrapper to the plot function:
plot.Custom <- function(x, y, ...) {
.limits <- range(x, y)
plot(x, y, xlim = .limits, ylim = .limits, ...)
}
One way is to manipulate interactively and then choose the right one. A slider will appear once you run the following code.
library(manipulate)
manipulate(
plot(cars, xlim=c(x.min,x.max)),
x.min=slider(0,15),
x.max=slider(15,30))
I'm not aware of anyway to do this using plot(doesn't mean there isn't one). ggplot might be the way to go; it lends itself more to be being retroactively changed since it is designed around a layer system.
library(ggplot2)
#Creating our ggplot object
loop_plot <- ggplot(cars, aes(x = speed, y = dist)) +
geom_point()
#pulling out the 'auto' x & y axis limits
rangepull <- t(cbind(
ggplot_build(loop_plot)$panel$ranges[[1]]$x.range,
ggplot_build(loop_plot)$panel$ranges[[1]]$y.range))
#taking the max and min(so we don't cut out data points)
newrange <- list(cor.min = min(rangepull[,1]), cor.max = max(rangepull[,2]))
#changing our plot size to be nice and symmetric
loop_plot <- loop_plot +
xlim(newrange$cor.min, newrange$cor.max) +
ylim(newrange$cor.min, newrange$cor.max)
Note that the loop_plot object is of ggplot class, and wont actually print until its called.
I used the cars dataset in the code above to show whats going on, but just sub in your data set[s] and then do whatever postmortem your end goal is.
You'll also be able to add in titles and the like based off of the dataset name et cetera which will likely end up producing a clearer visualization out of your loop.
Hopefully this works for your needs.
I would like to create dynamic plotting over given dates, ie i want the plots appear one after another through specific dates when the code is run. This code seems to work with plot function but not with qplot.
any ideas?
thanks in advance,
x with headings t, date, AUM, profit
windows(5,5)
dev.set()
for (i in 1:10){
z <- x[x$t == i,]
a <- unique(z$date)
qplot(z$AUM,z$profit,main=a,xlim=range(0:2.5e+08),ylim=range(0:6e+06))
}
You need to add a print() call, i.e. print(qplot(...)).
The reason is that ggplot2 uses grid graphics which requires a print call.
print(qplot(z$AUM,z$profit,main=a,xlim=range(0:2.5e+08),ylim=range(0:6e+06)))
This is R FAQ 7.16.