Plots.jl中Type Recipe与User Recipe的差异及协同使用疑问
Absolutely! Type Recipes and User Recipes in Plots.jl are designed to complement each other, not conflict—combining them lets you build modular, reusable plotting logic with ease. Let’s break down how they work together with a concrete example.
First, a quick recap to align on definitions:
- Type Recipe: Binds default plotting behavior to a custom type. Whenever you call
plot(my_custom_type_instance), this recipe automatically triggers to handle how the type is visualized. - User Recipe: Creates a custom plotting interface (like a dedicated function) for specialized workflows. Users call this function directly (e.g.,
foo(x)) to generate tailored plots.
Example: Combining Both Recipes
Let’s build a scenario where we have a custom data type, a Type Recipe for its default visualization, and a User Recipe that extends this with additional elements.
Define a Custom Type
struct ExperimentalData measurements::Vector{Float64} timepoints::Vector{Float64} endAdd a Type Recipe
This sets the default behavior when plotting anExperimentalDatainstance—we’ll make it a scatter plot of time vs. measurements:using Plots @recipe function f(data::ExperimentalData) seriestype := :scatter xlabel := "Time (s)" ylabel := "Measurement Value" label := "Raw Data" data.timepoints, data.measurements endNow calling
plot(my_data)will automatically render this scatter plot.Create a User Recipe for Enhanced Visualization
Let’s make atrendplotfunction that plots the raw data (using our Type Recipe) plus a rolling mean trend line:@userplot TrendPlot @recipe function f(tp::TrendPlot) data = tp.args[1] # First, use the Type Recipe to plot raw data @series begin data # Plots.jl automatically uses the ExperimentalData Type Recipe here end # Add a rolling mean trend line rolling_mean = [mean(data.measurements[i-2:i]) for i in 3:length(data.measurements)] @series begin seriestype := :line color := :red label := "Rolling Mean" data.timepoints[3:end], rolling_mean end endUse Them Together
Now we can call our User Recipe, which leverages the Type Recipe under the hood:# Generate sample data test_data = ExperimentalData(randn(20), 1:20) # Plot raw data + trend line in one call trendplot(test_data)
How It Works
The key is the @series macro in the User Recipe: when you pass an instance of your custom type to @series, Plots.jl automatically resolves and uses the corresponding Type Recipe to render that part of the plot. This lets you reuse the default type visualization as a building block for more complex, custom plots.
You can also go the other way—if your Type Recipe needs to include specialized elements defined in a User Recipe, you can call the User Recipe’s function within the Type Recipe using @series as well.
Final Takeaway
Type Recipes handle the "default look" for your custom types, while User Recipes let you build specialized, reusable plotting workflows on top of those defaults. Combining them keeps your code DRY (Don’t Repeat Yourself) and makes your plotting logic both modular and flexible.
内容的提问来源于stack exchange,提问作者Hamlet

