Vector type-recipe plotting in Julia

I saw this question on stackoverflow. And I also have the same question: Could we define plot for one data point and it automatically works for an Array of it?

IIs there a way to write a plotting type recipe for a type T and then have Julia somehow infer a corresponding recipe for the type Vector{T}?

Simple example, suppose I have a box struct B, and I write a simple type-recipe for plotting it:

using Plots

struct B
    x0
    x1
    y0
    y1
end
bshape(b::B) = Shape([b.x0,b.x1,b.x1,b.x0],[b.y0,b.y0,b.y1,b.y1])
@recipe f(::Type{B}, b::B) = bshape(b)

So now plot(B(0,1,2,3)) plots a filled rectangle like I wanted. Now say I have an array of Bs, and I want to plot all the rectangles in a single plot by calling plot(bs). Simply defining the type recipe for B doesn’t accomplish this. I can write another type recipe for vectors of B like this:

@recipe f(::Type{Vector{B}}, bs::Vector{B}) = bshape.(bs)

But, first of all, I don’t really love this, it’s got some repeated code. I’d rather be able to tell Julia to just use the original type recipe. Also, e.g., if I want to let each box be able to determine other things about how it gets plotted, say:

@recipe function f(::Type{B}, b::B)
    fillcolor --> (b.x0==0 ? :red : :blue)
    bshape(b)
end

At this point the vector version, as written above, won’t do what I want. I can probably modify it somehow, but it seems like there should be a “correct” way to do this.

I suspect that it might be simpler to write a method for each case, scalar and vector, as recipes are not functions we can broadcast.

For the last recipe, in the vector case one could write something like:

@recipe function f(::Type{Vector{B}}, b::Vector{B})
    fillcolor --> permutedims([(a.x0==0 ? :red : :blue) for a in b])
    bshape.(b)
end
1 Like