I created a 64x64 random 2D array in Julia, and then interpolated it using Interpolations.jl:
using Interpolations
using Plots
gr()
x = range(-10., length=64, stop=10.)
y = range(-10., length=64, stop=10.)
v_unscaled = interpolate(potential, BSpline(Cubic(Line(OnCell()))))
v_scaled = Interpolations.scale(v_unscaled, x, y)
v = extrapolate(v_scaled, 0)
p_int = contour(x, y, v_scaled, fill=true)
display(p_int)
p = contour(x, y, v, fill=true)
display(p)
When I plot the extrapolated function v, the non-zero part of the contour is shrunk to the lower left corner which is not as expected, because in the specified domain, the two plots should look the same. What is wrong with the procedures above?
Related
I am calculating points along a three-dimensional logarithmic spiral between two points. I seem to be close, but I think I'm missing a conditional sign flip somewhere.
This code works relatively well:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p1 = [1,1,1]
p2 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1-p2)
t = range(0,r,rez)
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]))
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p1[1];
y = sin.(theta).*exp.(-t).*r.+p1[2];
z = exp.(-t).*log.(r).+p1[3]
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
and produces the following plot. Values of the endpoints are shown on the plot, with an arrow from the coordinate to its respective marker. The first point is off, but it's close enough for my liking.
The problem comes when I flip p2 and p1 such that
p1 = [3,10,2]
p2 = [1,1,1]
In this case, I still get a spiral from p2 to p1, and the end point (p1) is highly accurate. However, the other endpoint (p2) is wildly off:
I think this is due to me changing the relative Z position of the two points, but I'm not sure, and I haven't been able to solve this riddle. Any help would be greatly appreciated. (Bonus points if you can help figure out why the Z value on p2 is off in the first example!)
Assuming this is a follow-up of your other question: Drawing an equiangular spiral between two known points in Julia
I assume you just want to add a third dimension to your previous 2D problem using cylindric coordinate system. This means that you need to separate the treatment of x and y coordinate on one side, and the z coordinate on the other side.
First you need to calculate your r on the first two coordinate:
r = norm(p1[1:2]-p2[1:2])
Then, when calculating z, you need to take only the third dimension in your formula (not sure why you used a log function there in the first place):
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
That will fix your z-axis.
Finally for your x and y coordinate, use the two argument atan function:
julia>?atan
help?> atan
atan(y)
atan(y, x)
Compute the inverse tangent of y or y/x, respectively.
For one argument, this is the angle in radians between the positive x-axis and the point (1, y), returning a value in the interval [-\pi/2, \pi/2].
For two arguments, this is the angle in radians between the positive x-axis and the point (x, y), returning a value in the interval [-\pi, \pi]. This corresponds to a standard atan2
(https://en.wikipedia.org/wiki/Atan2) function. Note that by convention atan(0.0,x) is defined as \pi and atan(-0.0,x) is defined as -\pi when x < 0.
like this:
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
And finally, like in your previous question, add the p2 point instead of the p1 point at the end of x, y, and z:
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
In the end, I have this:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p2 = [1,1,1]
p1 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1[1:2]-p2[1:2])
t = range(0.,norm(p1-p2), length=rez)
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
theta = range(0., 2*pi*rev, length=rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
#show (x[begin], y[begin], z[begin])
#show (x[end], y[end], z[end]);
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
Which give the expected results:
p2 = [1,1,1]
p1 = [3,10,2]
(x[begin], y[begin], z[begin]) = (3.0, 10.0, 2.0)
(x[end], y[end], z[end]) = (1.0001877364735474, 1.0008448141309634, 1.0000938682367737)
and:
p1 = [1,1,1]
p2 = [3,10,2]
(x[begin], y[begin], z[begin]) = (0.9999999999999987, 1.0, 1.0)
(x[end], y[end], z[end]) = (2.9998122635264526, 9.999155185869036, 1.9999061317632263)
In 2D, let us assume the pole at the point C, and the spiral from P to Q, corresponding to a variation of the parameter in the interval [0, 1].
We have
X = Cx + cos(at+b).e^(ct+d)
Y = Cy + sin(at+b).e^(ct+d)
Using the known points,
Px - Cx = cos(b).e^d
Py - Cy = sin(b).e^d
Qx - Cx = cos(a+b).e^(c+d)
Qy - Cy = sin(a+b).e^(c+d)
From the first two, by a Cartesian to polar transformation (and logarithm), you can obtain b and d. From the last two, you similarly obtain a+b and c+d, and the spiral is now defined.
For the Z coordinate, I cannot answer precisely as you don't describe how you generalize the spiral to 3D. Anyway, we can assume a certain function Z(t), that you can map to [Pz, Qz] by the linear transformation
(Qz - Pz) . (Z(t) - Z(0)) / (Z(1) - Z(0)) + Pz.
I'm trying to simultaneously plot the contour lines and the surface of a function in Julia, but I can't seem to find a way to that.
Is there an easy way to achieve this?
Here is an example I worked out for Plots. The PyPlot package has something better, and something could be done with Makie:
import Contour: contours, levels, level, lines, coordinates
function surface_contour(xs, ys, f; offset=0)
p = surface(xs, ys, f, legend=false, fillalpha=0.5)
## we add to the graphic p, then plot
zs = [f(x,y) for x in xs, y in ys] # reverse order for use with Contour package
for cl in levels(contours(xs, ys, zs))
lvl = level(cl) # the z-value of this contour level
for line in lines(cl)
_xs, _ys = coordinates(line) # coordinates of this line segment
_zs = offset .+ 0 .* _xs
plot!(p, _xs, _ys, _zs, alpha=0.5) # add curve on x-y plane
end
end
p
end
xs = ys = range(-pi, stop=pi, length=100)
f(x,y) = 2 + sin(x) - cos(y)
surface_contour(xs, ys, f)
imagine I have a 3 columns matrix
x, y, z where z is a height/intensity of x and y.
x = runif(1000)
y = runif(1000)
z = rnorm(1000)
How to use the rayshader packge for 3D surface from x, y, z?
although the rgl could do it, i think is it possible to directly use the rayshader for 3D surface from x, y, z?
Thanks
hees
You could use akima::interp to approximate the surface with a matrix of values, and maybe rayshader::ray_shade can handle that. Code would be
m <- akima::interp(x, y, z, nx = 200, ny = 200)
s <- rayshader::ray_shade(m$z)
This gives a matrix of shade values; it doesn't draw anything. To draw something, you'll need to turn those values into colours, and display them. For example,
plot(as.raster(s))
which gives this plot:
To plot a circle of radius 2 centered at (1, 1) I do the following:
θ = 0:0.1:2π
x = 1 .+ 2cos.(θ)
y = 1 .+ 2sin.(θ)
plot(x, y, aspect_ratio=:equal)
However, if I want to plot a set of parametric equations with more than two parameters I cannot use this approach. How should one approach plotting parametric equations with more than one parameter in Julia? For instance, how can I plot the cone described by the parametric equations
x = r*cos(θ)
y = r*sin(θ)
z = r
where r and θ are the parameters?
I am imagining the final plot to look like in the below image that has been generated by entering ParametricPlot3D[{r*Cos[t], r*Sin[t], r}, {r, -3, 3}, {t, 0, 2*Pi}] in Mathematica.
This works with the plotly and pyplot backends to Plots but not gr:
X(r,theta) = r * cos(theta)
Y(r,theta) = r * sin(theta)
Z(r,theta) = r
rs = range(0, 2, length=50)
ts = range(0, 2pi, length=50)
surface(X.(rs',ts), Y.(rs', ts), Z.(rs', ts))
I want to plot a univariate normal density function of the normal distribution onto a (x,y,z) coordinate system.
The code I am using is:
library(rgl)
open3d()
x <- seq(0, 10, length=100)
y <- seq(0, 10, length=100)
z = outer(x,y, function(x,y) dnorm(x,2.5,1)*dnorm(y,2.5,1))
persp3d(x, y, z,col = rainbow(100))
The problem I an encountering is that I want the normal distribution not to be around its mean only but also to be on a straight line or a circle. In latter case, I would expect the output to be similar to a volcano. I guess I must first create some probabilities within a loop. How can I do this? Or should I also use some surface command to plot the output? I am pretty sure this has nothing to do with a bivariate normal though.
Best
Fuji
The first part is easy: just don't let your z depend on y for instance:
z = outer(x,y, function(x,y) dnorm(x,2.5,1))
persp3d(x, y, z,col = rainbow(100))
For the second part, you can imagine that the means of the normal distribution lie on the x^2+y^2=1 circle. You will have infinite normal distributions with radial directions. Try this:
#define the volcano function
volcano<-function(x,y,sigma=1/2) {
alpha<-atan(y/x)+pi*(x<0)
d<-sqrt((cos(alpha)-x)^2 + (sin(alpha)-y)^2)
dnorm(d,0,sigma)
}
x<-seq(-2,2,length.out=100)
y<-seq(-2,2,length.out=100)
z<-outer(x,y,volcano)
persp3d(x, y, z,col = rainbow(100))