Fix vector attributes to bar plots (#3751)

This commit is contained in:
Yuval 2021-10-19 22:21:20 +03:00 committed by Zhanibek
parent e3a81e0712
commit dc98495514
3 changed files with 43 additions and 2 deletions

View File

@ -1232,6 +1232,23 @@ const _examples = PlotExample[
), ),
], ],
), ),
PlotExample( # 56
"Bar plot customizations",
"""
Width of bars may be specified as `bar_width`.
The bars' baseline may be specified as `fillto`.
Each may be scalar, or a vector spcifying one value per bar.
""",
[:(
begin
plot(bar([-1,0,2,3], [1,3,6,2],
fill_z = 4:-1:1, alpha = [1, 0.2, 0.8, 0.5], label = "", bar_width = 1:4),
bar(rand(5), bar_width=1.2, alpha=0.8,
color=[:lightsalmon, :tomato, :crimson, :firebrick, :darkred],
fillto=0:-0.1:-0.4, label="reds"))
end
)],
),
] ]
# Some constants for PlotDocs and PlotReferenceImages # Some constants for PlotDocs and PlotReferenceImages

View File

@ -508,6 +508,18 @@ end
primary := true primary := true
x := xseg.pts x := xseg.pts
y := yseg.pts y := yseg.pts
# expand attributes to match indices in new series data
for k in _segmenting_vector_attributes _segmenting_array_attributes
v = get(plotattributes, k, nothing)
if v isa AVec
if eachindex(v) != eachindex(y)
@warn "Indices $(eachindex(v)) of attribute `$k` do not match data indices $(eachindex(y))."
end
# Each segment is 6 elements long, including the NaN separator.
# There is no trailing NaN, so the last repetition is dropped.
plotattributes[k] = @view repeat(v; inner=6)[1:end-1]
end
end
() ()
end end

View File

@ -103,7 +103,10 @@ function series_segments(series::Series, seriestype::Symbol = :path; check = fal
segments = if has_attribute_segments(series) segments = if has_attribute_segments(series)
Iterators.flatten(map(nan_segments) do r Iterators.flatten(map(nan_segments) do r
if seriestype in (:scatter, :scatter3d) if seriestype == :shape
warn_on_inconsistent_shape_attr(series, x, y, z, r)
(SeriesSegment(r, first(r)),)
elseif seriestype in (:scatter, :scatter3d)
(SeriesSegment(i:i, i) for i in r) (SeriesSegment(i:i, i) for i in r)
else else
(SeriesSegment(i:(i + 1), i) for i in first(r):(last(r) - 1)) (SeriesSegment(i:(i + 1), i) for i in first(r):(last(r) - 1))
@ -140,6 +143,16 @@ function warn_on_attr_dim_mismatch(series, x, y, z, segments)
end end
end end
function warn_on_inconsistent_shape_attr(series, x, y, z, r)
for attr in _segmenting_vector_attributes
v = get(series, attr, nothing)
if v isa AVec && length(unique(v[r])) > 1
@warn "Different values of `$attr` specified for different shape vertices. Only first one will be used."
break
end
end
end
# helpers to figure out if there are NaN values in a list of array types # helpers to figure out if there are NaN values in a list of array types
anynan(i::Int, args::Tuple) = any(a -> try anynan(i::Int, args::Tuple) = any(a -> try
isnan(_cycle(a, i)) isnan(_cycle(a, i))
@ -573,7 +586,6 @@ const _segmenting_array_attributes = :line_z, :fill_z, :marker_z
function has_attribute_segments(series::Series) function has_attribute_segments(series::Series)
# we want to check if a series needs to be split into segments just because # we want to check if a series needs to be split into segments just because
# of its attributes # of its attributes
series[:seriestype] == :shape && return false
# check relevant attributes if they have multiple inputs # check relevant attributes if they have multiple inputs
return any( return any(
series[attr] isa AbstractVector && length(series[attr]) > 1 for series[attr] isa AbstractVector && length(series[attr]) > 1 for