Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c092d3cab4 | |||
| 07731614a9 | |||
| d8ffd729f4 | |||
| b23d94eeb8 | |||
| 4ed7144ca4 | |||
| ad924e8cc9 | |||
| aa929ec24f | |||
| 07f7fd3c7a | |||
| 83beca098b | |||
| 2c3d35d249 | |||
| 90e655d979 | |||
| 8204b51213 | |||
| c3f40d0555 | |||
| cbd134987b | |||
| 167fd68774 | |||
| 2b8cc7cfde | |||
| 62280fb24b | |||
| 2a7604ef5f | |||
| 0b47aafd14 | |||
| 24eefbed2b | |||
| ab7a73c879 | |||
| 81e0868725 |
@@ -57,6 +57,7 @@ export
|
||||
savefig,
|
||||
png,
|
||||
gui,
|
||||
inline,
|
||||
closeall,
|
||||
|
||||
backend,
|
||||
@@ -80,6 +81,8 @@ export
|
||||
Animation,
|
||||
frame,
|
||||
gif,
|
||||
mov,
|
||||
mp4,
|
||||
animate,
|
||||
@animate,
|
||||
@gif,
|
||||
|
||||
+58
-38
@@ -1,22 +1,24 @@
|
||||
|
||||
immutable Animation
|
||||
dir::String
|
||||
frames::Vector{String}
|
||||
dir::String
|
||||
frames::Vector{String}
|
||||
end
|
||||
|
||||
function Animation()
|
||||
tmpdir = convert(String, mktempdir())
|
||||
Animation(tmpdir, String[])
|
||||
tmpdir = convert(String, mktempdir())
|
||||
Animation(tmpdir, String[])
|
||||
end
|
||||
|
||||
function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
push!(anim.frames, filename)
|
||||
i = length(anim.frames) + 1
|
||||
filename = @sprintf("%06d.png", i)
|
||||
png(plt, joinpath(anim.dir, filename))
|
||||
push!(anim.frames, filename)
|
||||
end
|
||||
|
||||
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
|
||||
movfn() = (isijulia() ? "tmp.mov" : tempname()*".mov")
|
||||
mp4fn() = (isijulia() ? "tmp.mp4" : tempname()*".mp4")
|
||||
|
||||
type FrameIterator
|
||||
itr
|
||||
@@ -48,42 +50,60 @@ end
|
||||
|
||||
"Wraps the location of an animated gif so that it can be displayed"
|
||||
immutable AnimatedGif
|
||||
filename::String
|
||||
filename::String
|
||||
end
|
||||
|
||||
function gif(anim::Animation, fn = giffn(); fps::Integer = 20, loop::Integer = 0)
|
||||
fn = abspath(fn)
|
||||
file_extension(fn) = Base.Filesystem.splitext(fn)[2][2:end]
|
||||
|
||||
try
|
||||
gif(anim::Animation, fn = giffn(); 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...)
|
||||
|
||||
# high quality
|
||||
speed = round(Int, 100 / fps)
|
||||
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
|
||||
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
|
||||
include(file)
|
||||
const _imagemagick_initialized = Ref(false)
|
||||
|
||||
function buildanimation(animdir::AbstractString, fn::AbstractString;
|
||||
fps::Integer = 20, loop::Integer = 0)
|
||||
fn = abspath(fn)
|
||||
try
|
||||
if !_imagemagick_initialized[]
|
||||
file = joinpath(Pkg.dir("ImageMagick"), "deps","deps.jl")
|
||||
if isfile(file) && !haskey(ENV, "MAGICK_CONFIGURE_PATH")
|
||||
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
|
||||
# prefix = get(ENV, "MAGICK_CONFIGURE_PATH", "")
|
||||
run(`convert -delay $speed -loop $loop $(joinpath(anim.dir, "*.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 $(anim.dir)/%06d.png -y $fn`)
|
||||
# run(`ffmpeg -v warning -i "fps=$fps,scale=320:-1:flags=lanczos"`)
|
||||
end
|
||||
|
||||
info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
info("Saved animation to ", fn)
|
||||
AnimatedGif(fn)
|
||||
end
|
||||
|
||||
|
||||
|
||||
# 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)
|
||||
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
|
||||
|
||||
|
||||
@@ -149,7 +169,7 @@ Example:
|
||||
```
|
||||
"""
|
||||
macro gif(forloop::Expr, args...)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
_animate(forloop, args...; callgif = true)
|
||||
end
|
||||
|
||||
"""
|
||||
@@ -158,13 +178,13 @@ Collect one frame per for-block iteration and return an `Animation` object.
|
||||
Example:
|
||||
|
||||
```
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
p = plot(1)
|
||||
anim = @animate for x=0:0.1:5
|
||||
push!(p, 1, sin(x))
|
||||
end
|
||||
gif(anim)
|
||||
end
|
||||
gif(anim)
|
||||
```
|
||||
"""
|
||||
macro animate(forloop::Expr, args...)
|
||||
_animate(forloop, args...)
|
||||
_animate(forloop, args...)
|
||||
end
|
||||
|
||||
@@ -159,12 +159,12 @@ function create_window(plt::Plot{GLVisualizeBackend}, visible)
|
||||
# make sure we have any screen open
|
||||
if isempty(GLVisualize.get_screens())
|
||||
# create a fresh, new screen
|
||||
screen = GLVisualize.glscreen(
|
||||
parent_screen = GLVisualize.glscreen(
|
||||
"Plot",
|
||||
resolution = plt[:size],
|
||||
visible = visible
|
||||
)
|
||||
@async GLWindow.waiting_renderloop(screen)
|
||||
@async GLWindow.waiting_renderloop(parent_screen)
|
||||
end
|
||||
# now lets get ourselves a permanent Plotting screen
|
||||
plot_screens = get_plot_screen(GLVisualize.get_screens(), name)
|
||||
|
||||
+2
-2
@@ -614,8 +614,8 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
||||
|
||||
# GR.setlinetype(GR.LINETYPE_DOTTED)
|
||||
if sp[:grid]
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0)
|
||||
GR.grid3d(xtick, 0, ztick, xmin, ymax, zmin, 2, 0, 2)
|
||||
GR.grid3d(0, ytick, 0, xmin, ymax, zmin, 0, 2, 0)
|
||||
end
|
||||
GR.axes3d(xtick, 0, ztick, xmin, ymin, zmin, 2, 0, 2, -ticksize)
|
||||
GR.axes3d(0, ytick, 0, xmax, ymin, zmin, 0, 2, 0, ticksize)
|
||||
|
||||
@@ -57,6 +57,7 @@ end
|
||||
|
||||
|
||||
const _plotly_js_path = joinpath(dirname(@__FILE__), "..", "..", "deps", "plotly-latest.min.js")
|
||||
const _plotly_js_path_remote = "https://cdn.plot.ly/plotly-latest.min.js"
|
||||
|
||||
function _initialize_backend(::PlotlyBackend; kw...)
|
||||
@eval begin
|
||||
@@ -629,8 +630,12 @@ end
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
const _use_remote = Ref(false)
|
||||
|
||||
function html_head(plt::Plot{PlotlyBackend})
|
||||
"<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
|
||||
jsfilename = _use_remote[] ? _plotly_js_path_remote : _plotly_js_path
|
||||
# "<script src=\"$(joinpath(dirname(@__FILE__),"..","..","deps","plotly-latest.min.js"))\"></script>"
|
||||
"<script src=\"$jsfilename\"></script>"
|
||||
end
|
||||
|
||||
function html_body(plt::Plot{PlotlyBackend}, style = nothing)
|
||||
|
||||
@@ -86,7 +86,11 @@ end
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
function _show(io::IO, ::MIME"image/svg+xml", plt::Plot{PlotlyJSBackend})
|
||||
show(io, MIME("text/html"), plt.o)
|
||||
if Plots.isijulia()
|
||||
print(io, PlotlyJS.html_body(plt.o))
|
||||
else
|
||||
show(io, MIME("text/html"), plt.o)
|
||||
end
|
||||
end
|
||||
|
||||
function plotlyjs_save_hack(io::IO, plt::Plot{PlotlyJSBackend}, ext::String)
|
||||
|
||||
@@ -52,6 +52,16 @@ function tex(plt::Plot, fn::AbstractString)
|
||||
end
|
||||
tex(fn::AbstractString) = tex(current(), fn)
|
||||
|
||||
function html(plt::Plot, fn::AbstractString)
|
||||
fn = addExtension(fn, "html")
|
||||
io = open(fn, "w")
|
||||
_use_remote[] = true
|
||||
show(io, MIME("text/html"), plt)
|
||||
_use_remote[] = false
|
||||
close(io)
|
||||
end
|
||||
html(fn::AbstractString) = html(current(), fn)
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
@@ -63,6 +73,7 @@ const _savemap = Dict(
|
||||
"ps" => ps,
|
||||
"eps" => eps,
|
||||
"tex" => tex,
|
||||
"html" => html,
|
||||
)
|
||||
|
||||
function getExtension(fn::AbstractString)
|
||||
@@ -111,6 +122,13 @@ savefig(fn::AbstractString) = savefig(current(), fn)
|
||||
|
||||
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)
|
||||
prepare_output(plt)
|
||||
_display(plt)
|
||||
@@ -119,6 +137,13 @@ end
|
||||
# override the REPL display to open a gui window
|
||||
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(
|
||||
|
||||
+5
-6
@@ -126,9 +126,7 @@ function plot(plt1::Plot, plts_tail::Plot...; kw...)
|
||||
|
||||
# finish up
|
||||
current(plt)
|
||||
if get(d, :show, default(:show))
|
||||
gui()
|
||||
end
|
||||
_do_plot_show(plt, get(d, :show, default(:show)))
|
||||
plt
|
||||
end
|
||||
|
||||
@@ -234,9 +232,10 @@ function _plot!(plt::Plot, d::KW, args::Tuple)
|
||||
current(plt)
|
||||
|
||||
# do we want to force display?
|
||||
if plt[:show]
|
||||
gui(plt)
|
||||
end
|
||||
# if plt[:show]
|
||||
# gui(plt)
|
||||
# end
|
||||
_do_plot_show(plt, plt[:show])
|
||||
|
||||
plt
|
||||
end
|
||||
|
||||
+2
-3
@@ -526,8 +526,7 @@ end
|
||||
|
||||
function error_coords(xorig, yorig, ebar)
|
||||
# init empty x/y, and zip errors if passed Tuple{Vector,Vector}
|
||||
x, y = zeros(0), zeros(0)
|
||||
|
||||
x, y = Array(float_extended_type(xorig), 0), Array(Float64, 0)
|
||||
# for each point, create a line segment from the bottom to the top of the errorbar
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
xi = cycle(xorig, i)
|
||||
@@ -800,6 +799,6 @@ abline!(args...; kw...) = abline!(current(), args...; kw...)
|
||||
@recipe function f(cp::ComplexPlot)
|
||||
xguide --> "Real Part"
|
||||
yguide --> "Imaginary Part"
|
||||
linetype --> :scatter
|
||||
seriestype --> :scatter
|
||||
real(cp.args[1]), imag(cp.args[1])
|
||||
end
|
||||
|
||||
@@ -90,10 +90,18 @@ end
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
Base.getindex(plt::Plot, i::Integer) = plt.subplots[i]
|
||||
Base.length(plt::Plot) = length(plt.subplots)
|
||||
Base.endof(plt::Plot) = length(plt)
|
||||
|
||||
Base.getindex(plt::Plot, r::Integer, c::Integer) = plt.layout[r,c]
|
||||
Base.size(plt::Plot) = size(plt.layout)
|
||||
Base.size(plt::Plot, i::Integer) = size(plt.layout)[i]
|
||||
Base.ndims(plt::Plot) = 2
|
||||
|
||||
# attr(plt::Plot, k::Symbol) = plt.attr[k]
|
||||
# attr!(plt::Plot, v, k::Symbol) = (plt.attr[k] = v)
|
||||
|
||||
Base.getindex(sp::Subplot, i::Integer) = series_list(sp)[i]
|
||||
Base.endof(sp::Subplot) = length(series_list(sp))
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
@@ -228,6 +228,12 @@ function Base.next(itr::SegmentsIterator, nextidx::Int)
|
||||
istart:iend, i
|
||||
end
|
||||
|
||||
# Find minimal type that can contain NaN and x
|
||||
# To allow use of NaN separated segments with categorical x axis
|
||||
|
||||
float_extended_type{T}(x::AbstractArray{T}) = Union{T,Float64}
|
||||
float_extended_type{T<:Real}(x::AbstractArray{T}) = Float64
|
||||
|
||||
# ------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user