Recipe to plot unit points

I am bring to define a Recipe for my own data type, but following any thread here (for example Understanding recipes in Plots.jl ) I always end up with No user recipe defined for MyType errors and I would like to understand, where my mistake is. I try to simplify my problem with a (n)MWE.

Let’s assume I have a data type to store unit norm vectors and would like to have a plot for the following pts vector of uVs

using RecipesBase, Plots

struct uV
    value::Vector
end
pts = uV.([ [1., 0., 0.], [0., 1., 0.], [0., 0., -1.], 1/sqrt(3)*[1., 1., 1.] ])


@recipe f(::Type{uV}, x::uV) = x.value
plot(pts)

which should resemble a type recipe from https://docs.juliaplots.org/latest/recipes/ that what I think I should be aiming for? But nearly independent of what I tried I get the No user recipe, so maybe I don’t need a type recipe? That’s where I am confused.

What should the plot do?
First, just plot the points von uVas dots in R3 (if somebody could snuck a half transparent sphere in between, that would be really lovely). Later I would like to extend this to maybe even draw lines (or curves) between the points if they are given as an NTuple (instead of an array).

Your pts is like a Vector{Vector} which can not be plotted, try plotting pts[1] and it should work

2 Likes

Interesting. Yes that plots, but not what I want.

Maybe I am more into scattering my vector? As I described, I would like to draw a dot (or connect them with a line) for every entry of pts. That’s why I thought of a plot, basically it should

combine als first entries in x, all seconds in y all thirds in z and plot that (then getting points could be done using a marker?).

I am sorry if that’s confusing, but I really seem to miss the magic in the recipes for now.

Like so?

@recipe function f(x::AbstractVector{<:uV}) reduce(hcat, x.value for x in x)' end
plot(pts)
1 Like

That’s a good starting point!

And then even scatter(pts) works. The 'and reduce have to read carefully again, but I now see where my error was: I though with DataType the documentation referred to single data items, but actually a @reciepe transforms the input (so here the vector of data points) into something it can continue with.

Now I just have to find out why my plots then end up being 2D instead of 3D; but you already helped me a lot :slight_smile:

1 Like

With that mixup gone, I managed to do the following

@recipe f(x::AbstractVector{<:uV}) = Tuple( reduce(hcat, x.value for x in x)[i,:] for i=1:3 )

scatter3d(pts)

then beautifully scatters the uVs in the array pts. Might not be the most beautiful solution for the recipe, but one that works as intended.

Try this then, maybe a more efficient solution

Base.getindex(x::uV,i) = x.value[i]
Base.length(x::uV) = length(x.value)
@recipe f(x::AbstractVector{<:uV}) = ntuple(i->getindex.(x, i), length(x[1]))
scatter3d(pts)
1 Like

That’s a beautiful solution. Thanks.

1 Like