arrows with updated quiver recipe; only pyplot so far
This commit is contained in:
parent
93a35d8fdc
commit
678dde710b
@ -114,6 +114,7 @@ export
|
|||||||
brush,
|
brush,
|
||||||
Surface,
|
Surface,
|
||||||
OHLC,
|
OHLC,
|
||||||
|
arrow,
|
||||||
|
|
||||||
colorscheme,
|
colorscheme,
|
||||||
ColorScheme,
|
ColorScheme,
|
||||||
|
|||||||
@ -150,10 +150,12 @@ _seriesDefaults[:xerror] = nothing
|
|||||||
_seriesDefaults[:yerror] = nothing
|
_seriesDefaults[:yerror] = nothing
|
||||||
_seriesDefaults[:ribbon] = nothing
|
_seriesDefaults[:ribbon] = nothing
|
||||||
_seriesDefaults[:quiver] = 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[:normalize] = false # do we want a normalized histogram?
|
||||||
_seriesDefaults[:weights] = nothing # optional weights for histograms (1D and 2D)
|
_seriesDefaults[:weights] = nothing # optional weights for histograms (1D and 2D)
|
||||||
_seriesDefaults[:contours] = false # add contours to 3d surface and wireframe plots
|
_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
|
_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()
|
const _plotDefaults = KW()
|
||||||
@ -343,6 +345,7 @@ add_aliases(:yerror, :yerr, :yerrorbar, :err, :errorbar)
|
|||||||
add_aliases(:quiver, :velocity, :quiver2d, :gradient)
|
add_aliases(:quiver, :velocity, :quiver2d, :gradient)
|
||||||
add_aliases(:normalize, :norm, :normed, :normalized)
|
add_aliases(:normalize, :norm, :normed, :normalized)
|
||||||
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
|
add_aliases(:aspect_ratio, :aspectratio, :axis_ratio, :axisratio, :ratio)
|
||||||
|
add_aliases(:match_dimensions, :transpose, :transpose_z)
|
||||||
|
|
||||||
|
|
||||||
# add all pluralized forms to the _keyAliases dict
|
# 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.color == nothing || (d[:fillcolor] = arg.color == :auto ? :auto : colorscheme(arg.color))
|
||||||
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
|
arg.alpha == nothing || (d[:fillalpha] = arg.alpha)
|
||||||
|
|
||||||
|
elseif typeof(arg) <: Arrow || arg in (:arrow, :arrows)
|
||||||
|
d[:arrow] = arg
|
||||||
|
|
||||||
# linealpha
|
# linealpha
|
||||||
elseif allAlphas(arg)
|
elseif allAlphas(arg)
|
||||||
d[:linealpha] = arg
|
d[:linealpha] = arg
|
||||||
|
|||||||
@ -29,7 +29,7 @@ supportedArgs(::PyPlotBackend) = [
|
|||||||
:grid, :legend, :colorbar,
|
:grid, :legend, :colorbar,
|
||||||
:marker_z, :levels,
|
:marker_z, :levels,
|
||||||
:xerror, :yerror,
|
:xerror, :yerror,
|
||||||
:ribbon, :quiver,
|
:ribbon, :quiver, :arrow,
|
||||||
:orientation,
|
:orientation,
|
||||||
:overwrite_figure,
|
:overwrite_figure,
|
||||||
:polar,
|
:polar,
|
||||||
@ -151,7 +151,7 @@ function buildPyPlotPath(x, y)
|
|||||||
for i=1:n
|
for i=1:n
|
||||||
mat[i,1] = x[i]
|
mat[i,1] = x[i]
|
||||||
mat[i,2] = y[i]
|
mat[i,2] = y[i]
|
||||||
nan = !isfinite(x[i]) || !isfinite(y[i])
|
nan = !ok(x[i], y[i])
|
||||||
codes[i] = if nan
|
codes[i] = if nan
|
||||||
_path_CLOSEPOLY
|
_path_CLOSEPOLY
|
||||||
else
|
else
|
||||||
@ -415,9 +415,46 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW)
|
|||||||
color = pylinecolor(d),
|
color = pylinecolor(d),
|
||||||
linewidth = d[:linewidth],
|
linewidth = d[:linewidth],
|
||||||
linestyle = getPyPlotLineStyle(lt, d[:linestyle]),
|
linestyle = getPyPlotLineStyle(lt, d[:linestyle]),
|
||||||
|
solid_capstyle = "round",
|
||||||
|
dash_capstyle = "round",
|
||||||
drawstyle = getPyPlotStepStyle(lt)
|
drawstyle = getPyPlotStepStyle(lt)
|
||||||
)[1]
|
)[1]
|
||||||
push!(handles, handle)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -398,6 +398,38 @@ type OHLC{T<:Real}
|
|||||||
close::T
|
close::T
|
||||||
end
|
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
|
# @require FixedSizeArrays begin
|
||||||
|
|
||||||
|
|||||||
108
src/recipes.jl
108
src/recipes.jl
@ -320,69 +320,46 @@ end
|
|||||||
# quiver
|
# quiver
|
||||||
|
|
||||||
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
# function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
||||||
# d[:label] = ""
|
function quiver_using_arrows(d::KW)
|
||||||
# d[:linetype] = :scatter
|
d[:label] = ""
|
||||||
#
|
d[:linetype] = :path
|
||||||
# # create a second series to draw the arrow shaft
|
if !isa(d[:arrow], Arrow)
|
||||||
# dpath = copy(d)
|
d[:arrow] = arrow()
|
||||||
# error_style!(dpath)
|
end
|
||||||
# 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 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[:label] = ""
|
||||||
d[:linetype] = :shape
|
d[:linetype] = :shape
|
||||||
|
|
||||||
@ -427,6 +404,13 @@ function apply_series_recipe(d::KW, ::Type{Val{:quiver}})
|
|||||||
KW[d]
|
KW[d]
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# handle quiver plots
|
# handle quiver plots
|
||||||
if lt == :quiver
|
# either a series of velocity vectors are passed in (`:quiver` keyword),
|
||||||
d[:linetype] = lt = :path
|
# or we just add arrows to the path
|
||||||
d[:linewidth] = 0
|
|
||||||
end
|
# if lt == :quiver
|
||||||
|
# d[:linetype] = lt = :path
|
||||||
|
# d[:linewidth] = 0
|
||||||
|
# end
|
||||||
if get(d, :quiver, nothing) != nothing
|
if get(d, :quiver, nothing) != nothing
|
||||||
append!(ret, apply_series_recipe(copy(d), Val{:quiver}))
|
append!(ret, apply_series_recipe(copy(d), Val{:quiver}))
|
||||||
|
elseif lt == :quiver
|
||||||
|
d[:linetype] = lt = :path
|
||||||
|
d[:arrow] = arrow()
|
||||||
end
|
end
|
||||||
|
|
||||||
# now that we've processed a given series... optionally split into
|
# 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
|
||||||
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