Trouble understanding how plot recipes dispatches customized types containing other customized types

Can someone explain why the following doesn’t work?

julia> using RecipesBase

julia> struct Pair

julia> struct Pairs

julia> @recipe function plot(pair::Pair)
           pair.x, pair.y

julia> @recipe plot(pairs::Pairs) = pairs.pairs

julia> N = 10

julia> pvec = [Pair(rand(N), rand(N)) for m = 1:15];

julia> pairs = Pairs(pvec);

julia> using Plots

julia> plot(pairs.pairs[1])

Screenshot (1)

julia> plot(pairs)
ERROR: Cannot convert Pair to series data for plotting

Two things: Pair is defined in Base, (:a => 2 is a Pair{Symbol, Int64}). And Type recipes need a type argument as well:

@recipe f(::Type{MyPair}, x::MyPair) = x.x, x.y

Ah, didn’t know that when I built this MWE. Thanks.

Oh that’s right, I did see that they’re kind of inputted twice in the recipe signature, but I’m still confused as to why. I’ve been reading the Recipes documentation over and over, and a lot of it keeps going over my head.


I’m not so sure I did it right.

Yeah, it’s not entirely intuitive. If your recipe signature is (::Type{MyType}, ::MyType) then it’s a type recipe, and will mesh in with everything. Essentially “Hey Plots, if you see a MyType anywhere, do this”. If the signature is (::MyType) that’s a user recipe, and will only work for plot calls with that exact signature. I’m not 100% sure, but I don’t think that recipes in turn invoke user recipes, for instance.

I’m not entirely sure what’s going wrong here, but notice the x axis in your graph. Turns out we’re plotting the x vector against its indices.

I haven’t worked with a Vector{Vector} type before, maybe you actually have to resort to user recipes to get this working. One thing that works is turning it into a Vector{Tuple{Float64, Float64}}: @recipe f(::Type{MyPair}, mp::MyPair) = collect(zip(mp.x, m.y)).

1 Like