code and utils for plotly shapes

This commit is contained in:
Thomas Breloff 2016-06-13 01:45:53 -04:00
parent ed243f4e3e
commit e8ade18d47
3 changed files with 66 additions and 4 deletions

View File

@ -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

View File

@ -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)...)

View File

@ -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)