This question already has an answer here:
R: Get the min/max of each item of a vector compared to single value
(1 answer)
Closed 2 years ago.
I tried the following two ways. It seems to me they all take x as a vector instead of a single point. Is there a way to correctly plot this function?
eq = function(x){max(x,0)}
curve(eq, from=1, to=50, , xlab="x", ylab="y")
# It produces the following error:
#Error in curve(eq, from = 1, to = 50, , xlab = "x", ylab = "y") :
# 'expr' did not evaluate to an object of length 'n'
ggplot(data.frame(x=c(1,50)), aes(x=x)) + stat_function(fun=eq)
#It will draw a horizontal line at x=50
You probably want parallel maxima, pmax.
eq = function(x){pmax(x,0)}
curve(eq, from=-50, to=50, , xlab="x", ylab="y")
ggplot(data.frame(x=c(-50,50)), aes(x=x)) + stat_function(fun=eq)
Related
This question already has answers here:
How to plot a function curve in R
(7 answers)
Closed 3 years ago.
With R, how do I plot simple linear equations as lines on a plane? For example, how to plot line of the equation -2x + y = 0?
I did searched google but not got an answer.
Thanks!
Although a duplicate here is a quick answer.
If one were to do this in excel, one would create 2 columns, 1 with x values and 1 with the corrosponding y values. For your situation the equation is equivalent to y = 2x. As such plotting can be by either calculating a range of values and plotting this as one would in excel.
Alternatively one can create a function and plot the function over an interval. Both methods are shown below.
#method one
x <- seq(from = 0, to = 10)
y <- 2 * x
plot(y = y, x = x, xlab = "x", ylab = "y") #add type = 'l' for a line rather than a dot plot.
#method two
y <- function(x) 2 *x
plot(y, from = 0, to = 10)
Question 1
I have a function that takes in p and n. I need to graph every combination of p=c(0.05,0.1,0.25,0.5,0.9,0.95) and n=c(5,10,30,50,100). So total of 6*5=30 plots. I've tried using mapply which returns a plot shown below (EDIT: too low reputation to upload img but I shows I get 6 plots only). Based on where my ablines are, I think it's trying all values of p over only a single value of n!
Question 2
I am trying to put values of n and p into the plot using paste0() to track which plot belongs to which combination of n and p, but it does not seem to work when I use mapply (it works fine for single graphs that I manually plot)
ci.auto <- function(p,n,alpha){
# Repeat the process nsim times
nsim <- 10000
ci.mat <- replicate(nsim, conf.int(p, n, alpha))
# Graphing the first 100 intervals
matplot(rbind(1:100, 1:100), ci.mat[, 1:100], type = "l", lty = 1,
xlab = paste0("sample number n=",n), ylab = "confidence interval")
abline(h = p)
text(2.5, 0.8, paste0("p=",p), col = "red")
# Proportion of times the interval is correct
mean( (p >= ci.mat[1,])*(p <= ci.mat[2,]) )
}
par(mfrow = c(5,6))
mapply(ci.auto, p = c(0.05,0.1,0.25,0.5,0.9,0.95), n = c(5,10,30,50,100), alpha)
df<-expand.grid(p,n)
mapply(Fun = ci.auto, df$Var1,df$Var2,alpha)
In R I have created a simple matrix of one column yielding a list of numbers with a set mean and a given standard deviation.
rnorm2 <- function(n,mean,sd) { mean+sd*scale(rnorm(n)) }
r <- rnorm2(100,4,1)
I now would like to plot how these numbers differ from the mean. I can do this in Excel as shown below:
But I would like to use ggplot2 to create a graph in R. in the Excel graph I have cheated by using a line graph but if I could do this as columns it would be better. I have tried using a scatter plot but I cant work out how to turn this into deviations from the mean.
Perhaps you want:
rnorm2 <- function(n,mean,sd) { mean+sd*scale(rnorm(n)) }
set.seed(101)
r <- rnorm2(100,4,1)
x <- seq_along(r) ## sets up a vector from 1 to length(r)
par(las=1,bty="l") ## cosmetic preferences
plot(x, r, col = "green", pch=16) ## draws the points
## if you don't want points at all, use
## plot(x, r, type="n")
## to set up the axes without drawing anything inside them
segments(x0=x, y0=4, x1=x, y1=r, col="green") ## connects them to the mean line
abline(h=4)
If you were plotting around 0 you could do this automatically with type="h":
plot(x,r-4,type="h", col="green")
To do this in ggplot2:
library("ggplot2")
theme_set(theme_bw()) ## my cosmetic preferences
ggplot(data.frame(x,r))+
geom_segment(aes(x=x,xend=x,y=mean(r),yend=r),colour="green")+
geom_hline(yintercept=mean(r))
Ben's answer using ggplot2 works great, but if you don't want to manually adjust the line width, you could do this:
# Half of Ben's data
rnorm2 <- function(n,mean,sd) { mean+sd*scale(rnorm(n)) }
set.seed(101)
r <- rnorm2(50,4,1)
x <- seq_along(r) ## sets up a vector from 1 to length(r)
# New variable for the difference between each value and the mean
value <- r - mean(r)
ggplot(data.frame(x, value)) +
# geom_bar anchors each bar at zero (which is the mean minus the mean)
geom_bar(aes(x, value), stat = "identity"
, position = "dodge", fill = "green") +
# but you can change the y-axis labels with a function, to add the mean back on
scale_y_continuous(labels = function(x) {x + mean(r)})
in base R it's quite simple, just do
plot(r, col = "green", type = "l")
abline(4, 0)
You also tagged ggplot2, so in that case it will be a bit more complicated, because ggplot requires creating a data frame and then melting it.
library(ggplot2)
library(reshape2)
df <- melt(data.frame(x = 1:100, mean = 4, r = r), 1)
ggplot(df, aes(x, value, color = variable)) +
geom_line()
I'm interested in creating a histogram in R that will contain two (or more) population on top of each other, meaning - I don't want a two histograms sharing the same graph but a bar containing two colors or more.
Found the image below - this is what I want to accomplish.
Any ideas?
That is actually the annoying default in ggplot2:
library(ggplot2)
ggplot(iris, aes(x=Sepal.Length, fill=Species)) +
geom_histogram()
Here is another option without using ggplot:
#plot the entire data set (everything)
hist(everything, breaks=c(1:10), col="Red")
#then everything except one sub group (1 in this case)
hist(everything[everything!=1], breaks=c(1:10), col="Blue", add=TRUE)
#then everything except two sub groups (1&2 in this case)
hist(everything[everything!=1 && everything!=2], breaks=c(1:10), col="Green", add=TRUE)
# 1) Define the breaks to use on your Histogram
xrange = seq(-3,3,0.1)
# 2) Have your vectors ready
v1 = rnorm(n=300,mean=1.1,sd=1.5)
v2 = rnorm(n=350,mean=1.3,sd=1.5)
v3 = rnorm(n=380,mean=1.2,sd=1.9)
# 3) subset your vectors to be inside xrange
v1 = subset(v1,v1<=max(xrange) & v1>=min(xrange))
v2 = subset(v2,v2<=max(xrange) & v2>=min(xrange))
v3 = subset(v3,v3<=max(xrange) & v3>=min(xrange))
# 4) Now, use hist to compute the counts per interval
hv1 = hist(v1,breaks=xrange,plot=F)$counts
hv2 = hist(v2,breaks=xrange,plot=F)$counts
hv3 = hist(v3,breaks=xrange,plot=F)$counts
# 5) Finally, Generate a Frequency BarPlot that is equivalent to a Stacked histogram
maintitle = "Stacked Histogram Example using Barplot"
barplot(rbind(hv1,hv2,hv3),col=2:4,names.arg=xrange[-1],space=0,las=1,main=maintitle)
# 6) You can also generate a Density Barplot
Total = hv1 + hv2 + hv3
barplot(rbind(hv1/Total,hv2/Total,hv3/Total),col=2:4,names.arg=xrange[-1],space=0,las=1)
I am trying to create a 'before and after' line chart which shows results of blood tests before and after an operation. I have 307 pairs of data so need to get the lines function to plot a line for each of the 307 columns in the matrix of data created from pre- and post-operative data (one column: one patient). So I tried this:
ylabel<-"Platelet count (millions/ml)"
preoptpk<-c(100,101,102,103,104,105)
postoptpk<-c(106,107,108,109,110,111)
preoptpk<-t(matrix(preoptpk))
postoptpk<-t(matrix(postoptpk))
preoptpk
postoptpk
beforeandafterdata<-rbind(preoptpk, postoptpk)
beforeandafterdata
ylimits<-c(0.8*min(beforeandafterdata,na.rm=TRUE),1.15*max(beforeandafterdata, na.rm=TRUE))
ylimits
plot(beforeandafterdata[,1], type = "l", col = "black", xlim = c(0.9, 2.1),
ylim = ylimits, ann = FALSE, axes = FALSE)
title(ylab=ylabel, cex.lab=1.4)
axis(1,at=1:2,lab=c("Preop.","Postop."),cex.axis=1.5)
axis(2,labels=TRUE)
x<-c(1*2:6)
x
lines(beforeandafterdata[,x],type="l",col="black",
xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
..and nothing happened.
I don't understand why I can't use x<-c(1*2:307) since when I manually define x as 2 then 3 then 4 then 5 then 6 it works fine:
x <- 2 x
lines(beforeandafterdata[,x],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
x <-3 x
lines(beforeandafterdata[,x],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
x <-4 x
lines(beforeandafterdata[,x],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
x<-5 x
lines(beforeandafterdata[,x],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
x<-6 x
lines(beforeandafterdata[,x],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
x<-c(1*2:6)
Any help how I can get this to work? Since I have several variables and manually plotting 307 lines for each will be v. time consuming. Thanks for reply.
Trying to stay close to your example, you need to use xy.coords within lines.
plot(beforeandafterdata[,1],type="l",col="black",xlim=c(0.9,2.1),ylim=ylimits,
ann=FALSE,axes=FALSE)
title(ylab=ylabel, cex.lab=1.4)
axis(1,at=1:2,lab=c("Preop.","Postop."),cex.axis=1.5)
axis(2,labels=TRUE)
x<-c(1*2:6)
x
lapply(x, function(x){
lines(xy.coords(x=c(1, 2), y=c(beforeandafterdata[,x])), type="l", col="black",
xlim=c(0.9,2.1),ylim=ylimits,ann=FALSE)
})
lapply is needed to prevent one line being joined to the next
You could use a for loop to do this. e.g.:
for (x in 2:6) {
lines(beforendafterdata[,x], ...)
}
Or you can use the reshape2 and ggplot2 packages. First melt your data into a long format that ggplot2 likes:
library(reshape2)
beforeandafter_melted <- melt(beforeandafterdata)
Then plot away. You don't need the color argument, but the group is important to force individual lines to be drawn.
library(ggplot2)
ggplot(beforeandafter_melted, aes(x=Var1, y=value, color=factor(Var2), group=Var2)) +
geom_line()
Where Var1 is the row (1 or 2) and Var2 is the column (1 to 6) from your initial matrix beforeandafterdata.
Also, why have you written x <- c(1*2:307)? This is no different than 2:307 (unless you're trying to force numeric conversion, but that isn't the way to go about it).
all.equal(c(1*2:307), 2:307)
# [1] TRUE