Plotting scalar field - r

I was searching for a way to plot this function as a scalar field, in particular as continuous scalar field:
library(rgl)
points = seq(-2, 0, length=20)
XY = expand.grid(X=points,Y=-points)
Zf <- function(X,Y){
X^2-Y^2;
}
Z <- Zf(XY$X, XY$Y)
open3d()
rgl.surface(x=points, y=matrix(Z,20), coords=c(1,3,2),z=-points)
axes3d()
A scalar field is usually plotted with two axis X and Y, where Z is represent by a colour( http://en.wikipedia.org/wiki/Scalar_field)
With ggplot() I can do this:
daf=data.frame(XY$X,XY$Y,Z)
ggplot(daf)+geom_point(aes(XY.X,XY.Y,color=Z))
But still not a continuous field.

This can be achieved by the 'image' function:
Z <- outer(points, points, Zf)
image(points, points, Z)
This method just uses nearest neighbor interpolation, but if you want a smoother representation, you can use other types of interpolation:
library(fields)
# Bilinear interpolation
interp_points = seq(-2, 0, length = 200)
interp_bilinear <- interp.surface(list(x = X, y = Y, z = Z),
loc = expand.grid(interp_points, interp_points))
image(interp_points, interp_points, matrix(interp_bilinear, 200, 200))
# Bicubic interpolation
library(akima)
interp_bicubic <- bicubic.grid(X, Y, Z, xlim = c(-2, 0), ylim = c(-2, 0),
dx = 2 / (200 - 1), dy = 2 / (200 - 1))
image(interp_bicubic)
The difference between different interpolation schemes becomes clearer when you have fewer observations or more wildly behaving functions:

Related

Check how many times smooth spline intersects with x-axis

I want to check how many times my smoothed spline intersects with the x-axis. Is there an elegant way to do this?
Example: (1 intersection in this case)
]1)
Check the number of times y values go from positive to negative
set.seed(1571933401)
x = 1:100
y = rnorm(100)
sp = smooth.spline(x, y)
with(sp, sum((sign(c(0, y)) * sign(c(y, 0))) == -1))
#6
graphics.off()
plot(sp, type = "l")
abline(h = 0, lty = 2)

How to generate values for 2 variables to draw a circle

I have been trying to generate random values so that I can construct a circle.
The values of x and y are expected to satisfy the following equation
x^2 + y^2 = 1
Here is the code that I used.
par(type = "s")
x <- runif(1000, min = -1, max = 1)
y <- sqrt(1 - x^2)
z <- NULL
z$x <- x
z$y <- y
z <- as.data.frame(z)
plot.new()
plot(z$x, z$y, type = "p")
plot.window(xlim = c(-10,10), ylim = c(-10,10), asp = 1)
But the graph I get is not quite what I expected it to be.
The graph resembles an upper half of an ellipse rather than a semicircle
Why are there no values for y where y < 0
Please find the plot here.
I am also interested in finding out, how to generate random values for x, y, z, a; where x^2 + y^2 + z^2 + a^2 = 10
Maybe you missed #thelatemail's comment:
png()
plot(z$x, z$y, type = "p", asp=1)
dev.off()
The reason passing asp=1 to plot.window would fail(if it were called first, and this is what you might have tried) is that plot itself calls plot.window again, and in the process reacquires the default values. You can see that in the code of plot.default:
> plot.default
function (x, y = NULL, type = "p", xlim = NULL, ylim = NULL,
log = "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL,
ann = par("ann"), axes = TRUE, frame.plot = axes, panel.first = NULL,
panel.last = NULL, asp = NA, ...)
{
localAxis <- function(..., col, bg, pch, cex, lty, lwd) Axis(...)
localBox <- function(..., col, bg, pch, cex, lty, lwd) box(...)
localWindow <- function(..., col, bg, pch, cex, lty, lwd) plot.window(...)
#.... omitted the rest of the R code.
(Calling plot.window after that plot call should not be expected to have any favorable effect.)
The problem is within this part of your code:
x <- runif(1000, min = -1, max = 1)
y <- sqrt(1 - x^2)enter code here
This problem arises from interpreting two distinct mathematical entities as the same (functions and equations are two different things). A function f takes an input x, and returns a single output f(x). Equations don't have this limitation, so if you are encoding this equation as a function, you will lose half the points in the circle, you will generate all the points in the upper semicircle.
Since the circle equation has two y outputs for any x value you can just generate two pairs of coordinates for each point generated by your uniform distribution like this:
x1 = runif(1000, min = -1, max = 1)
x2 = x1
y1 = sqrt(1 - x1^2)
y2 = (-1)*y1
x = c(x1,x2)
y = c(y1,y2)
plot(x,y, asp=1)
As John Coleman recommended in his comment, i'd prefer using parametric/polar coordinates instead. Generate angles in radians between 0 and 2pi and then calculate the appropriate x and y positions using the generated angle and the radius you want.
radius = 1
theta = runif(1000, min = 0, max = 2*pi)
x = radius * cos(theta)
y = radius * sin(theta)
plot(x,y, asp=1)
For the last part of your question, for each value of a variable, you'd have to work out all the possible tuples that solve the equation, and if z and a are also variables, it may not be possible to represent it solely on a 2-dimensional graph.

3d Surface Plot in R with plotly

I am looking to use the R plotly library to create a 3d surface plot of x,y,z coordinate data, similar to what is shown at the link below:
https://plot.ly/r/3d-surface-plots/
It appears that the plot_ly function requires the z coordinates to be in a matrix of dimensions x * y, as seen in datasets::volcano, used in the linked example. I'd appreciate some guidance on how to construct this matrix. Here is my sample x,y coordinate data:
## x coordinates
xSeq = seq(0, 1, .01)
## y coordinates
ySeq = seq(0, 1, .01)
## list with x, y coordinates
exmplList = list(x = xSeq, y = ySeq)
The z coordinates would be calculated via a formula from the x,y pairs (example formula used here is x + y). I've played around with something like:
exmplList = within(exmplList, z <- matrix(x + y, nrow = length(xSeq), ncol = length(ySeq)))
But that doesn't accomplish the pair combinations that I am trying to achieve.
Plotly surface needs a matrix so you could simply use this bit directly:
z = matrix(xSeq + ySeq, nrow = length(xSeq), ncol = length(ySeq))
Instead of doing a list. So, by running the following code:
## x coordinates
xSeq = seq(0, 1, 0.01)
## y coordinates
ySeq = seq(0, 1, 0.01)
## list with x, y coordinates
z = matrix(xSeq + ySeq, nrow = length(xSeq), ncol = length(ySeq))
fig = plot_ly(z = ~z) %>% add_surface()
fig
One obtains the following plot:
You might need to click and rotate a bit to see the plane. Hope it helps, cheers.

'rgl' translation issues in R

I've plotted up a series of points using the rgl package in R. I've plotted them in two dimensions for simplicity, but the issue still exists in three dimensions. The code snippet and plot below show a basic line of points plotted in the xy-plane:
library(rgl)
seq <- seq(1, 10, by = 0.1)
df <- data.frame(x = seq, y = seq / 10)
clear3d("all")
bg3d(color = "white")
points3d(x = df$x, y = df$y, z = 0)
axes3d()
rgl.viewpoint(theta = 0, phi = 0)
The points plot as expected. However, if I take these same points and translate them by a significant amount, the graphics device does not seem to be able to handle the points:
library(rgl)
seq <- seq(1, 10, by = 0.1)
df <- data.frame(x = seq, y = seq / 10)
# Translate points
df <- df + 1000000
clear3d("all")
bg3d(color = "white")
points3d(x = df$x, y = df$y, z = 0)
axes3d()
rgl.viewpoint(theta = 0, phi = 0)
Is this a known limitation? Is the problem with OpenGL, or with the package? I'm working with some points and surfaces that have an associated coordinate system, so I'd prefer not to translate my data back to the origin.
#derhass had the right idea. From the rgl manual:
Note that many of these calculations are done on the graphics card using single precision; you will likely see signs of rounding error if your scene requires more than 4 or 5 digit precision to distinguish values in any coordinate.

Visualize a function using double integration in R - Wacky Result

I am trying to visualize a curve for pollination distribution. I am very new to R so please don't be upset by my stupidity.
llim <- 0
ulim <- 6.29
f <- function(x,y) {(.156812/((2*pi)*(.000005^2)*(gamma(2/.156812)))*exp(-((sqrt(x^2+y^2))/.000005)^.156812))}
integrate(function(y) {
sapply(y, function(y) {
integrate(function(x) f(x,y), llim, ulim)$value
})
}, llim, ulim)
fv <- Vectorize(f)
curve(fv, from=0, to=1000)
And I get:
Error in y^2 : 'y' is missing
I'm not quite sure what you're asking to plot. But I know you want to visualise your scalar function of two arguments.
Here are some approaches. First we define your function.
llim <- 0
ulim <- 6.29
f <- function(x,y) {
(.156812/((2*pi)*(.000005^2)*(gamma(2/.156812)))*exp(-((sqrt(x^2+y^2))/.000005)^.156812))
}
From your title I thought of the following. The function defined below intf integrates your function over the square [0,ul] x [0,ul] and return the value. We then vectorise and plot the integral over the square as a function the length of the side of the square.
intf <- function(ul) {
integrate(function(y) {
sapply(y, function(y) {
integrate(function(x) f(x,y), 0, ul)$value
})
}, 0, ul)$value
}
fv <- Vectorize(intf)
curve(fv, from=0, to=1000)
If f is a distribution, I guess you can make your (somewhat) nice probability interpretation of this curve. (I.e. ~20 % probability of pollination(?) in the 200 by 200 meter square.)
However, you can also do a contour plot (of the log-transformed values) which illustrate the function we are integrating above:
logf <- function(x, y) log(f(x, y))
x <- y <- seq(llim, ulim, length.out = 100)
contour(x, y, outer(x, y, logf), lwd = 2, drawlabels = FALSE)
You can also plot some profiles of the surface:
plot(1, xlim = c(llim, ulim), ylim = c(0, 0.005), xlab = "x", ylab = "f")
y <- seq(llim, ulim, length.out = 6)
for (i in seq_along(y)) {
tmp <- function(x) f(x, y = y[i])
curve(tmp, llim, ulim, add = TRUE, col = i)
}
legend("topright", lty = 1, col = seq_along(y),
legend = as.expression(paste("y = ",y)))
They need to be modified a bit to make them publication worthy, but you get the idea. Lastly, you can do some 3d plots as others have suggested.
EDIT
As per your comments, you can also do something like this:
# Define the function times radius (this time with general a and b)
# The default of a and b is as before
g <- function(z, a = 5e-6, b = .156812) {
z * (b/(2*pi*a^2*gamma(2/b)))*exp(-(z/a)^b)
}
# A function that integrates g from 0 to Z and rotates
# As g is not dependent on the angle we just multiply by 2pi
intg <- function(Z, ...) {
2*pi*integrate(g, 0, Z, ...)$value
}
# Vectorize the Z argument of intg
gv <- Vectorize(intg, "Z")
# Plot
Z <- seq(0, 1000, length.out = 100)
plot(Z, gv(Z), type = "l", lwd = 2)
lines(Z, gv(Z, a = 5e-5), col = "blue", lwd = 2)
lines(Z, gv(Z, b = .150), col = "red", lwd = 2)
lines(Z, gv(Z, a = 1e-4, b = .2), col = "orange", lwd = 2)
You can then plot the curves for the a and b you want. If either is not specified, the default is used.
Disclaimer: my calculus is rusty and I just did off this top of my head. You should verify that I've done the rotation of the function around the axis properly.
The lattice package has several functions that can help you draw 3 dimensional plots, including wireframe() and persp(). If you prefer not to use a 3d-plot, you can create a contour plot using contour().
Note: I don't know if this is intentional, but your data produces a very large spike in one corner of the plot. This produces a plot that is for all intents flat, with a barely noticable spike in one corner. This is particularly problematic with the contour plot below.
library(lattice)
x <- seq(0, 1000, length.out = 50)
y <- seq(0, 1000, length.out = 50)
First the wire frame plot:
df <- expand.grid(x=x, y=y)
df$z <- with(df, f(x, y))
wireframe(z ~ x * y, data = df)
Next the perspective plot:
dm <- outer(x, y, FUN=f)
persp(x, y, dm)
The contour plot:
contour(x, y, dm)

Resources