Skip to content

Commit

Permalink
Macro fps support (#4594)
Browse files Browse the repository at this point in the history
* fps support for macros

added support for fps specification for animation macros. Also changed the way parameters are parsed to simplify possible future additions of extra parameters.

* improved Documentation

Extended documentation for animation macros, to include the new fps parameter as well as filter mechanics

* Cleaned up and Formatted Code

* tests for macro parameters

added Tests for testing extra macro parameters for that juicy code coverage

* remove conditional

* adjust tests

---------

Co-authored-by: Simon Christ <SimonChrist@gmx.de>
  • Loading branch information
arikheinss and BeastyBlacksmith authored Feb 2, 2023
1 parent d2aa3ec commit 985808d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 21 deletions.
62 changes: 41 additions & 21 deletions src/animation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,26 +199,32 @@ function _animate(forloop::Expr, args...; type::Symbol = :none)
freqassert = :()
block = forloop.args[2]

# create filter
n = length(args)
filterexpr = if n == 0
# no filter... every iteration gets a frame
true

elseif args[1] === :every
# filter every `freq` frames (starting with the first frame)
@assert n == 2
freq = args[2]
freqassert = :(@assert isa($freq, Integer) && $freq > 0)
:(mod1($countersym, $freq) == 1)

elseif args[1] === :when
# filter on custom expression
@assert n == 2
args[2]
animationsKwargs = Any[]
filterexpr = true

else
error("Unsupported animate filter: $args")
n = length(args)
i = 1
# create filter and read parameters
while i <= n
arg = args[i]
if arg in (:when, :every)
# specification of frame filter
@assert i < n
filterexpr == true ||
error("Can only specify one filterexpression (one of 'when' or 'every')")

filterexpr = # when every
arg == :when ? args[i + 1] : :(mod1($countersym, $(args[i + 1])) == 1)

i += 1
elseif arg isa Expr && arg.head == Symbol("=")
#specification of type <kwarg> = <spec>
lhs, rhs = arg.args
push!(animationsKwargs, :($lhs = $rhs))
else
error("Parameter specification not understood: $(arg)")
end
i += 1
end

push!(block.args, :(
Expand All @@ -230,9 +236,9 @@ function _animate(forloop::Expr, args...; type::Symbol = :none)

# add a final call to `gif(anim)`?
retval = if type === :gif
:(Plots.gif($animsym))
:(Plots.gif($animsym; $(animationsKwargs...)))
elseif type === :apng
:(Plots.apng($animsym))
:(Plots.apng($animsym; $(animationsKwargs...)))
else
animsym
end
Expand All @@ -259,6 +265,11 @@ Example:
push!(p, 1, sin(x))
end
```
This macro supports additional parameters, that may be added after the main loop body.
- Add `fps=n` with positive Integer n, to specify the desired frames per second.
- Add `every n` with positive Integer n, to take only one frame every nth iteration.
- Add `when <cond>` where `<cond>` is an Expression resulting in a Boolean, to take a
frame only when `<cond>` returns `true`. Is incompatible with `every`.
"""
macro gif(forloop::Expr, args...)
_animate(forloop, args...; type = :gif)
Expand All @@ -275,6 +286,11 @@ Example:
push!(p, 1, sin(x))
end
```
This macro supports additional parameters, that may be added after the main loop body.
- Add `fps=n` with positive Integer n, to specify the desired frames per second.
- Add `every n` with positive Integer n, to take only one frame every nth iteration.
- Add `when <cond>` where `<cond>` is an Expression resulting in a Boolean, to take a
frame only when `<cond>` returns `true`. Is incompatible with `every`.
"""
macro apng(forloop::Expr, args...)
_animate(forloop, args...; type = :apng)
Expand All @@ -292,6 +308,10 @@ anim = @animate for x=0:0.1:5
end
gif(anim)
```
This macro supports additional parameters, that may be added after the main loop body.
- Add `every n` with positive Integer n, to take only one frame every nth iteration.
- Add `when <cond>` where `<cond>` is an Expression resulting in a Boolean, to take a
frame only when `<cond>` returns `true`. Is incompatible with `every`.
"""
macro animate(forloop::Expr, args...)
_animate(forloop, args...)
Expand Down
22 changes: 22 additions & 0 deletions test/test_animations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ end
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end when i % 5 == 0

@gif for i in 1:n
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end when i % 5 == 0 fps = 10

@test_throws LoadError macroexpand(
@__MODULE__,
quote
@gif for i in 1:n
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end when i % 5 == 0 every 10 # cannot use every and when together
end,
)

@test_nowarn macroexpand(
@__MODULE__,
quote
@gif for i in 1:n
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end asdf = bla #asdf is allowed
end,
)

anim = Plots.@apng for i in 1:n
circleplot(x, y, i, line_z = 1:n, cbar = false, framestyle = :zerolines)
end every 5
Expand Down

0 comments on commit 985808d

Please sign in to comment.