From a0ca9d675f70d5e6f5d0e9efc30cb23b96697656 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Tue, 10 May 2016 17:22:47 -0400 Subject: [PATCH] add_arrows function; plotly cleanup and arrows attempt --- src/backends/plotly.jl | 130 +++++++++++++++++++++++---------------- src/backends/plotlyjs.jl | 2 +- src/backends/pyplot.jl | 33 ++++------ src/components.jl | 14 +++++ 4 files changed, 104 insertions(+), 75 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index e91c3933..01e76e98 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -150,17 +150,6 @@ end # ---------------------------------------------------------------- -# TODO: -# _plotDefaults[:yrightlabel] = "" -# _plotDefaults[:xlims] = :auto -# _plotDefaults[:ylims] = :auto -# _plotDefaults[:xticks] = :auto -# _plotDefaults[:yticks] = :auto -# _plotDefaults[:xscale] = :identity -# _plotDefaults[:yscale] = :identity -# _plotDefaults[:xflip] = false -# _plotDefaults[:yflip] = false - function plotlyfont(font::Font, color = font.color) KW( :family => font.family, @@ -189,6 +178,29 @@ function get_annotation_dict(x, y, ptxt::PlotText) )) end +# function get_annotation_dict_for_arrow(d::KW, xyprev::Tuple, xy::Tuple, a::Arrow) +# xdiff = xyprev[1] - xy[1] +# ydiff = xyprev[2] - xy[2] +# dist = sqrt(xdiff^2 + ydiff^2) +# KW( +# :showarrow => true, +# :x => xy[1], +# :y => xy[2], +# # :ax => xyprev[1] - xy[1], +# # :ay => xy[2] - xyprev[2], +# # :ax => 0, +# # :ay => -40, +# :ax => 10xdiff / dist, +# :ay => -10ydiff / dist, +# :arrowcolor => webcolor(d[:linecolor], d[:linealpha]), +# :xref => "x", +# :yref => "y", +# :arrowsize => 10a.headwidth, +# # :arrowwidth => a.headlength, +# :arrowwidth => 0.1, +# ) +# end + function plotlyscale(scale::Symbol) if scale == :log10 "log" @@ -263,58 +275,72 @@ end # function get_plot_json(plt::Plot{PlotlyBackend}) # d = plt.plotargs -function plotly_layout(d::KW) - d_out = KW() +function plotly_layout(d::KW, seriesargs::AVec{KW}) + d_out = KW() - d_out[:width], d_out[:height] = d[:size] + d_out[:width], d_out[:height] = d[:size] - bgcolor = webcolor(d[:background_color]) - fgcolor = webcolor(d[:foreground_color]) + bgcolor = webcolor(d[:background_color]) + fgcolor = webcolor(d[:foreground_color]) - # set the fields for the plot - d_out[:title] = d[:title] - d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor) - d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20) - d_out[:plot_bgcolor] = bgcolor - d_out[:paper_bgcolor] = bgcolor + # set the fields for the plot + d_out[:title] = d[:title] + d_out[:titlefont] = plotlyfont(d[:guidefont], fgcolor) + d_out[:margin] = KW(:l=>35, :b=>30, :r=>8, :t=>20) + d_out[:plot_bgcolor] = bgcolor + d_out[:paper_bgcolor] = bgcolor - # TODO: x/y axis tick values/labels - if is3d(d) - d_out[:scene] = KW( - :xaxis => plotlyaxis(d, "x"), - :yaxis => plotlyaxis(d, "y"), - :xzxis => plotlyaxis(d, "z"), - ) - else - d_out[:xaxis] = plotlyaxis(d, "x") - d_out[:yaxis] = plotlyaxis(d, "y") - end + # TODO: x/y axis tick values/labels + if any(is3d, seriesargs) + d_out[:scene] = KW( + :xaxis => plotlyaxis(d, "x"), + :yaxis => plotlyaxis(d, "y"), + :xzxis => plotlyaxis(d, "z"), + ) + else + d_out[:xaxis] = plotlyaxis(d, "x") + d_out[:yaxis] = plotlyaxis(d, "y") + end - # legend - d_out[:showlegend] = d[:legend] != :none - if d[:legend] != :none - d_out[:legend] = KW( - :bgcolor => bgcolor, - :bordercolor => fgcolor, - :font => plotlyfont(d[:legendfont]), - ) - end + # legend + d_out[:showlegend] = d[:legend] != :none + if d[:legend] != :none + d_out[:legend] = KW( + :bgcolor => bgcolor, + :bordercolor => fgcolor, + :font => plotlyfont(d[:legendfont]), + ) + end - # annotations - anns = get(d, :annotation_list, []) - if !isempty(anns) - d_out[:annotations] = [get_annotation_dict(ann...) for ann in anns] - end + # annotations + anns = get(d, :annotation_list, []) + d_out[:annotations] = if isempty(anns) + KW[] + else + KW[get_annotation_dict(ann...) for ann in anns] + end - if get(d, :polar, false) - d_out[:direction] = "counterclockwise" - end + # # arrows + # for sargs in seriesargs + # a = sargs[:arrow] + # if sargs[:linetype] in (:path, :line) && typeof(a) <: Arrow + # add_arrows(sargs[:x], sargs[:y]) do xyprev, xy + # push!(d_out[:annotations], get_annotation_dict_for_arrow(sargs, xyprev, xy, a)) + # end + # end + # end + # dumpdict(d_out,"",true) + # @show d_out[:annotations] - d_out + if get(d, :polar, false) + d_out[:direction] = "counterclockwise" + end + + d_out end function get_plot_json(plt::Plot{PlotlyBackend}) - JSON.json(plotly_layout(plt.plotargs)) + JSON.json(plotly_layout(plt.plotargs, plt.seriesargs)) end diff --git a/src/backends/plotlyjs.jl b/src/backends/plotlyjs.jl index b736e270..3edc8f76 100644 --- a/src/backends/plotlyjs.jl +++ b/src/backends/plotlyjs.jl @@ -141,7 +141,7 @@ end # TODO: override this to update plot items (title, xlabel, etc) after creation function _update_plot(plt::Plot{PlotlyJSBackend}, d::KW) - pdict = plotly_layout(d) + pdict = plotly_layout(plt.plotargs, plt.seriesargs) syncplot = plt.o w,h = d[:size] PlotlyJS.relayout!(syncplot, pdict, width = w, height = h) diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index 938ac009..a7955322 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -421,37 +421,26 @@ function _add_series(pkg::PyPlotBackend, plt::Plot, d::KW) )[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 + a = d[:arrow] + if a != nothing && !is3d(d) # TODO: handle 3d later + if typeof(a) != Arrow + warn("Unexpected type for arrow: $(typeof(a))") + else 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 + add_arrows(x, y) do xyprev, xy + ax[:annotate]("", + xytext = (0.001xyprev[1] + 0.999xy[1], 0.001xyprev[2] + 0.999xy[2]), + xy = xy, + arrowprops = arrowprops + ) end end end diff --git a/src/components.jl b/src/components.jl index f29e3bac..f293799d 100644 --- a/src/components.jl +++ b/src/components.jl @@ -433,6 +433,20 @@ function arrow(args...) end +# allow for do-block notation which gets called on every valid start/end pair which +# we need to draw an arrow +function add_arrows(func::Function, x::AVec, y::AVec) + for i=2:length(x) + xyprev = (x[i-1], y[i-1]) + xy = (x[i], y[i]) + if ok(xyprev) && ok(xy) + if i==length(x) || !ok(x[i+1], y[i+1]) + # add the arrow from xyprev to xy + func(xyprev, xy) + end + end + end +end # -----------------------------------------------------------------------