From 59a1faf5909f8f010b496574834f0cb4248281fe Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 19:56:29 -0700 Subject: [PATCH 01/10] Add `even` arg to `make_steps` This is in preparation for `:stepmid` support. --- src/recipes.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index b69ed3f3..285915d7 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -181,8 +181,8 @@ end # --------------------------------------------------------------------------- # steps -make_steps(x, st) = x -function make_steps(x::AbstractArray, st) +make_steps(x, st, even) = x +function make_steps(x::AbstractArray, st, even) n = length(x) n == 0 && return zeros(0) newx = zeros(2n - 1) @@ -195,19 +195,19 @@ function make_steps(x::AbstractArray, st) end return newx end -make_steps(t::Tuple, st) = Tuple(make_steps(ti, st) for ti in t) +make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t) @nospecialize # create a path from steps @recipe function f(::Type{Val{:steppre}}, x, y, z) - plotattributes[:x] = make_steps(x, :post) - plotattributes[:y] = make_steps(y, :pre) + plotattributes[:x] = make_steps(x, :post, false) + plotattributes[:y] = make_steps(y, :pre, false) seriestype := :path # handle fillrange - plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre) + plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre, false) # create a secondary series for the markers if plotattributes[:markershape] != :none @@ -227,12 +227,12 @@ end # create a path from steps @recipe function f(::Type{Val{:steppost}}, x, y, z) - plotattributes[:x] = make_steps(x, :pre) - plotattributes[:y] = make_steps(y, :post) + plotattributes[:x] = make_steps(x, :pre, false) + plotattributes[:y] = make_steps(y, :post, false) seriestype := :path # handle fillrange - plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post) + plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, false) # create a secondary series for the markers if plotattributes[:markershape] != :none From 0508d05299bb76017a507ba1eafde987ef0fc46e Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 20:16:53 -0700 Subject: [PATCH 02/10] Remove conditional from `make_steps` for loop --- src/recipes.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 285915d7..5ee52f5f 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -186,12 +186,11 @@ function make_steps(x::AbstractArray, st, even) n = length(x) n == 0 && return zeros(0) newx = zeros(2n - 1) - for i = 1:n + newx[1] = x[1] + for i = 2:n idx = 2i - 1 newx[idx] = x[i] - if i > 1 - newx[idx - 1] = x[st == :pre ? i : i - 1] - end + newx[idx - 1] = x[st == :pre ? i : i - 1] end return newx end From 10fa36cdd97628b8c6b8da664b9024c67da2f090 Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 20:21:12 -0700 Subject: [PATCH 03/10] Use `even` to tweak length of `make_steps` output If `even` in false, `make_steps` returns an odd-length (2n-1) Vector as it did before. If even is `true`, `make_steps` now returns an even-length (2n) Vector whose first (2n-1) elements are the same as before and whose final element is the same as the final element of the input Vector. --- src/recipes.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/recipes.jl b/src/recipes.jl index 5ee52f5f..52310696 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -185,13 +185,14 @@ make_steps(x, st, even) = x function make_steps(x::AbstractArray, st, even) n = length(x) n == 0 && return zeros(0) - newx = zeros(2n - 1) + newx = zeros(2n - (even ? 0 : 1)) newx[1] = x[1] for i = 2:n idx = 2i - 1 newx[idx] = x[i] newx[idx - 1] = x[st == :pre ? i : i - 1] end + even && (newx[end] = x[end]) return newx end make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t) From 3bb406e0ea773727d485f9ab84b8fd5828779b6c Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 20:35:08 -0700 Subject: [PATCH 04/10] Add `:mid` support to `make_steps` --- src/recipes.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/recipes.jl b/src/recipes.jl index 52310696..b188a33d 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -189,8 +189,12 @@ function make_steps(x::AbstractArray, st, even) newx[1] = x[1] for i = 2:n idx = 2i - 1 - newx[idx] = x[i] - newx[idx - 1] = x[st == :pre ? i : i - 1] + if st == :mid + newx[idx] = newx[idx-1] = (x[i] + x[i-1]) / 2 + else + newx[idx] = x[i] + newx[idx - 1] = x[st == :pre ? i : i - 1] + end end even && (newx[end] = x[end]) return newx From 50f1106cd7badc04aaf1aa0be38228ad38db7c22 Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 20:47:14 -0700 Subject: [PATCH 05/10] Add recipe for `seriestype=:stepmid` --- src/recipes.jl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/recipes.jl b/src/recipes.jl index b188a33d..1ecbea62 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -229,6 +229,31 @@ make_steps(t::Tuple, st, even) = Tuple(make_steps(ti, st, even) for ti in t) end @deps steppre path scatter +# create a path from steps +@recipe function f(::Type{Val{:stepmid}}, x, y, z) + plotattributes[:x] = make_steps(x, :mid, true) + plotattributes[:y] = make_steps(y, :post, true) + seriestype := :path + + # handle fillrange + plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, true) + + # create a secondary series for the markers + if plotattributes[:markershape] != :none + @series begin + seriestype := :scatter + x := x + y := y + label := "" + primary := false + () + end + markershape := :none + end + () +end +@deps stepmid path scatter + # create a path from steps @recipe function f(::Type{Val{:steppost}}, x, y, z) plotattributes[:x] = make_steps(x, :pre, false) From ddf6aa976012cf5b091c3d46a9796536c255883e Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 23:24:31 -0700 Subject: [PATCH 06/10] Make Plots framework aware of new :stepmid option --- src/args.jl | 4 ++-- src/axes.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/args.jl b/src/args.jl index 2452dfdf..12e75cdd 100644 --- a/src/args.jl +++ b/src/args.jl @@ -54,7 +54,7 @@ const _3dTypes = [ :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d ] const _allTypes = vcat([ - :none, :line, :path, :steppre, :steppost, :sticks, :scatter, + :none, :line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d, :density, :bar, :hline, :vline, @@ -101,7 +101,7 @@ const _typeAliases = Dict{Symbol,Symbol}( add_non_underscore_aliases!(_typeAliases) const _histogram_like = [:histogram, :barhist, :barbins] -const _line_like = [:line, :path, :steppre, :steppost] +const _line_like = [:line, :path, :steppre, :stepmid, :steppost] const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image] like_histogram(seriestype::Symbol) = seriestype in _histogram_like diff --git a/src/axes.jl b/src/axes.jl index 7173999e..e2f031ad 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -441,7 +441,7 @@ function widen(lmin, lmax, scale = :identity) end # figure out if widening is a good idea. -const _widen_seriestypes = (:line, :path, :steppre, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d) +const _widen_seriestypes = (:line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter, :barbins, :barhist, :histogram, :scatterbins, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :bar, :shape, :path3d, :scatter3d) function default_should_widen(axis::Axis) should_widen = false From c2cb60ff1209ddae0fb4fc180af63519c9cfbaec Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 23:25:57 -0700 Subject: [PATCH 07/10] Make Plots backends aware of new :stepmid option --- src/backends.jl | 4 +++- src/backends/inspectdr.jl | 2 +- src/backends/plotly.jl | 2 ++ src/backends/pyplot.jl | 8 +++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/backends.jl b/src/backends.jl index c6c54f22..85ebfe98 100644 --- a/src/backends.jl +++ b/src/backends.jl @@ -555,6 +555,7 @@ const _pyplot_attr = merge_with_base_supported([ const _pyplot_seriestype = [ :path, :steppre, + :stepmid, :steppost, :shape, :straightline, @@ -636,6 +637,7 @@ const _hdf5_attr = merge_with_base_supported([ const _hdf5_seriestype = [ :path, :steppre, + :stepmid, :steppost, :shape, :straightline, @@ -707,7 +709,7 @@ const _inspectdr_attr = merge_with_base_supported([ ]) const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot] const _inspectdr_seriestype = [ - :path, :scatter, :shape, :straightline, #, :steppre, :steppost + :path, :scatter, :shape, :straightline, #, :steppre, :stepmid, :steppost ] #see: _allMarkers, _shape_keys const _inspectdr_marker = Symbol[ diff --git a/src/backends/inspectdr.jl b/src/backends/inspectdr.jl index 005d3da2..e3c8dee3 100644 --- a/src/backends/inspectdr.jl +++ b/src/backends/inspectdr.jl @@ -290,7 +290,7 @@ For st in :shape: color = linecolor, fillcolor = fillcolor ) end - elseif st in (:path, :scatter, :straightline) #, :steppre, :steppost) + elseif st in (:path, :scatter, :straightline) #, :steppre, :stepmid, :steppost) #NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think). linewidth = series[:linewidth] #More efficient & allows some support for markerstrokewidth: diff --git a/src/backends/plotly.jl b/src/backends/plotly.jl index a9aff316..9ff603da 100644 --- a/src/backends/plotly.jl +++ b/src/backends/plotly.jl @@ -789,6 +789,8 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z :width => get_linewidth(series, i), :shape => if st == :steppre "vh" + elseif st == :stepmid + "hvh" elseif st == :steppost "hv" else diff --git a/src/backends/pyplot.jl b/src/backends/pyplot.jl index aca6bb64..e23838ac 100644 --- a/src/backends/pyplot.jl +++ b/src/backends/pyplot.jl @@ -152,12 +152,14 @@ end function py_stepstyle(seriestype::Symbol) seriestype == :steppost && return "steps-post" + seriestype == :stepmid && return "steps-mid" seriestype == :steppre && return "steps-pre" return "default" end function py_fillstepstyle(seriestype::Symbol) seriestype == :steppost && return "post" + seriestype == :stepmid && return "mid" seriestype == :steppre && return "pre" return nothing end @@ -408,7 +410,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # for each plotting command, optionally build and add a series handle to the list # line plot - if st in (:path, :path3d, :steppre, :steppost, :straightline) + if st in (:path, :path3d, :steppre, :stepmid, :steppost, :straightline) if maximum(series[:linewidth]) > 0 # TODO: check LineCollection alternative for speed # if length(segments) > 1 && (any(typeof(series[attr]) <: AbstractVector for attr in (:fillcolor, :fillalpha)) || series[:fill_z] !== nothing) && !(typeof(series[:linestyle]) <: AbstractVector) @@ -485,7 +487,7 @@ function py_add_series(plt::Plot{PyPlotBackend}, series::Series) # add markers? if series[:markershape] != :none && st in ( - :path, :scatter, :path3d, :scatter3d, :steppre, :steppost, :bar + :path, :scatter, :path3d, :scatter3d, :steppre, :stepmid, :steppost, :bar ) for segment in series_segments(series, :scatter) i, rng = segment.attr_index, segment.range @@ -1363,7 +1365,7 @@ function py_add_legend(plt::Plot, sp::Subplot, ax) linestyle = py_linestyle(series[:seriestype], get_linestyle(series)), capstyle = "butt" ) - elseif series[:seriestype] in (:path, :straightline, :scatter, :steppre, :steppost) + elseif series[:seriestype] in (:path, :straightline, :scatter, :steppre, :stepmid, :steppost) hasline = get_linewidth(series) > 0 PyPlot.plt."Line2D"((0, 1),(0,0), color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), From 0d528b7c82b63d9f60bf314838188265fff4d95d Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Wed, 24 Mar 2021 23:27:16 -0700 Subject: [PATCH 08/10] Add :stepmid to line types example plot --- src/examples.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples.jl b/src/examples.jl index cfc8e96f..963413bb 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -193,7 +193,7 @@ const _examples = PlotExample[ [ :( begin - linetypes = [:path :steppre :steppost :sticks :scatter] + linetypes = [:path :steppre :stepmid :steppost :sticks :scatter] n = length(linetypes) x = Vector[sort(rand(20)) for i = 1:n] y = rand(20, n) From 074c56867de56e9c0d9105bd7a47a04dfe4b761b Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Fri, 26 Mar 2021 10:49:19 -0700 Subject: [PATCH 09/10] Revert "Add :stepmid to line types example plot" This reverts commit 0d528b7c82b63d9f60bf314838188265fff4d95d. --- src/examples.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples.jl b/src/examples.jl index 963413bb..cfc8e96f 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -193,7 +193,7 @@ const _examples = PlotExample[ [ :( begin - linetypes = [:path :steppre :stepmid :steppost :sticks :scatter] + linetypes = [:path :steppre :steppost :sticks :scatter] n = length(linetypes) x = Vector[sort(rand(20)) for i = 1:n] y = rand(20, n) From b3bf5db9bc104f3bb1745ff5a9022fa68b8b8b16 Mon Sep 17 00:00:00 2001 From: David MacMahon Date: Fri, 26 Mar 2021 11:12:14 -0700 Subject: [PATCH 10/10] Add new "Steps Types" example/test plot 53 This new example/test plot showcases the various step-like `seriestype`s: `:steppre`, `:stepmid`, and `:steppost`. --- src/examples.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/examples.jl b/src/examples.jl index cfc8e96f..c834be44 100644 --- a/src/examples.jl +++ b/src/examples.jl @@ -1119,6 +1119,25 @@ const _examples = PlotExample[ quiver(x,y,z, quiver=(u,v,w)) end] ), + PlotExample( # 53 + "Step Types", + "A comparison of the various step-like `seriestype`s", + [ + :( + begin + x = 1:5 + y = [1, 2, 3, 2, 1] + default(shape=:circle) + plot( + plot(x, y, markershape=:circle, seriestype=:steppre, label="steppre"), + plot(x, y, markershape=:circle, seriestype=:stepmid, label="stepmid"), + plot(x, y, markershape=:circle, seriestype=:steppost, label="steppost"), + layout=(3,1) + ) + end + ), + ], + ), ] # Some constants for PlotDocs and PlotReferenceImages