I plot a 3d plot in R using persp. I have two questions with respect to this:
Want to verify that I understand the docs correctly. persp will take the valuex from x and y, then depending on the index of each value in those vectors, say (i,j) corresponding to the current element in x and y, (x[i],y[j]), it will pluck out zfit[i,j] and plot (x[i],y[j],zfit[i,j]). Is this correct?
This does not produce the numbers on the actual axis but arrows in the increasing direction. How do I make numbers appear?
Example:
set.seed(1)
x = 1:10
y = rnorm(10)
z = x + y^2
g = expand.grid(list(x=seq(from=min(x), to=max(x), length.out=100),y=seq(from=min(y), to=max(y), length.out=100)))
mdl = loess(z ~ x+ y)
zfit = predict(mdl, newdata=g)
persp(x = seq(from=min(x), to=max(x), length.out=100), y = seq(from=min(y), to=max(y), length.out=100), z= zfit)
1 - Your understanding is correct.
2 - Add ticktype = "detailed" to show numbers on axis.
Related
I have a function,
x= (z-z^2.5)/(1+2*z-z^2)
y = z-z^2.5
where z is the only variable. How to draw a graph where x-axis shows value of function x, and y-axis shows value of function y as z range from 0 to 5?
You can get a very basic plot by simply following your own instructions.
## z ranges from 0 to 5
z = seq(0,5,0.01)
## x and y are functions of z
x = (z-z^2.5)/(1+2*z-z^2)
y = z-z^2.5
##plot
plot(x,y, pch=20, cex=0.5)
If you want a smooth curve it is a little trickier. There is a discontinuity in the curve at
z = 1 + sqrt(2) ~ 2.414. If you just draw the curve as one piece, you get an unwanted line connecting across the discontinuity. So, in two pieces,
plot(x[1:242],y[1:242], type='l', xlab='x', ylab='y',
xlim=range(x), ylim=range(y))
lines(x[243:501],y[243:501])
But be careful about interpreting this. There is something tricky going on from z=0 to z=1.
Using ggplot2
# z ranges from -1000 to 1000 (The range can be arbitrary)
z = seq(-1000,1000,.25)
# x as a function of z
x = (z-z^2.5) / ((1+2*z)-z^2)
# y as a function of z
y = z-z^2.5
# make a dataframe of x,y and z
df <- data.frame(x=x, y=y, z=z)
# subset the df where z is between 0 and 5
df_5 <- subset(df, (df$z>=0 & df$z<=5))
# plot the graph
library(ggplot2)
ggplot(df_5, aes(x,y))+ geom_point(color="red")
The only addition to #G5W answer is subset() of values between 0 and 5 from your dataset to plot and the use of ggplot2.
So I want to superimpose a regression line in a barplot in R. Similar to the attached image by Rosindell et al. 2011. However, when I try to do this with my data the line does not stretch the entire length of the barplot.
For a reproducible example, I made a dummy code:
x = 20:1
y = 1:20
barplot(x, y, space = 0)
lines(x, y, col = 'red')
How do I get the lines to transverse the entire stretch of the barplot bins?
PS: the line does not need to be non-linear. I just want to superimpose a straight line on the barplot
Thank you.
A more general solution could be to rely on the x-values that are generated by barplot(). This way, you can deal with scenarios where you only have counts (rather than x and y values). I am referring to a variable like this one, where your "x" is categorical (precisely, x-axis values correspond to the names of y).
p.x <- c(8,12,14,9,5,3,2)
x <- sample(c("A","B","C","D","E","F","G"),
prob = p.x/sum(p.x),
replace = TRUE,
size = 200)
y <- table(x)
y
# A B C D E F G
# 27 52 46 36 21 11 7
When you use barplot(), you can collect the x-positions of the bars in a variable (plot.dim in this case) and use to guide your line
plot.dim <- barplot(y)
lines(plot.dim, y, col = "red", lwd = 2)
The result
Now, back to your data. Even if you have both x and y, in a barplot you are displaying only your y variable, while x is used for the labels of y.
x <- 20:1
y <- as.integer(22 - 1 * sample(seq(0.7, 1.3, length.out = length(x))) * x)
names(y) <- x
y <- y[order(as.numeric(names(y)))]
Let's plot your y values again. Collect the barplot positions in the xpos variable.
xpos <- barplot(y, las = 2)
Note that the first bar (x=1) is not positioned at 1. Similarly, the last bar is positioned at 23.5 (and not 20).
xpos[1]
# x=1 is indeed at 0.7
xpos[length(xpos)]
# x=20 is indeed at 23.5
Do your regression (for example, use lm()). Compute the predicted y values at the first and the last x (y labels).
lm.fit <- lm(y~as.numeric(names(y)))
y.init <- lm.fit$coefficients[2] * as.numeric(names(y))[1] + lm.fit$coefficients[1]
y.end <- lm.fit$coefficients[2] * as.numeric(names(y))[(length(y))] + lm.fit$coefficients[1]
You can now over-pose a line using segments(), but remember to set your x-values according to what stored in xpos.
segments(xpos[1], y.init, xpos[length(xpos)], y.end, lwd = 2, col = "red")
Check out the help page ?barplot: the second argument is width - optional vector of bar widths, not the y coordinate. The following code does what you want, but I don't believe it's a general purpose solution.
barplot(y[x], space = 0)
lines(x, y, col = 'red')
Edit:
A probably better way would be to use the return value of barplot.
bp <- barplot(y[x], space = 0)
lines(c(bp), y[x], col = 'red')
For example, let say:
x <- rnorm(20)
y <- rnorm(20) + 1
n <- seq(1,20,1)
data <- data.frame(n, x, y)
Is it possible to plot y~x with the indexed value of each pair at the top of the plot?
Can it be done with the base graphics, not ggplot?
It may be simple, but I am struggling to find help via Google. My guess is I'm using a poor selection of words.
Any help is much appreciated!
plot(x,y)
text(x = x, y = y, n, pos = 3)
#Adds text 'n' at co-ordinate (x,y)
# "pos = 3" means the text will be just above the co-ordinates
#See ?text for more
If you wanted to plot all the indices on a same line above the plot boundary, you can specify the appropriate value for y when using text. However, you will first have to pass par(xpd=TRUE) to be able to draw outside plot boundary
Yes we can add label. Try this code:
x <- rnorm(20)
y <- rnorm(20) + 1
n <- seq(1,20,1)
data <- data.frame(n, x, y)
plot(y~x)
with(data, text(y~x, labels = row.names(data)))
I have a three column data frame with latitude, longitude, and underground measurements as the columns. I am trying to figure out how to interpolate data points between the points I have (which are irregularly space) and then create a smooth surface plot of the entire area. I have tried to use the 'surface3d' function in the 'rgl' package but my result looks like a single giant spike. I have been able to plot the data with 'plot3d' but I need to take it a step further and fill in the blank spaces with interpolation. Any ideas or suggestions? I'm also open to using other packages, the rgl just seemed like the best fit at the time.
EDIT: here's an excerpt from my data (measurements of aquifer depth) :
lat_dd_NAD83 long_dd_NAD83 lev_va_ft
1 37.01030 -101.5006 288.49
2 37.03977 -101.6633 191.68
3 37.05201 -100.4994 159.34
4 37.06567 -101.3292 174.07
5 37.06947 -101.4561 285.08
6 37.10098 -102.0134 128.94
Just to add small but (maybe) important note about interpolation.
Using very nice package "akima" you can easily interpolate your data:
library(akima)
library(rgl)
# library(deldir)
# Create some fake data
x <- rnorm(100)
y <- rnorm(100)
z <- x^2 + y^2
# # Triangulate it in x and y
# del <- deldir(x, y, z = z)
# triangs <- do.call(rbind, triang.list(del))
#
# # Plot the resulting surface
# plot3d(x, y, z, type = "n")
# triangles3d(triangs[, c("x", "y", "z")], col = "gray")
n_interpolation <- 200
spline_interpolated <- interp(x, y, z,
xo=seq(min(x), max(x), length = n_interpolation),
yo=seq(min(y), max(y), length = n_interpolation),
linear = FALSE, extrap = TRUE)
x.si <- spline_interpolated$x
y.si <- spline_interpolated$y
z.si <- spline_interpolated$z
persp3d(x.si, y.si, z.si, col = "gray")
Spline - interpolated picture (200 steps)
With this package you can easily change amount of steps of interpolation, etc. You will need at least 10 (the more the better) points to get a reasonable spline interpolation with this package. Linear version works well regardless amount of points.
P.S. Thanks for user 2554330 - didn't knew about deldir, really useful thing in some cases.
You could use the deldir package to get a Delaunay triangulation of your points, then convert it to the form of data required by triangles3d for plotting. I don't know how effective this would be on a really large dataset, but it seems to work on 100 points:
library(deldir)
library(rgl)
# Create some fake data
x <- rnorm(100)
y <- rnorm(100)
z <- x^2 + y^2
# Triangulate it in x and y
del <- deldir(x, y, z = z)
triangs <- do.call(rbind, triang.list(del))
# Plot the resulting surface
plot3d(x, y, z, type = "n")
triangles3d(triangs[, c("x", "y", "z")], col = "gray")
EDITED to add:
The version of rgl on R-forge now has a function to make this easy. You can now produce a plot similar to the one above using
library(deldir)
library(rgl)
plot3d(deldir(x, y, z = z))
There is also a function to construct mesh3d objects from the deldir() output.
Using R, I would like to plot a linear relationship between two variables, but I would like the fitted line to be present only within the range of the data.
For example, if I have the following code, I would like the line to exist only from x and y values of 1:10 (with default parameters this line extends beyond the range of data points).
x <- 1:10
y <- 1:10
plot(x,y)
abline(lm(y~x))
In addition to using predict with lines or segments you can also use the clip function with abline:
x <- 1:10
y <- 1:10
plot(x,y)
clip(1,10, -100, 100)
abline(lm(y~x))
Instead of using abline(), (a) save the fitted model, (b) use predict.lm() to find the fitted y-values corresponding to x=1 and x=10, and then (c) use lines() to add a line between the two points:
f <- lm(y~x)
X <- c(1, 10)
Y <- predict(f, newdata=data.frame(x=X))
plot(x,y)
lines(x=X, y=Y)
You can do this using predict.
You can predict on specific values of x (see ?predict)
x<-1:10
y<-1:10
plot(x,y)
new <- data.frame(x = seq(1, 5, 0.5))
lines(new$x, predict(lm(y~x), new))
The plotrix library has the ablineclip() function for just this:
x <- 1:10
y <- 1:10
plot(x,y)
ablineclip(lm(y~x),x1=1,x2=5)
An alternative is to use the segments function (doc here).
Say you estimated the line, and you got an intercept of a and a slope of b. Thus, your fitted function is y = a + bx.
Now, say you want to show the line for x between x0 and x1. Then, the following code plots your line:
# inputs
a <- 0.5
b <- 2
x0 <- 1
x1 <- 5
# graph
plot(c(0,5), c(0,5), type = "n", xlab = "", ylab = "", bty='l')
segments(x0, a+b*x0, x1, a+b*x1)
Simply replace the values of a, b, x0, x1 with those of your choosing.
For those like me who came to this question wanting to plot a line for an arbitrary pair of numbers (and not those that fit a given regression), the following code is what you need:
plot(c(0,5), c(0,5), type = "n", xlab = "", ylab = "", bty='l')
segments(x0, yo, x1, y1)
Simply replace the values of x0, y0, x1, y1 with those of your choosing.