Use Plots() library to graph a colored surface

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: Beautiful Makie

For instance: BlueMarbel

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()


using Plots, StaticArrays, Parameters

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))'

"""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...)

Colored torus:


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

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))



@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)
gif(anim, "torus.gif")


Colored sphere:


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

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))



@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)
gif(anim, "sphere.gif")


Interactive plotting with plotly()

The plotly() backend can be used to display interactive plots in Jupyter notebook.

1 Like
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
  [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("PyCall"; mode = PKGMODE_MANIFEST)

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


But your Plots.jl directory is


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.

1 Like

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.

2021-08-19 (3)

The URL that should be pasted is