Skip to content

Commit

Permalink
Merge pull request #26 from daschw/ds/rewrite
Browse files Browse the repository at this point in the history
rewrite
  • Loading branch information
daschw committed Apr 5, 2020
2 parents 7221e30 + 08eb4c9 commit 58aae33
Show file tree
Hide file tree
Showing 13 changed files with 1,282 additions and 380 deletions.
3 changes: 3 additions & 0 deletions RecipesPipeline/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ authors = ["Michael Krabbe Borregaard <mkborregaard@snm.ku.dk>"]
version = "0.1.0"

[deps]
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"

[compat]
julia = "1"
PlotUtils = "0.6.5"
RecipesBase = "0.8"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Expand Down
97 changes: 93 additions & 4 deletions RecipesPipeline/src/RecipePipeline.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,97 @@
module RecipePipeline

import RecipesBase
include("pipeline.jl")
include("process_recipes.jl")
include("default_recipes.jl")
import RecipesBase: @recipe, @series, RecipeData, is_explicit
import PlotUtils # tryrange and adapted_grid

end # module
export recipe_pipeline!
# Plots relies on these:
export SliceIt,
DefaultsDict,
Formatted,
AbstractSurface,
Surface,
Volume,
is3d,
is_surface,
needs_3d_axes,
group_as_matrix,
reset_kw!,
pop_kw!,
scale_func,
inverse_scale_func,
unzip
# API
export warn_on_recipe_aliases,
splittable_attribute,
split_attribute,
process_userrecipe!,
get_axis_limits,
is_axis_attribute,
type_alias,
plot_setup!,
slice_series_attributes!

include("api.jl")
include("utils.jl")
include("series.jl")
include("group.jl")
include("user_recipe.jl")
include("type_recipe.jl")
include("plot_recipe.jl")
include("series_recipe.jl")


"""
recipe_pipeline!(plt, plotattributes, args)
Recursively apply user recipes, type recipes, plot recipes and series recipes to build a
list of `Dict`s, each corresponding to a series. At the beginning `plotattributes`
contains only the keyword arguments passed in by the user. Add all series to the plot
bject `plt` and return it.
"""
function recipe_pipeline!(plt, plotattributes, args)
plotattributes[:plot_object] = plt

# --------------------------------
# "USER RECIPES"
# --------------------------------

# process user and type recipes
kw_list = _process_userrecipes!(plt, plotattributes, args)

# --------------------------------
# "PLOT RECIPES"
# --------------------------------

# The "Plot recipe" acts like a series type, and is processed before the plot layout
# is created, which allows for setting layouts and other plot-wide attributes.
# We get inputs which have been fully processed by "user recipes" and "type recipes",
# so we can expect standard vectors, surfaces, etc. No defaults have been set yet.

kw_list = _process_plotrecipes!(plt, kw_list)

# --------------------------------
# Plot/Subplot/Layout setup
# --------------------------------

plot_setup!(plt, plotattributes, kw_list)

# At this point, `kw_list` is fully decomposed into individual series... one KW per
# series. The next step is to recursively apply series recipes until the backend
# supports that series type.

# --------------------------------
# "SERIES RECIPES"
# --------------------------------

_process_seriesrecipes!(plt, kw_list)

# --------------------------------
# Return processed plot object
# --------------------------------

return plt
end

end
142 changes: 142 additions & 0 deletions RecipesPipeline/src/api.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
## Warnings

"""
warn_on_recipe_aliases!(plt, plotattributes, recipe_type, args...)
Warn if an alias is dedected in `plotattributes` after a recipe of type `recipe_type` is
applied to 'args'. `recipe_type` is either `:user`, `:type`, `:plot` or `:series`.
"""
function warn_on_recipe_aliases!(plt, plotattributes, recipe_type, args...) end


## Grouping

"""
splittable_attribute(plt, key, val, len)
Returns `true` if the attribute `key` with the value `val` can be split into groups with
group provided as a vector of length `len`, `false` otherwise.
"""
splittable_attribute(plt, key, val, len) = false
splittable_attribute(plt, key, val::AbstractArray, len) =
!(key in (:group, :color_palette)) && length(axes(val, 1)) == len
splittable_attribute(plt, key, val::Tuple, n) = all(splittable_attribute.(key, val, len))


"""
split_attribute(plt, key, val, indices)
Select the proper indices from `val` for attribute `key`.
"""
split_attribute(plt, key, val::AbstractArray, indices) =
val[indices, fill(Colon(), ndims(val) - 1)...]
split_attribute(plt, key, val::Tuple, indices) =
Tuple(split_attribute(key, v, indices) for v in val)


## Preprocessing attributes

"""
preprocess_attributes!(plt, plotattributes)
Any plotting package specific preprocessing of user or recipe input happens here.
For example, Plots replaces aliases and expands magic arguments.
"""
function preprocess_attributes!(plt, plotattributes) end

# TODO: should the Plots version be defined as fallback in RecipePipeline?
"""
is_subplot_attribute(plt, attr)
Returns `true` if `attr` is a subplot attribute, otherwise `false`.
"""
is_subplot_attribute(plt, attr) = false

# TODO: should the Plots version be defined as fallback in RecipePipeline?
"""
is_axis_attribute(plt, attr)
Returns `true` if `attr` is an axis attribute, i.e. it applies to `xattr`, `yattr` and
`zattr`, otherwise `false`.
"""
is_axis_attribute(plt, attr) = false


## User recipes

"""
process_userrecipe!(plt, attributes_list, attributes)
Do plotting package specific post-processing and add series attributes to attributes_list.
For example, Plots increases the number of series in `plt`, sets `:series_plotindex` in
attributes and possible adds new series attributes for errorbars or smooth.
"""
function process_userrecipe!(plt, attributes_list, attributes)
push!(attributes_list, attributes)
end

"""
get_axis_limits(plt, letter)
Get the limits for the axis specified by `letter` (`:x`, `:y` or `:z`) in `plt`. If it
errors, `tryrange` from PlotUtils is used.
"""
get_axis_limits(plt, letter) = ErrorException("Axis limits not defined.")


## Plot recipes

"""
type_alias(plt, st)
Return the seriestype alias for `st`.
"""
type_alias(plt, st) = st


## Plot setup

"""
plot_setup!(plt, plotattributes, kw_list)
Setup plot, subplots and layouts.
For example, Plots creates the backend figure, initializes subplots, expands extrema and
links subplot axes.
"""
function plot_setup!(plt, plotattributes, kw_list) end


## Series recipes

"""
slice_series_attributes!(plt, kw_list, kw)
For attributes given as vector with one element per series, only select the value for
current series.
"""
function slice_series_attributes!(plt, kw_list, kw) end


"""
series_defaults(plt)
Returns a `Dict` storing the defaults for series attributes.
"""
series_defaults(plt) = Dict{Symbol, Any}()

# TODO: Add a more sensible fallback including e.g. path, scatter, ...
"""
is_seriestype_supported(plt, st)
Check if the plotting package natively supports the seriestype `st`.
"""
is_seriestype_supported(plt, st) = false

"""
add_series!(plt, kw)
Adds the series defined by `kw` to the plot object.
For example Plots updates the current subplot arguments, expands extrema and pushes the
the series to the series_list of `plt`.
"""
function add_series!(plt, kw) end

0 comments on commit 58aae33

Please sign in to comment.