# RecipesBase: How to define the same recipe for different packages?

**URL:** <https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283>\
**Category:** Visualization\
**Tags:** plots, recipe\
**Created:** [November 10, 2021, 7:42pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283 "2021-11-10T19:42:47Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 10, 2021, 7:42pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/1 "2021-11-10T19:42:47Z")

</div>

I have packages `A`, `B`, `C`, where both `B` and `C` depend on `A`. In order to make some function `f` available to both `B` and `C` at the same time, I first define it in `A` and then overload it in `B` and `C` with some local methods, e.g.

```julia
module A
  function f end
  export f
end

module B
  using A
  ...
  A.f(x::SomeTypeInB) = ...
end

module C
  using A
  ...
  A.f(x::SomeTypeInC) = ...
end

```

So that I can then write `using A, B, C` and use `f`, dispatching without issues.

Can I use a similar approach to define recipe functions (using RecipesBase) common to both `B` and `C`? I’ve tried without success.

> **Additional info**
>
> For reference, atm I define recipes via
> 
> ```julia
> @userplot COOLPLOT
> @recipe function f(h::COOLPLOT)
> if h.args[1] isa SomeTypeInPackage
> ...
> else
> error("Got $(typeof(h.args[1])) instead of SomeTypeInPackage.")
> end
> end
> 
> ```
> 
> which exports `coolplot` and `coolplot!` automatically.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [November 11, 2021, 9:00am UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/2 "2021-11-11T09:00:16Z")

</div>

You can just define a `user recipe`[Recipes · Plots](https://docs.juliaplots.org/latest/recipes/#User-Recipes) on the Union of your types (or their abstract supertype if they have one).

---

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 11, 2021, 9:13am UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/3 "2021-11-11T09:13:18Z")

</div>

Although I want these recipes to share the same name, the actual codes for plotting `SomeTypeInB` and `SomeTypeInC` are quite different. I need to be able to differentiate between these types inside `B` and `C` respectively.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [November 11, 2021, 10:11am UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/4 "2021-11-11T10:11:50Z")

</div>

Do they need to have a particular name? Maybe can you be a litte more concrete about how the plots should look and what the types are?

---

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 11, 2021, 11:52am UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/5 "2021-11-11T11:52:13Z")

</div>

I’d like to define a common recipe `convergence` (and `convergence!`) that shows the standard converge plot (error vs iteration) of a fixed-point problem using some custom algorithms defined in `B` and `C`.

In other words, I have `SolutionUsingAlgorithmB` and `SolutionUsingAlgorithmC` (which in practice are two different `struct`s of common supertype `<: AbstractSolution`, where `AbstractSolution` is defined in `A`), defined in each respective package.

I would like to define `convergence(solution::SolutionUsingAlgorithmB)` and `convergence(solution::SolutionUsingAlgorithmC)` using `RecipesBase` alone. In practice, each method of `convergence` must be different (because `SolutionUsingAlgorithmB` and `SolutionUsingAlgorithmC` are very different), so I cannot simply make use of `convergence(solution::AbstractSolution)`.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [November 11, 2021, 12:57pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/6 "2021-11-11T12:57:53Z")

</div>

Ah, I see. I think. It’s a little tricky because Plots already uses dispatch to have the recipe names work.  
The easiest is probably to have a function inside the recipe that generates the data to be plotted from your solution, and have that function dispatch on the type of solution. So that the recipe itself only sets up what is visible to the user plotting (which should be the same).

---

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 11, 2021, 3:13pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/7 "2021-11-11T15:13:58Z")

</div>

Yes, that would do it! However, using this approach, how do I go about passing different Plots’ stylistic arguments, e.g. `markersize --> 4`, from such a function that lives inside the recipe to the recipe itself?

EDIT: Looking at this beautiful [daschw’s post](https://daschw.github.io/recipes/#preprocess_plotattributes), I realised that it is simply a matter of `push`ing to `plotattributes` as follows:

```julia
module A
  ...
  function _convergence end
  @userplot CONVERGENCE
  @recipe f(h::CONVERGENCE) = _convergence(h.args[1], plotattributes)
end

module B
  using A
  ...
  function A._convergence(solution::SolutionUsingAlgorithmB, plotattributes)
    push!(plotattributes, :framestyle => :box, :gridalpha => 0.2, ...)
    ...
    return solution.plottablefield
  end

```

and similarly for `C`.

---

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 11, 2021, 6:23pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/8 "2021-11-11T18:23:22Z")

</div>

For future reference, based on @mkborregaard’s comment, I found a better solution that involves wrapping `SolutionUsingAlgorithmB` and `SolutionUsingAlgorithmC` inside a constructor `_Convergence` defined in `A`:

```julia
module A
  ...
  struct _Convergence{solution_T}
    solution::solution_T
  end
  @userplot CONVERGENCE
  @recipe function f(h::CONVERGENCE)
    return _Convergence(h.args[1])
  end
end

module B
  using A
  ...
  @recipe function f(wrappedobject::NSDEBase._Convergence{<:SolutionUsingAlgorithmB})
    solution = wrappedobject.solution
    ...
  end
end

```

and similarly for `C`. This solution has the non-trivial advantage of allowing for the usage of the usual `RecipesBase` tricks (for loops of `@series`, etc) inside the relevant recipes defined in `B` and `C`, which otherwise couldn’t be used (that easily) with the previous approach based on `_convergence`.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [November 12, 2021, 1:50pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/9 "2021-11-12T13:50:25Z")

</div>

My idea was just something along the lines of

```julia
using RecipesBase

create_xy(x::A_type) = ...; x, y
create_xy(x::B_type) = ...; x, y

@userplot CoolPlot

@recipe function f(h::CoolPlot)
    markersize --> 4
    seriestype := :scatter
    create_xy(h.args[1])
end

```

---

<div class="post-metadata">

**Author:** ![giancarloantonucci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giancarloantonucci/32/202551_2.png) [@giancarloantonucci](https://discourse.julialang.org/u/giancarloantonucci)\
**Post date:** [November 12, 2021, 2:10pm UTC](https://discourse.julialang.org/t/recipesbase-how-to-define-the-same-recipe-for-different-packages/71283/10 "2021-11-12T14:10:57Z")

</div>

And that’s fine, but:

1. Oftentimes, you want to use different styling options depending on `A_type` and `B_type` (which, admittedly you could do with your “function” approach by passing around `plotattributes`).
2. Doing nested for loops with `@series` is possible if `create_xy` are recipes themselves.
