Conceptual problem with user recipes: draw a sphere before drawing the data

I am trying to do a user recipe from RecipesBase.jl but I seem to not get the idea how Recipes work I fear.

Context.
I would like to do something that I thought was quite easy. Given the M=Sphere(2) from Manifolds.jl and a set of points (maybe just pts=[ [ 1.0, 0.0, 0.0], [0.0, 1.0, 0.0] ] I would like to be able to write

scene = plot(M,pts)
to draw a sphere and two markers where these points are,
Best would be that for the scene I could also add things using plot!(scene, M, pts2) for a second set of points.

Here’s my current approach – and I can’t find what I am doing wrong, I fear I have a conceptual problem with recipes still.

Here’s my current (nonworking) MWE

using Manifolds, Plots, RecipesBase

@recipe function f(
    M::Sphere{2},
    pts::AbstractVector{T};
    wireframe_lat=33,
    wireframe_lon=33,
) where {T}
    show_axis --> false
    φ_range = range(0,stop=2*π,length=wireframe_lon)
    λ_range = range(0,stop=π,length=wireframe_lat)
    x = [cos(φ) * sin(λ) for φ ∈ φ_range, λ ∈ λ_range] 
    y = [sin(φ) * sin(λ) for φ ∈ φ_range, λ ∈ λ_range] 
    z = [cos(λ) for φ ∈ φ_range, λ ∈ λ_range] 
    scene = plot() # I assume this should be the global plot? Wherefrom?
    wireframe!(scene, x, y, z)
    seriestype --> :scatter
    return [p[1] for p ∈ pts], [p[2] for p ∈ pts], [p[3] for p ∈ pts]
end

M = Sphere(2)
pts = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0] ]
plot(M, pts)

and I also was not able to find something similar on the net.

How do I add something to a plot, when usually the recipe only returns x, y, z and I can’t seem to access the plot to add the sphere? It just plots the two points.

After a very quick glance at your code, I think you have a problem in the line with the following:

y = [sin(lon) * sin(lat) for φ ∈ φ_range, λ ∈ λ_range] 

lon and lat are not defined.

1 Like

Thanks for noticing, sorry, I copied an old version – name them φ and λ and it works, the plot actually has both points in, just no sphere

I also edited the original post.

I found one trick that seems to be a step forward – @series from

but I can’t do a surface with that as I would do with surface(x,y,z) below

using Manifolds, Plots, RecipesBase

@recipe function f(
    M::Sphere{2},
    pts::AbstractVector{T};
    wireframe_lat=33,
    wireframe_lon=33,
) where {T}
    show_axis --> false
    φ_range = range(0,stop=2*π,length=wireframe_lon)
    λ_range = range(0,stop=π,length=wireframe_lat)
    x = [cos(φ) * sin(λ) for φ ∈ φ_range, λ ∈ λ_range]
    y = [sin(φ) * sin(λ) for φ ∈ φ_range, λ ∈ λ_range]
    z = [cos(λ) for φ ∈ φ_range, λ ∈ λ_range]
    @series begin
        # seriestype := :surface # this line does not work if you provide a surfce as set of points?
        x,y,z #plots a line per z value not a surface
    end
    seriestype --> :scatter
    return [p[1] for p ∈ pts], [p[2] for p ∈ pts], [p[3] for p ∈ pts]
end

M = Sphere(2)
pts = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0] ]
plot(M, pts)

what I would like the @series is something either similar to wireframe or surface (in the end I want to be able to activate one, the other or both).

Edit: Ah, I see, so what I would like to obtain is what Make(!) does when you call `surface(x,y,z). on those data generated above, I.e. a nice surface of the sphere. How can I do that in Plots? And don’t recipes also work for Make? But they are still so different?

So my main problem seems to be that the series can not be convinced to do a 3D sphere (half transparent as a surface or as a mesh, either would be fine – later I want to be able to activate one of those or both). The result could vor example be similar to the plots I do with exports and rendering (Asymptote) here.

So how can I get a surface sphere in a series here ? Neither :surface nor :wireframe as series typedo work.

I found the culprit: Ith works with plotly() as backend but not with gr().

edit: I opened an Issue here at Plots.jl.

1 Like