Flexible equivalent of curve() for ggplot - r

I realize similar questions have already been asked already. For example, consider the one here: Equivalent of curve() for ggplot. Is it possible to plot the functions below using group somehow or would I have to write stat_function for each instance of a and b?
myfun <- function(x, i) {
sin(a[i] * x) + log(b[i] * x)
}
ggplot(data.frame(x=c(0, 10)), aes(x)) +
stat_function(fun = myfun(x, 1)) +
stat_function(fun = myfun(x, 2)) ...
What if a and b are big? The above seems inelegant.

I would not use stat_function for anything non-trivial, it's usually easier to explicitly create values,
myfun <- function(a, b, x) {
data.frame(x = x, y = sin(a * x) + log(b * x))
}
ab <- expand.grid(a=1:3, b=2:6)
d <- plyr::mdply(ab, myfun, x=seq(0,10, length=100))
ggplot(d, aes(x, y, colour=factor(a))) +
facet_wrap(~b) +
geom_line()

Related

How to depict a graph of an implicit differentiation equation on R?

I'm now learning about calculus and want to depict a graph of x^2 + 6x + y^4 = 7, which I can using online graphing tool desmos.
But when I'm not sure how this is achievable on R. The first thing I thought is convert it in a form of y = f(x), but return (x^2 + 6*x - 7)^(1/4) gave me a different result.
At the same time, it seems impossible to return a equation in a function (return (x^2 + 6*x + y^4 = 7)). So how can I depict it on R?
Here is a sample code I usually use to depict a continuous graph.
f <- function(x) {
return () # return an equation
}
ggplot(data.frame(x=seq(-10,10,length.out=10)), aes(x)) + stat_function(fun=f)
You can have separate functions for the positive and negative solutions for y
f1 <- function(x) (7 - x^2 - 6*x)^(1/4)
f2 <- function(x) -f1(x)
Now just create a vector each for positive and negative values along the domain of x:
x <- seq(-7, 1, length = 1000)
y1 <- f1(x)
y2 <- f2(x)
And plot:
ggplot() +
geom_line(aes(x, y1)) +
geom_line(aes(x, y2))
You can use contourLines:
f <- function(x,y) x^2 + 6*x + y^4
x <- seq(-10, 3, len = 200)
y <- seq(-3, 3, len = 200)
z <- outer(x, y, f)
cr <- contourLines(x, y, z, levels = 7)
plot(cr[[1]]$x, cr[[1]]$y, type = "l")
library(ggplot2)
dat <- data.frame(x = cr[[1]]$x, y = cr[[1]]$y)
ggplot(dat) + geom_path(aes(x, y))

Why is R creating a lumpy version of my periodic function

I am trying to make a graph of the periodic function -23.5*cospi/4(x)+23.5
It gives the results I want in Desmos for reference.
However, when I code it as a function and plot it in ggplot, I get a weird-looking periodic function.
x <- 0:32
test <- data.frame(x, y=-23.5*cos(pi/4*x)+23.5)
test2 <- function(x) -23.5*cos(pi/4*x)+23.5
ggplot(data = test, mapping = aes(x,y))+
geom_point()+
stat_smooth(se = FALSE)
The points show as normal, but the stat_smooth gives this lumpy hunk of garbage.
As you want to graph a function I would suggest to use geom_function:
Note: For smoothness I doubled the default number of interpolation points n.
x <- 0:32
test <- data.frame(x, y = -23.5 * cos(pi / 4 * x) + 23.5)
test2 <- function(x) -23.5 * cos(pi / 4 * x) + 23.5
library(ggplot2)
ggplot() +
geom_point(data = test, mapping = aes(x, y)) +
geom_function(fun = test2, n = 202)

Adding various functions to the same plot with a loop ggplot2

I have the following equation: y = 1 - cx, where c is a real number.
I'm trying to make something where I can pick the range of values for c and plot all the graphs of every function with the corresponding c.
Here's what I got as of now:
p <- ggplot(data = data.frame(x = 0), mapping = aes(x = x))
statfun1 <- c()
for (i in 1:3){
c <- i
fun1.i <- function(x){1 - c*x}
fun1.i.plot <- stat_function(fun = fun1.i, color="red")
statfun1 <- statfun1 + fun1.i.plot
}
p + statfun1 + xlim(-5, 5)
The p is basically what you need in ggplot2 to plot a function, then I go over in this case the values 1, 2 and 3 for c and I try to add them all at the end but this does not seem to work. Anyone maybe can help me out or put me on the right track?
Define your function
fun1.i <- function(x, c){1 - c*x}
Now from ?`+.gg`
You can add any of the following types of objects:
...
You can also supply a list, in which case each element of the list will be added in turn.
So you might use lapply
p + xlim(-5, 5) + lapply(1:3, function(c) {
stat_function(fun = fun1.i, args = list(c = c), geom = "line", color="red")
})
Result

Receiving errors when trying to use stat_function in ggplot

So my example data are:
x <- runif(1000, min = 0, max = 5)
y <- (2 / pi) * atan(x)
z <- floor(x)
df <- data.frame(x, y, z)
I draw boxplots of x, binned by z:
library(ggplot2)
g <- ggplot(df, aes(x = x, y = y, group = z)) +
geom_boxplot()
g
But the thing is, in my real-life data, I'm not completely sure that the y-values follow (2 / pi) * atan(x). There's a random element there. So, how do I draw the function on top of my graph to see for myself? As per the ggplot2 documentation, I tried...
g + stat_function(fun = (2 / pi) * atan(x), colour = "red")
...but am receiving the error Warning message:
Computation failed in 'stat_function()':
'what' must be a function or character string.
The error is saying:
'what' must be a function or character string
so it is asking you simply define your function.
You need to define your function suuch as func
func<-function(x){ (2 / pi) * atan(x)}
and then call it in ggplot
library(ggplot2)
g <- ggplot(df, aes(x = x, y = y, group = z)) +
geom_boxplot()
g+stat_function(fun = func, colour = "red")
Here is the result
the parameter fun must be a function
g + stat_function(fun = function(x){(2 / pi) * atan(x)}, colour = "red")
I could solve your problem by simply defining a new function and the pass it to as the argument of stat_function
Here it is
myfun <- function(x){(2 / pi) * atan(x)}
and then
g + stat_function(fun = myfun colour = "red")
would do it

How can I format axis labels with exponents with ggplot2 and scales?

With the new version ggplot2 and scales, I can't figure out how to get axis label in scientific notation. For example:
x <- 1:4
y <- c(0, 0.0001, 0.0002, 0.0003)
dd <- data.frame(x, y)
ggplot(dd, aes(x, y)) + geom_point()
gives me
I'd like the axis labels to be 0, 5 x 10^-5, 1 x 10^-4, 1.5 x 10^-4, etc. I can't figure out the correct combination of scale_y_continuous() and math_format() (at least I think those are what I need).
scale_y_log10() log transforms the axis, which I don't want. scale_y_continuous(label = math_format()) just gives me 10^0, 10^5e-5, etc. I see why the latter gives that result, but it's not what I'm looking for.
I am using ggplot2_0.9.1 and scales_0.2.1
I adapted Brian's answer and I think I got what you're after.
Simply by adding a parse() to the scientific_10() function (and changing 'x' to the correct 'times' symbol), you end up with this:
x <- 1:4
y <- c(0, 0.0001, 0.0002, 0.0003)
dd <- data.frame(x, y)
scientific_10 <- function(x) {
parse(text=gsub("e", " %*% 10^", scales::scientific_format()(x)))
}
ggplot(dd, aes(x, y)) + geom_point()+scale_y_continuous(label=scientific_10)
You might still want to smarten up the function so it deals with 0 a little more elegantly, but I think that's it!
As per the comments on the accepted solution, OP is looking to format exponents as exponents. This can be done with the trans_format and trans_breaks functions in the scales package:
library(ggplot2)
library(scales)
x <- 1:4
y <- c(0, 0.0001, 0.0002, 0.0003)
dd <- data.frame(x, y)
ggplot(dd, aes(x, y)) + geom_point() +
scale_y_log10("y",
breaks = trans_breaks("log10", function(x) 10^x),
labels = trans_format("log10", math_format(10^.x)))
scale_y_continuous(label=scientific_format())
gives labels with e instead of 10:
I suppose if you really want 10's in there, you could then wrap that in another function.
scientific_10 <- function(x) {
gsub("e", " x 10^", scientific_format()(x))
}
ggplot(dd, aes(x, y)) + geom_point() +
scale_y_continuous(label=scientific_10)
Riffing off of Tom's answer above, the following removes + signs, and handles 0 better (the function is anonymously inlined as well):
scale_y_continuous(label= function(x) {ifelse(x==0, "0", parse(text=gsub("[+]", "", gsub("e", " %*% 10^", scientific_format()(x)))))} ) +
I wrote a version of scientific_10 that avoids the scales package; it also removes leading zeroes in exponents (10^04 to 10^4, etc.). This was adapted from the helpful answers given above.
I've also included wrapper scale functions below.
scientific_10 <- function(x) {
xout <- gsub("1e", "10^{", format(x),fixed=TRUE)
xout <- gsub("{-0", "{-", xout,fixed=TRUE)
xout <- gsub("{+", "{", xout,fixed=TRUE)
xout <- gsub("{0", "{", xout,fixed=TRUE)
xout <- paste(xout,"}",sep="")
return(parse(text=xout))
}
scale_x_log10nice <- function(name=NULL,omag=seq(-10,20),...) {
breaks10 <- 10^omag
scale_x_log10(name,breaks=breaks10,labels=scientific_10(breaks10),...)
}
scale_y_log10nice <- function(name=NULL,omag=seq(-10,20),...) {
breaks10 <- 10^omag
scale_y_log10(name,breaks=breaks10,labels=scientific_10(breaks10),...)
}
scale_loglog <- function(...) {
list(scale_x_log10nice(...),scale_y_log10nice(...))
}
qplot(x=exp(5*rnorm(100)),geom="density",kernel="rectangular") +
scale_x_log10nice()
I think this became really easy using the great ggtext-package.
What I did was:
library(ggplot)
library(ggtext)
ggplot(mtcars, aes(x = log10(mpg), y = wt)) +
geom_point() +
scale_x_continuous(labels = function(x){return(paste0("10^", x))}) +
theme(
axis.text.x = element_markdown()
)
Merging the previous answer I've created a function that can get arbitrary power ot tens for x and y as a multiply factor and then create the plot adding the factor near the axes
library(ggplot2)
x <- seq(1,25)
y <- rnorm(25)/10000
dd <- data.frame(x, y)
trim10 <- function(x) {
parse(text=gsub(".*e", "x10^", scales::scientific_format()(x)))
}
ggplot_trim10 <- function(x,y,xfac,yfac,...){
xnew <- x*xfac
ynew <- y*yfac
dd <- data.frame(xnew,ynew)
xunit <- abs(max(xnew) - min(xnew))
yunit <- abs(max(ynew) - min(ynew))
x_min_label <- min(xnew) - xunit*0.1
x_max_label <- max(xnew) - xunit*0.1
y_min_label <- min(ynew) - yunit*0.1
y_max_label <- max(ynew) - yunit*0.1
ggplot(data=dd, aes(x=xnew, y=ynew),...) +
geom_line() +
annotate("text", x = x_max_label, y = y_min_label, label = trim10(xfac)) +
annotate("text", x = x_min_label, y = y_max_label, label = trim10(yfac)) +
coord_cartesian(xlim = c(min(xnew), max(xnew)),ylim = c(min(ynew),max(ynew)), clip = "off")
}
ggplot_trim10(x,y,10,10)
as a note I know that "x" is not the correct symbol but I was getting a bit crazy mixing expression, paste etc. if anyone will fix it it would be great

Resources