Merge pull request #597 from tbreloff/dev

Output/Animation improvements
This commit is contained in:
Tom Breloff 2016-12-01 15:26:21 -05:00 committed by GitHub
commit d8ffd729f4
4 changed files with 72 additions and 43 deletions

View File

@ -57,6 +57,7 @@ export
savefig, savefig,
png, png,
gui, gui,
inline,
closeall, closeall,
backend, backend,

View File

@ -1,19 +1,19 @@
immutable Animation immutable Animation
dir::String dir::String
frames::Vector{String} frames::Vector{String}
end end
function Animation() function Animation()
tmpdir = convert(String, mktempdir()) tmpdir = convert(String, mktempdir())
Animation(tmpdir, String[]) Animation(tmpdir, String[])
end end
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current()) function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
i = length(anim.frames) + 1 i = length(anim.frames) + 1
filename = @sprintf("%06d.png", i) filename = @sprintf("%06d.png", i)
png(plt, joinpath(anim.dir, filename)) png(plt, joinpath(anim.dir, filename))
push!(anim.frames, filename) push!(anim.frames, filename)
end end
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif") giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
@ -50,45 +50,60 @@ end
"Wraps the location of an animated gif so that it can be displayed" "Wraps the location of an animated gif so that it can be displayed"
immutable AnimatedGif immutable AnimatedGif
filename::String filename::String
end end
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...) gif(anim::Animation, fn = giffn(); kw...) = buildanimation(anim.dir, fn; kw...)
mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...) mov(anim::Animation, fn = movfn(); kw...) = buildanimation(anim.dir, fn; kw...)
mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...) mp4(anim::Animation, fn = mp4fn(); kw...) = buildanimation(anim.dir, fn; kw...)
const _imagemagick_initialized = Ref(false)
function buildanimation(animdir::AbstractString, fn::AbstractString; function buildanimation(animdir::AbstractString, fn::AbstractString;
fps::Integer = 20, loop::Integer = 0) fps::Integer = 20, loop::Integer = 0)
fn = abspath(fn) fn = abspath(fn)
try try
# high quality if !_imagemagick_initialized[]
speed = round(Int, 100 / fps) file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl") if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH") include(file)
include(file) end
_imagemagick_initialized[] = true
end
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
# high quality
speed = round(Int, 100 / fps)
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
catch err
warn("""Tried to create gif using convert (ImageMagick), but got error: $err
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
end end
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
run(`convert -delay $speed -loop $loop $(joinpath(animdir, "*.png")) -alpha off $fn`)
catch err info("Saved animation to ", fn)
warn("""Tried to create gif using convert (ImageMagick), but got error: $err AnimatedGif(fn)
ImageMagick can be installed by executing `Pkg.add("ImageMagick")`
Will try ffmpeg, but it's lower quality...)""")
# low quality
run(`ffmpeg -v 0 -framerate $fps -loop $loop -i $(animdir)/%06d.png -y $fn`)
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
end
info("Saved animation to ", fn)
AnimatedGif(fn)
end end
# write out html to view the gif... note the rand call which is a hack so the image doesn't get cached # write out html to view the gif... note the rand call which is a hack so the image doesn't get cached
function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif) function Base.show(io::IO, ::MIME"text/html", agif::AnimatedGif)
write(io, "<img src=\"$(relpath(agif.filename))?$(rand())>\" />") ext = file_extension(agif.filename)
write(io, if ext == "gif"
"<img src=\"$(relpath(agif.filename))?$(rand())>\" />"
elseif ext in ("mov", "mp4")
"<video controls><source src=\"$(relpath(agif.filename))?$(rand())>\" type=\"video/$ext\"></video>"
else
error("Cannot show animation with extension $ext: $agif")
end)
end end
@ -154,7 +169,7 @@ Example:
``` ```
""" """
macro gif(forloop::Expr, args...) macro gif(forloop::Expr, args...)
_animate(forloop, args...; callgif = true) _animate(forloop, args...; callgif = true)
end end
""" """
@ -163,13 +178,13 @@ Collect one frame per for-block iteration and return an `Animation` object.
Example: Example:
``` ```
p = plot(1) p = plot(1)
anim = @animate for x=0:0.1:5 anim = @animate for x=0:0.1:5
push!(p, 1, sin(x)) push!(p, 1, sin(x))
end end
gif(anim) gif(anim)
``` ```
""" """
macro animate(forloop::Expr, args...) macro animate(forloop::Expr, args...)
_animate(forloop, args...) _animate(forloop, args...)
end end

View File

@ -122,6 +122,13 @@ savefig(fn::AbstractString) = savefig(current(), fn)
gui(plt::Plot = current()) = display(PlotsDisplay(), plt) gui(plt::Plot = current()) = display(PlotsDisplay(), plt)
# IJulia only... inline display
function inline(plt::Plot = current())
isijulia() || error("inline() is IJulia-only")
Main.IJulia.clear_output(true)
display(Main.IJulia.InlineDisplay(), plt)
end
function Base.display(::PlotsDisplay, plt::Plot) function Base.display(::PlotsDisplay, plt::Plot)
prepare_output(plt) prepare_output(plt)
_display(plt) _display(plt)
@ -130,6 +137,13 @@ end
# override the REPL display to open a gui window # override the REPL display to open a gui window
Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt) Base.display(::Base.REPL.REPLDisplay, ::MIME"text/plain", plt::Plot) = gui(plt)
_do_plot_show(plt, showval::Bool) = showval && gui(plt)
function _do_plot_show(plt, showval::Symbol)
showval == :gui && gui(plt)
showval in (:inline,:ijulia) && inline(plt)
end
# --------------------------------------------------------- # ---------------------------------------------------------
const _mimeformats = Dict( const _mimeformats = Dict(

View File

@ -126,9 +126,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
# finish up # finish up
current(plt) current(plt)
if get(d, :show, default(:show)) _do_plot_show(plt, get(d, :show, default(:show)))
gui()
end
plt plt
end end
@ -234,9 +232,10 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
current(plt) current(plt)
# do we want to force display? # do we want to force display?
if plt[:show] # if plt[:show]
gui(plt) # gui(plt)
end # end
_do_plot_show(plt, plt[:show])
plt plt
end end