Base.cycle to cycle; text_size; animate; MixedMeasures; SeriesAnnotations
This commit is contained in:
parent
281b92c262
commit
350ffdee25
@ -89,6 +89,7 @@ export
|
|||||||
Animation,
|
Animation,
|
||||||
frame,
|
frame,
|
||||||
gif,
|
gif,
|
||||||
|
animate,
|
||||||
@animate,
|
@animate,
|
||||||
@gif,
|
@gif,
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,33 @@ function frame{P<:AbstractPlot}(anim::Animation, plt::P=current())
|
|||||||
push!(anim.frames, filename)
|
push!(anim.frames, filename)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
giffn() = (isijulia() ? "tmp.gif" : tempname()*".gif")
|
||||||
|
|
||||||
|
type FrameIterator
|
||||||
|
itr
|
||||||
|
every::Int
|
||||||
|
kw
|
||||||
|
end
|
||||||
|
FrameIterator(itr; every=1, kw...) = FrameIterator(itr, every, kw)
|
||||||
|
|
||||||
|
"""
|
||||||
|
Animate from an iterator which returns the plot args each iteration.
|
||||||
|
"""
|
||||||
|
function animate(fitr::FrameIterator, fn = giffn(); kw...)
|
||||||
|
anim = Animation()
|
||||||
|
for (i, plotargs) in enumerate(fitr.itr)
|
||||||
|
if mod1(i, fitr.every) == 1
|
||||||
|
plot(wraptuple(plotargs)...; fitr.kw...)
|
||||||
|
frame(anim)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
gif(anim, fn; kw...)
|
||||||
|
end
|
||||||
|
|
||||||
|
# most things will implement this
|
||||||
|
function animate(obj, fn = giffn(); every=1, fps=20, loop=0, kw...)
|
||||||
|
animate(FrameIterator(obj, every, kw); fps=fps, loop=loop)
|
||||||
|
end
|
||||||
|
|
||||||
# -----------------------------------------------
|
# -----------------------------------------------
|
||||||
|
|
||||||
@ -24,7 +51,7 @@ immutable AnimatedGif
|
|||||||
filename::String
|
filename::String
|
||||||
end
|
end
|
||||||
|
|
||||||
function gif(anim::Animation, fn = (isijulia() ? "tmp.gif" : tempname()*".gif"); fps::Integer = 20, loop::Integer = 0)
|
function gif(anim::Animation, fn = giffn(); fps::Integer = 20, loop::Integer = 0)
|
||||||
fn = abspath(fn)
|
fn = abspath(fn)
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|||||||
@ -51,6 +51,20 @@ _before_layout_calcs(plt::Plot) = nothing
|
|||||||
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
|
title_padding(sp::Subplot) = sp[:title] == "" ? 0mm : sp[:titlefont].pointsize * pt
|
||||||
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
|
guide_padding(axis::Axis) = axis[:guide] == "" ? 0mm : axis[:guidefont].pointsize * pt
|
||||||
|
|
||||||
|
"Returns the (width,height) of a text label."
|
||||||
|
function text_size(lablen::Int, sz::Number, rot::Number = 0)
|
||||||
|
# we need to compute the size of the ticks generically
|
||||||
|
# this means computing the bounding box and then getting the width/height
|
||||||
|
ptsz = sz * pt
|
||||||
|
width = 0.8lablen * ptsz
|
||||||
|
|
||||||
|
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||||
|
height = abs(sind(rot)) * width + abs(cosd(rot)) * ptsz
|
||||||
|
width = abs(sind(rot+90)) * width + abs(cosd(rot+90)) * ptsz
|
||||||
|
width, height
|
||||||
|
end
|
||||||
|
text_size(lab::AbstractString, sz::Number, rot::Number = 0) = text_size(length(lab), sz, rot)
|
||||||
|
|
||||||
# account for the size/length/rotation of tick labels
|
# account for the size/length/rotation of tick labels
|
||||||
function tick_padding(axis::Axis)
|
function tick_padding(axis::Axis)
|
||||||
ticks = get_ticks(axis)
|
ticks = get_ticks(axis)
|
||||||
@ -59,19 +73,23 @@ function tick_padding(axis::Axis)
|
|||||||
else
|
else
|
||||||
vals, labs = ticks
|
vals, labs = ticks
|
||||||
isempty(labs) && return 0mm
|
isempty(labs) && return 0mm
|
||||||
ptsz = axis[:tickfont].pointsize * pt
|
# ptsz = axis[:tickfont].pointsize * pt
|
||||||
|
|
||||||
# we need to compute the size of the ticks generically
|
|
||||||
# this means computing the bounding box and then getting the width/height
|
|
||||||
longest_label = maximum(length(lab) for lab in labs)
|
longest_label = maximum(length(lab) for lab in labs)
|
||||||
labelwidth = 0.8longest_label * ptsz
|
|
||||||
|
|
||||||
# generalize by "rotating" y labels
|
# generalize by "rotating" y labels
|
||||||
rot = axis[:rotation] + (axis[:letter] == :y ? 90 : 0)
|
rot = axis[:rotation] + (axis[:letter] == :y ? 90 : 0)
|
||||||
|
|
||||||
# now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
# # we need to compute the size of the ticks generically
|
||||||
hgt = abs(sind(rot)) * labelwidth + abs(cosd(rot)) * ptsz + 1mm
|
# # this means computing the bounding box and then getting the width/height
|
||||||
hgt
|
# labelwidth = 0.8longest_label * ptsz
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# # now compute the generalized "height" after rotation as the "opposite+adjacent" of 2 triangles
|
||||||
|
# hgt = abs(sind(rot)) * labelwidth + abs(cosd(rot)) * ptsz + 1mm
|
||||||
|
# hgt
|
||||||
|
|
||||||
|
# get the height of the rotated label
|
||||||
|
text_size(longest_label, axis[:tickfont].pointsize, rot)[2]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1021,6 +1021,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
for ann in sp[:annotations]
|
for ann in sp[:annotations]
|
||||||
|
if isa(ann, SeriesAnnotation)
|
||||||
|
# TODO handle series annotations
|
||||||
|
else
|
||||||
x, y, val = ann
|
x, y, val = ann
|
||||||
x, y = if is3d(sp)
|
x, y = if is3d(sp)
|
||||||
# GR.wc3towc(x, y, z)
|
# GR.wc3towc(x, y, z)
|
||||||
@ -1030,6 +1033,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
gr_set_font(val.font)
|
gr_set_font(val.font)
|
||||||
gr_text(x, y, val.str)
|
gr_text(x, y, val.str)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
GR.restorestate()
|
GR.restorestate()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -308,10 +308,6 @@ function text(str, args...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
annotations(::Void) = []
|
|
||||||
annotations(anns::AVec) = anns
|
|
||||||
annotations(anns) = Any[anns]
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
@ -387,6 +383,47 @@ end
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type SeriesAnnotations
|
||||||
|
strs::AbstractVector # the labels/names
|
||||||
|
font::Font
|
||||||
|
shape::Nullable{Shape}
|
||||||
|
shapefill::Brush
|
||||||
|
shapestroke::Stroke
|
||||||
|
bboxes::Vector{BBox}
|
||||||
|
end
|
||||||
|
function SeriesAnnotations(strs::AbstractVector, args...)
|
||||||
|
fnt = font()
|
||||||
|
shp = Nullable{Shape}()
|
||||||
|
br = brush(:steelblue)
|
||||||
|
stk = stroke(:black, 1)
|
||||||
|
for arg in args
|
||||||
|
if isa(arg, Shape)
|
||||||
|
shp = Nullable{Shape}(arg)
|
||||||
|
elseif isa(arg, Brush)
|
||||||
|
brush = arg
|
||||||
|
elseif isa(arg, Stroke)
|
||||||
|
stk = arg
|
||||||
|
elseif isa(arg, Font)
|
||||||
|
fnt = arg
|
||||||
|
elseif isa(arg, Symbol) && haskey(_shapes, arg)
|
||||||
|
shape = _shapes[arg]
|
||||||
|
else
|
||||||
|
warn("Unused SeriesAnnotations arg: $arg ($(typeof(arg)))")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# note: x/y coords are added later
|
||||||
|
SeriesAnnotations(strs, fnt, shp, br, stk, BBox[])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
annotations(::Void) = []
|
||||||
|
annotations(anns::AVec) = anns
|
||||||
|
annotations(anns) = Any[anns]
|
||||||
|
annotations(sa::SeriesAnnotations) = sa
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
"type which represents z-values for colors and sizes (and anything else that might come up)"
|
"type which represents z-values for colors and sizes (and anything else that might come up)"
|
||||||
immutable ZValues
|
immutable ZValues
|
||||||
values::Vector{Float64}
|
values::Vector{Float64}
|
||||||
|
|||||||
@ -96,6 +96,31 @@ function Base.show(io::IO, bbox::BoundingBox)
|
|||||||
print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
|
print(io, "BBox{l,t,r,b,w,h = $(left(bbox)),$(top(bbox)), $(right(bbox)),$(bottom(bbox)), $(width(bbox)),$(height(bbox))}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# -----------------------------------------------------------
|
||||||
|
|
||||||
|
# points combined by x/y, pct, and length
|
||||||
|
type MixedMeasures
|
||||||
|
xy::Float64
|
||||||
|
pct::Float64
|
||||||
|
len::AbsoluteLength
|
||||||
|
end
|
||||||
|
|
||||||
|
function resolve_mixed(mix::MixedMeasures, sp::Subplot, letter::Symbol)
|
||||||
|
xy = mix.xy
|
||||||
|
pct = mix.pct
|
||||||
|
if mix.len != 0mm
|
||||||
|
f = (letter == :x ? width : height)
|
||||||
|
totlen = f(plotarea(sp))
|
||||||
|
pct += mix.len / totlen
|
||||||
|
end
|
||||||
|
if pct != 0
|
||||||
|
amin, amax = axis_limits(sp[Symbol(letter,:axis)])
|
||||||
|
xy += pct * (amax-amin)
|
||||||
|
end
|
||||||
|
xy
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------
|
# -----------------------------------------------------------
|
||||||
# AbstractLayout
|
# AbstractLayout
|
||||||
|
|
||||||
|
|||||||
@ -333,14 +333,29 @@ function _prepare_annotations(sp::Subplot, d::KW)
|
|||||||
# strip out series annotations (those which are based on series x/y coords)
|
# strip out series annotations (those which are based on series x/y coords)
|
||||||
# and add them to the subplot attr
|
# and add them to the subplot attr
|
||||||
sp_anns = annotations(sp[:annotations])
|
sp_anns = annotations(sp[:annotations])
|
||||||
anns = annotations(pop!(d, :series_annotations, []))
|
series_anns = annotations(pop!(d, :series_annotations, []))
|
||||||
if length(anns) > 0
|
if isa(series_anns, SeriesAnnotations)
|
||||||
|
# x, y = d[:x], d[:y]
|
||||||
|
# nx, ny, na = map(length, (x,y,series_anns.strs))
|
||||||
|
# n = max(nx, ny, na)
|
||||||
|
# for i=1:n
|
||||||
|
# str = cycle(series_anns.strs,i)
|
||||||
|
# xi = cycle(x,i)
|
||||||
|
# yi = cycle(y,i)
|
||||||
|
# mwidth, mheight = text_size(str, series_anns.font.pointsize)
|
||||||
|
# xsz = measure_to_data(sp[:xaxis], mwidth)
|
||||||
|
# ysz = measure_to_data(sp[:yaxis], mheight)
|
||||||
|
error()
|
||||||
|
|
||||||
|
elseif length(series_anns) > 0
|
||||||
x, y = d[:x], d[:y]
|
x, y = d[:x], d[:y]
|
||||||
nx, ny, na = map(length, (x,y,anns))
|
nx, ny, na = map(length, (x,y,series_anns))
|
||||||
n = max(nx, ny, na)
|
n = max(nx, ny, na)
|
||||||
anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(anns[mod1(i,na)])) for i=1:n]
|
series_anns = [(x[mod1(i,nx)], y[mod1(i,ny)], text(series_anns[mod1(i,na)])) for i=1:n]
|
||||||
end
|
end
|
||||||
sp.attr[:annotations] = vcat(sp_anns, anns)
|
sp.attr[:annotations] = vcat(sp_anns, series_anns)
|
||||||
|
# sp[:series_annotations] = series_anns
|
||||||
|
# sp[:annotations] = sp_anns
|
||||||
end
|
end
|
||||||
|
|
||||||
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
function _expand_subplot_extrema(sp::Subplot, d::KW, st::Symbol)
|
||||||
|
|||||||
20
src/utils.jl
20
src/utils.jl
@ -234,19 +234,19 @@ end
|
|||||||
nop() = nothing
|
nop() = nothing
|
||||||
notimpl() = error("This has not been implemented yet")
|
notimpl() = error("This has not been implemented yet")
|
||||||
|
|
||||||
Base.cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
cycle(wrapper::InputWrapper, idx::Int) = wrapper.obj
|
||||||
Base.cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
cycle(wrapper::InputWrapper, idx::AVec{Int}) = wrapper.obj
|
||||||
|
|
||||||
Base.cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
cycle(v::AVec, idx::Int) = v[mod1(idx, length(v))]
|
||||||
Base.cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
cycle(v::AMat, idx::Int) = size(v,1) == 1 ? v[1, mod1(idx, size(v,2))] : v[:, mod1(idx, size(v,2))]
|
||||||
Base.cycle(v, idx::Int) = v
|
cycle(v, idx::Int) = v
|
||||||
|
|
||||||
Base.cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
cycle(v::AVec, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
||||||
Base.cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
cycle(v::AMat, indices::AVec{Int}) = map(i -> cycle(v,i), indices)
|
||||||
Base.cycle(v, indices::AVec{Int}) = fill(v, length(indices))
|
cycle(v, indices::AVec{Int}) = fill(v, length(indices))
|
||||||
|
|
||||||
Base.cycle(grad::ColorGradient, idx::Int) = cycle(grad.colors, idx)
|
cycle(grad::ColorGradient, idx::Int) = cycle(grad.colors, idx)
|
||||||
Base.cycle(grad::ColorGradient, indices::AVec{Int}) = cycle(grad.colors, indices)
|
cycle(grad::ColorGradient, indices::AVec{Int}) = cycle(grad.colors, indices)
|
||||||
|
|
||||||
makevec(v::AVec) = v
|
makevec(v::AVec) = v
|
||||||
makevec{T}(v::T) = T[v]
|
makevec{T}(v::T) = T[v]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user