arrows with updated quiver recipe; only pyplot so far
This commit is contained in:
parent
93a35d8fdc
commit
678dde710b
@ -114,6 +114,7 @@ export
|
||||
brush,
|
||||
Surface,
|
||||
OHLC,
|
||||
arrow,
|
||||
|
||||
colorscheme,
|
||||
ColorScheme,
|
||||
|
||||
@ -150,10 +150,12 @@ _seriesDefaults[:xerror] = nothing
|
||||
_seriesDefaults[:yerror] = nothing
|
||||
_seriesDefaults[:ribbon] = nothing
|
||||
_seriesDefaults[:quiver] = nothing
|
||||
_seriesDefaults[:arrow] = nothing # allows for adding arrows to line/path... call `arrow(args...)`
|
||||
_seriesDefaults[:normalize] = false # do we want a normalized histogram?
|
||||
_seriesDefaults[:weights] = nothing # optional weights for histograms (1D and 2D)
|
||||
_seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots
|
||||
_seriesDefaults[:match_dimensions] = false # do rows match x (true) or y (false) for heatmap/image/spy? see issue 196
|
||||
# this ONLY effects whether or not the z-matrix is transposed for a heatmap display!
|
||||
|
||||
|
||||
const _plotDefaults = KW()
|
||||
@ -343,6 +345,7 @@ add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
|
||||
add_aliases(:quiver, :velocity, :quiver2d, :gradient)
|
||||
add_aliases(:normalize, :norm, :normed, :normalized)
|
||||
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
|
||||
add_aliases(:match_dimensions, :transpose, :transpose_z)
|
||||
|
||||
|
||||
# add all pluralized forms to the _keyAliases dict
|
||||
@ -464,6 +467,9 @@ function processLineArg(d::KW, arg)
|
||||
arg.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
|
||||
|
||||
elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows)
|
||||
d[:arrow] = arg
|
||||
|
||||
# linealpha
|
||||
elseif allAlphas(arg)
|
||||
d[:linealpha] = arg
|
||||
|
||||
@ -29,7 +29,7 @@ supportedArgs(::PyPlotBackend) = [
|
||||
:grid, :legend, :colorbar,
|
||||
:marker_z, :levels,
|
||||
:xerror, :yerror,
|
||||
:ribbon, :quiver,
|
||||
:ribbon, :quiver, :arrow,
|
||||
:orientation,
|
||||
:overwrite_figure,
|
||||
:polar,
|
||||
@ -151,7 +151,7 @@ function buildPyPlotPath(x, y)
|
||||
for i=1:n
|
||||
mat[i,1] = x[i]
|
||||
mat[i,2] = y[i]
|
||||
nan = !isfinite(x[i]) || !isfinite(y[i])
|
||||
nan = !ok(x[i], y[i])
|
||||
codes[i] = if nan
|
||||
_path_CLOSEPOLY
|
||||
else
|
||||
@ -415,9 +415,46 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW)
|
||||
color = pylinecolor(d),
|
||||
linewidth = d[:linewidth],
|
||||
linestyle = getPyPlotLineStyle(lt, d[:linestyle]),
|
||||
solid_capstyle = "round",
|
||||
dash_capstyle = "round",
|
||||
drawstyle = getPyPlotStepStyle(lt)
|
||||
)[1]
|
||||
push!(handles, handle)
|
||||
|
||||
if d[:arrow] != nothing
|
||||
if !is3d(d) # TODO: handle 3d later
|
||||
n = length(x)
|
||||
a = d[:arrow]
|
||||
@assert typeof(a) == Arrow
|
||||
arrowprops = KW(
|
||||
# :arrowstyle => (a.style == :open ? "->" : (a.style == :closed ? "-|>" : string(a.style))),
|
||||
:arrowstyle => "simple,head_length=$(a.headlength),head_width=$(a.headwidth)",
|
||||
# :arrowstyle => "simple",
|
||||
:shrinkA => 0,
|
||||
:shrinkB => 0,
|
||||
:edgecolor => pylinecolor(d),
|
||||
:facecolor => pylinecolor(d),
|
||||
:linewidth => d[:linewidth],
|
||||
:linestyle => getPyPlotLineStyle(lt, d[:linestyle]),
|
||||
# :head_length => a.headlength,
|
||||
# :head_width => a.headwidth,
|
||||
)
|
||||
for i=2:n
|
||||
xystart = (x[i-1], y[i-1])
|
||||
xyend = (x[i], y[i])
|
||||
if ok(xystart) && ok(xyend)
|
||||
if i==n || !ok(x[i+1], y[i+1])
|
||||
# add the arrow from xystart to xyend
|
||||
ax[:annotate]("",
|
||||
xytext = (0.001xystart[1] + 0.999xyend[1], 0.001xystart[2] + 0.999xyend[2]),
|
||||
xy = xyend,
|
||||
arrowprops = arrowprops
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -398,6 +398,38 @@ type OHLC{T<:Real}
|
||||
close::T
|
||||
end
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# style is :open or :closed (for now)
|
||||
immutable Arrow
|
||||
style::Symbol
|
||||
headlength::Float64
|
||||
headwidth::Float64
|
||||
end
|
||||
|
||||
function arrow(args...)
|
||||
style = :simple
|
||||
headlength = 0.3
|
||||
headwidth = 0.2
|
||||
for arg in args
|
||||
T = typeof(arg)
|
||||
if T == Symbol
|
||||
style = arg
|
||||
elseif T <: Number
|
||||
headlength = headwidth = Float64(arg)
|
||||
elseif T <: Tuple && length(arg) == 2
|
||||
headlength, headwidth = Float64(arg[1]), Float64(arg[2])
|
||||
else
|
||||
warn("Skipped arrow arg $arg")
|
||||
end
|
||||
end
|
||||
Arrow(style, headlength, headwidth)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
|
||||
# @require FixedSizeArrays begin
|
||||
|
||||
|
||||
108
src/recipes.jl
108
src/recipes.jl
@ -320,69 +320,46 @@ end
|
||||
# quiver
|
||||
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
# d[:label] = ""
|
||||
# d[:linetype] = :scatter
|
||||
#
|
||||
# # create a second series to draw the arrow shaft
|
||||
# dpath = copy(d)
|
||||
# error_style!(dpath)
|
||||
# dpath[:markershape] = :none
|
||||
#
|
||||
# velocity = error_zipit(d[:quiver])
|
||||
# xorig, yorig = d[:x], d[:y]
|
||||
#
|
||||
# # for each point, we create an arrow of velocity vi, translated to the x/y coordinates
|
||||
# # x, y = zeros(0), zeros(0)
|
||||
# paths = P2[]
|
||||
# arrows = P2[]
|
||||
# arrowshapes = Shape[]
|
||||
# for i = 1:max(length(xorig), length(yorig))
|
||||
#
|
||||
# # get the starting position
|
||||
# xi = get_mod(xorig, i)
|
||||
# yi = get_mod(yorig, i)
|
||||
# p = P2(xi, yi)
|
||||
#
|
||||
# # get the velocity
|
||||
# vi = get_mod(velocity, i)
|
||||
# vx, vy = if istuple(vi)
|
||||
# first(vi), last(vi)
|
||||
# elseif isscalar(vi)
|
||||
# vi, vi
|
||||
# else
|
||||
# error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
||||
# end
|
||||
# v = P2(vx, vy)
|
||||
#
|
||||
# nanappend!(paths, [p, p+v])
|
||||
# push!(arrows, p+v)
|
||||
# push!(arrowshapes, makearrowhead(compute_angle(v)))
|
||||
#
|
||||
# # # dist = sqrt(vx^2 + vy^2)
|
||||
# # dist = norm(v)
|
||||
# # arrow_h = 0.1dist # height of arrowhead
|
||||
# # arrow_w = 0.5arrow_h # halfwidth of arrowhead
|
||||
# # U1 = v ./ dist # vector of arrowhead height
|
||||
# # U2 = P2(-U1[2], U1[1]) # vector of arrowhead halfwidth
|
||||
# # U1 *= arrow_h
|
||||
# # U2 *= arrow_w
|
||||
# #
|
||||
# # append!(pts, P2(xi, yi) .+ P2[(0,0), v-U1, v-U1+U2, v, v-U1-U2, v-U1, (NaN,NaN)])
|
||||
# # # a1 = v - arrow_h * U1 + arrow_w * U2
|
||||
# # # a2 = v - arrow_h * U1 - arrow_w * U2
|
||||
# # # nanappend!(x, xi + [0.0, vx, a1[1], a2[1], vx])
|
||||
# # # nanappend!(y, yi + [0.0, vy, a1[2], a2[2], vy])
|
||||
# end
|
||||
#
|
||||
# # d[:x], d[:y] = Plots.unzip(pts)
|
||||
# dpath[:x], dpath[:y] = Plots.unzip(paths)
|
||||
# d[:x], d[:y] = Plots.unzip(arrows)
|
||||
# d[:markershape] = arrowshapes
|
||||
#
|
||||
# KW[dpath, d]
|
||||
# end
|
||||
function quiver_using_arrows(d::KW)
|
||||
d[:label] = ""
|
||||
d[:linetype] = :path
|
||||
if !isa(d[:arrow], Arrow)
|
||||
d[:arrow] = arrow()
|
||||
end
|
||||
|
||||
function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
velocity = error_zipit(d[:quiver])
|
||||
xorig, yorig = d[:x], d[:y]
|
||||
|
||||
# for each point, we create an arrow of velocity vi, translated to the x/y coordinates
|
||||
x, y = zeros(0), zeros(0)
|
||||
for i = 1:max(length(xorig), length(yorig))
|
||||
# get the starting position
|
||||
xi = get_mod(xorig, i)
|
||||
yi = get_mod(yorig, i)
|
||||
|
||||
# get the velocity
|
||||
vi = get_mod(velocity, i)
|
||||
vx, vy = if istuple(vi)
|
||||
first(vi), last(vi)
|
||||
elseif isscalar(vi)
|
||||
vi, vi
|
||||
elseif isa(vi,Function)
|
||||
vi(xi, yi)
|
||||
else
|
||||
error("unexpected vi type $(typeof(vi)) for quiver: $vi")
|
||||
end
|
||||
|
||||
# add the points
|
||||
nanappend!(x, [xi, xi+vx, NaN])
|
||||
nanappend!(y, [yi, yi+vy, NaN])
|
||||
end
|
||||
|
||||
d[:x], d[:y] = x, y
|
||||
KW[d]
|
||||
end
|
||||
|
||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
function quiver_using_hack(d::KW)
|
||||
d[:label] = ""
|
||||
d[:linetype] = :shape
|
||||
|
||||
@ -427,6 +404,13 @@ function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
KW[d]
|
||||
end
|
||||
|
||||
function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||
if :arrow in supportedArgs()
|
||||
quiver_using_arrows(d)
|
||||
else
|
||||
quiver_using_hack(d)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@ -184,12 +184,18 @@ function build_series_args(plt::AbstractPlot, kw::KW) #, idxfilter)
|
||||
end
|
||||
|
||||
# handle quiver plots
|
||||
if lt == :quiver
|
||||
d[:linetype] = lt = :path
|
||||
d[:linewidth] = 0
|
||||
end
|
||||
# either a series of velocity vectors are passed in (`:quiver` keyword),
|
||||
# or we just add arrows to the path
|
||||
|
||||
# if lt == :quiver
|
||||
# d[:linetype] = lt = :path
|
||||
# d[:linewidth] = 0
|
||||
# end
|
||||
if get(d, :quiver, nothing) != nothing
|
||||
append!(ret, apply_series_recipe(copy(d), Val{:quiver}))
|
||||
elseif lt == :quiver
|
||||
d[:linetype] = lt = :path
|
||||
d[:arrow] = arrow()
|
||||
end
|
||||
|
||||
# now that we've processed a given series... optionally split into
|
||||
|
||||
@ -291,6 +291,11 @@ function transpose_z(d::KW, z, transpose_on_match::Bool = true)
|
||||
end
|
||||
end
|
||||
|
||||
function ok(x::Number, y::Number, z::Number = 0)
|
||||
isfinite(x) && isfinite(y) && isfinite(z)
|
||||
end
|
||||
ok(tup::Tuple) = ok(tup...)
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user