I want to plot 3D HeatMap for 3D function f(x,y,z).
For 2D function f(x,y), I know the below code works.
using Plots
x = 1:L # coordinate range
y = 1:L
F = Float64[f(ix,iy) for ix in x, iy in y]' #convert f(x,y) to an array
plot(F,st=:heatmap,color= cgrad(:blues))
plot!(xlabel="x",ylabel="y",aspect_ratio=:equal)
plot!(xlims=(1,L),ylims=(1,L))
For 3D function, where should I change?
using Plots
x = 1:L # coordinate range
y = 1:L
z = 1:L
F = Float64[f(ix,iy,iz) for ix in x, iy in y,iz in z] #convert f(x,y,z) to an array
plot(F,st=:heatmap,color = cgrad(:blues),alpha=0.1)
plot!(xlabel="x",ylabel="y",zlabel="z",aspect_ratio=:equal)
plot!(xlims=(1,L),ylims=(1,L),zlims=(1,L))
This code passes, but something is wrong.
color = cgrad(:blues),alpha=0.1,xlabel="x",ylabel="y" are not reflected.
In addition, the figure does not seem to be f(x,y,z). For example, f(x,y,z) = x^2 + y^2 +z^2 gives a spherical gradation, but the result is not.
The above approach is slow for more data points. However, I think you don't want heatmaps as the heatmaps in the previous link are just projections from 2D into 3D planes.
I think you need something like this.
See code here.
https://lazarusa.github.io/BeautifulMakie/surfWireLines/volume/
See image
And for convenience also here:
using GLMakie
let
x = 1:10
y = 1:10
z = 1:10
f(x,y,z) = x^2 + y^2 + z^2
vol = [f(ix,iy,iz) for ix in x, iy in y, iz in z]
fig, ax, _ = volume(x, y, z, vol, colormap = :plasma,colorrange = (minimum(vol), maximum(vol)),
figure = (; resolution = (800,800)),
axis=(; type=Axis3, perspectiveness = 0.5, azimuth = 7.19, elevation = 0.57,
aspect = (1,1,1)))
fig
end
3D HeatMap by Makie.jl
I don't know how to plot 3D HeatMap by Plots.jl yet, but I found the another way by Makie.jl : https://lazarusa.github.io/BeautifulMakie/surfWireLines/RGBcube/ .
With the help of this sample code, I got the following code.
using GLMakie, GeometryBasics, Colors
positions = vec([(i, j, k) for i=1:L,j=1:L,k=1:L]) #3D coordinate
F = zeros(Float64,length(positions)
for i = 1:length(positions) #convert f(x,y,z) to an array
x = positions[i][1]
y = positions[i][2]
z = positions[i][3]
F[i] = f(x,y,z)
end
fig, ax = mesh(HyperRectangle(Vec3f0(positions[1]...),Vec3f0(0.8)), color = RGBA(0,0,F[1],0.5), transparency = false) #HyperRectangle(::position,::length),color=(::red,::green,::blue,::alpha)
wireframe!(ax,HyperRectangle(Vec3f0(positions[1]...), Vec3f0(0.8)), linewidth = 0.1, overdraw = false)
for i in 2:length(positions)
mesh!(ax, HyperRectangle(Vec3f0(positions[i]...), Vec3f0(0.8)), color = RGBA(0,0,F[i],0.5))
wireframe!(ax, HyperRectangle(Vec3f0(positions[i]...), Vec3f0(0.8)), linewidth = 0.1, overdraw = false)
end
fig
Related
I'd like to plot a function f(x,y,z) in xyz-space by HeatMap.
I have the following code by https://lazarusa.github.io/BeautifulMakie/surfWireLines/RGBcube/ .
using GLMakie, GeometryBasics, Colors
positions = vec([(i, j, k) for i=1:L,j=1:L,k=1:L]) #3D coordinate
F = zeros(Float64,length(positions)
for i = 1:length(positions) #convert f(x,y,z) to an array
x = positions[i][1]
y = positions[i][2]
z = positions[i][3]
F[i] = f(x,y,z)
end
fig, ax = mesh(HyperRectangle(Vec3f0(positions[1]...),Vec3f0(0.8)), color = RGBA(0,0,F[1],0.5), transparency = false) #HyperRectangle(::position,::length),color=(::red,::green,::blue,::alpha)
wireframe!(ax,HyperRectangle(Vec3f0(positions[1]...), Vec3f0(0.8)), linewidth = 0.1, overdraw = false)
for i in 2:length(positions)
mesh!(ax, HyperRectangle(Vec3f0(positions[i]...), Vec3f0(0.8)), color = RGBA(0,0,F[i],0.5))
wireframe!(ax, HyperRectangle(Vec3f0(positions[i]...), Vec3f0(0.8)), linewidth = 0.1, overdraw = false)
end
fig
This code has mostly helped, but there's still a little problem.:
How to move the camera? (update_camera! needs Scene, but ax is LScene. I don't know what this is.)
How to adjust the axis (labels, ticks, etc.)?
How to add the colorbar?
How to save the figure?
again.
I did another example. This one is really fast. There, you have most of the options you want.
https://lazarusa.github.io/BeautifulMakie/surfWireLines/volumeScatters/
For custom ticks, you can always do
ax.xticks = ([1,2,3], ["1","2", "3"])
also, consider joining https://discourse.julialang.org, there more people could help, much much faster.
Complete code here as well.
# by Lazaro Alonso
using GLMakie
let
x = 1:10
y = 1:10
z = 1:10
f(x,y,z) = x^2 + y^2 + z^2
positions = vec([(i, j, k) for i in x,j in y, k in z])
vals = [f(ix,iy,iz) for ix in x, iy in y, iz in z]
fig, ax, pltobj = meshscatter(positions, color = vec(vals),
marker = FRect3D(Vec3f0(0), Vec3f0(10)), # here, if you use less than 10, you will see smaller squares.
colormap = :Spectral_11, colorrange = (minimum(vals), maximum(vals)),
transparency = true, # set to false, if you don't want the transparency.
shading= false,
figure = (; resolution = (800,800)),
axis=(; type=Axis3, perspectiveness = 0.5, azimuth = 7.19, elevation = 0.57,
xlabel = "x label", ylabel = "y label", zlabel = "z label",
aspect = (1,1,1)))
cbar = Colorbar(fig, pltobj, label = "f values", height = Relative(0.5))
xlims!(ax,-1,11)
ylims!(ax,-1,11)
zlims!(ax,-1,11)
fig[1,2] = cbar
fig
#save("fileName.png", fig) # here, you save your figure.
end
Is it possible to reproduce this graph using the Julia Plots Package?
Plotting using gnuplot
x = y = -15:0.4:15
f1 = (x,y) -> #. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y)
surf(x, y, f1, w = :p, marker = "dot", Axes(hidden3d = :on))
Not exactly the same, but you can plot a surface with surface:
using Plots
x = y = -15:0.4:15
f(x,y) = sin(sqrt(x^2+y^2))/sqrt(x^2+y^2)
surface(x, y, f)
which will give
or a wireframe
wireframe(x, y, f)
will give
But if you really want a 3D scatter, then you need to create the mesh by hand and rearrange the data into vectors I think, like
X = [x for x in x for y in y]
Y = [y for x in x for y in y]
scatter3d(X, Y, f.(X,Y))
I plotted a 3d scatter plot in R using the scatter3d function.
Now, I want to plot the labels on every dot in the 3d scatter, such as every point has its ID next to it i.e., "1", "2" etc..
Here is what I tried:
library("car")
library("rgl")
scatter3d(geometry[,1],geometry[,2],geometry[,3] , surface=FALSE, labels = rownames(geometry), id.n=nrow(geometry))
This tutorial says that adding arguments labels=rownames(geometry), id.n=nrow(geometry) should display the labels on every dot but that did not work.
EDIT:
I uploaded the coordinate file here, you can read it like this
geometry = read.csv("geometry.txt",sep = " ")
colnames(geometry) = c("x","y","z")
EDIT:
Actually, even the example from the tutorial does not label the points and does not produce the plot displayed. There is probably something wrong with the package.
scatter3d(x = sep.l, y = pet.l, z = sep.w,
surface=FALSE, labels = rownames(iris), id.n=nrow(iris))
I can give you a quick fix if you want to use any other function other than scatter3d. This can be achieved using plot3d and text3d function. I have provided the basic code block of how it can be implemented. You can customize it to your needs.
plot3d(geometry[,1],geometry[,2],geometry[,3])
text3d(geometry[,1],geometry[,2],geometry[,3],rownames(geometry))
points3d(geometry[,1],geometry[,2],geometry[,3], size = 5)
After much messing around I got it (I also have the method for plot_ly if you,re interested)
test2 <- cbind(dataSet[,paste(d)],set.final$Groups,test)
X <- test2[,1]
Y <- test2[,2]
Z <- test2[,3]
# 3D plot with the regression plane
scatter3d(x = X, y = Y, z = Z, groups = test2$`set.final$Groups`,
grid = FALSE, fit = "linear",ellipsoid = FALSE, surface=FALSE,
surface.col = c("green", "blue", "red"),
#showLabels(x = x, y = y, z = z, labels=test2$test, method="identify",n = nrow(test2), cex=1, col=carPalette()[1], location=c("lr"))
#labels = test2$test,
id=list(method = "mahal", n = length(test2$test), labels = test2$test)
#id.n=nrow(test2$test)
)
#identify3d(x = X, y = Y, z = Z, labels = test2$test, n = length(test2$test), plot = TRUE, adj = c(-0.1, 0.5), tolerance = 20, buttons = c("right"))
rglwidget()
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.
I want to plot a matrix of z values with x rows and y columns as a surface similar to this graph from MATLAB.
Surface plot:
Code to generate matrix:
# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 0.240)# 2013 length
y<-seq(from = -241.440, to = 241.440, by = 0.240)
matrix_fun<-matrix(data = 0, nrow = length(x), ncol = length(y))
# Generate two dimensional travel distance probability density function
for (i in 1:length(x)) {
for (j in 1:length(y)){
dxy<-sqrt(x[i]^2+y[j]^2)
prob<-1/(scale^(shape)*gamma(shape))*dxy^(shape-1)*exp(-(dxy/scale))
matrix_fun[i,j]<-prob
}}
# Rescale 2-d pdf to sum to 1
a<-sum(matrix_fun)
matrix_scale<-matrix_fun/a
I am able to generate surface plots using a couple methods (persp(), persp3d(), surface3d()) but the colors aren't displaying the z values (the probabilities held within the matrix). The z values only seem to display as heights not as differentiated colors as in the MATLAB figure.
Example of graph code and graphs:
library(rgl)
persp3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
surface3d(x=x, y=y, z=matrix_scale, color=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)))
persp(x=x, y=y, z=matrix_scale, theta=30, phi=30, col=rainbow(25, start=min(matrix_scale), end=max(matrix_scale)), border=NA)
Image of the last graph
Any other tips to recreate the image in R would be most appreciated (i.e. legend bar, axis tick marks, etc.)
So here's a ggplot solution which seems to come a little bit closer to the MATLAB plot
# Parameters
shape<-1.849241
scale<-38.87986
x<-seq(from = -241.440, to = 241.440, by = 2.40)
y<-seq(from = -241.440, to = 241.440, by = 2.40)
df <- expand.grid(x=x,y=y)
df$dxy <- with(df,sqrt(x^2+y^2))
df$prob <- dgamma(df$dxy,shape=shape,scale=scale)
df$prob <- df$prob/sum(df$prob)
library(ggplot2)
library(colorRamps) # for matlab.like(...)
library(scales) # for labels=scientific
ggplot(df, aes(x,y))+
geom_tile(aes(fill=prob))+
scale_fill_gradientn(colours=matlab.like(10), labels=scientific)
BTW: You can generate your data frame of probabilities much more efficiently using the built-in dgamma(...) function, rather than calculating it yourself.
In line with alexis_laz's comment, here is an example using filled.contour. You might want to increase your by to 2.40 since the finer granularity increases the time it takes to generate the plot by a lot but doesn't improve quality.
filled.contour(x = x, y = y, z = matrix_scale, color = terrain.colors)
# terrain.colors is in the base grDevices package
If you want something closer to your color scheme above, you can fiddle with the rainbow function:
filled.contour(x = x, y = y, z = matrix_scale,
color = (function(n, ...) rep(rev(rainbow(n/2, ...)[1:9]), each = 3)))
Finer granularity:
filled.contour(x = x, y = y, z = matrix_scale, nlevels = 150,
color = (function(n, ...)
rev(rep(rainbow(50, start = 0, end = 0.75, ...), each = 3))[5:150]))