Repository: JuliaPlots/Makie.jl (julia)

Issue:
`colorscale=-` results in a black image
Result of `image(randn(20, 20), colorscale=-)` is just an empty black image:
![Image](https://github.com/user-attachments/assets/20162007-d9ad-45ed-9a09-d1eadef4e5b0)
I would expect the same visual result as `image(-A)`, with the only difference being labels for the colorbar.

- [ ] what version of Makie are you running? (`]st -m Makie`) latest, v0.22.2
- [x] can you reproduce the bug with a fresh environment ? (`]activate --temp; add Makie`) yes
- [ ] What platform + GPU are you on? any

Pull request:
# Description

Fixes #4883

Wraps calls to `apply_scale(scale, colorrange)` in `extrema` so that the computed colorrange is robust to e.g. `colorscale = -`. 

Not sure this needs a reference test given it's a bug on the Makie end of things.

## Type of change

Delete options that do not apply:

- [X] Bug fix (non-breaking change which fixes an issue)

## Checklist

- [X] Added an entry in CHANGELOG.md (for new features and breaking changes)
- [ ] Added or changed relevant sections in the documentation
- [X] Added unit tests for new algorithms, conversion methods, etc.
- [ ] Added reference image tests for new plotting functions, recipes, visual options, etc.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e145a64e0e..bc994c81eaa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 - Improved compatibility of marker attributes with float32convert, fixing issues with scatter markers being render too small with `markerspace = :data` in an Axis [#4869](https://github.com/MakieOrg/Makie.jl/pull/4869)
 - Added `font` attribute and fixed faulty selection in `scatter`. Scatter fonts can now be themed with `markerfont`. [#4832](https://github.com/MakieOrg/Makie.jl/pull/4832)
 - Fixed categorical `cgrad` interpolating at small enough steps [#4858](https://github.com/MakieOrg/Makie.jl/pull/4858)
+- Fixed the computed `colorrange` being out of order with `colorscale = -` or similar colorscale functions that break sorting [#4884](https://github.com/MakieOrg/Makie.jl/pull/4884)
 - Added `transform_marker` to arrows [#4871](https://github.com/MakieOrg/Makie.jl/pull/4871)
 - Reverted change in `meshscatter` transformation behavior by using `transform_marker = true` as the default [#4871](https://github.com/MakieOrg/Makie.jl/pull/4871)
 - Fixed an error with Colorbar for categorical colormaps, where they displayed values out of colorrange and NaN. [#4894](https://github.com/MakieOrg/Makie.jl/pull/4894)
diff --git a/src/colorsampler.jl b/src/colorsampler.jl
index 1158d8b629c..4945a4a508e 100644
--- a/src/colorsampler.jl
+++ b/src/colorsampler.jl
@@ -135,6 +135,13 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f};
     return Sampler(cmap, uv, alpha, interpolation, Scaling())
 end
 
+"""
+    apply_scale(scale, x)
+
+Applies the scale function / callable `scale` to each element of `x`.  
+If `scale` is an Observable then this returns an Observable via `lift`,
+otherwise simply returns `broadcast(scale, x)`.
+"""
 apply_scale(scale::AbstractObservable, x) = lift(apply_scale, scale, x)
 apply_scale(::Union{Nothing,typeof(identity)}, x) = x  # noop
 apply_scale(scale, x) = broadcast(scale, x)
@@ -166,8 +173,7 @@ function numbers_to_colors(
     )::Union{Array{RGBAf, N},RGBAf} where {N}
 
     cmin, cmax = colorrange
-    scaled_cmin = apply_scale(colorscale, cmin)
-    scaled_cmax = apply_scale(colorscale, cmax)
+    scaled_cmin, scaled_cmax = extrema(apply_scale(colorscale, (cmin, cmax)))
 
     return map(numbers) do number
         scaled_number = apply_scale(colorscale, Float64(number))  # ints don't work in interpolated_getindex
@@ -307,7 +313,7 @@ function _colormapping(
     end
 
     colorrange_scaled = lift(colorrange, colorscale; ignore_equal_values=true) do range, scale
-        return Vec2f(apply_scale(scale, range))
+        return Vec2f(extrema(apply_scale(scale, range)))
     end
 
     color_scaled = Observable(el32convert(apply_scale(colorscale[], color_tight[])))


Test patch:
diff --git a/test/issues.jl b/test/issues.jl
index 0013c819a78..15f8bca4cb2 100644
--- a/test/issues.jl
+++ b/test/issues.jl
@@ -46,4 +46,12 @@
         @test p.plots[1].plots[1].transformation.model[][3, 4] == 10.0
         @test p.plots[1].plots[2].transformation.model[][3, 4] == 10.0
     end
+
+    @testset "#4883 colorscale that breaks sort" begin
+        data = Float32.(Makie.peaks())
+        f, a, p = image(data; colorscale = -)
+        @test p.calculated_colors[].colorrange_scaled[][1] == -maximum(data)
+        @test p.calculated_colors[].colorrange_scaled[][2] == -minimum(data)
+        @test issorted(p.calculated_colors[].colorrange_scaled[])
+    end
 end