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 uV
s
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 Recipes · Plots 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 uV
as 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 scatter
ing 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
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 uV
s 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