Basic Calculations with stat_functions -- Plotting hazard functions - r

I am currently trying to plot some density distributions functions with R's ggplot2. I have the following code:
f <- stat_function(fun="dweibull",
args=list("shape"=1),
"x" = c(0,10))
stat_F <- stat_function(fun="pweibull",
args=list("shape"=1),
"x" = c(0,10))
S <- function() 1 - stat_F
h <- function() f / S
wei_h <- ggplot(data.frame(x=c(0,10))) +
stat_function(fun=h) +
...
Basically I want to plot hazard functions based on a Weibull Distribution with varying parameters, meaning I want to plot:
The above code gives me this error:
Computation failed in stat_function():
unused argument (x_trans)
I also tried to directly use
S <- 1 - stat_function(fun="pweibull", ...)
instead of above "workaround" with the custom function construction. This threw another error, since I was trying to do numeric arithmetics on an object:
non-numeric argument for binary operator
I get that error, but I have no idea for a solution.
I have done some research, but without success. I feel like this should be straightforward. Also I would like to do it "manually" as much as possible, but if there is no simple way to do this, then a packaged solution is just fine aswell.
Thanks in advance for any suggestions!
PS: I basically want to recreate the graph you can find in Kiefer, 1988 on page 10 of the linked PDF file.

Three comments:
stat_function is a function statistic for ggplot2, you cannot divide two stat_function expressions by each other or otherwise use them in mathematical expressions, as in S <- 1 - stat_function(fun="pweibull", ...). That's a fundamental misunderstanding of what stat_function is. stat_function always needs to be added to a ggplot2 plot, as in the example below.
The fun argument for stat_function takes a function as an argument, not a string. You can define functions on the fly if you need ones that don't exist already.
You need to set up an aesthetic mapping, via the aes function.
This code works:
args = list("shape" = 1.2)
ggplot(data.frame(x = seq(0, 10, length.out = 100)), aes(x)) +
stat_function(fun = dweibull, args = args, color = "red") +
stat_function(fun = function(...){1-pweibull(...)}, args = args, color = "green") +
stat_function(fun = function(...){dweibull(...)/(1-pweibull(...))},
args = args, color = "blue")

Related

Plot a normal distribution in R with specific parameters

I'd like to plot something like this:
plot(dnorm(mean=2),from=-3,to=3)
But it doesn't work as if you do:
plot(dnorm,from=-3,to=3)
what is the problem?
The answer you received from #r2evans is excellent. You might also want to consider learning ggplot, as in the long run it will likely make your life much easier. In that case, you can use stat_function which will plot the results of an arbitrary function along a grid of the x variable. It accepts arguments to the function as a list.
library(ggplot2)
ggplot(data = data.frame(x=c(-3,3)), aes(x = x)) +
stat_function(fun = dnorm, args = list(mean = 2))
curve(dnorm(x, mean = 2), from = -3, to = 3)
The curve function looks for the xname= variable (defaults to x) in the function call, so in dnorm(x, mean=2), it is not referencing an x in the calling environment, it is a placeholder for curve to use for iterated values.
The reason plot(dnorm, ...) works as it does is because there exists graphics::plot.function, since dnorm in that case is a function. When you try plot(dnorm(mean=2)), the dnorm(mean=2) is no longer a function, it is a call ... that happens to fail because it requires x (its first argument) be provided.
Incidentally, plot.function calls curve(...), so other than being a convenience function, there is very little reason to use plot(dnorm, ...) over curve(dnorm(x), ...) other than perhaps a little code-golf. The biggest advantage to curve is that it lets you control arbitrary arguments to the dnorm() function, whereas plot.function does not.

Using user-defined functions within "curve" function in R graphics

I am needing to produce normally distributed density plots with different total areas (summing to 1). Using the following function, I can specify the lambda - which gives the relative area:
sdnorm <- function(x, mean=0, sd=1, lambda=1){lambda*dnorm(x, mean=mean, sd=sd)}
I then want to plot up the function using different parameters. Using ggplot2, this code works:
require(ggplot2)
qplot(x, geom="blank") + stat_function(fun=sdnorm,args=list(mean=8,sd=2,lambda=0.7)) +
stat_function(fun=sdnorm,args=list(mean=18,sd=4,lambda=0.30))
but I really want to do this in base R graphics, for which I think I need to use the "curve" function. However, I am struggling to get this to work.
If you take a look at the help file for ? curve, you'll see that the first argument can be a number of different things:
The name of a function, or a call or an expression written as a function of x which will evaluate to an object of the same length as x.
This means you can specify the first argument as either a function name or an expression, so you could just do:
curve(sdnorm)
to get a plot of the function with its default arguments. Otherwise, to recreate your ggplot2 representation you would want to do:
curve(sdnorm(x, mean=8,sd=2,lambda=0.7), from = 0, to = 30)
curve(sdnorm(x, mean=18,sd=4,lambda=0.30), add = TRUE)
The result:
You can do the following in base R
x <- seq(0, 50, 1)
plot(x, sdnorm(x, mean = 8, sd = 2, lambda = 0.7), type = 'l', ylab = 'y')
lines(x, sdnorm(x, mean = 18, sd = 4, lambda = 0.30))
EDIT I added ylab = 'y' and updated the picture to have the y-axis re-labeled.
This should get you started.

Cannot save plots as pdf when ggplot function is called inside a function

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())

ggplot2: easy way to plot integral over independent variable?

I'm integrating a function f(t) = 2t (just an example) and would like to plot the integral as a function of time t using
awesome_thing <- function(t) {2*t}
integrate(awesome_thing, lower=0, upper=10)
However, I would like to plot the integral as a function of time in ggplot2, so for this example the plotted points would be (1,1), (2,4), (3,9), ..., (10,100).
Is there an easy way to do this in ggplot (e.g., something similar to how functions are plotted)? I understand I can "manually" evaluate and plot the data for each t, but I thought i'd see if anyone could recommend a simpler way.
Here is a ggplot solution and stat_function
# create a function that is vectorized over the "upper" limit of your
# integral
int_f <- Vectorize(function(f = awesome_thing, lower=0,upper,...){
integrate(f,lower,upper,...)[['value']] },'upper')
ggplot(data.frame(x = c(0,10)),aes(x=x)) +
stat_function(fun = int_f, args = list(f = awesome_thing, lower=0))
Not ggplot2 but shouldn't be difficult to adapt by creating a dataframe to pass to that paradgm:
plot(x=seq(0.1,10, by=0.1),
y= sapply(seq(0.1,10, by=0.1) ,
function(x) integrate(awesome_thing, lower=0, upper=x)$value ) ,
type="l")
The trick with the integrate function is that it retruns a list and you need to extract the 'value'-element for various changes in the upper limit.

How to draw loess estimation in GGally using ggpairs?

I tried GGally package a little bit. Especially the ggpairs function. However, I cannot figure out how to use loess instead of lm when plot smooth. Any ideas?
Here is my code:
require(GGally)
diamonds.samp <- diamonds[sample(1:dim(diamonds)[1],200),]
ggpairs(diamonds.samp[,c(1,5)],
lower = list(continuous = "smooth"),
params = c(method = "loess"),
axisLabels = "show")
Thanks!
P.S. compare with the plotmatrix function, ggpairs is much much slower... As a result, most of the time, I just use plotmatrix from ggplot2.
Often it is best to write your own function for it to use. Adapted from this answer to similar question.
library(GGally)
diamonds_sample = diamonds[sample(1:dim(diamonds)[1],200),]
# Function to return points and geom_smooth
# allow for the method to be changed
custom_function = function(data, mapping, method = "loess", ...){
p = ggplot(data = data, mapping = mapping) +
geom_point() +
geom_smooth(method=method, ...)
p
}
# test it
ggpairs(diamonds_sample,
lower = list(continuous = custom_function)
)
Produces this:
Well the documentation doesn't say, so use the source, Luke
You can dig deeper into the source with:
ls('package:GGally')
GGally::ggpairs
... and browse every function it references ...
seems like the args get mapped into ggpairsPlots and then -> plotMatrix which then gets called
So apparently selecting smoother is not explicitly supported, you can only select continuous = "smooth". If it behaves like ggplot2:geom_smooth it internally automatically figures out which of the supported smoothers to call (loess for <1000 datapoints, gam for >=1000).
You might like to step it through the debugger to see what's happening inside your plot. I tried to follow the source but my eyes glaze over.
or 2. Browse on https://github.com/ggobi/ggally/blob/master/R/ggpairs.r [4/14/2013]
#' upper and lower are lists that may contain the variables 'continuous',
#' 'combo' and 'discrete'. Each element of the list is a string implementing
#' the following options: continuous = exactly one of ('points', 'smooth',
#' 'density', 'cor', 'blank') , ...
#'
#' diag is a list that may only contain the variables 'continuous' and 'discrete'.
#' Each element of the diag list is a string implmenting the following options:
#' continuous = exactly one of ('density', 'bar', 'blank');

Resources