diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b1222dc6..b20069a7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ - Added aesthetics for `Stairs` [#573](https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/573). +- Added `Volume`, `Stairs` aesthetic mapping and `stephistogram` analysis [#572](https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/572). + ## v0.8.12 - 2024-10-07 - Added `legend` keyword in `visual` to allow overriding legend element attributes [#570](https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/570). diff --git a/src/AlgebraOfGraphics.jl b/src/AlgebraOfGraphics.jl index 161c66b6d..af2575554 100644 --- a/src/AlgebraOfGraphics.jl +++ b/src/AlgebraOfGraphics.jl @@ -34,7 +34,7 @@ export hideinnerdecorations!, deleteemptyaxes! export Layer, Layers, ProcessedLayer, ProcessedLayers, zerolayer export Entry, AxisEntries export renamer, sorter, nonnumeric, verbatim, presorted -export density, histogram, linear, smooth, expectation, frequency, contours, filled_contours +export density, histogram, stephistogram, linear, smooth, expectation, frequency, contours, filled_contours export visual, data, geodata, dims, mapping export datetimeticks export draw, draw! @@ -70,6 +70,7 @@ include("transformations/frequency.jl") include("transformations/expectation.jl") include("transformations/contours.jl") include("transformations/filled_contours.jl") +include("transformations/stephistogram.jl") include("guides/guides.jl") include("guides/legend.jl") include("guides/colorbar.jl") diff --git a/src/aesthetics.jl b/src/aesthetics.jl index 8a2f69707..3def24f5d 100644 --- a/src/aesthetics.jl +++ b/src/aesthetics.jl @@ -166,6 +166,14 @@ function aesthetic_mapping(::Type{ScatterLines}, N::Int) ]) end +function aesthetic_mapping(::Type{Stairs}, ::Normal, ::Normal) + dictionary([ + pointlike_positionals(2)..., + :color => AesColor, + :linestyle => AesLineStyle, + ]) +end + function aesthetic_mapping(::Type{HLines}, ::Normal) dictionary([ 1 => AesY, @@ -218,6 +226,15 @@ function aesthetic_mapping(::Type{Heatmap}, ::Normal, ::Normal, ::Normal) ]) end +function aesthetic_mapping(::Type{Volume}, ::Normal, ::Normal, ::Normal, ::Normal) + dictionary([ + 1 => AesX, + 2 => AesY, + 3 => AesZ, + 4 => AesVolumeColor, # set to AesColor would not work + ]) +end + function aesthetic_mapping(::Type{LinesFill}, ::Normal, ::Normal) dictionary([ 1 => AesX, diff --git a/src/algebra/layers.jl b/src/algebra/layers.jl index 7f573a29e..bf56063a0 100644 --- a/src/algebra/layers.jl +++ b/src/algebra/layers.jl @@ -476,7 +476,7 @@ function full_rescale(data, aes::Type{AesMarkerSize}, scale::ContinuousScale) values_to_markersizes(data, props.sizerange, scale.extrema) end -full_rescale(data, aes::Type{<:Union{AesContourColor,AesABIntercept,AesABSlope}}, scale::ContinuousScale) = data # passthrough, this aes is a mock one anyway +full_rescale(data, aes::Type{<:Union{AesContourColor,AesABIntercept,AesABSlope,AesVolumeColor}}, scale::ContinuousScale) = data # passthrough, this aes is a mock one anyway function values_to_markersizes(data, sizerange, extrema) # we scale the area linearly with the values diff --git a/src/scales.jl b/src/scales.jl index 58089805c..65f039d05 100644 --- a/src/scales.jl +++ b/src/scales.jl @@ -24,6 +24,7 @@ struct AesText <: Aesthetic end # maybe aesthetics that completely avoid scales struct AesViolinSide <: Aesthetic end struct AesContourColor <: Aesthetic end # this is just so the third contour argument doesn't conflict with other things for now, it's complex to handle in its interplay with `color` and `levels` +struct AesVolumeColor <: Aesthetic end # this is the fourth argument of volume struct AesPlaceholder <: Aesthetic end # choropleth for example takes as first arg only geometries which avoid scales, but for now we still have to give an aes to 1, so this can serve for that purpose struct AesABIntercept <: Aesthetic end struct AesABSlope <: Aesthetic end diff --git a/src/transformations/stephistogram.jl b/src/transformations/stephistogram.jl new file mode 100644 index 000000000..f7b4f5feb --- /dev/null +++ b/src/transformations/stephistogram.jl @@ -0,0 +1,28 @@ +Base.@kwdef struct StepHistogramAnalysis{D, B} + datalimits::D=automatic + bins::B=automatic + closed::Symbol=:left + normalization::Symbol=:none +end + +function (h::StepHistogramAnalysis)(input::ProcessedLayer) + datalimits = h.datalimits === automatic ? defaultdatalimits(input.positional) : h.datalimits + options = valid_options(; datalimits, h.bins, h.closed, h.normalization) + + output = map(input) do p, n + hist = _histogram(Tuple(p); pairs(n)..., pairs(options)...) + edges, weights = hist.edges, hist.weights + return (map(midpoints, edges)..., weights), (;) + end + + N = length(input.positional) + @assert N == 1 "StepHistogram only supports 1D data" + label = h.normalization == :none ? "count" : string(h.normalization) + labels = set(output.labels, N+1 => label) + attributes = output.attributes + default_plottype = Stairs + plottype = Makie.plottype(input.plottype, default_plottype) + return ProcessedLayer(output; plottype, labels, attributes) +end + +stephistogram(; options...) = transformation(StepHistogramAnalysis(; options...)) \ No newline at end of file