Merge pull request #3382 from david-macmahon/stepmid-branch

Add support for `seriestype=:stepmid`
This commit is contained in:
Daniel Schwabeneder 2021-03-28 21:27:12 +02:00 committed by GitHub
commit 23cbfe9378
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 22 deletions

View File

@ -54,7 +54,7 @@ const _3dTypes = [
:path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d :path3d, :scatter3d, :surface, :wireframe, :contour3d, :volume, :mesh3d
] ]
const _allTypes = vcat([ const _allTypes = vcat([
:none, :line, :path, :steppre, :steppost, :sticks, :scatter, :none, :line, :path, :steppre, :stepmid, :steppost, :sticks, :scatter,
:heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins, :heatmap, :hexbin, :barbins, :barhist, :histogram, :scatterbins,
:scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d, :scatterhist, :stepbins, :stephist, :bins2d, :histogram2d, :histogram3d,
:density, :bar, :hline, :vline, :density, :bar, :hline, :vline,
@ -101,7 +101,7 @@ const _typeAliases = Dict{Symbol,Symbol}(
add_non_underscore_aliases!(_typeAliases) add_non_underscore_aliases!(_typeAliases)
const _histogram_like = [:histogram, :barhist, :barbins] 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] const _surface_like = [:contour, :contourf, :contour3d, :heatmap, :surface, :wireframe, :image]
like_histogram(seriestype::Symbol) = seriestype in _histogram_like like_histogram(seriestype::Symbol) = seriestype in _histogram_like

View File

@ -441,7 +441,7 @@ function widen(lmin, lmax, scale = :identity)
end end
# figure out if widening is a good idea. # 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) function default_should_widen(axis::Axis)
should_widen = false should_widen = false

View File

@ -555,6 +555,7 @@ const _pyplot_attr = merge_with_base_supported([
const _pyplot_seriestype = [ const _pyplot_seriestype = [
:path, :path,
:steppre, :steppre,
:stepmid,
:steppost, :steppost,
:shape, :shape,
:straightline, :straightline,
@ -636,6 +637,7 @@ const _hdf5_attr = merge_with_base_supported([
const _hdf5_seriestype = [ const _hdf5_seriestype = [
:path, :path,
:steppre, :steppre,
:stepmid,
:steppost, :steppost,
:shape, :shape,
:straightline, :straightline,
@ -707,7 +709,7 @@ const _inspectdr_attr = merge_with_base_supported([
]) ])
const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot] const _inspectdr_style = [:auto, :solid, :dash, :dot, :dashdot]
const _inspectdr_seriestype = [ const _inspectdr_seriestype = [
:path, :scatter, :shape, :straightline, #, :steppre, :steppost :path, :scatter, :shape, :straightline, #, :steppre, :stepmid, :steppost
] ]
#see: _allMarkers, _shape_keys #see: _allMarkers, _shape_keys
const _inspectdr_marker = Symbol[ const _inspectdr_marker = Symbol[

View File

@ -287,7 +287,7 @@ For st in :shape:
color = linecolor, fillcolor = fillcolor color = linecolor, fillcolor = fillcolor
) )
end 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). #NOTE: In Plots.jl, :scatter plots have 0-linewidths (I think).
linewidth = series[:linewidth] linewidth = series[:linewidth]
#More efficient & allows some support for markerstrokewidth: #More efficient & allows some support for markerstrokewidth:

View File

@ -789,6 +789,8 @@ function plotly_series_segments(series::Series, plotattributes_base::KW, x, y, z
:width => get_linewidth(series, i), :width => get_linewidth(series, i),
:shape => if st == :steppre :shape => if st == :steppre
"vh" "vh"
elseif st == :stepmid
"hvh"
elseif st == :steppost elseif st == :steppost
"hv" "hv"
else else

View File

@ -152,12 +152,14 @@ end
function py_stepstyle(seriestype::Symbol) function py_stepstyle(seriestype::Symbol)
seriestype == :steppost && return "steps-post" seriestype == :steppost && return "steps-post"
seriestype == :stepmid && return "steps-mid"
seriestype == :steppre && return "steps-pre" seriestype == :steppre && return "steps-pre"
return "default" return "default"
end end
function py_fillstepstyle(seriestype::Symbol) function py_fillstepstyle(seriestype::Symbol)
seriestype == :steppost && return "post" seriestype == :steppost && return "post"
seriestype == :stepmid && return "mid"
seriestype == :steppre && return "pre" seriestype == :steppre && return "pre"
return nothing return nothing
end 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 # for each plotting command, optionally build and add a series handle to the list
# line plot # line plot
if st in (:path, :path3d, :steppre, :steppost, :straightline) if st in (:path, :path3d, :steppre, :stepmid, :steppost, :straightline)
if maximum(series[:linewidth]) > 0 if maximum(series[:linewidth]) > 0
# TODO: check LineCollection alternative for speed # 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) # 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? # add markers?
if series[:markershape] != :none && st in ( 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) for segment in series_segments(series, :scatter)
i, rng = segment.attr_index, segment.range 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)), linestyle = py_linestyle(series[:seriestype], get_linestyle(series)),
capstyle = "butt" 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 hasline = get_linewidth(series) > 0
PyPlot.plt."Line2D"((0, 1),(0,0), PyPlot.plt."Line2D"((0, 1),(0,0),
color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)), color = py_color(single_color(get_linecolor(series, clims)), get_linealpha(series)),

View File

@ -1119,6 +1119,25 @@ const _examples = PlotExample[
quiver(x,y,z, quiver=(u,v,w)) quiver(x,y,z, quiver=(u,v,w))
end] 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 # Some constants for PlotDocs and PlotReferenceImages

View File

@ -181,33 +181,37 @@ end
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# steps # steps
make_steps(x, st) = x make_steps(x, st, even) = x
function make_steps(x::AbstractArray, st) function make_steps(x::AbstractArray, st, even)
n = length(x) n = length(x)
n == 0 && return zeros(0) n == 0 && return zeros(0)
newx = zeros(2n - 1) newx = zeros(2n - (even ? 0 : 1))
for i = 1:n newx[1] = x[1]
for i = 2:n
idx = 2i - 1 idx = 2i - 1
newx[idx] = x[i] if st == :mid
if i > 1 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] newx[idx - 1] = x[st == :pre ? i : i - 1]
end end
end end
even && (newx[end] = x[end])
return newx return newx
end 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 @nospecialize
# create a path from steps # create a path from steps
@recipe function f(::Type{Val{:steppre}}, x, y, z) @recipe function f(::Type{Val{:steppre}}, x, y, z)
plotattributes[:x] = make_steps(x, :post) plotattributes[:x] = make_steps(x, :post, false)
plotattributes[:y] = make_steps(y, :pre) plotattributes[:y] = make_steps(y, :pre, false)
seriestype := :path seriestype := :path
# handle fillrange # handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre) plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :pre, false)
# create a secondary series for the markers # create a secondary series for the markers
if plotattributes[:markershape] != :none if plotattributes[:markershape] != :none
@ -226,13 +230,38 @@ end
@deps steppre path scatter @deps steppre path scatter
# create a path from steps # create a path from steps
@recipe function f(::Type{Val{:steppost}}, x, y, z) @recipe function f(::Type{Val{:stepmid}}, x, y, z)
plotattributes[:x] = make_steps(x, :pre) plotattributes[:x] = make_steps(x, :mid, true)
plotattributes[:y] = make_steps(y, :post) plotattributes[:y] = make_steps(y, :post, true)
seriestype := :path seriestype := :path
# handle fillrange # handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post) 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)
plotattributes[:y] = make_steps(y, :post, false)
seriestype := :path
# handle fillrange
plotattributes[:fillrange] = make_steps(plotattributes[:fillrange], :post, false)
# create a secondary series for the markers # create a secondary series for the markers
if plotattributes[:markershape] != :none if plotattributes[:markershape] != :none