I want to make a surface in 3D and color the surface using a fourth coordinate. I want to do this task using Plots and Plotly to rotate the graph at all angles. Here I put examples of the surfaces I want:
I want to make a surface in 3D and color the surface using a fourth coordinate. I want to do this task using Plots and Plotly to rotate the graph at all angles. Here I put examples of the surfaces I want:
Just to double check, you don’t accept a solution with Makie.jl? BeautifulMakie has various examples: https://lazarusa.github.io/BeautifulMakie/
For instance: https://lazarusa.github.io/BeautifulMakie/GeoPlots/
I didn’t know the library before, I’ll give it a try. But I want to dominate the library Plots first.
with PlotlyJS.jl you can color a surface according to the values of a scalar field defined on that surface:
using PlotlyJS
n= 256
θ = LinRange(0, 2π, n) #\theta
ϕ = LinRange(-π/2, π/2, n)
Θ = [t for t in θ, p in ϕ] #\Theta
Φ = [p for t in θ, p in ϕ]
x= cos.(Θ) .* cos.(Φ)
y= sin.(Θ) .* cos.(Φ)
z= sin.(Φ)
J = [j for i in 0:n-1, j in 0:n-1]
ScalarF = xor.(J', J)
pl= Plot(surface(x=x, y=y, z=z, colorbar_len=0.7, surfacecolor=ScalarF),
Layout(width=500, height=500))
The code function directly in Julia. But in jupyter notebook the library PlotlyJS I got the error:
“Unable to load WebIO. Please make sure WebIO works for your Jupyter client. For troubleshooting, please see the WebIO/IJulia documentation.”
In order to plot a colored surface with Plots.jl pyplot(), give a fourth coordinate meshgrid array h
to the keyword argument fill_z
:
surface(x, y, z; fill_z = h)
Working example with Plots.jl pyplot()
Preparation:
using Plots, StaticArrays, Parameters
default(colorbar=false)
rotate(u, v, w) = let c = cosd, s = sind
SMatrix{3, 3}(
c(u)*c(v), c(u)*s(v)*s(w)-s(u)*c(w), c(u)*s(v)*c(w)+s(u)*s(w),
s(u)*c(v), s(u)*s(v)*s(w)+c(u)*c(w), c(u)*s(v)*s(w)-c(u)*s(w),
-s(v), c(v)*s(w), c(v)*c(w))'
end
"""Assume `surffunc(u, v)` returns `(x, y, z, h)`."""
function plot_surface(u, v, surffunc, param; R = rotate(0, 0, 0), kwargs...)
xyzh = surffunc.(u', v, Ref(param))
xyz = (((x, y, z, h),) -> R * SVector(x, y, z)).(xyzh)
x, y, z = ((a -> a[i]).(xyz) for i in 1:3)
fill_z = (((x, y, z, h),) -> h).(xyzh)
surface(x, y, z; fill_z, kwargs...)
end
Colored torus:
pyplot(fmt=:png)
function torusfunc(u, v, param)
@unpack a, b, d = param
x = (b + a * cos(u)) * cos(v)
y = (b + a * cos(u)) * sin(v)
z = a * sin(u)
h = d' * SVector(x, y, z)
x, y, z, h
end
torusparam = (a = 5, b = 10, d = SVector(1, 0, 1))
n = 50
u_torus = v_torus = range(0, 2π; length = n + 1)
plot_surface(u_torus, v_torus, torusfunc, torusparam; size=(500, 400),
lims=(-20, 20), color=:CMRmap, R=rotate(30, 30, 30))
Animation:
pyplot(fmt=:png)
@time anim = @animate for t in range(0, 360; length=41)[1:end-1]
plot_surface(u_torus, v_torus, torusfunc, torusparam; size=(400, 300),
lims=(-20, 20), color=:CMRmap, R=rotate(30, 30, 30),
camera=(t, 20), ticks=false)
end
PyPlot.clf()
gif(anim, "torus.gif")
Colored sphere:
pyplot(fmt=:png)
function spherefunc(u, v, param)
@unpack r, d, f = param
x = r * cos(u) * cos(v)
y = r * cos(u) * sin(v)
z = r * sin(u)
h = f(d' * SVector(x, y, z))
x, y, z, h
end
sphereparam = (
r = 20,
d = SVector(0, 0, 1),
f = h -> (1 + abs(h - 1)) * sin(h)
)
n = 50
u_sphere = range(-π/2, π/2; length = n + 1)
v_sphere = range(0, 2π; length = 2n + 1)
plot_surface(u_sphere, v_sphere, spherefunc, sphereparam; size=(500, 400),
lims=(-20, 20), color=:gist_earth, R=rotate(30, 30, 30),
camera=(30, 20))
Animation:
pyplot(fmt=:png)
@time anim = @animate for t in range(0, 360; length=41)[1:end-1]
plot_surface(u_sphere, v_sphere, spherefunc, sphereparam; size=(400, 300),
lims=(-20, 20), color=:gist_earth, R=rotate(30, 30, 30),
camera=(t, 20), ticks=false)
end
PyPlot.clf()
gif(anim, "sphere.gif")
Interactive plotting with plotly()
The plotly() backend can be used to display interactive plots in Jupyter notebook.
julia> plot_surface(u_torus, v_torus, torusfunc, torusparam; size=(500, 400),
lims=(-20, 20), color=:CMRmap, R=rotate(30, 30, 30))
sys:1: MatplotlibDeprecationWarning: Passing the fontdict parameter of _set_ticklabels() positionally is deprecated since Matplotlib 3.3; the parameter will become keyword-only two minor releases later.
sys:1: UserWarning: FixedFormatter should only be used together with FixedLocator
Error showing value of type Plots.Plot{Plots.PyPlotBackend}:
ERROR: MethodError: no method matching getproperty(::Char, ::String)
Closest candidates are:
getproperty(::PyPlot.ColorMap, ::AbstractString) at C:\Users\Hermesr\.julia\packages\PyPlot\XHEG0\src\colormaps.jl:26
getproperty(::PyPlot.LazyPyModule, ::AbstractString) at C:\Users\Hermesr\.julia\packages\PyPlot\XHEG0\src\plot3d.jl:16
getproperty(::PyCall.PyObject, ::AbstractString) at C:\Users\Hermesr\.julia\packages\PyCall\BD546\src\PyCall.jl:311
...
Stacktrace:
[1] py_set_axis_colors(sp::Plots.Subplot{Plots.PyPlotBackend}, ax::PyCall.PyObject, a::Plots.Axis)
@ Plots C:\Users\Hermesr\.julia\packages\Plots\hyS17\src\backends\pyplot.jl:815
[2] _before_layout_calcs(plt::Plots.Plot{Plots.PyPlotBackend})
@ Plots C:\Users\Hermesr\.julia\packages\Plots\hyS17\src\backends\pyplot.jl:1100
[3] prepare_output(plt::Plots.Plot{Plots.PyPlotBackend})
@ Plots C:\Users\Hermesr\.julia\packages\Plots\hyS17\src\plot.jl:177
[4] display(d::VSCodeServer.InlineDisplay, m::MIME{Symbol("image/svg+xml")}, x::Plots.Plot{Plots.PyPlotBackend})
@ VSCodeServer c:\Users\Hermesr\.vscode\extensions\julialang.language-julia-1.3.30\scripts\packages\VSCodeServer\src\display.jl:0
[5] display(d::VSCodeServer.InlineDisplay, mime::String, x::Any)
@ Base.Multimedia .\multimedia.jl:216
[6] display(d::VSCodeServer.InlineDisplay, x::Plots.Plot{Plots.PyPlotBackend})
@ VSCodeServer c:\Users\Hermesr\.vscode\extensions\julialang.language-julia-1.3.30\scripts\packages\VSCodeServer\src\display.jl:109
[7] display(x::Any)
@ Base.Multimedia .\multimedia.jl:328
[8] #invokelatest#2
@ .\essentials.jl:708 [inlined]
[9] invokelatest
@ .\essentials.jl:706 [inlined]
[10] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:247
[11] (::REPL.var"#40#41"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:231
[12] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:462
[13] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:229
[14] (::REPL.var"#do_respond#61"{Bool, Bool, REPL.var"#72#82"{REPL.LineEditREPL, REPL.REPLHistoryProvider}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:798
[15] #invokelatest#2
@ .\essentials.jl:708 [inlined]
[16] invokelatest
@ .\essentials.jl:706 [inlined]
[17] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
@ REPL.LineEdit C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\LineEdit.jl:2441
[18] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
@ REPL C:\buildbot\worker\package_win64\build\usr\share\julia\stdlib\v1.6\REPL\src\REPL.jl:1126
[19] (::REPL.var"#44#49"{REPL.LineEditREPL, REPL.REPLBackendRef})()
@ REPL .\task.jl:411
My environment is Windows 10 with
using Pkg
println("Julia v", VERSION)
Pkg.status("IJulia")
Pkg.status("PyCall"; mode = PKGMODE_MANIFEST)
Pkg.status("Plots")
Pkg.status("PyPlot")
Pkg.status("Plotly")
Pkg.status("StaticArrays")
Pkg.status("Parameters")
↓
Julia v1.6.2
Status `D:\.julia\environments\v1.6\Project.toml`
[7073ff75] IJulia v1.23.2
Status `D:\.julia\environments\v1.6\Manifest.toml`
[438e738f] PyCall v1.92.3
Status `D:\.julia\environments\v1.6\Project.toml`
[91a5bcdd] Plots v1.20.1
Status `D:\.julia\environments\v1.6\Project.toml`
[d330b81b] PyPlot v2.9.0
Status `D:\.julia\environments\v1.6\Project.toml`
[58dd65bb] Plotly v0.4.0
Status `D:\.julia\environments\v1.6\Project.toml`
[90137ffa] StaticArrays v1.2.12
Status `D:\.julia\environments\v1.6\Project.toml`
[d96e819e] Parameters v0.12.2
I use Plots.jl v1.20.1 installed in the directory
D:\.julia\packages\Plots\HcxwM
But your Plots.jl directory is
C:\Users\Hermesr\.julia\packages\Plots\hyS17
Your hyS17 is not equal to my HcxwM.
Probably you are using an older version of Plots.jl due to conflicts with other packages.
First, upgrade installed packages by
pkg> up
and check if Plots.jl is upgraded to version ≥ v1.20.1 or not.
If not, restart Julia in an empty directory and run
pkg> activate .
pkg> add Plots
pkg> status
Confirm the version of Plots.jl is ≥ v1.20.1. Then try to run my code.
I have created the Pluto notebook version of the sample Jupyter notebook above.
If you have trouble resolving package dependency issues, you may try the Pluto notebook version. Pluto has a feature automatically resolving package dependencies.
Please copy-and-paste the GitHub URL of Pluto notebook into the browser tab opened by Pluto.
The URL that should be pasted is
https://github.com/genkuroki/public/blob/main/0016/Pluto%20-%203d%20colored%20surface%20plots.jl