From e8ade18d47941f83a794032cd3b0dc097f8639b7 Mon Sep 17 00:00:00 2001 From: Thomas Breloff Date: Mon, 13 Jun 2016 01:45:53 -0400 Subject: [PATCH] code and utils for plotly shapes --- src/backends/plotly.jl | 35 +++++++++++++++++++++++++++++++++-- src/components.jl | 11 +++++++++-- src/utils.jl | 24 ++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index c1a46aa1..17e7edde 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -40,7 +40,7 @@ supported_args(::PlotlyBackend) = [ supported_types(::PlotlyBackend) = [ :path, :scatter, :bar, :pie, :heatmap, - :contour, :surface, :path3d, :scatter3d + :contour, :surface, :path3d, :scatter3d, :shape ] supported_styles(::PlotlyBackend) = [:auto, :solid, :dash, :dot, :dashdot] supported_markers(::PlotlyBackend) = [ @@ -321,6 +321,17 @@ function plotly_subplot_index(sp::Subplot) end +# the Shape contructor will automatically close the shape. since we need it closed, +# we split by NaNs and then construct/destruct the shapes to get the closed coords +function plotly_close_shapes(x, y) + xs, ys = nansplit(x), nansplit(y) + for i=1:length(xs) + shape = Shape(xs[i], ys[i]) + xs[i], ys[i] = shape_coords(shape) + end + nanvcat(xs), nanvcat(ys) +end + # get a dictionary representing the series params (d is the Plots-dict, d_out is the Plotly-dict) function plotly_series(plt::Plot, series::Series) d = series.d @@ -338,7 +349,8 @@ function plotly_series(plt::Plot, series::Series) st = d[:seriestype] isscatter = st in (:scatter, :scatter3d) hasmarker = isscatter || d[:markershape] != :none - hasline = !isscatter + # hasline = !isscatter + hasline = st in (:path, :path3d) # set the "type" if st in (:path, :scatter) @@ -356,6 +368,25 @@ function plotly_series(plt::Plot, series::Series) end d_out[:x], d_out[:y] = x, y + elseif st == :shape + # to draw polygons, we actually draw lines with fill + d_out[:type] = "scatter" + d_out[:mode] = "lines" + d_out[:x], d_out[:y] = plotly_close_shapes(x, y) + # @show map(length, (x,y,d_out[:x],d_out[:y])) + # @show d_out[:x] d_out[:y] + d_out[:fill] = "tozeroy" + d_out[:fillcolor] = webcolor(d[:markercolor], d[:markeralpha]) + if d[:markerstrokewidth] > 0 + d_out[:line] = KW( + :color => webcolor(d[:markerstrokecolor], d[:markerstrokealpha]), + :width => d[:markerstrokewidth], + :dash => string(d[:markerstrokestyle]), + ) + end + + + elseif st == :bar d_out[:type] = "bar" d_out[:x], d_out[:y] = x, y diff --git a/src/components.jl b/src/components.jl index 7b1a08eb..65055dc3 100644 --- a/src/components.jl +++ b/src/components.jl @@ -12,8 +12,15 @@ compute_angle(v::P2) = (angle = atan2(v[2], v[1]); angle < 0 ? 2π - angle : ang # ------------------------------------------------------------- immutable Shape - x::AVec - y::AVec + x::Vector{Float64} + y::Vector{Float64} + function Shape(x::AVec, y::AVec) + if x[1] != x[end] || y[1] != y[end] + new(vcat(x, x[1]), vcat(y, y[1])) + else + new(x, y) + end + end end Shape(verts::AVec) = Shape(unzip(verts)...) diff --git a/src/utils.jl b/src/utils.jl index 96e99490..66bc8d53 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -306,6 +306,30 @@ Base.merge(a::AbstractVector, b::AbstractVector) = sort(unique(vcat(a,b))) nanpush!(a::AbstractVector, b) = (push!(a, NaN); push!(a, b)) nanappend!(a::AbstractVector, b) = (push!(a, NaN); append!(a, b)) +function nansplit(v::AVec) + vs = Vector{eltype(v)}[] + while true + idx = findfirst(isnan, v) + if idx <= 0 + # no nans + push!(vs, v) + break + elseif idx > 1 + push!(vs, v[1:idx-1]) + end + v = v[idx+1:end] + end + vs +end + +function nanvcat(vs::AVec) + v_out = zeros(0) + for v in vs + nanappend!(v_out, v) + end + v_out +end + # given an array of discrete values, turn it into an array of indices of the unique values # returns the array of indices (znew) and a vector of unique values (vals) function indices_and_unique_values(z::AbstractArray)