Skip to content

Commit 9be4352

Browse files
authored
Make singular limits nonsingular (#634)
Fixes #590 Calculation of colors and markersizes failed when the limits were singular, so with this PR they are expanded to 0, v or v, 0 depending on if v is below or above zero, and to 0, 1 if v is zero. ```julia f = Figure(size = (500, 600)) fg = draw!(f[1, 1], pregrouped([1:3], [1:2], [ones(3, 2)]) * visual(Heatmap)) colorbar!(f[1, 2], fg) fg2 = draw!(f[2, 1], pregrouped([1:3], [1:2], [zeros(3, 2)]) * visual(Heatmap)) colorbar!(f[2, 2], fg2) fg3 = draw!(f[3, 1], pregrouped([1:3], [1:2], [-2 .* ones(3, 2)]) * visual(Heatmap)) colorbar!(f[3, 2], fg3) fg4 = draw!(f[1, 3], mapping(1:5, 1:5, markersize = ones(5)) * visual(Scatter)) legend!(f[1, 4], fg4) fg5 = draw!(f[2, 3], mapping(1:5, 1:5, markersize = zeros(5)) * visual(Scatter)) legend!(f[2, 4], fg5) fg6 = draw!(f[3, 3], mapping(1:5, 1:5, markersize = -2 .* ones(5)) * visual(Scatter)) legend!(f[3, 4], fg6) f ``` <img width="490" alt="image" src="https://github.com/user-attachments/assets/c46816e5-6ec9-4d17-858c-08f3bd0e36b2" />
1 parent 0f0cea7 commit 9be4352

File tree

6 files changed

+50
-7
lines changed

6 files changed

+50
-7
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Added better error messages for the common case of failing to construct single element NamedTuples in calls like `draw(axis = (key = value))` [#630](https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/630).
6+
- Fixed bug when color or markersize mappings had singular limits by expanding the limits to `(0, v)`, `(-v, 0)` or `(0, 1)` [#634](https://github.com/MakieOrg/AlgebraOfGraphics.jl/pull/634).
67

78
## v0.10.0 - 2025-03-30
89

src/algebra/layers.jl

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,10 +496,35 @@ end
496496

497497
full_rescale(data, aes, scale::CategoricalScale) = rescale(data, scale)
498498

499+
function nonsingular_colorrange(scale::ContinuousScale)
500+
props = scale.props.aesprops::AesColorContinuousProps
501+
cr = @something(props.colorrange, scale.extrema)
502+
nonsingular_limits(cr)
503+
end
504+
505+
# expand singular limits to (0, v) or (v, 0) if singular value v is nonzero
506+
# or to (0, 1) if it is, which should be easier to read than choosing a middle
507+
# value like it's done in Makie with axis limits
508+
function nonsingular_limits(r)
509+
if r[1] == r[2]
510+
if r[1] == 0
511+
return (r[1], oneunit(r[1]))
512+
else
513+
if r[1] < 0
514+
return (r[1], false * r[1])
515+
else
516+
return (false * r[1], r[1])
517+
end
518+
end
519+
else
520+
return r
521+
end
522+
end
523+
499524
function full_rescale(data, aes::Type{AesColor}, scale::ContinuousScale)
500525
props = scale.props.aesprops::AesColorContinuousProps
501526
colormap = Makie.to_colormap(@something(props.colormap, default_colormap()))
502-
colorrange = Makie.Vec2(@something(props.colorrange, scale.extrema))
527+
colorrange = Makie.Vec2(nonsingular_colorrange(scale))
503528
lowclip = Makie.to_color(@something(props.lowclip, first(colormap)))
504529
highclip = Makie.to_color(@something(props.highclip, last(colormap)))
505530
nan_color = Makie.to_color(@something(props.nan_color, RGBAf(0, 0, 0, 0)))
@@ -514,9 +539,9 @@ function full_rescale(data, aes::Type{AesColor}, scale::ContinuousScale)
514539
)
515540
end
516541

517-
function full_rescale(data, aes::Type{AesMarkerSize}, scale::ContinuousScale)
542+
function full_rescale(data, ::Type{AesMarkerSize}, scale::ContinuousScale)
518543
props = scale.props.aesprops::AesMarkerSizeContinuousProps
519-
values_to_markersizes(data, props.sizerange, scale.extrema)
544+
values_to_markersizes(data, props.sizerange, nonsingular_limits(scale.extrema))
520545
end
521546

522547
full_rescale(data, aes::Type{<:Union{AesContourColor,AesABIntercept,AesABSlope}}, scale::ContinuousScale) = data # passthrough, this aes is a mock one anyway
@@ -568,7 +593,7 @@ function to_entry(P::Type{Heatmap}, p::ProcessedLayer, categoricalscales::Dictio
568593
else
569594
color_attributes = dictionary([
570595
:colormap => @something(scale.props.aesprops.colormap, default_colormap()),
571-
:colorrange => @something(scale.props.aesprops.colorrange, scale.extrema),
596+
:colorrange => nonsingular_colorrange(scale),
572597
:nan_color => @something(scale.props.aesprops.nan_color, :transparent),
573598
:lowclip => @something(scale.props.aesprops.lowclip, Makie.automatic),
574599
:highclip => @something(scale.props.aesprops.highclip, Makie.automatic),

src/guides/colorbar.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ end
5555

5656
function continuous_colorbar(colorscale::ContinuousScale)
5757
label = getlabel(colorscale)
58-
limits = @something colorscale.props.aesprops.colorrange colorscale.extrema
58+
limits = nonsingular_colorrange(colorscale)
5959
is_highclipped = limits[2] < colorscale.extrema[2]
6060
is_lowclipped = limits[1] > colorscale.extrema[1]
6161

src/guides/legend.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ end
300300
datavalues_plotvalues_datalabels(aes, scale::CategoricalScale) = datavalues(scale), plotvalues(scale), datalabels(scale)
301301
function datavalues_plotvalues_datalabels(aes::Type{AesMarkerSize}, scale::ContinuousScale)
302302
props = scale.props.aesprops::AesMarkerSizeContinuousProps
303-
_, s_extrema = strip_units(scale, collect(scale.extrema))
303+
_, s_extrema = strip_units(scale, collect(nonsingular_limits(scale.extrema)))
304304
tickvalues, ticklabels = Makie.get_ticks(props.ticks, identity, props.tickformat, s_extrema...)
305305
t_extrema = extrema(tickvalues)
306306
if t_extrema[1] < s_extrema[1] || t_extrema[2] > s_extrema[2]

test/reference_tests.jl

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,4 +1331,21 @@ reftest("hidden axis labels col row") do
13311331
mapping(:x, :y, row = :group)
13321332
draw!(f[1, 2], rowspec, facet = (; linkxaxes = false))
13331333
f
1334-
end
1334+
end
1335+
1336+
reftest("singular color and markersize limits", true) do
1337+
f = Figure(size = (500, 600))
1338+
fg = draw!(f[1, 1], pregrouped([1:3], [1:2], [ones(3, 2)]) * visual(Heatmap))
1339+
colorbar!(f[1, 2], fg)
1340+
fg2 = draw!(f[2, 1], pregrouped([1:3], [1:2], [zeros(3, 2)]) * visual(Heatmap))
1341+
colorbar!(f[2, 2], fg2)
1342+
fg3 = draw!(f[3, 1], pregrouped([1:3], [1:2], [-2 .* ones(3, 2)]) * visual(Heatmap))
1343+
colorbar!(f[3, 2], fg3)
1344+
fg4 = draw!(f[1, 3], mapping(1:5, 1:5, markersize = ones(5)) * visual(Scatter))
1345+
legend!(f[1, 4], fg4)
1346+
fg5 = draw!(f[2, 3], mapping(1:5, 1:5, markersize = zeros(5)) * visual(Scatter))
1347+
legend!(f[2, 4], fg5)
1348+
fg6 = draw!(f[3, 3], mapping(1:5, 1:5, markersize = -2 .* ones(5)) * visual(Scatter))
1349+
legend!(f[3, 4], fg6)
1350+
f
1351+
end
56 KB
Loading

0 commit comments

Comments
 (0)