diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index ec8aa27e7b2..9166a08f377 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -985,6 +985,34 @@ end f end +@reference_test "Log scale histogram (barplot)" begin + f = Figure() + hist( + f[1, 1], + RNG.randn(10^6); + axis=(; yscale=log2) + ) + hist( + f[1, 2], + RNG.randn(10^6); + axis=(; xscale=log2), + direction = :x + ) + # make a gap in histogram as edge case + hist( + f[2, 1], + filter!(x-> x<0 || x > 1.5, RNG.randn(10^6)); + axis=(; yscale=log10) + ) + hist( + f[2, 2], + filter!(x-> x<0 || x > 1.5, RNG.randn(10^6)); + axis=(; xscale=log10), + direction = :x + ) + f +end + @reference_test "Stephist" begin stephist(RNG.rand(10000)) current_figure() diff --git a/src/basic_recipes/barplot.jl b/src/basic_recipes/barplot.jl index b62164c1f15..0cc49a0d488 100644 --- a/src/basic_recipes/barplot.jl +++ b/src/basic_recipes/barplot.jl @@ -2,6 +2,38 @@ function bar_label_formatter(value::Number) return string(round(value; digits=3)) end +""" + bar_default_fillto(tf, ys, offset)::(ys, offset) + +Returns the default y-positions and offset positions for the given transform `tf`. + +In order to customize this for your own transformation type, you can dispatch on +`tf`. + +Returns a Tuple of new y positions and offset arrays. + +## Arguments +- `tf`: `plot.transformation.transform_func[]`. +- `ys`: The y-values passed to `barplot`. +- `offset`: The `offset` parameter passed to `barplot`. +""" +function bar_default_fillto(tf, ys, offset, in_y_direction) + return ys, offset +end + +# `fillto` is related to `y-axis` transofrmation only, thus we expect `tf::Tuple` +function bar_default_fillto(tf::Tuple, ys, offset, in_y_direction) + _logT = Union{typeof(log), typeof(log2), typeof(log10), Base.Fix1{typeof(log), <: Real}} + if in_y_direction && tf[2] isa _logT || (!in_y_direction && tf[1] isa _logT) + # x-scale log and !(in_y_direction) is equiavlent to y-scale log in_y_direction + # use the minimal non-zero y divided by 2 as lower bound for log scale + smart_fillto = minimum(y -> y<=0 ? oftype(y, Inf) : y, ys) / 2 + return clamp.(ys, smart_fillto, Inf), smart_fillto + else + return ys, offset + end +end + """ barplot(x, y; kwargs...) @@ -190,7 +222,7 @@ function Makie.plot!(p::BarPlot) label_aligns = Observable(Vec2f[]) label_offsets = Observable(Vec2f[]) label_colors = Observable(RGBAf[]) - function calculate_bars(xy, fillto, offset, width, dodge, n_dodge, gap, dodge_gap, stack, + function calculate_bars(xy, fillto, offset, transformation, width, dodge, n_dodge, gap, dodge_gap, stack, dir, bar_labels, flip_labels_at, label_color, color_over_background, color_over_bar, label_formatter, label_offset) @@ -217,7 +249,7 @@ function Makie.plot!(p::BarPlot) if stack === automatic if fillto === automatic - fillto = offset + y, fillto = bar_default_fillto(transformation, y, offset, in_y_direction) end elseif eltype(stack) <: Integer fillto === automatic || @warn "Ignore keyword fillto when keyword stack is provided" @@ -249,7 +281,7 @@ function Makie.plot!(p::BarPlot) return bar_rectangle.(x̂, y .+ offset, barwidth, fillto, in_y_direction) end - bars = lift(calculate_bars, p, p[1], p.fillto, p.offset, p.width, p.dodge, p.n_dodge, p.gap, + bars = lift(calculate_bars, p, p[1], p.fillto, p.offset, p.transformation.transform_func, p.width, p.dodge, p.n_dodge, p.gap, p.dodge_gap, p.stack, p.direction, p.bar_labels, p.flip_labels_at, p.label_color, p.color_over_background, p.color_over_bar, p.label_formatter, p.label_offset) diff --git a/src/display.jl b/src/display.jl index f3d61b8ef1c..90c2d05c26b 100644 --- a/src/display.jl +++ b/src/display.jl @@ -278,6 +278,10 @@ Save a `Scene` with the specified filename and format. ## All Backends - `resolution`: `(width::Int, height::Int)` of the scene in dimensionless units (equivalent to `px` for GLMakie and WGLMakie). +- `update`: Whether the figure should be updated before saving. This resets the limits of all Axes in the figure. Defaults to `true`. +- `backend`: Specify the `Makie` backend that should be used for saving. Defaults to the current backend. +- Further keywords will be forwarded to the screen. + ## CairoMakie