From af19465b144eed81a73d48a74d08791a0abe7a90 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Tue, 13 Dec 2022 09:58:43 +0100 Subject: [PATCH 01/38] fix `Colorbar` `scale` --- ReferenceTests/src/tests/examples2d.jl | 8 ++++++++ src/makielayout/blocks/axis.jl | 2 +- src/makielayout/blocks/colorbar.jl | 5 +++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 04c134fbe1f..11c0f2a8b06 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -580,6 +580,14 @@ end fig end +@reference_test "scaled colormap" begin + x = 10.0.^(1:0.1:4) + y = 1.0:0.1:5.0 + fig, ax, hm = heatmap(x, y, (x, y) -> log10(x); axis = (; xscale = log10)) + Colorbar(fig[1, 2], hm; scale = log10) + fig +end + @reference_test "multi rect with poly" begin # use thick strokewidth, so it will make tests fail if something is missing poly([Rect2f(0, 0, 1, 1)], color=:green, strokewidth=100, strokecolor=:black) diff --git a/src/makielayout/blocks/axis.jl b/src/makielayout/blocks/axis.jl index 5b5a1180320..afb04bf7b2a 100644 --- a/src/makielayout/blocks/axis.jl +++ b/src/makielayout/blocks/axis.jl @@ -818,7 +818,7 @@ function expandlimits(lims, margin_low, margin_high, scale) w_scaled = lims_scaled[2] - lims_scaled[1] d_low_scaled = w_scaled * margin_low d_high_scaled = w_scaled * margin_high - inverse = Makie.inverse_transform(scale) + inverse = inverse_transform(scale) lims = inverse.((lims_scaled[1] - d_low_scaled, lims_scaled[2] + d_high_scaled)) # guard against singular limits from something like a vline or hline diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index e29b95e9928..dd2b60ca3d8 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -87,6 +87,8 @@ function initialize_block!(cb::Colorbar) return something(limits, colorrange, (0, 1)) end + unscaled_limits = @lift inverse_transform($(cb.scale)).($limits) + onany(cb.size, cb.vertical) do sz, vertical if vertical cb.layoutobservables.autosize[] = (sz, nothing) @@ -170,7 +172,6 @@ function initialize_block!(cb::Colorbar) # for categorical colormaps we make a number of rectangle polys rects_and_colors = lift(barbox, cb.vertical, steps, cgradient, cb.scale, limits) do bbox, v, steps, gradient, scale, lims - # we need to convert the 0 to 1 steps into rescaled 0 to 1 steps given the # colormap's `scale` attribute @@ -313,7 +314,7 @@ function initialize_block!(cb::Colorbar) end axis = LineAxis(blockscene, endpoints = axispoints, flipped = cb.flipaxis, - limits = limits, ticklabelalign = cb.ticklabelalign, label = cb.label, + limits = unscaled_limits, ticklabelalign = cb.ticklabelalign, label = cb.label, labelpadding = cb.labelpadding, labelvisible = cb.labelvisible, labelsize = cb.labelsize, labelcolor = cb.labelcolor, labelrotation = cb.labelrotation, labelfont = cb.labelfont, ticklabelfont = cb.ticklabelfont, ticks = cb.ticks, tickformat = cb.tickformat, From 6180d8df4177b1f22281a55135bf9ace907a3a2b Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 22 Dec 2022 16:48:37 +0100 Subject: [PATCH 02/38] fix axis scaled colormap --- CairoMakie/src/utils.jl | 5 ++-- src/layouting/transformation.jl | 10 +++++++ src/makielayout/blocks/colorbar.jl | 48 +++++++++++++----------------- src/makielayout/lineaxis.jl | 6 ++-- 4 files changed, 36 insertions(+), 33 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 695f957aa0e..b3c42104540 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -123,12 +123,13 @@ end function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) Makie.@get_attribute attributes (colormap, colorrange, nan_color, lowclip, highclip) - + tr = reduce(∘, Makie.transform_func_obs(attributes)[]) nan_color = Makie.to_color(nan_color) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in img] + colorrange = tr.(colorrange) + [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in tr.(img)] end to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 98af0448537..5ba7c581e24 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -360,6 +360,16 @@ function inv_symlog10(x, low, high) end end +const CONCRETE_INVERSE_SCALES = Union{ + typeof(log10), + typeof(log), + typeof(log2), + typeof(sqrt), + typeof(pseudolog10), + typeof(logit), + Symlog10, +} + inverse_transform(::typeof(identity)) = identity inverse_transform(::typeof(log10)) = exp10 inverse_transform(::typeof(log)) = exp diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index dd2b60ca3d8..0cc13fca563 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -77,6 +77,15 @@ function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs.. end +unscale_limits(lims, _) = lims # noop +function unscale_limits(lims, scale::CONCRETE_INVERSE_SCALES) + inverse_transform(scale).(lims) +end + +colorbar_range(start, stop, length, _) = LinRange(start, stop, length) # noop +function colorbar_range(start, stop, length, scale::CONCRETE_INVERSE_SCALES) + inverse_transform(scale).(range(start, stop; length)) +end function initialize_block!(cb::Colorbar) blockscene = cb.blockscene @@ -87,8 +96,6 @@ function initialize_block!(cb::Colorbar) return something(limits, colorrange, (0, 1)) end - unscaled_limits = @lift inverse_transform($(cb.scale)).($limits) - onany(cb.size, cb.vertical) do sz, vertical if vertical cb.layoutobservables.autosize[] = (sz, nothing) @@ -152,11 +159,11 @@ function initialize_block!(cb::Colorbar) map_is_categorical = lift(x -> x isa PlotUtils.CategoricalColorGradient, cgradient) - steps = lift(cgradient, cb.nsteps) do cgradient, n + steps = lift(cgradient, cb.nsteps, cb.scale) do cgradient, n, scale s = if cgradient isa PlotUtils.CategoricalColorGradient cgradient.values else - collect(LinRange(0, 1, n)) + collect(colorbar_range(0, 1, n, scale)) end::Vector{Float64} end @@ -207,7 +214,7 @@ function initialize_block!(cb::Colorbar) continous_pixels = lift(cb.vertical, cb.nsteps, cgradient, limits, cb.scale) do v, n, grad, lims, scale - s_steps = scaled_steps(LinRange(0, 1, n), scale, lims) + s_steps = scaled_steps(colorbar_range(0, 1, n, scale), scale, lims) px = get.(Ref(grad), s_steps) v ? reshape(px, 1, n) : reshape(px, n, 1) end @@ -269,24 +276,16 @@ function initialize_block!(cb::Colorbar) borderpoints = lift(barbox, highclip_tri_visible, lowclip_tri_visible) do bb, hcv, lcv if cb.vertical[] points = [bottomright(bb), topright(bb)] - if hcv - push!(points, highclip_tri[][3]) - end + hcv && push!(points, highclip_tri[][3]) append!(points, [topleft(bb), bottomleft(bb)]) - if lcv - push!(points, lowclip_tri[][3]) - end + lcv && push!(points, lowclip_tri[][3]) push!(points, bottomright(bb)) points else points = [bottomleft(bb), bottomright(bb)] - if hcv - push!(points, highclip_tri[][3]) - end + hcv && push!(points, highclip_tri[][3]) append!(points, [topright(bb), topleft(bb)]) - if lcv - push!(points, lowclip_tri[][3]) - end + lcv && push!(points, lowclip_tri[][3]) push!(points, bottomleft(bb)) points end @@ -314,7 +313,7 @@ function initialize_block!(cb::Colorbar) end axis = LineAxis(blockscene, endpoints = axispoints, flipped = cb.flipaxis, - limits = unscaled_limits, ticklabelalign = cb.ticklabelalign, label = cb.label, + limits = limits, ticklabelalign = cb.ticklabelalign, label = cb.label, labelpadding = cb.labelpadding, labelvisible = cb.labelvisible, labelsize = cb.labelsize, labelcolor = cb.labelcolor, labelrotation = cb.labelrotation, labelfont = cb.labelfont, ticklabelfont = cb.ticklabelfont, ticks = cb.ticks, tickformat = cb.tickformat, @@ -330,11 +329,7 @@ function initialize_block!(cb::Colorbar) cb.axis = axis - - onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, - vertical, flipaxis - - + onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, vertical, flipaxis left, right, top, bottom = 0f0, 0f0, 0f0, 0f0 if vertical @@ -368,10 +363,7 @@ end Sets the space allocated for the ticklabels of the `Colorbar` to the minimum that is needed and returns that value. """ -function tight_ticklabel_spacing!(cb::Colorbar) - space = tight_ticklabel_spacing!(cb.axis) - return space -end +tight_ticklabel_spacing!(cb::Colorbar) = tight_ticklabel_spacing!(cb.axis) function scaled_steps(steps, scale, lims) # first scale to limits so we can actually apply the scale to the values @@ -380,5 +372,5 @@ function scaled_steps(steps, scale, lims) # scale with scaling function s_limits_scaled = scale.(s_limits) # then rescale to 0 to 1 - s_scaled = (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) + (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) end diff --git a/src/makielayout/lineaxis.jl b/src/makielayout/lineaxis.jl index aed8d714e90..4558746d9af 100644 --- a/src/makielayout/lineaxis.jl +++ b/src/makielayout/lineaxis.jl @@ -687,7 +687,8 @@ function get_ticks(m::MultiplesTicks, any_scale, ::Automatic, vmin, vmax) multiples .* m.multiple, Showoff.showoff(multiples) .* m.suffix end -function get_minor_tickvalues(i::IntervalsBetween, scale, tickvalues, vmin, vmax) +# identity or unsupported scales +function get_minor_tickvalues(i::IntervalsBetween, _, tickvalues, vmin, vmax) vals = Float64[] length(tickvalues) < 2 && return vals n = i.n @@ -720,8 +721,7 @@ function get_minor_tickvalues(i::IntervalsBetween, scale, tickvalues, vmin, vmax end # for log scales, we need to step in log steps at the edges -function get_minor_tickvalues(i::IntervalsBetween, scale::Union{typeof(log), typeof(log2), typeof(log10)}, tickvalues, vmin, vmax) - +function get_minor_tickvalues(i::IntervalsBetween, scale::CONCRETE_INVERSE_SCALES, tickvalues, vmin, vmax) vals = Float64[] length(tickvalues) < 2 && return vals n = i.n From 915618d11e9665382470dcccbffa981d4ec7417d Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 11:26:51 +0100 Subject: [PATCH 03/38] fix colormap sampling --- CairoMakie/src/utils.jl | 6 +++--- src/colorsampler.jl | 20 ++++++++++---------- src/layouting/transformation.jl | 13 ++++++++++++- src/makielayout/blocks/colorbar.jl | 9 +-------- src/makielayout/lineaxis.jl | 2 +- 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index b3c42104540..137732c0270 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -123,13 +123,13 @@ end function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) Makie.@get_attribute attributes (colormap, colorrange, nan_color, lowclip, highclip) - tr = reduce(∘, Makie.transform_func_obs(attributes)[]) + transform = Makie.composed_transform_func(attributes) nan_color = Makie.to_color(nan_color) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - colorrange = tr.(colorrange) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in tr.(img)] + colorrange = transform.(colorrange) + [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in transform.(img)] end to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) diff --git a/src/colorsampler.jl b/src/colorsampler.jl index a730f0931ee..a52ad29ff0f 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -131,31 +131,31 @@ end function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} - _colorrange = get_attribute(primitive, :colorrange)::Union{Nothing, Vec2f} - colorrange = if isnothing(_colorrange) + colorrange = get_attribute(primitive, :colorrange)::Union{Nothing, Vec2f} + transform = composed_transform_func(primitive) + cmin, cmax = if isnothing(colorrange) # TODO, plot primitive should always expand automatic values - Vec2f(extrema_nan(numbers)) + transform.(Vec2f(extrema_nan(numbers))) else - _colorrange + transform.(colorrange) end lowclip = get_attribute(primitive, :lowclip) highclip = get_attribute(primitive, :highclip) nan_color = get_attribute(primitive, :nan_color, RGBAf(0,0,0,0)) - cmin, cmax = colorrange::Vec2f - return map(numbers) do number - if isnan(number) + scaled_number = transform(Float64(number)) # ints don't work in interpolated_getindex + if isnan(scaled_number) return nan_color - elseif !isnothing(lowclip) && number < cmin + elseif !isnothing(lowclip) && scaled_number < cmin return lowclip - elseif !isnothing(highclip) && number > cmax + elseif !isnothing(highclip) && scaled_number > cmax return highclip end return interpolated_getindex( colormap, - Float64(number), # ints don't work in interpolated_getindex + scaled_number, (cmin, cmax)) end end diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 5ba7c581e24..0169f5b5d38 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -195,6 +195,16 @@ transformationmatrix(x) = transformation(x).model transform_func(x) = transform_func_obs(x)[] transform_func_obs(x) = transformation(x).transform_func +reduce_transform(x::Tuple) = reduce(∘, x) +reduce_transform(x) = x + +""" + composed_transform_func(x) + +Returns transformation composition e.g. log10 ∘ identity for xscale=log10 in 2D. +""" +composed_transform_func(x) = reduce_transform(transform_func(x)) + """ apply_transform(f, data, space) Apply the data transform func to the data if the space matches one @@ -360,7 +370,8 @@ function inv_symlog10(x, low, high) end end -const CONCRETE_INVERSE_SCALES = Union{ +const INVERSABLE_SCALES = Union{ + # typeof(identity), # no, this is a noop typeof(log10), typeof(log), typeof(log2), diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index 0cc13fca563..cc245c7ee1d 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -25,7 +25,6 @@ function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") end end - Colorbar( fig_or_scene; colormap = plot.colormap, @@ -41,7 +40,6 @@ function Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") end end - Colorbar( fig_or_scene; colormap = heatmap.colormap, @@ -77,13 +75,8 @@ function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs.. end -unscale_limits(lims, _) = lims # noop -function unscale_limits(lims, scale::CONCRETE_INVERSE_SCALES) - inverse_transform(scale).(lims) -end - colorbar_range(start, stop, length, _) = LinRange(start, stop, length) # noop -function colorbar_range(start, stop, length, scale::CONCRETE_INVERSE_SCALES) +function colorbar_range(start, stop, length, scale::INVERSABLE_SCALES) inverse_transform(scale).(range(start, stop; length)) end diff --git a/src/makielayout/lineaxis.jl b/src/makielayout/lineaxis.jl index 4558746d9af..a38e3b9bca7 100644 --- a/src/makielayout/lineaxis.jl +++ b/src/makielayout/lineaxis.jl @@ -721,7 +721,7 @@ function get_minor_tickvalues(i::IntervalsBetween, _, tickvalues, vmin, vmax) end # for log scales, we need to step in log steps at the edges -function get_minor_tickvalues(i::IntervalsBetween, scale::CONCRETE_INVERSE_SCALES, tickvalues, vmin, vmax) +function get_minor_tickvalues(i::IntervalsBetween, scale::INVERSABLE_SCALES, tickvalues, vmin, vmax) vals = Float64[] length(tickvalues) < 2 && return vals n = i.n From f073f8c4da193aaa4daac964a093159996a78075 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 22 Dec 2022 23:25:54 +0100 Subject: [PATCH 04/38] implement `colorscale` --- CairoMakie/src/utils.jl | 7 +++---- MakieCore/src/basic_plots.jl | 21 +++++++++++++++++++++ precompile/shared-precompile.jl | 2 +- src/colorsampler.jl | 8 ++++---- src/layouting/transformation.jl | 10 ---------- src/makielayout/blocks/colorbar.jl | 1 + 6 files changed, 30 insertions(+), 19 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 137732c0270..cc9870e932c 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -122,14 +122,13 @@ function to_cairo_image(img::AbstractMatrix{<: AbstractFloat}, attributes) end function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) - Makie.@get_attribute attributes (colormap, colorrange, nan_color, lowclip, highclip) - transform = Makie.composed_transform_func(attributes) + Makie.@get_attribute attributes (colormap, colorrange, colorscale, nan_color, lowclip, highclip) nan_color = Makie.to_color(nan_color) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - colorrange = transform.(colorrange) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in transform.(img)] + colorrange = colorscale.(colorrange) + [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in colorscale.(img)] end to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) diff --git a/MakieCore/src/basic_plots.jl b/MakieCore/src/basic_plots.jl index 325d59d6806..575558488d2 100644 --- a/MakieCore/src/basic_plots.jl +++ b/MakieCore/src/basic_plots.jl @@ -36,6 +36,7 @@ Plots an image on range `x, y` (defaults to dimensions). - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` is set by the plot. - `colormap::Union{Symbol, Vector{<:Colorant}} = [:black, :white` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for the position of the image. See `Makie.spaces()` for possible inputs. @@ -44,6 +45,7 @@ Plots an image on range `x, y` (defaults to dimensions). Attributes(; default_theme(scene)..., colormap = [:black, :white], + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -80,6 +82,7 @@ Plots a heatmap as an image on `x, y` (defaults to interpretation as dimensions) - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` is set by the plot. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for the position of the heatmap. See `Makie.spaces()` for possible inputs. @@ -88,6 +91,7 @@ Plots a heatmap as an image on `x, y` (defaults to interpretation as dimensions) Attributes(; default_theme(scene)..., colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -132,6 +136,7 @@ Available algorithms are: - `depth_shift::Float32 = 0f0` adjusts the depth value of a plot after all other transformations, i.e. in clip space, where `0 <= depth <= 1`. This only applies to GLMakie and WGLMakie and can be used to adjust render order (like a tunable overdraw). - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for box encompassing the volume plot. See `Makie.spaces()` for possible inputs. @@ -151,6 +156,7 @@ Available algorithms are: isorange = 0.05, color = nothing, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = (0, 1), fxaa = true, inspectable = theme(scene, :inspectable), @@ -184,6 +190,8 @@ Plots a surface, where `(x, y)` define a grid whose heights are the entries in - `depth_shift::Float32 = 0f0` adjusts the depth value of a plot after all other transformations, i.e. in clip space, where `0 <= depth <= 1`. This only applies to GLMakie and WGLMakie and can be used to adjust render order (like a tunable overdraw). - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for vertices generated by surface. See `Makie.spaces()` for possible inputs. @@ -202,6 +210,7 @@ Plots a surface, where `(x, y)` define a grid whose heights are the entries in backlight = 0f0, color = nothing, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -242,6 +251,7 @@ Creates a connected line plot for each element in `(x, y, z)`, `(x, y)` or `posi - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. The color can also be set for each point in the line by passing a `Vector` of colors or be used to index the `colormap` by passing a `Real` number or `Vector{<: Real}`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for line position. See `Makie.spaces()` for possible inputs. @@ -252,6 +262,7 @@ Creates a connected line plot for each element in `(x, y, z)`, `(x, y)` or `posi linewidth = theme(scene, :linewidth), color = theme(scene, :linecolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, linestyle = nothing, fxaa = false, @@ -288,6 +299,7 @@ Plots a line for each pair of points in `(x, y, z)`, `(x, y)`, or `positions`. - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. The color can also be set for each point in the line by passing a `Vector` or be used to index the `colormap` by passing a `Real` number or `Vector{<: Real}`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for line position. See `Makie.spaces()` for possible inputs. @@ -318,6 +330,7 @@ Plots a 3D or 2D mesh. Supported `mesh_object`s include `Mesh` types from [Geome - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. A `Vector` of any of these can be passed to define the color per vertex. (It may be helpful to check `GeometryBasics.coordinates(my_mesh)` for this.) A `Vector{<: Real}` can also be passed to sample a colormap for each vertex. And finally, if the mesh includes uv coordinates you can pass a `Matrix` of colors to be used as a texture. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for vertex positions. See `Makie.spaces()` for possible inputs. @@ -339,6 +352,7 @@ Plots a 3D or 2D mesh. Supported `mesh_object`s include `Mesh` types from [Geome color = :black, backlight = 0f0, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -385,6 +399,7 @@ Plots a marker for each element in `(x, y, z)`, `(x, y)`, or `positions`. - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. The color can also be set for each scattered marker by passing a `Vector` of colors or be used to index the `colormap` by passing a `Real` number or `Vector{<: Real}`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for positions of markers. See `Makie.spaces()` for possible inputs. @@ -394,6 +409,7 @@ Plots a marker for each element in `(x, y, z)`, `(x, y)`, or `positions`. default_theme(scene)..., color = theme(scene, :markercolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, marker = theme(scene, :marker), markersize = theme(scene, :markersize), @@ -444,6 +460,7 @@ Plots a mesh for each element in `(x, y, z)`, `(x, y)`, or `positions` (similar - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. The color can also be set for each scattered mesh by passing a `Vector` of colors or be used to index the `colormap` by passing a `Real` number or `Vector{<: Real}`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for the positions of meshes. See `Makie.spaces()` for possible inputs. @@ -461,6 +478,7 @@ Plots a mesh for each element in `(x, y, z)`, `(x, y)`, or `positions` (similar default_theme(scene)..., color = :black, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, marker = :Sphere, markersize = 0.1, @@ -570,6 +588,7 @@ Plots polygons, which are defined by - `inspectable::Bool = true` sets whether this plot should be seen by `DataInspector`. - `color` is set by the plot. - `colormap::Union{Symbol, Vector{<:Colorant}} = [:black, :white` sets the colormap that is sampled for numeric `color`s. +- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for the position of the image. See `Makie.spaces()` for possible inputs. @@ -582,6 +601,7 @@ Plots polygons, which are defined by visible = theme(scene, :visible), strokecolor = theme(scene, :patchstrokecolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -620,6 +640,7 @@ end normalize = false, lengthscale = 1f0, colormap = theme(scene, :colormap), + colorscale = identity, quality = 32, inspectable = theme(scene, :inspectable), markerspace = :pixel, diff --git a/precompile/shared-precompile.jl b/precompile/shared-precompile.jl index 923eff489a3..83083434cd8 100644 --- a/precompile/shared-precompile.jl +++ b/precompile/shared-precompile.jl @@ -44,7 +44,7 @@ end end @compile begin - heatmap(rand(10, 5), axis = (yscale = log10, xscale=log10)) + heatmap(1 .+ rand(10, 5), axis = (yscale = log10, xscale=log10)) end @compile begin diff --git a/src/colorsampler.jl b/src/colorsampler.jl index a52ad29ff0f..2acd6034a39 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -132,12 +132,12 @@ end function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} colorrange = get_attribute(primitive, :colorrange)::Union{Nothing, Vec2f} - transform = composed_transform_func(primitive) + colorscale = get_attribute(primitive, :colorscale) cmin, cmax = if isnothing(colorrange) # TODO, plot primitive should always expand automatic values - transform.(Vec2f(extrema_nan(numbers))) + colorscale.(Vec2f(extrema_nan(numbers))) else - transform.(colorrange) + colorscale.(colorrange) end lowclip = get_attribute(primitive, :lowclip) @@ -145,7 +145,7 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) nan_color = get_attribute(primitive, :nan_color, RGBAf(0,0,0,0)) return map(numbers) do number - scaled_number = transform(Float64(number)) # ints don't work in interpolated_getindex + scaled_number = colorscale(Float64(number)) # ints don't work in interpolated_getindex if isnan(scaled_number) return nan_color elseif !isnothing(lowclip) && scaled_number < cmin diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 0169f5b5d38..5a22f130f53 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -195,16 +195,6 @@ transformationmatrix(x) = transformation(x).model transform_func(x) = transform_func_obs(x)[] transform_func_obs(x) = transformation(x).transform_func -reduce_transform(x::Tuple) = reduce(∘, x) -reduce_transform(x) = x - -""" - composed_transform_func(x) - -Returns transformation composition e.g. log10 ∘ identity for xscale=log10 in 2D. -""" -composed_transform_func(x) = reduce_transform(transform_func(x)) - """ apply_transform(f, data, space) Apply the data transform func to the data if the space matches one diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index cc245c7ee1d..c238cd93750 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -46,6 +46,7 @@ function Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) limits = heatmap.colorrange, highclip = heatmap.highclip, lowclip = heatmap.lowclip, + scale = heatmap.colorscale, kwargs... ) end From 2716a8f38390120a4d10b8b397983079f9b69ff6 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 22 Dec 2022 23:50:32 +0100 Subject: [PATCH 05/38] modify recipes with default `colorscale` --- precompile/shared-precompile.jl | 2 +- src/basic_recipes/arrows.jl | 8 ++++---- src/basic_recipes/barplot.jl | 3 ++- src/basic_recipes/contourf.jl | 1 + src/basic_recipes/contours.jl | 23 ++++++++--------------- src/basic_recipes/error_and_rangebars.jl | 8 +++++--- src/basic_recipes/poly.jl | 3 +++ src/basic_recipes/scatterlines.jl | 3 +++ src/basic_recipes/spy.jl | 3 ++- src/basic_recipes/stem.jl | 4 ++++ src/basic_recipes/streamplot.jl | 6 ++++-- src/basic_recipes/tricontourf.jl | 3 +++ src/makielayout/blocks/colorbar.jl | 2 ++ 13 files changed, 42 insertions(+), 27 deletions(-) diff --git a/precompile/shared-precompile.jl b/precompile/shared-precompile.jl index 83083434cd8..923eff489a3 100644 --- a/precompile/shared-precompile.jl +++ b/precompile/shared-precompile.jl @@ -44,7 +44,7 @@ end end @compile begin - heatmap(1 .+ rand(10, 5), axis = (yscale = log10, xscale=log10)) + heatmap(rand(10, 5), axis = (yscale = log10, xscale=log10)) end @compile begin diff --git a/src/basic_recipes/arrows.jl b/src/basic_recipes/arrows.jl index 4a8ef74e836..122a37b6d67 100644 --- a/src/basic_recipes/arrows.jl +++ b/src/basic_recipes/arrows.jl @@ -110,7 +110,7 @@ convert_arguments(::Type{<: Arrows}, x, y, z, u, v, w) = (Point3f.(x, y, z), Vec function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) where {N, V} @extract arrowplot ( - points, directions, colormap, normalize, align, + points, directions, colormap, colorscale, normalize, align, arrowtail, color, linecolor, linestyle, linewidth, lengthscale, arrowhead, arrowsize, arrowcolor, quality, # passthrough @@ -160,7 +160,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher linesegments!( arrowplot, headstart, - color = line_c, colormap = colormap, linestyle = linestyle, + color = line_c, colormap = colormap, colorscale = colorscale, linestyle = linestyle, linewidth = @lift($linewidth === automatic ? 1f0 : $linewidth), fxaa = fxaa_bool, inspectable = inspectable, transparency = transparency, visible = visible, @@ -208,7 +208,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher start, rotations = directions, marker = @lift(arrow_tail(3, $arrowtail, $quality)), markersize = msize, - color = line_c, colormap = colormap, + color = line_c, colormap = colormap, colorscale = colorscale, fxaa = fxaa_bool, ssao = ssao, diffuse = diffuse, specular = specular, shininess = shininess, inspectable = inspectable, @@ -219,7 +219,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher start, rotations = directions, marker = @lift(arrow_head(3, $arrowhead, $quality)), markersize = markersize, - color = arrow_c, colormap = colormap, + color = arrow_c, colormap = colormap, colorscale = colorscale, fxaa = fxaa_bool, ssao = ssao, diffuse = diffuse, specular = specular, shininess = shininess, inspectable = inspectable, diff --git a/src/basic_recipes/barplot.jl b/src/basic_recipes/barplot.jl index 44517db2eae..6d6596b8e3c 100644 --- a/src/basic_recipes/barplot.jl +++ b/src/basic_recipes/barplot.jl @@ -18,6 +18,7 @@ $(ATTRIBUTES) offset = 0.0, color = theme(scene, :patchcolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, lowclip = automatic, highclip = automatic, @@ -254,7 +255,7 @@ function Makie.plot!(p::BarPlot) p.label_color, p.color_over_background, p.color_over_bar, p.label_formatter, p.label_offset) poly!( - p, bars, color = p.color, colormap = p.colormap, colorrange = p.colorrange, + p, bars, color = p.color, colormap = p.colormap, colorscale = p.colorscale, colorrange = p.colorrange, strokewidth = p.strokewidth, strokecolor = p.strokecolor, visible = p.visible, inspectable = p.inspectable, transparency = p.transparency, highclip = p.highclip, lowclip = p.lowclip, nan_color = p.nan_color, diff --git a/src/basic_recipes/contourf.jl b/src/basic_recipes/contourf.jl index 2d8699d64a8..dc5603222e1 100644 --- a/src/basic_recipes/contourf.jl +++ b/src/basic_recipes/contourf.jl @@ -32,6 +32,7 @@ $(ATTRIBUTES) levels = 10, mode = :normal, colormap = theme(scene, :colormap), + colorscale = identity, extendlow = nothing, extendhigh = nothing, # TODO, Isoband doesn't seem to support nans? diff --git a/src/basic_recipes/contours.jl b/src/basic_recipes/contours.jl index 5094b86eaf7..a2b1931d8c9 100644 --- a/src/basic_recipes/contours.jl +++ b/src/basic_recipes/contours.jl @@ -22,6 +22,7 @@ $(ATTRIBUTES) default..., color = nothing, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = Makie.automatic, levels = 5, linewidth = 1.0, @@ -126,19 +127,11 @@ function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol} volume!(plot, attr, x, y, z, volume) end -function color_per_level(color, colormap, colorrange, alpha, levels) - color_per_level(to_color(color), colormap, colorrange, alpha, levels) -end - -function color_per_level(color::Colorant, colormap, colorrange, alpha, levels) - fill(color, length(levels)) -end - -function color_per_level(colors::AbstractVector, colormap, colorrange, alpha, levels) - color_per_level(to_colormap(colors), colormap, colorrange, alpha, levels) -end +color_per_level(color, args...) = color_per_level(to_color(color), args...) +color_per_level(color::Colorant, _, _, _, _, levels) = fill(color, length(levels)) +color_per_level(colors::AbstractVector, args...) = color_per_level(to_colormap(colors), args...) -function color_per_level(colors::AbstractVector{<: Colorant}, colormap, colorrange, alpha, levels) +function color_per_level(colors::AbstractVector{<: Colorant}, _, _, _, _, levels) if length(levels) == length(colors) return colors else @@ -149,10 +142,10 @@ function color_per_level(colors::AbstractVector{<: Colorant}, colormap, colorran end end -function color_per_level(::Nothing, colormap, colorrange, a, levels) +function color_per_level(::Nothing, colormap, colorscale, colorrange, a, levels) cmap = to_colormap(colormap) map(levels) do level - c = interpolated_getindex(cmap, level, colorrange) + c = interpolated_getindex(cmap, colorscale(level), colorscale.(colorrange)) RGBAf(color(c), alpha(c) * a) end end @@ -172,7 +165,7 @@ function plot!(plot::T) where T <: Union{Contour, Contour3d} replace_automatic!(()-> zrange, plot, :colorrange) - args = @extract plot (color, colormap, colorrange, alpha) + args = @extract plot (color, colormap, colorscale, colorrange, alpha) level_colors = lift(color_per_level, args..., levels) result = lift(x, y, z, levels, level_colors) do x, y, z, levels, level_colors t = eltype(z) diff --git a/src/basic_recipes/error_and_rangebars.jl b/src/basic_recipes/error_and_rangebars.jl index 69a35f65e4a..36a02d97e5b 100644 --- a/src/basic_recipes/error_and_rangebars.jl +++ b/src/basic_recipes/error_and_rangebars.jl @@ -25,6 +25,7 @@ $(ATTRIBUTES) direction = :y, visible = theme(scene, :visible), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, inspectable = theme(scene, :inspectable), transparency = false @@ -53,6 +54,7 @@ $(ATTRIBUTES) direction = :y, visible = theme(scene, :visible), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, inspectable = theme(scene, :inspectable), transparency = false @@ -185,7 +187,7 @@ function _plot_bars!(plot, linesegpairs, is_in_y_direction) f_if(condition, f, arg) = condition ? f(arg) : arg - @extract plot (whiskerwidth, color, linewidth, visible, colormap, colorrange, inspectable, transparency) + @extract plot (whiskerwidth, color, linewidth, visible, colormap, colorscale, colorrange, inspectable, transparency) scene = parent_scene(plot) @@ -225,12 +227,12 @@ function _plot_bars!(plot, linesegpairs, is_in_y_direction) linesegments!( plot, linesegpairs, color = color, linewidth = linewidth, visible = visible, - colormap = colormap, colorrange = colorrange, inspectable = inspectable, + colormap = colormap, colorscale = colorscale, colorrange = colorrange, inspectable = inspectable, transparency = transparency ) linesegments!( plot, whiskers, color = whiskercolors, linewidth = whiskerlinewidths, - visible = visible, colormap = colormap, colorrange = colorrange, + visible = visible, colormap = colormap, colorscale = colorscale, colorrange = colorrange, inspectable = inspectable, transparency = transparency ) plot diff --git a/src/basic_recipes/poly.jl b/src/basic_recipes/poly.jl index e8d4a7ee57a..9d0ca21d4a2 100644 --- a/src/basic_recipes/poly.jl +++ b/src/basic_recipes/poly.jl @@ -13,6 +13,7 @@ function plot!(plot::Poly{<: Tuple{Union{GeometryBasics.Mesh, GeometryPrimitive} plot, lift(triangle_mesh, plot[1]), color = plot[:color], colormap = plot[:colormap], + colorscale = plot[:colorscale], colorrange = plot[:colorrange], lowclip = plot[:lowclip], highclip = plot[:highclip], @@ -91,6 +92,7 @@ function plot!(plot::Poly{<: Tuple{<: Union{Polygon, AbstractVector{<: PolyEleme shading = plot.shading, color = plot.color, colormap = plot.colormap, + colorscale = plot.colorscale, colorrange = plot.colorrange, lowclip = plot.lowclip, highclip = plot.highclip, @@ -136,6 +138,7 @@ function plot!(plot::Mesh{<: Tuple{<: AbstractVector{P}}}) where P <: Union{Abst highclip = get(plot, :highclip, automatic), nan_color = get(plot, :nan_color, :transparent), colormap = get(plot, :colormap, nothing), + colorscale = get(plot, :colorscale, identity), colorrange = get(plot, :colorrange, automatic) ) diff --git a/src/basic_recipes/scatterlines.jl b/src/basic_recipes/scatterlines.jl index d63b9446a4f..6f6ffb48576 100644 --- a/src/basic_recipes/scatterlines.jl +++ b/src/basic_recipes/scatterlines.jl @@ -12,6 +12,7 @@ $(ATTRIBUTES) Attributes( color = l_theme.color, colormap = l_theme.colormap, + colorscale = l_theme.colorscale, colorrange = get(l_theme.attributes, :colorrange, automatic), linestyle = l_theme.linestyle, linewidth = l_theme.linewidth, @@ -45,6 +46,7 @@ function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N linestyle = p.linestyle, linewidth = p.linewidth, colormap = p.colormap, + colorscale = p.colorscale, colorrange = p.colorrange, inspectable = p.inspectable ) @@ -55,6 +57,7 @@ function plot!(p::Combined{scatterlines, <:NTuple{N, Any}}) where N marker = p.marker, markersize = p.markersize, colormap = p.markercolormap, + colorscale = p.colorscale, colorrange = p.markercolorrange, inspectable = p.inspectable ) diff --git a/src/basic_recipes/spy.jl b/src/basic_recipes/spy.jl index 2b3a0469722..ee7bd616aa7 100644 --- a/src/basic_recipes/spy.jl +++ b/src/basic_recipes/spy.jl @@ -18,6 +18,7 @@ $(ATTRIBUTES) marker = automatic, markersize = automatic, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, framecolor = :black, framesize = 1, @@ -76,7 +77,7 @@ function plot!(p::Spy) p, lift(first, xycol), color = lift(last, xycol), marker = marker, markersize = markersize, colorrange = p.colorrange, - colormap = p.colormap, inspectable = p.inspectable, visible = p.visible + colormap = p.colormap, colorscale = p.colorscale,inspectable = p.inspectable, visible = p.visible ) lines!(p, rect, color = p.framecolor, linewidth = p.framesize, inspectable = p.inspectable, diff --git a/src/basic_recipes/stem.jl b/src/basic_recipes/stem.jl index d3737b8c31c..f828d5bbbbd 100644 --- a/src/basic_recipes/stem.jl +++ b/src/basic_recipes/stem.jl @@ -29,6 +29,7 @@ $(ATTRIBUTES) markersize = theme(scene, :markersize), color = theme(scene, :markercolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = automatic, strokecolor = theme(scene, :markerstrokecolor), strokewidth = theme(scene, :markerstrokewidth), @@ -61,6 +62,7 @@ function plot!(s::Stem{<:Tuple{<:AbstractVector{<:Point}}}) linewidth = s.trunkwidth, color = s.trunkcolor, colormap = s.trunkcolormap, + colorscale = s.colorscale, colorrange = s.trunkcolorrange, visible = s.visible, linestyle = s.trunklinestyle, @@ -69,6 +71,7 @@ function plot!(s::Stem{<:Tuple{<:AbstractVector{<:Point}}}) linewidth = s.stemwidth, color = s.stemcolor, colormap = s.stemcolormap, + colorscale = s.colorscale, colorrange = s.stemcolorrange, visible = s.visible, linestyle = s.stemlinestyle, @@ -76,6 +79,7 @@ function plot!(s::Stem{<:Tuple{<:AbstractVector{<:Point}}}) scatter!(s, s[1], color = s.color, colormap = s.colormap, + colorscale = s.colorscale, colorrange = s.colorrange, markersize = s.markersize, marker = s.marker, diff --git a/src/basic_recipes/streamplot.jl b/src/basic_recipes/streamplot.jl index 63e12505192..6f357824a25 100644 --- a/src/basic_recipes/streamplot.jl +++ b/src/basic_recipes/streamplot.jl @@ -23,6 +23,7 @@ See the function `Makie.streamplot_impl` for implementation details. gridsize = (32, 32, 32), maxsteps = 500, colormap = theme(scene, :colormap), + colorscale = identity, colorrange = Makie.automatic, arrow_size = 15, arrow_head = automatic, @@ -169,7 +170,8 @@ function plot!(p::StreamPlot) end lines!( p, - lift(x->x[3], data), color = lift(last, data), colormap = p.colormap, colorrange = p.colorrange, + lift(x->x[3], data), color = lift(last, data), + colormap = p.colormap, colorscale = p.colorscale, colorrange = p.colorrange, linestyle = p.linestyle, linewidth = p.linewidth, inspectable = p.inspectable, @@ -205,7 +207,7 @@ function plot!(p::StreamPlot) lift(first, data), markersize = p.arrow_size, marker = @lift(arrow_head(N, $(p.arrow_head), $(p.quality))), color = lift(x-> x[4], data), rotations = rotations, - colormap = p.colormap, colorrange = p.colorrange, + colormap = p.colormap, colorscale = p.colorscale, colorrange = p.colorrange, inspectable = p.inspectable, transparency = p.transparency ) end diff --git a/src/basic_recipes/tricontourf.jl b/src/basic_recipes/tricontourf.jl index deef1fc3e49..a88ef97c6b5 100644 --- a/src/basic_recipes/tricontourf.jl +++ b/src/basic_recipes/tricontourf.jl @@ -27,6 +27,7 @@ and vertical positions `ys`. - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `color` sets the color of the plot. It can be given as a named color `Symbol` or a `Colors.Colorant`. Transparency can be included either directly as an alpha value in the `Colorant` or as an additional float in a tuple `(color, alpha)`. The color can also be set for each scattered marker by passing a `Vector` of colors or be used to index the `colormap` by passing a `Real` number or `Vector{<: Real}`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap from which the band colors are sampled. +- `colorscale::Function = identity` color transform function. ## Attributes $(ATTRIBUTES) @@ -36,6 +37,7 @@ $(ATTRIBUTES) levels = 10, mode = :normal, colormap = theme(scene, :colormap), + colorscale = identity, extendlow = nothing, extendhigh = nothing, nan_color = :transparent, @@ -164,6 +166,7 @@ function Makie.plot!(c::Tricontourf{<:Tuple{<:AbstractVector{<:Real},<:AbstractV poly!(c, polys, colormap = c._computed_colormap, + colorscale = c.colorscale, colorrange = colorrange, highclip = highcolor, lowclip = lowcolor, diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index c238cd93750..8a11b28c9fc 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -29,6 +29,7 @@ function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) fig_or_scene; colormap = plot.colormap, limits = plot.colorrange, + scale = plot.colorscale, kwargs... ) end @@ -71,6 +72,7 @@ function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs.. limits = limits, lowclip = contourf._computed_extendlow, highclip = contourf._computed_extendhigh, + scale = contourf.colorscale, kwargs... ) From 052591d039f63b159b4e3e6a5f1c997820b1fa2a Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 11:27:55 +0100 Subject: [PATCH 06/38] hexbin: replace `scale` with `colorscale` - add NEWS note --- NEWS.md | 2 ++ src/stats/boxplot.jl | 2 ++ src/stats/crossbar.jl | 2 ++ src/stats/density.jl | 3 ++- src/stats/hexbin.jl | 17 +++++++++-------- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/NEWS.md b/NEWS.md index d3b0b1712ad..f9c26e60a6a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ ## master +- Add default `colorscale = identity` to all plotting functions. As such, `scale` for `hexbin` is replaced with `colorscale`. + ## v0.19.1 - Add `show_data` method for `band` which shows the min and max values of the band at the x position of the cursor [#2497](https://github.com/MakieOrg/Makie.jl/pull/2497). diff --git a/src/stats/boxplot.jl b/src/stats/boxplot.jl index 7ec7fb4f5ae..6844cda0444 100644 --- a/src/stats/boxplot.jl +++ b/src/stats/boxplot.jl @@ -36,6 +36,7 @@ The boxplot has 3 components: weights = automatic, color = theme(scene, :patchcolor), colormap = theme(scene, :colormap), + colorscale=identity, colorrange = automatic, orientation = :vertical, # box and dodging @@ -219,6 +220,7 @@ function Makie.plot!(plot::BoxPlot) color = boxcolor, colorrange = plot[:colorrange], colormap = plot[:colormap], + colorscale = plot[:colorscale], strokecolor = plot[:strokecolor], strokewidth = plot[:strokewidth], midlinecolor = plot[:mediancolor], diff --git a/src/stats/crossbar.jl b/src/stats/crossbar.jl index 683b341ecba..a2712f44d76 100644 --- a/src/stats/crossbar.jl +++ b/src/stats/crossbar.jl @@ -25,6 +25,7 @@ It is most commonly used as part of the `boxplot`. t = Theme( color=theme(scene, :patchcolor), colormap=theme(scene, :colormap), + colorscale=identity, colorrange=automatic, orientation=:vertical, # box and dodging @@ -111,6 +112,7 @@ function Makie.plot!(plot::CrossBar) color=plot.color, colorrange=plot.colorrange, colormap=plot.colormap, + colorscale=plot.colorscale, strokecolor=plot.strokecolor, strokewidth=plot.strokewidth, inspectable = plot[:inspectable] diff --git a/src/stats/density.jl b/src/stats/density.jl index 4d19df179fa..abe243265db 100644 --- a/src/stats/density.jl +++ b/src/stats/density.jl @@ -37,6 +37,7 @@ $(ATTRIBUTES) Theme( color = theme(scene, :patchcolor), colormap = theme(scene, :colormap), + colorscale = identity, colorrange = Makie.automatic, strokecolor = theme(scene, :patchstrokecolor), strokewidth = theme(scene, :patchstrokewidth), @@ -113,7 +114,7 @@ function plot!(plot::Density{<:Tuple{<:AbstractVector}}) end end - band!(plot, lower, upper, color = colorobs, colormap = plot.colormap, + band!(plot, lower, upper, color = colorobs, colormap = plot.colormap, colorscale = plot.colorscale, colorrange = plot.colorrange, inspectable = plot.inspectable) l = lines!(plot, linepoints, color = plot.strokecolor, linestyle = plot.linestyle, linewidth = plot.strokewidth, diff --git a/src/stats/hexbin.jl b/src/stats/hexbin.jl index 21527975726..bb961bf1b39 100644 --- a/src/stats/hexbin.jl +++ b/src/stats/hexbin.jl @@ -10,7 +10,7 @@ Plots a heatmap with hexagonal bins for the observations `xs` and `ys`. - `bins = 20`: If an `Int`, sets the number of bins in x and y direction. If a `Tuple{Int, Int}`, sets the number of bins for x and y separately. - `cellsize = nothing`: If a `Real`, makes equally-sided hexagons with width `cellsize`. If a `Tuple{Real, Real}` specifies hexagon width and height separately. - `threshold::Int = 1`: The minimal number of observations in the bin to be shown. If 0, all zero-count hexagons fitting into the data limits will be shown. -- `scale = identity`: A function to scale the number of observations in a bin, eg. log10. +- `colorscale = identity`: A function to scale the number of observations in a bin, eg. log10. ### Generic @@ -20,11 +20,11 @@ Plots a heatmap with hexagonal bins for the observations `xs` and `ys`. @recipe(Hexbin) do scene return Attributes(; colormap=theme(scene, :colormap), + colorscale=identity, colorrange=Makie.automatic, bins=20, cellsize=nothing, threshold=1, - scale=identity, strokewidth=0, strokecolor=:black) end @@ -76,7 +76,7 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) count_hex = Observable(Float64[]) markersize = Observable(Vec2f(1, 1)) - function calculate_grid(xy, bins, cellsize, threshold, scale) + function calculate_grid(xy, bins, cellsize, threshold) empty!(points[]) empty!(count_hex[]) @@ -93,8 +93,8 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) x_diff = xma - xmi y_diff = yma - ymi - xspacing, yspacing, xoff, yoff, nbinsx, nbinsy = spacings_offsets_nbins(bins, cellsize, xmi, xma, ymi, - yma) + xspacing, yspacing, xoff, yoff, nbinsx, nbinsy = + spacings_offsets_nbins(bins, cellsize, xmi, xma, ymi, yma) ysize = yspacing / 3 * 4 ry = ysize / 2 @@ -143,7 +143,7 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) _y = yoff + iy * yspacing c = get(d, (ix, iy), 0) push!(points[], Point2f(_x, _y)) - push!(count_hex[], scale(c)) + push!(count_hex[], c) end end else @@ -153,7 +153,7 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) _x = xoff + 2 * ix * xspacing + (isodd(iy) * xspacing) _y = yoff + iy * yspacing push!(points[], Point2f(_x, _y)) - push!(count_hex[], scale(value)) + push!(count_hex[], value) end end end @@ -162,7 +162,7 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) notify(points) return notify(count_hex) end - onany(calculate_grid, xy, hb.bins, hb.cellsize, hb.threshold, hb.scale) + onany(calculate_grid, xy, hb.bins, hb.cellsize, hb.threshold) # trigger once notify(hb.bins) @@ -180,6 +180,7 @@ function Makie.plot!(hb::Hexbin{<:Tuple{<:AbstractVector{<:Point2}}}) colorrange=hb.colorrange, color=count_hex, colormap=hb.colormap, + colorscale=hb.colorscale, marker=hexmarker, markersize=markersize, markerspace=:data, From a50451f971ffe812e7ea0d90d4dc5a3874ba1b4e Mon Sep 17 00:00:00 2001 From: t-bltg Date: Wed, 28 Dec 2022 18:29:33 +0100 Subject: [PATCH 07/38] fix `per_face_colors` --- CairoMakie/src/primitives.jl | 11 ++++++----- CairoMakie/src/utils.jl | 7 ++++--- MakieCore/src/basic_plots.jl | 1 - 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index 765295e6d0a..57dd7dbe12e 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -693,6 +693,7 @@ function draw_mesh2D(scene, screen, @nospecialize(plot), @nospecialize(mesh)) uv = decompose_uv(mesh)::Union{Nothing, Vector{Vec2f}} model = plot.model[]::Mat4f colormap = haskey(plot, :colormap) ? to_colormap(plot.colormap[]) : nothing + colorscale = haskey(plot, :colorscale) ? plot.colorscale[] : nothing colorrange = convert_attribute(to_value(get(plot, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} lowclip = get_color_attr(plot, :lowclip) @@ -700,7 +701,7 @@ function draw_mesh2D(scene, screen, @nospecialize(plot), @nospecialize(mesh)) nan_color = get_color_attr(plot, :nan_color) cols = per_face_colors( - color, colormap, colorrange, nothing, fs, nothing, uv, + color, colormap, colorscale, colorrange, nothing, fs, nothing, uv, lowclip, highclip, nan_color) space = to_value(get(plot, :space, :data))::Symbol @@ -746,9 +747,10 @@ nan2zero(x) = !isnan(x) * x function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f0) # Priorize colors of the mesh if present - @get_attribute(attributes, (color,)) + @get_attribute attributes (color,) colormap = haskey(attributes, :colormap) ? to_colormap(attributes.colormap[]) : nothing + colorscale = haskey(plot, :colorscale) ? plot.colorscale[] : nothing colorrange = convert_attribute(to_value(get(attributes, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} matcap = to_value(get(attributes, :matcap, nothing)) @@ -763,12 +765,11 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f nan_color = get_color_attr(attributes, :nan_color) per_face_col = per_face_colors( - color, colormap, colorrange, matcap, meshfaces, meshnormals, meshuvs, + color, colormap, colorscale, colorrange, matcap, meshfaces, meshnormals, meshuvs, lowclip, highclip, nan_color ) - @get_attribute(attributes, (shading, diffuse, - specular, shininess, faceculling)) + @get_attribute attributes (shading, diffuse, specular, shininess, faceculling) model = attributes.model[]::Mat4f space = to_value(get(attributes, :space, :data))::Symbol diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index cc9870e932c..7f986d11946 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -194,7 +194,7 @@ function get_color_attr(attributes, attribute)::Union{Nothing, RGBAf} end function per_face_colors( - color, colormap, colorrange, matcap, faces, normals, uv, + color, colormap, colorscale, colorrange, matcap, faces, normals, uv, lowclip=nothing, highclip=nothing, nan_color=nothing ) if matcap !== nothing @@ -212,7 +212,8 @@ function per_face_colors( if color isa AbstractVector{<: Colorant} return FaceIterator(color, faces) elseif color isa AbstractArray{<: Number} - low, high = extrema(colorrange) + scaled_colorrange = colorscale.(colorrange) + low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c if isnan(c) && nan_color !== nothing return nan_color @@ -221,7 +222,7 @@ function per_face_colors( elseif c > high && highclip !== nothing return highclip else - Makie.interpolated_getindex(colormap, c, colorrange) + Makie.interpolated_getindex(colormap, colorscale(c), scaled_colorrange) end end return FaceIterator(cvec, faces) diff --git a/MakieCore/src/basic_plots.jl b/MakieCore/src/basic_plots.jl index 575558488d2..c96ac1e6781 100644 --- a/MakieCore/src/basic_plots.jl +++ b/MakieCore/src/basic_plots.jl @@ -191,7 +191,6 @@ Plots a surface, where `(x, y)` define a grid whose heights are the entries in - `model::Makie.Mat4f` sets a model matrix for the plot. This replaces adjustments made with `translate!`, `rotate!` and `scale!`. - `colormap::Union{Symbol, Vector{<:Colorant}} = :viridis` sets the colormap that is sampled for numeric `color`s. - `colorscale::Function = identity` color transform function. -- `colorscale::Function = identity` color transform function. - `colorrange::Tuple{<:Real, <:Real}` sets the values representing the start and end points of `colormap`. - `nan_color::Union{Symbol, <:Colorant} = RGBAf(0,0,0,0)` sets a replacement color for `color = NaN`. - `space::Symbol = :data` sets the transformation space for vertices generated by surface. See `Makie.spaces()` for possible inputs. From b9567cc8ce4bc90400caf289f9fb324806f8139f Mon Sep 17 00:00:00 2001 From: t-bltg Date: Wed, 28 Dec 2022 20:47:40 +0100 Subject: [PATCH 08/38] heatmap proof of concept for GLMakie --- GLMakie/src/drawing_primitives.jl | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index dc438ca4796..bcf04767790 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -85,7 +85,7 @@ function cached_robj!(robj_func, screen, scene, x::AbstractPlot) filtered = filter(x.attributes) do (k, v) !in(k, ( :transformation, :tickranges, :ticklabels, :raw, :SSAO, - :lightposition, :material, + :lightposition, :material, :colorscale, :inspector_label, :inspector_hover, :inspector_clear, :inspectable )) end @@ -183,6 +183,10 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) +apply_scale(::Nothing, x) = x +apply_scale(::typeof(identity), x) = x +apply_scale(scale, x) = broadcast(scale, x) + function handle_intensities!(attributes) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} c = pop!(attributes, :color) @@ -392,28 +396,23 @@ xy_convert(x, n) = Float32[LinRange(extrema(x)..., n + 1);] function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) return cached_robj!(screen, scene, x) do gl_attributes t = Makie.transform_func_obs(scene) - mat = x[3] space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call - xypos = map(t, x[1], x[2], space) do t, x, y, space - x1d = xy_convert(x, size(mat[], 1)) - y1d = xy_convert(y, size(mat[], 2)) + xypos = map(t, x[1], x[2], x[3], space) do t, xs, ys, mat, space + x1d = xy_convert(xs, size(mat, 1)) + y1d = xy_convert(ys, size(mat, 2)) # Only if transform doesn't do anything, we can stay linear in 1/2D - if Makie.is_identity_transform(t) - return (x1d, y1d) - else + if !Makie.is_identity_transform(t) # If we do any transformation, we have to assume things aren't on the grid anymore # so x + y need to become matrices. - map!(x1d, x1d) do x - return apply_transform(t, Point(x, 0), space)[1] - end - map!(y1d, y1d) do y - return apply_transform(t, Point(0, y), space)[2] - end - return (x1d, y1d) + map!(x -> apply_transform(t, Point(x, 0), space)[1], x1d, x1d) + map!(y -> apply_transform(t, Point(0, y), space)[2], y1d, y1d) end + return x1d, y1d end + colorscale = to_value(x.colorscale) xpos = map(first, xypos) ypos = map(last, xypos) + mat = map(x -> apply_scale(colorscale, x), x[3]) gl_attributes[:position_x] = Texture(xpos, minfilter = :nearest) gl_attributes[:position_y] = Texture(ypos, minfilter = :nearest) # number of planes used to render the heatmap @@ -429,6 +428,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) end pop!(gl_attributes, :color) gl_attributes[:stroke_width] = pop!(gl_attributes, :thickness) + gl_attributes[:color_norm] = apply_scale(colorscale, pop!(gl_attributes, :color_norm)[]) connect_camera!(gl_attributes, scene.camera) return draw_heatmap(screen, tex, gl_attributes) From 4dc96cddb7bfd879636eccbc80752f73b4868fae Mon Sep 17 00:00:00 2001 From: t-bltg Date: Wed, 28 Dec 2022 21:30:19 +0100 Subject: [PATCH 09/38] fix `Surface` primitive --- CairoMakie/src/primitives.jl | 2 +- GLMakie/src/drawing_primitives.jl | 33 ++++++++++++++++++------------- NEWS.md | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index 57dd7dbe12e..23129ce138e 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -750,7 +750,7 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f @get_attribute attributes (color,) colormap = haskey(attributes, :colormap) ? to_colormap(attributes.colormap[]) : nothing - colorscale = haskey(plot, :colorscale) ? plot.colorscale[] : nothing + colorscale = haskey(attributes, :colorscale) ? attributes.colorscale[] : nothing colorrange = convert_attribute(to_value(get(attributes, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} matcap = to_value(get(attributes, :matcap, nothing)) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index bcf04767790..23bf904525b 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -198,6 +198,15 @@ function handle_intensities!(attributes) end end +function handle_colorscale!(p::AbstractPlot, attributes, x) + colorscale = to_value(p.colorscale) + color_norm = to_value(pop!(attributes, :color_norm)) + attributes[:color_norm] = apply_scale(colorscale, color_norm) + lift(x) do x + el32convert(apply_scale(colorscale, to_value(x))) + end +end + function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter, MeshScatter})) return cached_robj!(screen, scene, x) do gl_attributes # signals not supported for shading yet @@ -412,7 +421,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) colorscale = to_value(x.colorscale) xpos = map(first, xypos) ypos = map(last, xypos) - mat = map(x -> apply_scale(colorscale, x), x[3]) + mat = handle_colorscale!(x, gl_attributes, x[3]) gl_attributes[:position_x] = Texture(xpos, minfilter = :nearest) gl_attributes[:position_y] = Texture(ypos, minfilter = :nearest) # number of planes used to render the heatmap @@ -428,7 +437,6 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) end pop!(gl_attributes, :color) gl_attributes[:stroke_width] = pop!(gl_attributes, :thickness) - gl_attributes[:color_norm] = apply_scale(colorscale, pop!(gl_attributes, :color_norm)[]) connect_camera!(gl_attributes, scene.camera) return draw_heatmap(screen, tex, gl_attributes) @@ -515,7 +523,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) # signals not supported for shading yet # We automatically insert x[3] into the color channel, so if it's equal we don't need to do anything if isa(to_value(color), AbstractMatrix{<: Number}) && to_value(color) !== to_value(x[3]) - img = el32convert(color) + img = handle_colorscale!(x, gl_attributes, color) elseif to_value(color) isa Makie.AbstractPattern pattern_img = lift(x -> el32convert(Makie.to_image(x)), color) img = ShaderAbstractions.Sampler(pattern_img, x_repeat=:repeat, minfilter=:nearest) @@ -536,12 +544,14 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true)) connect_camera!(gl_attributes, scene.camera) - @assert to_value(x[3]) isa AbstractMatrix - types = map(v -> typeof(to_value(v)), x[1:2]) + mat = x[3] + @assert to_value(mat) isa AbstractMatrix - if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types) + if isnothing(img) + gl_attributes[:image] = Texture(handle_colorscale!(x, gl_attributes, mat); minfilter=:linear) + end + if all(T -> T <: Union{AbstractMatrix, AbstractVector}, map(v -> typeof(to_value(v)), x[1:2])) t = Makie.transform_func_obs(scene) - mat = x[3] xypos = map(t, x[1], x[2], space) do t, x, y, space # Only if transform doesn't do anything, we can stay linear in 1/2D if Makie.is_identity_transform(t) @@ -562,16 +572,11 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) args = map((xpos, ypos, mat)) do arg Texture(map(x-> convert(Array, el32convert(x)), arg); minfilter=:linear) end - if isnothing(img) - gl_attributes[:image] = args[3] - end + return draw_surface(screen, args, gl_attributes) else gl_attributes[:ranges] = to_range.(to_value.(x[1:2])) - z_data = Texture(el32convert(x[3]); minfilter=:linear) - if isnothing(img) - gl_attributes[:image] = z_data - end + z_data = Texture(el32convert(mat); minfilter=:linear) return draw_surface(screen, z_data, gl_attributes) end end diff --git a/NEWS.md b/NEWS.md index f9c26e60a6a..6f781ea27b3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,7 @@ ## master -- Add default `colorscale = identity` to all plotting functions. As such, `scale` for `hexbin` is replaced with `colorscale`. +- Add default `colorscale = identity` to all plotting functions. Consequently, `scale` for `hexbin` is replaced with `colorscale`. ## v0.19.1 From fb85b5dff84b62f0f9a2fb47cb5f08f6776b37ee Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 13:56:15 +0100 Subject: [PATCH 10/38] conditional access `color_norm` --- GLMakie/src/drawing_primitives.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 23bf904525b..f506156b543 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -200,8 +200,10 @@ end function handle_colorscale!(p::AbstractPlot, attributes, x) colorscale = to_value(p.colorscale) - color_norm = to_value(pop!(attributes, :color_norm)) - attributes[:color_norm] = apply_scale(colorscale, color_norm) + if haskey(attributes, :color_norm) + color_norm = to_value(pop!(attributes, :color_norm)) + attributes[:color_norm] = apply_scale(colorscale, color_norm) + end lift(x) do x el32convert(apply_scale(colorscale, to_value(x))) end From 7eb0289d7b1723ec0225ed8d96092d5f15a795de Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 14:15:16 +0100 Subject: [PATCH 11/38] `WGLMakie`: handle `colorscale` in upstream `interfaces.jl` --- WGLMakie/src/precompiles.jl | 4 ++-- src/interfaces.jl | 32 +++++++++++++++++++------------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/WGLMakie/src/precompiles.jl b/WGLMakie/src/precompiles.jl index ac7b41ed554..32406492f6f 100644 --- a/WGLMakie/src/precompiles.jl +++ b/WGLMakie/src/precompiles.jl @@ -9,9 +9,9 @@ macro compile(block) # So we just do all parts of the stack we can do without browser scene = Makie.get_scene(figlike) session = Session(JSServe.NoConnection(); asset_server=JSServe.NoServer()) - three_display(session, scene) + WGLMakie.three_display(session, scene) JSServe.jsrender(session, figlike) - s = serialize_scene(scene) + s = WGLMakie.serialize_scene(scene) JSServe.serialize_binary(session, Dict(:data => s)) end end diff --git a/src/interfaces.jl b/src/interfaces.jl index da63febdc95..adeb48b4ae2 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -18,30 +18,36 @@ function default_theme(scene) ) end +apply_scale(::Nothing, x) = x +apply_scale(::typeof(identity), x) = x +apply_scale(scale, x) = broadcast(scale, x) - -function color_and_colormap!(plot, intensity = plot[:color]) +function color_colormap_and_colorscale!(plot, intensity = plot[:color]) if isa(intensity[], AbstractArray{<: Number}) haskey(plot, :colormap) || error("Plot $(typeof(plot)) needs to have a colormap to allow the attribute color to be an array of numbers") replace_automatic!(plot, :colorrange) do - lift(distinct_extrema_nan, intensity) + lift(intensity, plot.colorscale) do intensity, colorscale + return apply_scale(colorscale, distinct_extrema_nan(intensity)) + end end replace_automatic!(plot, :highclip) do - lift(plot.colormap) do cmap - return to_colormap(cmap)[end] + lift(plot.colormap, plot.colorscale) do cmap, colorscale + return apply_scale(colorscale, to_colormap(cmap)[end]) end end replace_automatic!(plot, :lowclip) do - lift(plot.colormap) do cmap - return to_colormap(cmap)[1] + lift(plot.colormap, plot.colorscale) do cmap, colorscale + return apply_scale(colorscale, to_colormap(cmap)[begin]) end end + delete!(plot, :colorscale) # handled here, on the CPU return true else delete!(plot, :highclip) delete!(plot, :lowclip) delete!(plot, :colorrange) + delete!(plot, :colorscale) return false end end @@ -49,14 +55,14 @@ end function calculated_attributes!(T::Type{<: Mesh}, plot) mesha = lift(GeometryBasics.attributes, plot.mesh) color = haskey(mesha[], :color) ? lift(x-> x[:color], mesha) : plot.color - need_cmap = color_and_colormap!(plot, color) + need_cmap = color_colormap_and_colorscale!(plot, color) need_cmap || delete!(plot, :colormap) return end function calculated_attributes!(::Type{<: Union{Heatmap, Image}}, plot) plot[:color] = plot[3] - color_and_colormap!(plot) + color_colormap_and_colorscale!(plot) end function calculated_attributes!(::Type{<: Surface}, plot) @@ -67,17 +73,17 @@ function calculated_attributes!(::Type{<: Surface}, plot) colors = plot[:color] end end - color_and_colormap!(plot, colors) + color_colormap_and_colorscale!(plot, colors) end function calculated_attributes!(::Type{<: MeshScatter}, plot) - color_and_colormap!(plot) + color_colormap_and_colorscale!(plot) end function calculated_attributes!(::Type{<: Scatter}, plot) # calculate base case - color_and_colormap!(plot) + color_colormap_and_colorscale!(plot) replace_automatic!(plot, :marker_offset) do # default to middle @@ -96,7 +102,7 @@ function calculated_attributes!(::Type{<: Scatter}, plot) end function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines, LineSegments}} - color_and_colormap!(plot) + color_colormap_and_colorscale!(plot) pos = plot[1][] # extend one color/linewidth per linesegment to be one (the same) color/linewidth per vertex if T <: LineSegments From 8aa127aa2877be0a5bcaae5fdce78fb86b5c83ec Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 16:01:45 +0100 Subject: [PATCH 12/38] update - precompiles --- CairoMakie/src/utils.jl | 12 ++++++------ GLMakie/src/drawing_primitives.jl | 11 +++-------- src/colorsampler.jl | 22 ++++++++++++++-------- src/interfaces.jl | 10 +++------- src/layouting/transformation.jl | 2 +- src/makielayout/blocks/colorbar.jl | 2 +- src/makielayout/lineaxis.jl | 2 +- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 7f986d11946..b19466670c8 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -127,8 +127,8 @@ function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - colorrange = colorscale.(colorrange) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in colorscale.(img)] + colorrange = Makie.apply_scale(colorscale, colorrange) + [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in Makie.apply_scale(colorscale, img)] end to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) @@ -212,17 +212,17 @@ function per_face_colors( if color isa AbstractVector{<: Colorant} return FaceIterator(color, faces) elseif color isa AbstractArray{<: Number} - scaled_colorrange = colorscale.(colorrange) + scaled_colorrange = Makie.apply_scale(colorscale, colorrange) low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c if isnan(c) && nan_color !== nothing return nan_color elseif c < low && lowclip !== nothing - return lowclip + return Makie.apply_scale(colorscale, lowclip) elseif c > high && highclip !== nothing - return highclip + return Makie.apply_scale(colorscale, highclip) else - Makie.interpolated_getindex(colormap, colorscale(c), scaled_colorrange) + Makie.interpolated_getindex(colormap, Makie.apply_scale(colorscale, c), scaled_colorrange) end end return FaceIterator(cvec, faces) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index f506156b543..b08ff66178d 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -183,10 +183,6 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) -apply_scale(::Nothing, x) = x -apply_scale(::typeof(identity), x) = x -apply_scale(scale, x) = broadcast(scale, x) - function handle_intensities!(attributes) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} c = pop!(attributes, :color) @@ -199,13 +195,13 @@ function handle_intensities!(attributes) end function handle_colorscale!(p::AbstractPlot, attributes, x) - colorscale = to_value(p.colorscale) + colorscale = haskey(p, :colorscale) ? to_value(p.colorscale) : nothing if haskey(attributes, :color_norm) color_norm = to_value(pop!(attributes, :color_norm)) - attributes[:color_norm] = apply_scale(colorscale, color_norm) + attributes[:color_norm] = Makie.apply_scale(colorscale, color_norm) end lift(x) do x - el32convert(apply_scale(colorscale, to_value(x))) + el32convert(Makie.apply_scale(colorscale, to_value(x))) end end @@ -420,7 +416,6 @@ function draw_atomic(screen::Screen, scene::Scene, x::Heatmap) end return x1d, y1d end - colorscale = to_value(x.colorscale) xpos = map(first, xypos) ypos = map(last, xypos) mat = handle_colorscale!(x, gl_attributes, x[3]) diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 2acd6034a39..a5f19b27185 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -76,6 +76,10 @@ function apply_scaling(value::Number, scaling::Scaling)::Float64 return isfinite(clamped) ? clamped : zero(clamped) end +apply_scale(::Nothing, x) = x +apply_scale(::typeof(identity), x) = x +apply_scale(scale, x) = broadcast(scale, x) + function Base.getindex(sampler::Sampler, i)::RGBAf value = sampler.values[i] scaled = apply_scaling(value, sampler.scaling) @@ -135,27 +139,29 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colorscale = get_attribute(primitive, :colorscale) cmin, cmax = if isnothing(colorrange) # TODO, plot primitive should always expand automatic values - colorscale.(Vec2f(extrema_nan(numbers))) + Vec2f(extrema_nan(numbers)) else - colorscale.(colorrange) + colorrange end + cmin_scaled = apply_scale(colorscale, cmin) + cmax_scaled = apply_scale(colorscale, cmax) lowclip = get_attribute(primitive, :lowclip) highclip = get_attribute(primitive, :highclip) nan_color = get_attribute(primitive, :nan_color, RGBAf(0,0,0,0)) return map(numbers) do number - scaled_number = colorscale(Float64(number)) # ints don't work in interpolated_getindex + scaled_number = apply_scale(colorscale, Float64(number)) # ints don't work in interpolated_getindex if isnan(scaled_number) return nan_color - elseif !isnothing(lowclip) && scaled_number < cmin - return lowclip - elseif !isnothing(highclip) && scaled_number > cmax - return highclip + elseif !isnothing(lowclip) && scaled_number < cmin_scaled + return apply_scale(colorscale, lowclip) + elseif !isnothing(highclip) && scaled_number > cmax_scaled + return apply_scale(colorscale, highclip) end return interpolated_getindex( colormap, scaled_number, - (cmin, cmax)) + (cmin_scaled, cmax_scaled)) end end diff --git a/src/interfaces.jl b/src/interfaces.jl index adeb48b4ae2..1ff9735ed63 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -18,27 +18,23 @@ function default_theme(scene) ) end -apply_scale(::Nothing, x) = x -apply_scale(::typeof(identity), x) = x -apply_scale(scale, x) = broadcast(scale, x) - function color_colormap_and_colorscale!(plot, intensity = plot[:color]) if isa(intensity[], AbstractArray{<: Number}) haskey(plot, :colormap) || error("Plot $(typeof(plot)) needs to have a colormap to allow the attribute color to be an array of numbers") replace_automatic!(plot, :colorrange) do lift(intensity, plot.colorscale) do intensity, colorscale - return apply_scale(colorscale, distinct_extrema_nan(intensity)) + return Makie.apply_scale(colorscale, distinct_extrema_nan(intensity)) end end replace_automatic!(plot, :highclip) do lift(plot.colormap, plot.colorscale) do cmap, colorscale - return apply_scale(colorscale, to_colormap(cmap)[end]) + return Makie.apply_scale(colorscale, to_colormap(cmap)[end]) end end replace_automatic!(plot, :lowclip) do lift(plot.colormap, plot.colorscale) do cmap, colorscale - return apply_scale(colorscale, to_colormap(cmap)[begin]) + return Makie.apply_scale(colorscale, to_colormap(cmap)[begin]) end end delete!(plot, :colorscale) # handled here, on the CPU diff --git a/src/layouting/transformation.jl b/src/layouting/transformation.jl index 5a22f130f53..af94e3abf6b 100644 --- a/src/layouting/transformation.jl +++ b/src/layouting/transformation.jl @@ -360,7 +360,7 @@ function inv_symlog10(x, low, high) end end -const INVERSABLE_SCALES = Union{ +const REVERSIBLE_SCALES = Union{ # typeof(identity), # no, this is a noop typeof(log10), typeof(log), diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index 8a11b28c9fc..2f73c87d825 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -79,7 +79,7 @@ function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs.. end colorbar_range(start, stop, length, _) = LinRange(start, stop, length) # noop -function colorbar_range(start, stop, length, scale::INVERSABLE_SCALES) +function colorbar_range(start, stop, length, scale::REVERSIBLE_SCALES) inverse_transform(scale).(range(start, stop; length)) end diff --git a/src/makielayout/lineaxis.jl b/src/makielayout/lineaxis.jl index a38e3b9bca7..8abe534a2ce 100644 --- a/src/makielayout/lineaxis.jl +++ b/src/makielayout/lineaxis.jl @@ -721,7 +721,7 @@ function get_minor_tickvalues(i::IntervalsBetween, _, tickvalues, vmin, vmax) end # for log scales, we need to step in log steps at the edges -function get_minor_tickvalues(i::IntervalsBetween, scale::INVERSABLE_SCALES, tickvalues, vmin, vmax) +function get_minor_tickvalues(i::IntervalsBetween, scale::REVERSIBLE_SCALES, tickvalues, vmin, vmax) vals = Float64[] length(tickvalues) < 2 && return vals n = i.n From e3790c6aa0ce9dc394201b7267a11f56eefd40c1 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 16:38:41 +0100 Subject: [PATCH 13/38] revert handling in `interfaces` --- CairoMakie/src/utils.jl | 13 +++++++------ src/interfaces.jl | 30 ++++++++++++++---------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index b19466670c8..d2940aa84b8 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -215,14 +215,15 @@ function per_face_colors( scaled_colorrange = Makie.apply_scale(colorscale, colorrange) low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c - if isnan(c) && nan_color !== nothing + c_scaled = Makie.apply_scale(colorscale, c) + if isnan(c_scaled) && nan_color !== nothing return nan_color - elseif c < low && lowclip !== nothing - return Makie.apply_scale(colorscale, lowclip) - elseif c > high && highclip !== nothing - return Makie.apply_scale(colorscale, highclip) + elseif c_scaled < low && lowclip !== nothing + return lowclip + elseif c_scaled > high && highclip !== nothing + return highclip else - Makie.interpolated_getindex(colormap, Makie.apply_scale(colorscale, c), scaled_colorrange) + Makie.interpolated_getindex(colormap, c_scaled, scaled_colorrange) end end return FaceIterator(cvec, faces) diff --git a/src/interfaces.jl b/src/interfaces.jl index 1ff9735ed63..da63febdc95 100644 --- a/src/interfaces.jl +++ b/src/interfaces.jl @@ -18,32 +18,30 @@ function default_theme(scene) ) end -function color_colormap_and_colorscale!(plot, intensity = plot[:color]) + + +function color_and_colormap!(plot, intensity = plot[:color]) if isa(intensity[], AbstractArray{<: Number}) haskey(plot, :colormap) || error("Plot $(typeof(plot)) needs to have a colormap to allow the attribute color to be an array of numbers") replace_automatic!(plot, :colorrange) do - lift(intensity, plot.colorscale) do intensity, colorscale - return Makie.apply_scale(colorscale, distinct_extrema_nan(intensity)) - end + lift(distinct_extrema_nan, intensity) end replace_automatic!(plot, :highclip) do - lift(plot.colormap, plot.colorscale) do cmap, colorscale - return Makie.apply_scale(colorscale, to_colormap(cmap)[end]) + lift(plot.colormap) do cmap + return to_colormap(cmap)[end] end end replace_automatic!(plot, :lowclip) do - lift(plot.colormap, plot.colorscale) do cmap, colorscale - return Makie.apply_scale(colorscale, to_colormap(cmap)[begin]) + lift(plot.colormap) do cmap + return to_colormap(cmap)[1] end end - delete!(plot, :colorscale) # handled here, on the CPU return true else delete!(plot, :highclip) delete!(plot, :lowclip) delete!(plot, :colorrange) - delete!(plot, :colorscale) return false end end @@ -51,14 +49,14 @@ end function calculated_attributes!(T::Type{<: Mesh}, plot) mesha = lift(GeometryBasics.attributes, plot.mesh) color = haskey(mesha[], :color) ? lift(x-> x[:color], mesha) : plot.color - need_cmap = color_colormap_and_colorscale!(plot, color) + need_cmap = color_and_colormap!(plot, color) need_cmap || delete!(plot, :colormap) return end function calculated_attributes!(::Type{<: Union{Heatmap, Image}}, plot) plot[:color] = plot[3] - color_colormap_and_colorscale!(plot) + color_and_colormap!(plot) end function calculated_attributes!(::Type{<: Surface}, plot) @@ -69,17 +67,17 @@ function calculated_attributes!(::Type{<: Surface}, plot) colors = plot[:color] end end - color_colormap_and_colorscale!(plot, colors) + color_and_colormap!(plot, colors) end function calculated_attributes!(::Type{<: MeshScatter}, plot) - color_colormap_and_colorscale!(plot) + color_and_colormap!(plot) end function calculated_attributes!(::Type{<: Scatter}, plot) # calculate base case - color_colormap_and_colorscale!(plot) + color_and_colormap!(plot) replace_automatic!(plot, :marker_offset) do # default to middle @@ -98,7 +96,7 @@ function calculated_attributes!(::Type{<: Scatter}, plot) end function calculated_attributes!(::Type{T}, plot) where {T<:Union{Lines, LineSegments}} - color_colormap_and_colorscale!(plot) + color_and_colormap!(plot) pos = plot[1][] # extend one color/linewidth per linesegment to be one (the same) color/linewidth per vertex if T <: LineSegments From 2bbf592e8631e3aaeea13e108eb50f91d700d005 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 17:57:40 +0100 Subject: [PATCH 14/38] all backends precompile --- WGLMakie/src/imagelike.jl | 9 ++++++--- WGLMakie/src/particles.jl | 5 +++++ src/colorsampler.jl | 12 ++++++------ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index f27b422223e..e2fd567fbec 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -93,6 +93,7 @@ function create_shader(mscene::Scene, plot::Surface) pcolor = if haskey(plot, :color) && plot.color[] isa AbstractArray if plot.color[] isa AbstractMatrix{<:Colorant} delete!(plot_attributes, :colormap) + delete!(plot_attributes, :colorscale) delete!(plot_attributes, :colorrange) end plot.color @@ -100,7 +101,9 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - color = Sampler(lift(x -> el32convert(to_color(permutedims(x))), pcolor), minfilter=minfilter) + color = Sampler(lift(x -> el32convert(to_color(Makie.apply_scale(plot.colorscale, permutedims(x)))), pcolor); + minfilter=minfilter) + delete!(plot_attributes, :colorscale) # handled here normals = Buffer(lift(surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) mesh = GeometryBasics.Mesh(vertices, faces) @@ -116,7 +119,7 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] - color = Sampler(map(x -> el32convert(x'), image); + color = Sampler(lift(x -> el32convert(Makie.apply_scale(plot.colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) plot_attributes = copy(plot.attributes) @@ -124,7 +127,7 @@ function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) delete!(plot_attributes, :colormap) delete!(plot_attributes, :colorrange) end - + delete!(plot_attributes, :colorscale) # handled here return draw_mesh(mscene, mesh, plot_attributes; uniform_color=color, color=false, normals=Vec3f(0), shading=false, diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index 1564feb8135..4414b8c5ef2 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -11,7 +11,12 @@ function handle_color!(uniform_dict, instance_dict) color isa AbstractVector{<:Colorant} || color === nothing delete!(uniform_dict, :colormap) + delete!(uniform_dict, :colorscale) elseif color isa AbstractArray{<:Real} + if haskey(uniform_dict, :colorscale) + colorscale = pop!(uniform_dict, :colorscale) + udict[:color] = Makie.apply_scale(colorscale, color) + end uniform_dict[:color_getter] = """ vec4 get_color(){ vec2 norm = get_colorrange(); diff --git a/src/colorsampler.jl b/src/colorsampler.jl index a5f19b27185..3f53cb27488 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -76,10 +76,6 @@ function apply_scaling(value::Number, scaling::Scaling)::Float64 return isfinite(clamped) ? clamped : zero(clamped) end -apply_scale(::Nothing, x) = x -apply_scale(::typeof(identity), x) = x -apply_scale(scale, x) = broadcast(scale, x) - function Base.getindex(sampler::Sampler, i)::RGBAf value = sampler.values[i] scaled = apply_scaling(value, sampler.scaling) @@ -132,6 +128,10 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end +apply_scale(::Nothing, x) = x +apply_scale(::typeof(identity), x) = x +apply_scale(scale, x) = broadcast(scale, x) +apply_scale(scale::AbstractObservable, x) = apply_scale(scale[], x) function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} @@ -155,9 +155,9 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) if isnan(scaled_number) return nan_color elseif !isnothing(lowclip) && scaled_number < cmin_scaled - return apply_scale(colorscale, lowclip) + return lowclip elseif !isnothing(highclip) && scaled_number > cmax_scaled - return apply_scale(colorscale, highclip) + return highclip end return interpolated_getindex( colormap, From 4c5478e83f698aca56b9dfe3caf1ed78745a4acf Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 18:34:03 +0100 Subject: [PATCH 15/38] fix WGLMakie heatmap colorrange --- WGLMakie/src/imagelike.jl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index e2fd567fbec..014cf76310e 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -15,8 +15,12 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) uniforms[:colormap] = Sampler(cmap) end + colorscale = pop!(plot, :colorscale) + colorrange = if haskey(plot, :colorrange) - uniforms[:colorrange] = lift(Vec2f, plot.colorrange) + uniforms[:colorrange] = lift(plot.colorrange, colorscale) do colorrange, colorscale + return Vec2f(Makie.apply_scale(colorscale, colorrange)) + end end get!(uniforms, :colormap, false) @@ -103,7 +107,6 @@ function create_shader(mscene::Scene, plot::Surface) minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest color = Sampler(lift(x -> el32convert(to_color(Makie.apply_scale(plot.colorscale, permutedims(x)))), pcolor); minfilter=minfilter) - delete!(plot_attributes, :colorscale) # handled here normals = Buffer(lift(surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) mesh = GeometryBasics.Mesh(vertices, faces) @@ -119,20 +122,18 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] - color = Sampler(lift(x -> el32convert(Makie.apply_scale(plot.colorscale, permutedims(x))), image); + plot_attributes = copy(plot.attributes) + color = Sampler(map(x -> el32convert(Makie.apply_scale(plot.colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) - plot_attributes = copy(plot.attributes) if eltype(color) <: Colorant delete!(plot_attributes, :colormap) delete!(plot_attributes, :colorrange) end - delete!(plot_attributes, :colorscale) # handled here return draw_mesh(mscene, mesh, plot_attributes; uniform_color=color, color=false, normals=Vec3f(0), shading=false, diffuse=plot.diffuse, specular=plot.specular, - colorrange=haskey(plot, :colorrange) ? plot.colorrange : false, shininess=plot.shininess, highclip=get_color(plot, :highclip), lowclip=get_color(plot, :lowclip), @@ -159,7 +160,6 @@ function create_shader(mscene::Scene, plot::Volume) return Program(WebGL(), lasset("volume.vert"), lasset("volume.frag"), box, volumedata=Sampler(lift(Makie.el32convert, vol)), modelinv=modelinv, colormap=Sampler(lift(to_colormap, plot.colormap)), - colorrange=lift(Vec2f, plot.colorrange), isovalue=lift(Float32, plot.isovalue), isorange=lift(Float32, plot.isorange), absorption=lift(Float32, get(plot, :absorption, Observable(1f0))), From 2b409290fb46857eccf50aa62060fcbb08c8c88c Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 19:16:46 +0100 Subject: [PATCH 16/38] cleanup --- CairoMakie/src/primitives.jl | 4 ++-- CairoMakie/src/utils.jl | 10 +++++----- GLMakie/src/drawing_primitives.jl | 4 ++-- WGLMakie/src/imagelike.jl | 2 +- src/colorsampler.jl | 15 +++++++-------- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/CairoMakie/src/primitives.jl b/CairoMakie/src/primitives.jl index 23129ce138e..3a4b6b7ec17 100644 --- a/CairoMakie/src/primitives.jl +++ b/CairoMakie/src/primitives.jl @@ -693,7 +693,7 @@ function draw_mesh2D(scene, screen, @nospecialize(plot), @nospecialize(mesh)) uv = decompose_uv(mesh)::Union{Nothing, Vector{Vec2f}} model = plot.model[]::Mat4f colormap = haskey(plot, :colormap) ? to_colormap(plot.colormap[]) : nothing - colorscale = haskey(plot, :colorscale) ? plot.colorscale[] : nothing + colorscale = haskey(plot, :colorscale) ? plot.colorscale : nothing colorrange = convert_attribute(to_value(get(plot, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} lowclip = get_color_attr(plot, :lowclip) @@ -750,7 +750,7 @@ function draw_mesh3D(scene, screen, attributes, mesh; pos = Vec4f(0), scale = 1f @get_attribute attributes (color,) colormap = haskey(attributes, :colormap) ? to_colormap(attributes.colormap[]) : nothing - colorscale = haskey(attributes, :colorscale) ? attributes.colorscale[] : nothing + colorscale = haskey(attributes, :colorscale) ? attributes.colorscale : nothing colorrange = convert_attribute(to_value(get(attributes, :colorrange, nothing)), key"colorrange"())::Union{Nothing, Vec2f} matcap = to_value(get(attributes, :matcap, nothing)) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index d2940aa84b8..a65493aa134 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -215,15 +215,15 @@ function per_face_colors( scaled_colorrange = Makie.apply_scale(colorscale, colorrange) low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c - c_scaled = Makie.apply_scale(colorscale, c) - if isnan(c_scaled) && nan_color !== nothing + scaled_c = Makie.apply_scale(colorscale, c) + if isnan(scaled_c) && nan_color !== nothing return nan_color - elseif c_scaled < low && lowclip !== nothing + elseif scaled_c < low && lowclip !== nothing return lowclip - elseif c_scaled > high && highclip !== nothing + elseif scaled_c > high && highclip !== nothing return highclip else - Makie.interpolated_getindex(colormap, c_scaled, scaled_colorrange) + Makie.interpolated_getindex(colormap, scaled_c, scaled_colorrange) end end return FaceIterator(cvec, faces) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index b08ff66178d..b5f70d23ee3 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -195,9 +195,9 @@ function handle_intensities!(attributes) end function handle_colorscale!(p::AbstractPlot, attributes, x) - colorscale = haskey(p, :colorscale) ? to_value(p.colorscale) : nothing + colorscale = haskey(p, :colorscale) ? p.colorscale : nothing if haskey(attributes, :color_norm) - color_norm = to_value(pop!(attributes, :color_norm)) + color_norm = to_value(attributes[:color_norm]) attributes[:color_norm] = Makie.apply_scale(colorscale, color_norm) end lift(x) do x diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 014cf76310e..18304928648 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -15,7 +15,7 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) uniforms[:colormap] = Sampler(cmap) end - colorscale = pop!(plot, :colorscale) + colorscale = pop!(plot, :colorscale, identity) colorrange = if haskey(plot, :colorrange) uniforms[:colorrange] = lift(plot.colorrange, colorscale) do colorrange, colorscale diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 3f53cb27488..a620871b440 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -128,10 +128,9 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end -apply_scale(::Nothing, x) = x -apply_scale(::typeof(identity), x) = x -apply_scale(scale, x) = broadcast(scale, x) apply_scale(scale::AbstractObservable, x) = apply_scale(scale[], x) +apply_scale(::Union{Nothing,typeof(identity)}, x) = x # noop +apply_scale(scale, x) = broadcast(scale, x) function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} @@ -143,8 +142,8 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) else colorrange end - cmin_scaled = apply_scale(colorscale, cmin) - cmax_scaled = apply_scale(colorscale, cmax) + scaled_cmin = apply_scale(colorscale, cmin) + scaled_cmax = apply_scale(colorscale, cmax) lowclip = get_attribute(primitive, :lowclip) highclip = get_attribute(primitive, :highclip) @@ -154,14 +153,14 @@ function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) scaled_number = apply_scale(colorscale, Float64(number)) # ints don't work in interpolated_getindex if isnan(scaled_number) return nan_color - elseif !isnothing(lowclip) && scaled_number < cmin_scaled + elseif !isnothing(lowclip) && scaled_number < scaled_cmin return lowclip - elseif !isnothing(highclip) && scaled_number > cmax_scaled + elseif !isnothing(highclip) && scaled_number > scaled_cmax return highclip end return interpolated_getindex( colormap, scaled_number, - (cmin_scaled, cmax_scaled)) + (scaled_cmin, scaled_cmax)) end end From 44dfe13b1701a1046f44dbcd6cb6b2ab3a2e4906 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 19:53:47 +0100 Subject: [PATCH 17/38] fix GLMakie `scatter` --- GLMakie/src/drawing_primitives.jl | 16 +++++++++++----- src/colorsampler.jl | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index b5f70d23ee3..b39141acb17 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -183,10 +183,16 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) -function handle_intensities!(attributes) +function handle_intensities!(attributes, colorscale) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} - c = pop!(attributes, :color) - attributes[:intensity] = lift(x-> convert(Vector{Float32}, x), c) + color = pop!(attributes, :color) + attributes[:intensity] = lift(color, colorscale) do color, colorscale + return convert(Vector{Float32}, Makie.apply_scale(colorscale, color)) + end + if haskey(attributes, :color_norm) + color_norm = to_value(attributes[:color_norm]) + attributes[:color_norm] = Makie.apply_scale(colorscale, color_norm) + end else delete!(attributes, :intensity) delete!(attributes, :color_map) @@ -261,7 +267,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte end return draw_pixel_scatter(screen, positions, gl_attributes) else - handle_intensities!(gl_attributes) + handle_intensities!(gl_attributes, x.colorscale) if x isa MeshScatter return draw_mesh_particle(screen, (marker, positions), gl_attributes) else @@ -285,7 +291,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines)) space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call positions = handle_view(x[1], data) positions = apply_transform(transform_func_obs(x), positions, space) - handle_intensities!(data) + handle_intensities!(data, x.colorscale) connect_camera!(data, scene.camera) return draw_lines(screen, positions, data) end diff --git a/src/colorsampler.jl b/src/colorsampler.jl index a620871b440..6954fb2a0d8 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -128,7 +128,9 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end +apply_scale(scale::AbstractObservable, x::AbstractObservable) = apply_scale(scale[], x[]) apply_scale(scale::AbstractObservable, x) = apply_scale(scale[], x) +apply_scale(scale, x::AbstractObservable) = apply_scale(scale, x[]) apply_scale(::Union{Nothing,typeof(identity)}, x) = x # noop apply_scale(scale, x) = broadcast(scale, x) From 7cc54556d734261ab06df383b0590dcfa61af366 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 20:30:12 +0100 Subject: [PATCH 18/38] fix WGLMAkie scatter --- WGLMakie/src/particles.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index 4414b8c5ef2..99afae61bd8 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -15,7 +15,8 @@ function handle_color!(uniform_dict, instance_dict) elseif color isa AbstractArray{<:Real} if haskey(uniform_dict, :colorscale) colorscale = pop!(uniform_dict, :colorscale) - udict[:color] = Makie.apply_scale(colorscale, color) + udict[:color] = c = Makie.apply_scale(colorscale, color) + uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(c)) end uniform_dict[:color_getter] = """ vec4 get_color(){ From f5fb2b83c047e33ff17cd7cc057ca191ca583e4d Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 21:03:57 +0100 Subject: [PATCH 19/38] fix WGLMakie `lines` --- WGLMakie/src/lines.jl | 11 ++++++++++- WGLMakie/src/meshes.jl | 9 --------- src/colorsampler.jl | 4 +--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index 8b5673c1223..aa3aeab5edf 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -11,6 +11,15 @@ function topoint(x::AbstractArray{<:Tuple{P,P}}) where {P<:Point} return topoint(reinterpret(P, x)) end +function array2color(colors, cmap, crange, cscale) + cmap = RGBAf.(Colors.color.(to_colormap(cmap)), 1.0) + return Makie.interpolated_getindex.((cmap,), Makie.apply_scale(cscale, colors), (Makie.apply_scale(cscale, crange),)) +end + +function array2color(colors::AbstractArray{<:Colorant}, _, _, _) + return RGBAf.(colors) +end + function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) # Potentially per instance attributes positions = lift(plot[1], transform_func_obs(plot), get(plot, :space, :data)) do points, trans, space @@ -48,7 +57,7 @@ function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) uniforms[Symbol("$(k)_end")] = attribute else if attribute[] isa AbstractVector{<:Number} && haskey(plot, :colorrange) - attribute = lift(array2color, attribute, plot.colormap, plot.colorrange) + attribute = lift(array2color, attribute, plot.colormap, plot.colorrange, plot.colorscale) end per_instance[Symbol("$(k)_start")] = Buffer(lift(x -> x[startr[]], attribute)) per_instance[Symbol("$(k)_end")] = Buffer(lift(x -> x[endr[]], attribute)) diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 8abdfb832b2..223e70439fc 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -12,15 +12,6 @@ facebuffer(x::AbstractArray{<:GLTriangleFace}) = x facebuffer(x::Observable) = Buffer(lift(facebuffer, x)) -function array2color(colors, cmap, crange) - cmap = RGBAf.(Colors.color.(to_colormap(cmap)), 1.0) - return Makie.interpolated_getindex.((cmap,), colors, (crange,)) -end - -function array2color(colors::AbstractArray{<:Colorant}, cmap, crange) - return RGBAf.(colors) -end - function converted_attribute(plot::AbstractPlot, key::Symbol) return lift(plot[key]) do value return convert_attribute(value, Key{key}(), Key{plotkey(plot)}()) diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 6954fb2a0d8..5d99fd1c7ce 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -128,11 +128,9 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end -apply_scale(scale::AbstractObservable, x::AbstractObservable) = apply_scale(scale[], x[]) apply_scale(scale::AbstractObservable, x) = apply_scale(scale[], x) -apply_scale(scale, x::AbstractObservable) = apply_scale(scale, x[]) apply_scale(::Union{Nothing,typeof(identity)}, x) = x # noop -apply_scale(scale, x) = broadcast(scale, x) +apply_scale(scale, x) = broadcast(scale, to_value(x)) function numbers_to_colors(numbers::AbstractArray{<:Number}, primitive) colormap = get_attribute(primitive, :colormap)::Vector{RGBAf} From 66515a80080b22108d8bd7172471654830a3af65 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 21:43:15 +0100 Subject: [PATCH 20/38] add `lines` & `scatter` ref examples --- ReferenceTests/src/tests/examples2d.jl | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 11c0f2a8b06..34d9606d4ec 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -580,11 +580,31 @@ end fig end -@reference_test "scaled colormap" begin +@reference_test "scaled colors (heatmap)" begin x = 10.0.^(1:0.1:4) y = 1.0:0.1:5.0 - fig, ax, hm = heatmap(x, y, (x, y) -> log10(x); axis = (; xscale = log10)) - Colorbar(fig[1, 2], hm; scale = log10) + fig, ax, hm = heatmap(x, y, (x, y) -> x; axis = (; xscale = log10), colorscale = log10) + Colorbar(fig[1, 2], hm) + fig +end + +@reference_test "scaled colors (lines)" begin + xs = 0:0.01:10 + ys = 2(1 .+ sin.(xs)) + fig = Figure() + lines(fig[1, 1], xs, ys; linewidth = 10, color = ys, colorscale = identity) + lines(fig[2, 1], xs, ys; linewidth = 10, color = ys, colorscale = sqrt) + fig +end + +@reference_test "scaled colors (scatter)" begin + xs = range(0, 10; length = 30) + ys = 0.5 .* sin.(xs) + markersize = range(5, 30; length = 30) + color = 1:30 + fig = Figure() + scatter(fig[1, 1], xs, ys; markersize, color, colorscale = identity) + scatter(fig[2, 1], xs, ys; markersize, color, colorscale = log10) fig end From ac4a35074598aba1525941c96b61058ed82ba1d0 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Thu, 5 Jan 2023 21:48:06 +0100 Subject: [PATCH 21/38] add `hexbin` example --- ReferenceTests/src/tests/examples2d.jl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ReferenceTests/src/tests/examples2d.jl b/ReferenceTests/src/tests/examples2d.jl index 34d9606d4ec..301a466eb07 100644 --- a/ReferenceTests/src/tests/examples2d.jl +++ b/ReferenceTests/src/tests/examples2d.jl @@ -580,7 +580,7 @@ end fig end -@reference_test "scaled colors (heatmap)" begin +@reference_test "colorscale (heatmap)" begin x = 10.0.^(1:0.1:4) y = 1.0:0.1:5.0 fig, ax, hm = heatmap(x, y, (x, y) -> x; axis = (; xscale = log10), colorscale = log10) @@ -588,7 +588,7 @@ end fig end -@reference_test "scaled colors (lines)" begin +@reference_test "colorscale (lines)" begin xs = 0:0.01:10 ys = 2(1 .+ sin.(xs)) fig = Figure() @@ -597,7 +597,7 @@ end fig end -@reference_test "scaled colors (scatter)" begin +@reference_test "colorscale (scatter)" begin xs = range(0, 10; length = 30) ys = 0.5 .* sin.(xs) markersize = range(5, 30; length = 30) @@ -608,6 +608,15 @@ end fig end +@reference_test "colorscale (hexbin)" begin + x = RNG.randn(10_000) + y = RNG.randn(10_000) + fig = Figure() + hexbin(fig[1, 1], x, y; bins = 40, colorscale = identity) + hexbin(fig[1, 2], x, y; bins = 40, colorscale = log10) + fig +end + @reference_test "multi rect with poly" begin # use thick strokewidth, so it will make tests fail if something is missing poly([Rect2f(0, 0, 1, 1)], color=:green, strokewidth=100, strokecolor=:black) From 46ea7b98239ab1832ad8dd95eea54daf4bf154f4 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 10:32:24 +0100 Subject: [PATCH 22/38] fix WGLMakie Volume --- WGLMakie/src/imagelike.jl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 18304928648..846e32ad8b3 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -1,4 +1,4 @@ -using Makie: el32convert, surface_normals, get_dim +using Makie: el32convert, surface_normals, get_dim, apply_scale # Somehow we started using Nothing for some colors in Makie, # but the convert leaves them at nothing -.- @@ -19,7 +19,7 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) colorrange = if haskey(plot, :colorrange) uniforms[:colorrange] = lift(plot.colorrange, colorscale) do colorrange, colorscale - return Vec2f(Makie.apply_scale(colorscale, colorrange)) + return Vec2f(apply_scale(colorscale, colorrange)) end end @@ -105,7 +105,7 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - color = Sampler(lift(x -> el32convert(to_color(Makie.apply_scale(plot.colorscale, permutedims(x)))), pcolor); + color = Sampler(lift(x -> el32convert(to_color(apply_scale(plot.colorscale, permutedims(x)))), pcolor); minfilter=minfilter) normals = Buffer(lift(surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) @@ -123,7 +123,7 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] plot_attributes = copy(plot.attributes) - color = Sampler(map(x -> el32convert(Makie.apply_scale(plot.colorscale, permutedims(x))), image); + color = Sampler(map(x -> el32convert(apply_scale(plot.colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) if eltype(color) <: Colorant @@ -158,8 +158,9 @@ function create_shader(mscene::Scene, plot::Volume) algorithm = lift(x -> Cuint(convert_attribute(x, key"algorithm"())), plot.algorithm) return Program(WebGL(), lasset("volume.vert"), lasset("volume.frag"), box, - volumedata=Sampler(lift(Makie.el32convert, vol)), + volumedata=Sampler(lift(el32convert, apply_scale(plot.colorscale, vol))), modelinv=modelinv, colormap=Sampler(lift(to_colormap, plot.colormap)), + colorrange=lift(Vec2f, apply_scale(plot.colorscale, plot.colorrange)), isovalue=lift(Float32, plot.isovalue), isorange=lift(Float32, plot.isorange), absorption=lift(Float32, get(plot, :absorption, Observable(1f0))), From 8d0d78f77802be4c91c81c60cb038a4765d59b8b Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 11:01:49 +0100 Subject: [PATCH 23/38] fix WGLMakie Mesh --- WGLMakie/src/meshes.jl | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 223e70439fc..377c4831b12 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -46,20 +46,22 @@ function create_shader(scene::Scene, plot::Makie.Mesh) uniforms[:uniform_color] = false else color_signal = converted_attribute(plot, :color) - color = color_signal[] - mesh_color = color_signal[] - uniforms[:uniform_color] = Observable(false) # this is the default - - if color isa Colorant && haskey(data, :color) + if color_signal[] isa Colorant && haskey(data, :color) color_signal = get_attribute(mesh_signal, :color) - color = color_signal[] end + color = color_signal[] + uniforms[:uniform_color] = Observable(false) # this is the default if color isa AbstractArray + if eltype(color) <: Number + uniforms[:colorrange] = lift(x -> Makie.apply_scale(plot.colorscale, x), converted_attribute(plot, :colorrange)) + uniforms[:colormap] = Sampler(converted_attribute(plot, :colormap)) + color = Makie.apply_scale(plot.colorscale, color) + end if color isa AbstractVector - attributes[:color] = Buffer(color_signal) # per vertex colors + attributes[:color] = Buffer(color) # per vertex colors else - uniforms[:uniform_color] = Sampler(color_signal) # Texture + uniforms[:uniform_color] = Sampler(color) # Texture uniforms[:color] = false if color isa Makie.AbstractPattern uniforms[:pattern] = true @@ -69,10 +71,6 @@ function create_shader(scene::Scene, plot::Makie.Mesh) attributes[:uv] = uv end end - if eltype(color_signal[]) <: Number - uniforms[:colorrange] = converted_attribute(plot, :colorrange) - uniforms[:colormap] = Sampler(converted_attribute(plot, :colormap)) - end elseif color isa Colorant && !haskey(attributes, :color) uniforms[:uniform_color] = color_signal else From 94b1f87d84ba938dca467475273a83dbdef12a0c Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 11:06:39 +0100 Subject: [PATCH 24/38] simplifications --- GLMakie/src/drawing_primitives.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index b39141acb17..69995dd5bc8 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -1,4 +1,4 @@ -using Makie: transform_func_obs, apply_transform +using Makie: transform_func_obs, apply_transform, apply_scale using Makie: attribute_per_char, FastPixel, el32convert, Pixel using Makie: convert_arguments @@ -187,11 +187,11 @@ function handle_intensities!(attributes, colorscale) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} color = pop!(attributes, :color) attributes[:intensity] = lift(color, colorscale) do color, colorscale - return convert(Vector{Float32}, Makie.apply_scale(colorscale, color)) + return convert(Vector{Float32}, apply_scale(colorscale, color)) end if haskey(attributes, :color_norm) color_norm = to_value(attributes[:color_norm]) - attributes[:color_norm] = Makie.apply_scale(colorscale, color_norm) + attributes[:color_norm] = apply_scale(colorscale, color_norm) end else delete!(attributes, :intensity) @@ -204,10 +204,10 @@ function handle_colorscale!(p::AbstractPlot, attributes, x) colorscale = haskey(p, :colorscale) ? p.colorscale : nothing if haskey(attributes, :color_norm) color_norm = to_value(attributes[:color_norm]) - attributes[:color_norm] = Makie.apply_scale(colorscale, color_norm) + attributes[:color_norm] = apply_scale(colorscale, color_norm) end lift(x) do x - el32convert(Makie.apply_scale(colorscale, to_value(x))) + el32convert(apply_scale(colorscale, to_value(x))) end end From b99f98d774f85363a2af9793c5ab0af4ae801f05 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 11:18:51 +0100 Subject: [PATCH 25/38] fix GLMakie Mesh --- GLMakie/src/drawing_primitives.jl | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 69995dd5bc8..235a588e371 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -183,16 +183,19 @@ end pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) +function handle_color_norm!(attributes, colorscale) + if haskey(attributes, :color_norm) + attributes[:color_norm] = apply_scale(colorscale, attributes[:color_norm]) + end +end + function handle_intensities!(attributes, colorscale) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} color = pop!(attributes, :color) attributes[:intensity] = lift(color, colorscale) do color, colorscale return convert(Vector{Float32}, apply_scale(colorscale, color)) end - if haskey(attributes, :color_norm) - color_norm = to_value(attributes[:color_norm]) - attributes[:color_norm] = apply_scale(colorscale, color_norm) - end + handle_color_norm!(attributes, colorscale) else delete!(attributes, :intensity) delete!(attributes, :color_map) @@ -202,13 +205,8 @@ end function handle_colorscale!(p::AbstractPlot, attributes, x) colorscale = haskey(p, :colorscale) ? p.colorscale : nothing - if haskey(attributes, :color_norm) - color_norm = to_value(attributes[:color_norm]) - attributes[:color_norm] = apply_scale(colorscale, color_norm) - end - lift(x) do x - el32convert(apply_scale(colorscale, to_value(x))) - end + handle_color_norm!(attributes, colorscale) + lift(x -> el32convert(apply_scale(colorscale, x)), x) end function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter, MeshScatter})) @@ -464,7 +462,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Image) gl_attributes[:shading] = false space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call connect_camera!(gl_attributes, scene.camera) - return mesh_inner(screen, mesh, transform_func_obs(x), gl_attributes, space) + return mesh_inner(screen, mesh, transform_func_obs(x), x.colorscale, gl_attributes, space) end end @@ -475,12 +473,13 @@ function update_positions(mesh::GeometryBasics.Mesh, positions) return GeometryBasics.Mesh(meta(positions; attr...), faces(mesh)) end -function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) +function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, space=:data) # signals not supported for shading yet gl_attributes[:shading] = to_value(pop!(gl_attributes, :shading)) color = pop!(gl_attributes, :color) interp = to_value(pop!(gl_attributes, :interpolate, true)) interp = interp ? :linear : :nearest + if to_value(color) isa Colorant gl_attributes[:vertex_color] = color delete!(gl_attributes, :color_map) @@ -494,10 +493,14 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert, color), minfilter = interp) + gl_attributes[:image] = Texture(const_lift(el32convert, apply_scale(colorscale, color)), minfilter = interp) + handle_color_norm!(gl_attributes, colorscale) gl_attributes[:color] = nothing - elseif to_value(color) isa AbstractVector{<: Union{Number, Colorant}} + elseif to_value(color) isa AbstractVector{<:Colorant} gl_attributes[:vertex_color] = lift(el32convert, color) + elseif to_value(color) isa AbstractVector{<:Number} + gl_attributes[:vertex_color] = lift(el32convert, apply_scale(colorscale, color)) + handle_color_norm!(gl_attributes, colorscale) else error("Unsupported color type: $(typeof(to_value(color)))") end @@ -510,12 +513,12 @@ function mesh_inner(screen::Screen, mesh, transfunc, gl_attributes, space=:data) return draw_mesh(screen, mesh, gl_attributes) end -function draw_atomic(screen::Screen, scene::Scene, meshplot::Mesh) - return cached_robj!(screen, scene, meshplot) do gl_attributes - t = transform_func_obs(meshplot) +function draw_atomic(screen::Screen, scene::Scene, x::Mesh) + return cached_robj!(screen, scene, x) do gl_attributes + t = transform_func_obs(x) space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call connect_camera!(gl_attributes, scene.camera) - return mesh_inner(screen, meshplot[1], t, gl_attributes, space) + return mesh_inner(screen, x[1], t, x.colorscale, gl_attributes, space) end end From cf5779964ded2b80b6a26962df9f03be6bcd3f44 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 12:50:32 +0100 Subject: [PATCH 26/38] add `surface` test --- ReferenceTests/src/tests/examples3d.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ReferenceTests/src/tests/examples3d.jl b/ReferenceTests/src/tests/examples3d.jl index 938ef68f456..306f72f88ef 100644 --- a/ReferenceTests/src/tests/examples3d.jl +++ b/ReferenceTests/src/tests/examples3d.jl @@ -230,6 +230,15 @@ end fig end +@reference_test "colorscale (surface)" begin + x = y = range(-1, 1; length = 20) + f(x, y) = exp(-(x^2 + y^2)^2) + fig = Figure() + surface(fig[1, 1], x, y, f; colorscale = identity) + surface(fig[1, 2], x, y, f; colorscale = log10) + fig +end + @reference_test "FEM mesh 3D" begin cat = loadasset("cat.obj") vertices = decompose(Point3f, cat) From 37195be2a2eb84a0dfe1eedbae1e85fa2cdb11ea Mon Sep 17 00:00:00 2001 From: t-bltg Date: Fri, 6 Jan 2023 18:05:09 +0100 Subject: [PATCH 27/38] simplify imports --- CairoMakie/src/CairoMakie.jl | 2 +- CairoMakie/src/utils.jl | 8 ++++---- WGLMakie/src/WGLMakie.jl | 2 +- WGLMakie/src/imagelike.jl | 4 +--- WGLMakie/src/lines.jl | 2 +- WGLMakie/src/meshes.jl | 4 ++-- WGLMakie/src/particles.jl | 2 +- WGLMakie/src/serialization.jl | 4 ++-- 8 files changed, 13 insertions(+), 15 deletions(-) diff --git a/CairoMakie/src/CairoMakie.jl b/CairoMakie/src/CairoMakie.jl index b5995fe1f33..3eaacf12c36 100644 --- a/CairoMakie/src/CairoMakie.jl +++ b/CairoMakie/src/CairoMakie.jl @@ -9,7 +9,7 @@ import Cairo using Makie: Scene, Lines, Text, Image, Heatmap, Scatter, @key_str, broadcast_foreach using Makie: convert_attribute, @extractvalue, LineSegments, to_ndim, NativeFont using Makie: @info, @get_attribute, Combined, MakieScreen -using Makie: to_value, to_colormap, extrema_nan +using Makie: to_value, to_colormap, extrema_nan, apply_scale using Makie.Observables using Makie: spaces, is_data_space, is_pixel_space, is_relative_space, is_clip_space using Makie: numbers_to_colors diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index a65493aa134..978dd7851b3 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -127,8 +127,8 @@ function to_rgba_image(img::AbstractMatrix{<: AbstractFloat}, attributes) lowclip = isnothing(lowclip) ? lowclip : Makie.to_color(lowclip) highclip = isnothing(highclip) ? highclip : Makie.to_color(highclip) - colorrange = Makie.apply_scale(colorscale, colorrange) - [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in Makie.apply_scale(colorscale, img)] + colorrange = apply_scale(colorscale, colorrange) + [get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in apply_scale(colorscale, img)] end to_rgba_image(img::AbstractMatrix{<: Colorant}, attributes) = RGBAf.(img) @@ -212,10 +212,10 @@ function per_face_colors( if color isa AbstractVector{<: Colorant} return FaceIterator(color, faces) elseif color isa AbstractArray{<: Number} - scaled_colorrange = Makie.apply_scale(colorscale, colorrange) + scaled_colorrange = apply_scale(colorscale, colorrange) low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c - scaled_c = Makie.apply_scale(colorscale, c) + scaled_c = apply_scale(colorscale, c) if isnan(scaled_c) && nan_color !== nothing return nan_color elseif scaled_c < low && lowclip !== nothing diff --git a/WGLMakie/src/WGLMakie.jl b/WGLMakie/src/WGLMakie.jl index ed705f25e6b..43854874a6c 100644 --- a/WGLMakie/src/WGLMakie.jl +++ b/WGLMakie/src/WGLMakie.jl @@ -25,7 +25,7 @@ import Makie.FileIO using Makie: get_texture_atlas, SceneSpace, Pixel using Makie: attribute_per_char, layout_text using Makie: MouseButtonEvent, KeyEvent -using Makie: apply_transform, transform_func_obs +using Makie: apply_transform, apply_scale, transform_func_obs, el32convert using Makie: spaces, is_data_space, is_pixel_space, is_relative_space, is_clip_space struct WebGL <: ShaderAbstractions.AbstractContext end diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 846e32ad8b3..e86f7ff6270 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -1,5 +1,3 @@ -using Makie: el32convert, surface_normals, get_dim, apply_scale - # Somehow we started using Nothing for some colors in Makie, # but the convert leaves them at nothing -.- # TODO clean this up in Makie @@ -107,7 +105,7 @@ function create_shader(mscene::Scene, plot::Surface) minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest color = Sampler(lift(x -> el32convert(to_color(apply_scale(plot.colorscale, permutedims(x)))), pcolor); minfilter=minfilter) - normals = Buffer(lift(surface_normals, px, py, pz)) + normals = Buffer(lift(Makie.surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) mesh = GeometryBasics.Mesh(vertices, faces) return draw_mesh(mscene, mesh, plot_attributes; uniform_color=color, color=false, diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index aa3aeab5edf..c7953e19846 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -13,7 +13,7 @@ end function array2color(colors, cmap, crange, cscale) cmap = RGBAf.(Colors.color.(to_colormap(cmap)), 1.0) - return Makie.interpolated_getindex.((cmap,), Makie.apply_scale(cscale, colors), (Makie.apply_scale(cscale, crange),)) + return Makie.interpolated_getindex.((cmap,), apply_scale(cscale, colors), (apply_scale(cscale, crange),)) end function array2color(colors::AbstractArray{<:Colorant}, _, _, _) diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 377c4831b12..07e340c1714 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -54,9 +54,9 @@ function create_shader(scene::Scene, plot::Makie.Mesh) if color isa AbstractArray if eltype(color) <: Number - uniforms[:colorrange] = lift(x -> Makie.apply_scale(plot.colorscale, x), converted_attribute(plot, :colorrange)) + uniforms[:colorrange] = lift(x -> apply_scale(plot.colorscale, x), converted_attribute(plot, :colorrange)) uniforms[:colormap] = Sampler(converted_attribute(plot, :colormap)) - color = Makie.apply_scale(plot.colorscale, color) + color = apply_scale(plot.colorscale, color) end if color isa AbstractVector attributes[:color] = Buffer(color) # per vertex colors diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index 99afae61bd8..9bcf5226b62 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -15,7 +15,7 @@ function handle_color!(uniform_dict, instance_dict) elseif color isa AbstractArray{<:Real} if haskey(uniform_dict, :colorscale) colorscale = pop!(uniform_dict, :colorscale) - udict[:color] = c = Makie.apply_scale(colorscale, color) + udict[:color] = c = apply_scale(colorscale, color) uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(c)) end uniform_dict[:color_getter] = """ diff --git a/WGLMakie/src/serialization.jl b/WGLMakie/src/serialization.jl index 7be3001196c..e2a62121cc0 100644 --- a/WGLMakie/src/serialization.jl +++ b/WGLMakie/src/serialization.jl @@ -152,9 +152,9 @@ end function wgl_convert(value, key1, key2) val = Makie.convert_attribute(value, key1, key2) return if val isa AbstractArray{<:Float64} - return Makie.el32convert(val) + el32convert(val) else - return val + val end end From 6c292e449ce9712f8645147a28b25c2e02ae8c33 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sat, 7 Jan 2023 10:47:01 +0100 Subject: [PATCH 28/38] remove unrelated changes --- WGLMakie/src/lines.jl | 5 +---- WGLMakie/src/precompiles.jl | 4 ++-- src/makielayout/blocks/axis.jl | 2 +- src/makielayout/blocks/colorbar.jl | 30 +++++++++++++++++++++++------- 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/WGLMakie/src/lines.jl b/WGLMakie/src/lines.jl index c7953e19846..cfdbfa96968 100644 --- a/WGLMakie/src/lines.jl +++ b/WGLMakie/src/lines.jl @@ -11,15 +11,12 @@ function topoint(x::AbstractArray{<:Tuple{P,P}}) where {P<:Point} return topoint(reinterpret(P, x)) end +array2color(colors::AbstractArray{<:Colorant}, _, _, _) = RGBAf.(colors) function array2color(colors, cmap, crange, cscale) cmap = RGBAf.(Colors.color.(to_colormap(cmap)), 1.0) return Makie.interpolated_getindex.((cmap,), apply_scale(cscale, colors), (apply_scale(cscale, crange),)) end -function array2color(colors::AbstractArray{<:Colorant}, _, _, _) - return RGBAf.(colors) -end - function create_shader(scene::Scene, plot::Union{Lines,LineSegments}) # Potentially per instance attributes positions = lift(plot[1], transform_func_obs(plot), get(plot, :space, :data)) do points, trans, space diff --git a/WGLMakie/src/precompiles.jl b/WGLMakie/src/precompiles.jl index 32406492f6f..ac7b41ed554 100644 --- a/WGLMakie/src/precompiles.jl +++ b/WGLMakie/src/precompiles.jl @@ -9,9 +9,9 @@ macro compile(block) # So we just do all parts of the stack we can do without browser scene = Makie.get_scene(figlike) session = Session(JSServe.NoConnection(); asset_server=JSServe.NoServer()) - WGLMakie.three_display(session, scene) + three_display(session, scene) JSServe.jsrender(session, figlike) - s = WGLMakie.serialize_scene(scene) + s = serialize_scene(scene) JSServe.serialize_binary(session, Dict(:data => s)) end end diff --git a/src/makielayout/blocks/axis.jl b/src/makielayout/blocks/axis.jl index afb04bf7b2a..5b5a1180320 100644 --- a/src/makielayout/blocks/axis.jl +++ b/src/makielayout/blocks/axis.jl @@ -818,7 +818,7 @@ function expandlimits(lims, margin_low, margin_high, scale) w_scaled = lims_scaled[2] - lims_scaled[1] d_low_scaled = w_scaled * margin_low d_high_scaled = w_scaled * margin_high - inverse = inverse_transform(scale) + inverse = Makie.inverse_transform(scale) lims = inverse.((lims_scaled[1] - d_low_scaled, lims_scaled[2] + d_high_scaled)) # guard against singular limits from something like a vline or hline diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index 2f73c87d825..195979f0459 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -175,6 +175,7 @@ function initialize_block!(cb::Colorbar) # for categorical colormaps we make a number of rectangle polys rects_and_colors = lift(barbox, cb.vertical, steps, cgradient, cb.scale, limits) do bbox, v, steps, gradient, scale, lims + # we need to convert the 0 to 1 steps into rescaled 0 to 1 steps given the # colormap's `scale` attribute @@ -272,16 +273,24 @@ function initialize_block!(cb::Colorbar) borderpoints = lift(barbox, highclip_tri_visible, lowclip_tri_visible) do bb, hcv, lcv if cb.vertical[] points = [bottomright(bb), topright(bb)] - hcv && push!(points, highclip_tri[][3]) + if hcv + push!(points, highclip_tri[][3]) + end append!(points, [topleft(bb), bottomleft(bb)]) - lcv && push!(points, lowclip_tri[][3]) + if lcv + push!(points, lowclip_tri[][3]) + end push!(points, bottomright(bb)) points else points = [bottomleft(bb), bottomright(bb)] - hcv && push!(points, highclip_tri[][3]) + if hcv + push!(points, highclip_tri[][3]) + end append!(points, [topright(bb), topleft(bb)]) - lcv && push!(points, lowclip_tri[][3]) + if lcv + push!(points, lowclip_tri[][3]) + end push!(points, bottomleft(bb)) points end @@ -325,7 +334,11 @@ function initialize_block!(cb::Colorbar) cb.axis = axis - onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, vertical, flipaxis + + onany(axis.protrusion, cb.vertical, cb.flipaxis) do axprotrusion, + vertical, flipaxis + + left, right, top, bottom = 0f0, 0f0, 0f0, 0f0 if vertical @@ -359,7 +372,10 @@ end Sets the space allocated for the ticklabels of the `Colorbar` to the minimum that is needed and returns that value. """ -tight_ticklabel_spacing!(cb::Colorbar) = tight_ticklabel_spacing!(cb.axis) +function tight_ticklabel_spacing!(cb::Colorbar) + space = tight_ticklabel_spacing!(cb.axis) + return space +end function scaled_steps(steps, scale, lims) # first scale to limits so we can actually apply the scale to the values @@ -368,5 +384,5 @@ function scaled_steps(steps, scale, lims) # scale with scaling function s_limits_scaled = scale.(s_limits) # then rescale to 0 to 1 - (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) + s_scaled = (s_limits_scaled .- s_limits_scaled[1]) ./ (s_limits_scaled[end] - s_limits_scaled[1]) end From fff22f21ab235fb1c6ced1b46d959dfdeabf5027 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sat, 7 Jan 2023 10:54:15 +0100 Subject: [PATCH 29/38] simplify `Colorbar` checks --- src/makielayout/blocks/colorbar.jl | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/makielayout/blocks/colorbar.jl b/src/makielayout/blocks/colorbar.jl index 195979f0459..08fe764eba3 100644 --- a/src/makielayout/blocks/colorbar.jl +++ b/src/makielayout/blocks/colorbar.jl @@ -17,14 +17,17 @@ function block_docs(::Type{Colorbar}) """ end - -function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) - - for key in (:colormap, :limits) - if key in keys(kwargs) +function colorbar_check(keys, kwargs_keys) + for key in keys + if key in kwargs_keys error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") end end +end + +function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) + colorbar_check((:colormap, :limits), keys(kwargs)) + Colorbar( fig_or_scene; colormap = plot.colormap, @@ -35,12 +38,8 @@ function Colorbar(fig_or_scene, plot::AbstractPlot; kwargs...) end function Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) + colorbar_check((:colormap, :limits, :highclip, :lowclip), keys(kwargs)) - for key in (:colormap, :limits, :highclip, :lowclip) - if key in keys(kwargs) - error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") - end - end Colorbar( fig_or_scene; colormap = heatmap.colormap, @@ -53,12 +52,7 @@ function Colorbar(fig_or_scene, heatmap::Union{Heatmap, Image}; kwargs...) end function Colorbar(fig_or_scene, contourf::Union{Contourf, Tricontourf}; kwargs...) - - for key in (:colormap, :limits, :highclip, :lowclip) - if key in keys(kwargs) - error("You should not pass the `$key` attribute to the colorbar when constructing it using an existing plot object. This attribute is copied from the plot object, and setting it from the colorbar will make the plot object and the colorbar go out of sync.") - end - end + colorbar_check((:colormap, :limits, :highclip, :lowclip), keys(kwargs)) steps = contourf._computed_levels From 9269b5e1ac087ca62441599052a2cf07cd92e01e Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sat, 7 Jan 2023 11:50:16 +0100 Subject: [PATCH 30/38] add `poly` example --- ReferenceTests/src/tests/examples3d.jl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ReferenceTests/src/tests/examples3d.jl b/ReferenceTests/src/tests/examples3d.jl index 306f72f88ef..c48ce8b043c 100644 --- a/ReferenceTests/src/tests/examples3d.jl +++ b/ReferenceTests/src/tests/examples3d.jl @@ -239,6 +239,21 @@ end fig end +@reference_test "colorscale (poly)" begin + X = [0. 1 1 2; 1 1 2 2; 0 0 1 1] + Y = [1. 1 1 1; 1 0 1 0; 0 0 0 0] + Z = [1. 1 1 1; 1 0 1 0; 0 0 0 0] + C = [.5 1. 1. .5; 1. .5 .5 .1667; .333 .333 .5 .5] + + vertices = connect(reshape([X[:] Y[:] Z[:]]', :), Point3f) + indices = connect(1:length(X), TriangleFace) + + fig = Figure() + poly!(Axis3(fig[1, 1]), vertices, indices; color = C[:], strokewidth = 1, colorscale = identity) + poly!(Axis3(fig[1, 2]), vertices, indices; color = C[:], strokewidth = 1, colorscale = log10) + fig +end + @reference_test "FEM mesh 3D" begin cat = loadasset("cat.obj") vertices = decompose(Point3f, cat) From 0ae2786561e91e92b90fa03d687ae3ea51e93631 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 14:09:11 +0200 Subject: [PATCH 31/38] fix interactivity bugs --- GLMakie/src/drawing_primitives.jl | 4 ++-- src/colorsampler.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 90b340e0fe7..57f27e31b84 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -187,7 +187,7 @@ pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) function handle_color_norm!(attributes, colorscale) if haskey(attributes, :color_norm) - attributes[:color_norm] = apply_scale(colorscale, attributes[:color_norm]) + attributes[:color_norm] = lift(x -> apply_scale(colorscale, x), attributes[:color_norm]) end end @@ -206,7 +206,7 @@ function handle_intensities!(attributes, colorscale) end function handle_colorscale!(p::AbstractPlot, attributes, x) - colorscale = haskey(p, :colorscale) ? p.colorscale : nothing + colorscale = default_colorscale(p) handle_color_norm!(attributes, colorscale) lift(x -> el32convert(apply_scale(colorscale, x)), x) end diff --git a/src/colorsampler.jl b/src/colorsampler.jl index 70fe6b71f22..f24285c4fe3 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -128,7 +128,7 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end -apply_scale(scale::AbstractObservable, x) = apply_scale(scale[], x) +apply_scale(scale::AbstractObservable, x) = lift(scale -> apply_scale(scale, x), scale) apply_scale(::Union{Nothing,typeof(identity)}, x) = x # noop apply_scale(scale, x) = broadcast(scale, to_value(x)) From 40d90e3f49c5ff3e4b9256038372f6e40bca63c1 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 14:36:09 +0200 Subject: [PATCH 32/38] fix precompilation --- CairoMakie/src/utils.jl | 4 ++-- GLMakie/src/drawing_primitives.jl | 6 +++--- WGLMakie/src/imagelike.jl | 8 ++++---- WGLMakie/src/particles.jl | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 85adbd5a4e0..7584fa99022 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -242,10 +242,10 @@ function per_face_colors( if color isa AbstractVector{<: Colorant} return FaceIterator(color, faces) elseif color isa AbstractArray{<: Number} - scaled_colorrange = apply_scale(colorscale, colorrange) + scaled_colorrange = apply_scale(colorscale, colorrange) |> to_value low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c - scaled_c = apply_scale(colorscale, c) + scaled_c = apply_scale(colorscale, c) |> to_value if isnan(scaled_c) && nan_color !== nothing return nan_color elseif scaled_c < low && lowclip !== nothing diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 57f27e31b84..59799716ca1 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -187,7 +187,7 @@ pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) function handle_color_norm!(attributes, colorscale) if haskey(attributes, :color_norm) - attributes[:color_norm] = lift(x -> apply_scale(colorscale, x), attributes[:color_norm]) + attributes[:color_norm] = apply_scale(colorscale, attributes[:color_norm]) end end @@ -521,13 +521,13 @@ function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert, apply_scale(colorscale, color)), minfilter = interp) + gl_attributes[:image] = Texture(const_lift(el32convert ∘ to_value, apply_scale(colorscale, color)), minfilter = interp) handle_color_norm!(gl_attributes, colorscale) gl_attributes[:color] = nothing elseif to_value(color) isa AbstractVector{<:Colorant} gl_attributes[:vertex_color] = lift(el32convert, color) elseif to_value(color) isa AbstractVector{<:Number} - gl_attributes[:vertex_color] = lift(el32convert, apply_scale(colorscale, color)) + gl_attributes[:vertex_color] = lift(el32convert ∘ to_value, apply_scale(colorscale, color)) handle_color_norm!(gl_attributes, colorscale) else error("Unsupported color type: $(typeof(to_value(color)))") diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index b6e7bb13e19..8b659e43fa0 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -134,7 +134,7 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - color = Sampler(lift(x -> el32convert(to_color(apply_scale(plot.colorscale, permutedims(x)))), pcolor); + color = Sampler(lift(x -> (el32convert ∘ to_color ∘ to_value)(apply_scale(plot.colorscale, permutedims(x))), pcolor); minfilter=minfilter) normals = Buffer(lift(Makie.surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) @@ -152,7 +152,7 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] plot_attributes = copy(plot.attributes) - color = Sampler(map(x -> el32convert(apply_scale(plot.colorscale, permutedims(x))), image); + color = Sampler(map(x -> (el32convert ∘ to_value)(apply_scale(plot.colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) if eltype(color) <: Colorant @@ -191,10 +191,10 @@ function create_shader(mscene::Scene, plot::Volume) shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot.shininess) uniforms = Dict{Symbol, Any}( - :volumedata => Sampler(lift(el32convert, apply_scale(plot.colorscale, vol))), + :volumedata => Sampler(lift(x -> (el32convert ∘ to_value)(apply_scale(plot.colorscale, x)), vol)), :modelinv => modelinv, :colormap => Sampler(lift(to_colormap, plot.colormap)), - :colorrange => lift(Vec2f, apply_scale(plot.colorscale, plot.colorrange)), + :colorrange => lift(Vec2f, apply_scale(plot.colorscale, plot.colorrange) |> to_value), :isovalue => lift(Float32, plot.isovalue), :isorange => lift(Float32, plot.isorange), :absorption => lift(Float32, get(plot, :absorption, Observable(1.0f0))), diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index 4191cf0ca7a..d5bf647a6d1 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -16,7 +16,7 @@ function handle_color!(uniform_dict, instance_dict) if haskey(uniform_dict, :colorscale) colorscale = pop!(uniform_dict, :colorscale) udict[:color] = c = apply_scale(colorscale, color) - uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(c)) + uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(to_value(c))) end uniform_dict[:color_getter] = """ vec4 get_color(){ From feacbea2ddba6eab097d0a056efb5285c0f1d741 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 18:59:18 +0200 Subject: [PATCH 33/38] fix WGLMakie --- GLMakie/src/drawing_primitives.jl | 19 +++++++++---------- WGLMakie/src/imagelike.jl | 17 +++++++++-------- WGLMakie/src/meshes.jl | 5 +++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 59799716ca1..2f3444b02a8 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -20,8 +20,6 @@ to_range(x::VecTypes{2}) = x to_range(x::AbstractRange) = (minimum(x), maximum(x)) to_range(x::AbstractVector) = (minimum(x), maximum(x)) -default_colorscale(x) = hasproperty(x, :colorscale) ? x.colorscale : nothing - function to_range(x::AbstractArray) if length(x) in size(x) # assert that just one dim != 1 to_range(vec(x)) @@ -206,7 +204,7 @@ function handle_intensities!(attributes, colorscale) end function handle_colorscale!(p::AbstractPlot, attributes, x) - colorscale = default_colorscale(p) + colorscale = get(p, :colorscale, nothing) handle_color_norm!(attributes, colorscale) lift(x -> el32convert(apply_scale(colorscale, x)), x) end @@ -267,7 +265,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatte end return draw_pixel_scatter(screen, positions, gl_attributes) else - handle_intensities!(gl_attributes, default_colorscale(x)) + handle_intensities!(gl_attributes, get(x, :colorscale, nothing)) if x isa MeshScatter if haskey(gl_attributes, :color) && to_value(gl_attributes[:color]) isa AbstractMatrix{<: Colorant} gl_attributes[:image] = gl_attributes[:color] @@ -317,7 +315,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines)) output end end - handle_intensities!(data, default_colorscale(x)) + handle_intensities!(data, get(x, :colorscale, nothing)) return draw_lines(screen, positions, data) end end @@ -490,7 +488,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Image) gl_attributes[:shading] = false space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call connect_camera!(x, gl_attributes, scene.camera) - return mesh_inner(screen, mesh, transform_func_obs(x), default_colorscale(x), gl_attributes, space) + return mesh_inner(screen, mesh, transform_func_obs(x), get(x, :colorscale, nothing), gl_attributes, space) end end @@ -506,6 +504,7 @@ function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, gl_attributes[:shading] = to_value(pop!(gl_attributes, :shading)) color = pop!(gl_attributes, :color) interp = to_value(pop!(gl_attributes, :interpolate, true)) + colorscale = to_value(colorscale) interp = interp ? :linear : :nearest if to_value(color) isa Colorant @@ -521,13 +520,13 @@ function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert ∘ to_value, apply_scale(colorscale, color)), minfilter = interp) + gl_attributes[:image] = Texture(const_lift(el32convert, apply_scale(colorscale, color)), minfilter = interp) handle_color_norm!(gl_attributes, colorscale) gl_attributes[:color] = nothing elseif to_value(color) isa AbstractVector{<:Colorant} gl_attributes[:vertex_color] = lift(el32convert, color) elseif to_value(color) isa AbstractVector{<:Number} - gl_attributes[:vertex_color] = lift(el32convert ∘ to_value, apply_scale(colorscale, color)) + gl_attributes[:vertex_color] = lift(el32convert, apply_scale(colorscale, color)) handle_color_norm!(gl_attributes, colorscale) else error("Unsupported color type: $(typeof(to_value(color)))") @@ -546,7 +545,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Mesh) t = transform_func_obs(x) space = get(gl_attributes, :space, :data) # needs to happen before connect_camera! call connect_camera!(x, gl_attributes, scene.camera) - return mesh_inner(screen, x[1], t, default_colorscale(x), gl_attributes, space) + return mesh_inner(screen, x[1], t, get(x, :colorscale, nothing), gl_attributes, space) end end @@ -557,7 +556,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) # signals not supported for shading yet # We automatically insert x[3] into the color channel, so if it's equal we don't need to do anything if isa(to_value(color), AbstractMatrix{<: Number}) && to_value(color) !== to_value(x[3]) - img = handle_colorscale!(x, gl_attributes, color) + img = handle_colorscale!(x, gl_attributes, color) |> to_value elseif to_value(color) isa Makie.AbstractPattern pattern_img = lift(x -> el32convert(Makie.to_image(x)), color) img = ShaderAbstractions.Sampler(pattern_img, x_repeat=:repeat, minfilter=:nearest) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 8b659e43fa0..3a0200e8c25 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -16,12 +16,10 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) uniforms[:colormap] = Sampler(cmap) end - colorscale = pop!(plot, :colorscale, identity) + colorscale = to_value(pop!(plot, :colorscale, nothing)) colorrange = if haskey(plot, :colorrange) - uniforms[:colorrange] = lift(plot.colorrange, colorscale) do colorrange, colorscale - return Vec2f(apply_scale(colorscale, colorrange)) - end + uniforms[:colorrange] = lift(x -> Vec2f(apply_scale(colorscale, x)), plot.colorrange) end get!(uniforms, :colormap, false) @@ -134,7 +132,8 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - color = Sampler(lift(x -> (el32convert ∘ to_color ∘ to_value)(apply_scale(plot.colorscale, permutedims(x))), pcolor); + colorscale = to_value(get(plot, :colorscale, nothing)) + color = Sampler(lift(x -> (el32convert ∘ to_color)(apply_scale(colorscale, permutedims(x))), pcolor); minfilter=minfilter) normals = Buffer(lift(Makie.surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) @@ -152,7 +151,8 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] plot_attributes = copy(plot.attributes) - color = Sampler(map(x -> (el32convert ∘ to_value)(apply_scale(plot.colorscale, permutedims(x))), image); + colorscale = to_value(get(plot, :colorscale, nothing)) + color = Sampler(lift(x -> el32convert(apply_scale(colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) if eltype(color) <: Colorant @@ -189,12 +189,13 @@ function create_shader(mscene::Scene, plot::Volume) diffuse = lift(x -> convert_attribute(x, Key{:diffuse}()), plot.diffuse) specular = lift(x -> convert_attribute(x, Key{:specular}()), plot.specular) shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot.shininess) + colorscale = to_value(get(plot, :colorscale, nothing)) uniforms = Dict{Symbol, Any}( - :volumedata => Sampler(lift(x -> (el32convert ∘ to_value)(apply_scale(plot.colorscale, x)), vol)), + :volumedata => Sampler(lift(x -> el32convert(apply_scale(colorscale, x)), vol)), :modelinv => modelinv, :colormap => Sampler(lift(to_colormap, plot.colormap)), - :colorrange => lift(Vec2f, apply_scale(plot.colorscale, plot.colorrange) |> to_value), + :colorrange => lift(Vec2f, apply_scale(colorscale, plot.colorrange)), :isovalue => lift(Float32, plot.isovalue), :isorange => lift(Float32, plot.isorange), :absorption => lift(Float32, get(plot, :absorption, Observable(1.0f0))), diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 63b7b0f7498..173439b7263 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -51,12 +51,13 @@ function create_shader(scene::Scene, plot::Makie.Mesh) end color = color_signal[] uniforms[:uniform_color] = Observable(false) # this is the default + colorscale = to_value(get(plot, :colorscale, nothing)) if color isa AbstractArray if eltype(color) <: Number - uniforms[:colorrange] = lift(x -> apply_scale(plot.colorscale, x), converted_attribute(plot, :colorrange)) + uniforms[:colorrange] = apply_scale(colorscale, converted_attribute(plot, :colorrange)) uniforms[:colormap] = Sampler(converted_attribute(plot, :colormap)) - color = apply_scale(plot.colorscale, color) + color = apply_scale(colorscale, color) end if color isa AbstractVector attributes[:color] = Buffer(color) # per vertex colors From bcbabbd26ae4182c747a50ac18c41a3a73bf7267 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 19:40:36 +0200 Subject: [PATCH 34/38] fix GLMakie --- GLMakie/src/drawing_primitives.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 2f3444b02a8..641edde1421 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -192,7 +192,7 @@ end function handle_intensities!(attributes, colorscale) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} color = pop!(attributes, :color) - attributes[:intensity] = lift(color, colorscale) do color, colorscale + attributes[:intensity] = lift(colorscale, color) do colorscale, color return convert(Vector{Float32}, apply_scale(colorscale, color)) end handle_color_norm!(attributes, colorscale) @@ -582,7 +582,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) types = map(v -> typeof(to_value(v)), x[1:2]) if isnothing(img) - gl_attributes[:image] = Texture(handle_colorscale!(x, gl_attributes, mat); minfilter=:linear) + gl_attributes[:image] = Texture(handle_colorscale!(x, gl_attributes, mat) |> to_value; minfilter=:linear) end if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types) t = Makie.transform_func_obs(x) From 25abda9974ab32c92aa7bdfd558b4529a848ba05 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 22:34:56 +0200 Subject: [PATCH 35/38] rework - all tests pass --- CairoMakie/src/utils.jl | 4 ++-- GLMakie/src/drawing_primitives.jl | 17 ++++++++++------- WGLMakie/src/imagelike.jl | 6 +++--- WGLMakie/src/meshes.jl | 2 +- src/colorsampler.jl | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CairoMakie/src/utils.jl b/CairoMakie/src/utils.jl index 7584fa99022..85adbd5a4e0 100644 --- a/CairoMakie/src/utils.jl +++ b/CairoMakie/src/utils.jl @@ -242,10 +242,10 @@ function per_face_colors( if color isa AbstractVector{<: Colorant} return FaceIterator(color, faces) elseif color isa AbstractArray{<: Number} - scaled_colorrange = apply_scale(colorscale, colorrange) |> to_value + scaled_colorrange = apply_scale(colorscale, colorrange) low, high = extrema(scaled_colorrange) cvec = map(color[:]) do c - scaled_c = apply_scale(colorscale, c) |> to_value + scaled_c = apply_scale(colorscale, c) if isnan(scaled_c) && nan_color !== nothing return nan_color elseif scaled_c < low && lowclip !== nothing diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 641edde1421..00b38741833 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -185,7 +185,9 @@ pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize) function handle_color_norm!(attributes, colorscale) if haskey(attributes, :color_norm) - attributes[:color_norm] = apply_scale(colorscale, attributes[:color_norm]) + attributes[:color_norm] = lift(colorscale, attributes[:color_norm]) do colorscale, color_norm + apply_scale(colorscale, color_norm) + end end end @@ -193,7 +195,7 @@ function handle_intensities!(attributes, colorscale) if haskey(attributes, :color) && attributes[:color][] isa AbstractVector{<: Number} color = pop!(attributes, :color) attributes[:intensity] = lift(colorscale, color) do colorscale, color - return convert(Vector{Float32}, apply_scale(colorscale, color)) + convert(Vector{Float32}, apply_scale(colorscale, color)) end handle_color_norm!(attributes, colorscale) else @@ -204,9 +206,11 @@ function handle_intensities!(attributes, colorscale) end function handle_colorscale!(p::AbstractPlot, attributes, x) - colorscale = get(p, :colorscale, nothing) + colorscale = get(p, :colorscale, Observable(nothing)) handle_color_norm!(attributes, colorscale) - lift(x -> el32convert(apply_scale(colorscale, x)), x) + lift(colorscale, x) do colorscale, x + el32convert(apply_scale(colorscale, x)) + end end function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Union{Scatter, MeshScatter})) @@ -504,7 +508,6 @@ function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, gl_attributes[:shading] = to_value(pop!(gl_attributes, :shading)) color = pop!(gl_attributes, :color) interp = to_value(pop!(gl_attributes, :interpolate, true)) - colorscale = to_value(colorscale) interp = interp ? :linear : :nearest if to_value(color) isa Colorant @@ -556,7 +559,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) # signals not supported for shading yet # We automatically insert x[3] into the color channel, so if it's equal we don't need to do anything if isa(to_value(color), AbstractMatrix{<: Number}) && to_value(color) !== to_value(x[3]) - img = handle_colorscale!(x, gl_attributes, color) |> to_value + img = handle_colorscale!(x, gl_attributes, color) elseif to_value(color) isa Makie.AbstractPattern pattern_img = lift(x -> el32convert(Makie.to_image(x)), color) img = ShaderAbstractions.Sampler(pattern_img, x_repeat=:repeat, minfilter=:nearest) @@ -582,7 +585,7 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface) types = map(v -> typeof(to_value(v)), x[1:2]) if isnothing(img) - gl_attributes[:image] = Texture(handle_colorscale!(x, gl_attributes, mat) |> to_value; minfilter=:linear) + gl_attributes[:image] = Texture(handle_colorscale!(x, gl_attributes, mat); minfilter=:linear) end if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types) t = Makie.transform_func_obs(x) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 3a0200e8c25..6c29442828f 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -132,7 +132,7 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - colorscale = to_value(get(plot, :colorscale, nothing)) + colorscale = get(plot, :colorscale, nothing) color = Sampler(lift(x -> (el32convert ∘ to_color)(apply_scale(colorscale, permutedims(x))), pcolor); minfilter=minfilter) normals = Buffer(lift(Makie.surface_normals, px, py, pz)) @@ -151,7 +151,7 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] plot_attributes = copy(plot.attributes) - colorscale = to_value(get(plot, :colorscale, nothing)) + colorscale = get(plot, :colorscale, nothing) color = Sampler(lift(x -> el32convert(apply_scale(colorscale, permutedims(x))), image); minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) @@ -189,7 +189,7 @@ function create_shader(mscene::Scene, plot::Volume) diffuse = lift(x -> convert_attribute(x, Key{:diffuse}()), plot.diffuse) specular = lift(x -> convert_attribute(x, Key{:specular}()), plot.specular) shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot.shininess) - colorscale = to_value(get(plot, :colorscale, nothing)) + colorscale = get(plot, :colorscale, nothing) uniforms = Dict{Symbol, Any}( :volumedata => Sampler(lift(x -> el32convert(apply_scale(colorscale, x)), vol)), diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 173439b7263..8013a7cfd34 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -51,7 +51,7 @@ function create_shader(scene::Scene, plot::Makie.Mesh) end color = color_signal[] uniforms[:uniform_color] = Observable(false) # this is the default - colorscale = to_value(get(plot, :colorscale, nothing)) + colorscale = get(plot, :colorscale, nothing) if color isa AbstractArray if eltype(color) <: Number diff --git a/src/colorsampler.jl b/src/colorsampler.jl index f24285c4fe3..551c600f502 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -128,7 +128,7 @@ function sampler(cmap::Matrix{<: Colorant}, uv::AbstractVector{Vec2f}; return Sampler(cmap, uv, alpha, interpolation, Scaling()) end -apply_scale(scale::AbstractObservable, x) = lift(scale -> apply_scale(scale, x), scale) +apply_scale(scale::AbstractObservable, x) = apply_scale(to_value(scale), x) apply_scale(::Union{Nothing,typeof(identity)}, x) = x # noop apply_scale(scale, x) = broadcast(scale, to_value(x)) From fd63175781d617fc4c01ccebdcaecf013b866d07 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 9 Apr 2023 23:03:44 +0200 Subject: [PATCH 36/38] rework WGLMakie interactivity --- WGLMakie/src/imagelike.jl | 30 +++++++++++++++++++----------- WGLMakie/src/meshes.jl | 2 +- WGLMakie/src/particles.jl | 2 +- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 6c29442828f..db41172b8f9 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -16,10 +16,12 @@ function draw_mesh(mscene::Scene, mesh, plot; uniforms...) uniforms[:colormap] = Sampler(cmap) end - colorscale = to_value(pop!(plot, :colorscale, nothing)) + colorscale = pop!(plot, :colorscale, Observable(nothing)) colorrange = if haskey(plot, :colorrange) - uniforms[:colorrange] = lift(x -> Vec2f(apply_scale(colorscale, x)), plot.colorrange) + uniforms[:colorrange] = lift(colorscale, plot.colorrange) do colorscale, colorrange + Vec2f(apply_scale(colorscale, colorrange)) + end end get!(uniforms, :colormap, false) @@ -132,9 +134,10 @@ function create_shader(mscene::Scene, plot::Surface) pz end minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - colorscale = get(plot, :colorscale, nothing) - color = Sampler(lift(x -> (el32convert ∘ to_color)(apply_scale(colorscale, permutedims(x))), pcolor); - minfilter=minfilter) + colorscale = get(plot, :colorscale, Observable(nothing)) + color = Sampler(lift(colorscale, pcolor) do colorscale, x + apply_scale(colorscale, permutedims(x)) |> to_color|> el32convert + end; minfilter=minfilter) normals = Buffer(lift(Makie.surface_normals, px, py, pz)) vertices = GeometryBasics.meta(positions; uv=uv, normals=normals) mesh = GeometryBasics.Mesh(vertices, faces) @@ -151,9 +154,10 @@ end function create_shader(mscene::Scene, plot::Union{Heatmap, Image}) image = plot[3] plot_attributes = copy(plot.attributes) - colorscale = get(plot, :colorscale, nothing) - color = Sampler(lift(x -> el32convert(apply_scale(colorscale, permutedims(x))), image); - minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) + colorscale = get(plot, :colorscale, Observable(nothing)) + color = Sampler(lift(colorscale, image) do colorscale, x + apply_scale(colorscale, permutedims(x)) |> el32convert + end; minfilter=to_value(get(plot, :interpolate, false)) ? :linear : :nearest) mesh = limits_to_uvmesh(plot) if eltype(color) <: Colorant delete!(plot_attributes, :colormap) @@ -189,13 +193,17 @@ function create_shader(mscene::Scene, plot::Volume) diffuse = lift(x -> convert_attribute(x, Key{:diffuse}()), plot.diffuse) specular = lift(x -> convert_attribute(x, Key{:specular}()), plot.specular) shininess = lift(x -> convert_attribute(x, Key{:shininess}()), plot.shininess) - colorscale = get(plot, :colorscale, nothing) + colorscale = get(plot, :colorscale, Observable(nothing)) uniforms = Dict{Symbol, Any}( - :volumedata => Sampler(lift(x -> el32convert(apply_scale(colorscale, x)), vol)), + :volumedata => lift(colorscale, vol) do colorscale, x + el32convert(apply_scale(colorscale, x)) + end |> Sampler, :modelinv => modelinv, :colormap => Sampler(lift(to_colormap, plot.colormap)), - :colorrange => lift(Vec2f, apply_scale(colorscale, plot.colorrange)), + :colorrange => lift(colorscale, plot.colorrange) do colorscale, colorrange + Vec2f(apply_scale(colorscale, colorrange)) + end, :isovalue => lift(Float32, plot.isovalue), :isorange => lift(Float32, plot.isorange), :absorption => lift(Float32, get(plot, :absorption, Observable(1.0f0))), diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 8013a7cfd34..c09cd69595d 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -51,7 +51,7 @@ function create_shader(scene::Scene, plot::Makie.Mesh) end color = color_signal[] uniforms[:uniform_color] = Observable(false) # this is the default - colorscale = get(plot, :colorscale, nothing) + colorscale = get(plot, :colorscale, Observable(nothing)) if color isa AbstractArray if eltype(color) <: Number diff --git a/WGLMakie/src/particles.jl b/WGLMakie/src/particles.jl index d5bf647a6d1..4191cf0ca7a 100644 --- a/WGLMakie/src/particles.jl +++ b/WGLMakie/src/particles.jl @@ -16,7 +16,7 @@ function handle_color!(uniform_dict, instance_dict) if haskey(uniform_dict, :colorscale) colorscale = pop!(uniform_dict, :colorscale) udict[:color] = c = apply_scale(colorscale, color) - uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(to_value(c))) + uniform_dict[:colorrange] = Vec2f(Makie.distinct_extrema_nan(c)) end uniform_dict[:color_getter] = """ vec4 get_color(){ From 45870ff1952c089b3f0fcae0e7c5cfbf0f62c3f5 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sat, 15 Apr 2023 19:34:10 +0200 Subject: [PATCH 37/38] fix mesh --- GLMakie/src/drawing_primitives.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/GLMakie/src/drawing_primitives.jl b/GLMakie/src/drawing_primitives.jl index 00b38741833..3840a794f3b 100644 --- a/GLMakie/src/drawing_primitives.jl +++ b/GLMakie/src/drawing_primitives.jl @@ -523,13 +523,17 @@ function mesh_inner(screen::Screen, mesh, transfunc, colorscale, gl_attributes, delete!(gl_attributes, :color_map) delete!(gl_attributes, :color_norm) elseif to_value(color) isa AbstractMatrix{<: Number} - gl_attributes[:image] = Texture(const_lift(el32convert, apply_scale(colorscale, color)), minfilter = interp) + gl_attributes[:image] = Texture(lift(colorscale, color) do scale, col + el32convert(apply_scale(scale, col)) + end; minfilter = interp) handle_color_norm!(gl_attributes, colorscale) gl_attributes[:color] = nothing elseif to_value(color) isa AbstractVector{<:Colorant} gl_attributes[:vertex_color] = lift(el32convert, color) elseif to_value(color) isa AbstractVector{<:Number} - gl_attributes[:vertex_color] = lift(el32convert, apply_scale(colorscale, color)) + gl_attributes[:vertex_color] = lift(colorscale, color) do scale, col + el32convert(apply_scale(scale, col)) + end handle_color_norm!(gl_attributes, colorscale) else error("Unsupported color type: $(typeof(to_value(color)))") From 659f3c6391da691bd4e0fdf97bd1fab38d28c7b9 Mon Sep 17 00:00:00 2001 From: t-bltg Date: Sun, 16 Apr 2023 09:12:39 +0200 Subject: [PATCH 38/38] add interactive tests --- ReferenceTests/src/tests/primitives.jl | 2 +- ReferenceTests/src/tests/updating.jl | 42 +++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/ReferenceTests/src/tests/primitives.jl b/ReferenceTests/src/tests/primitives.jl index 211f350862b..fd30d410d93 100644 --- a/ReferenceTests/src/tests/primitives.jl +++ b/ReferenceTests/src/tests/primitives.jl @@ -150,7 +150,7 @@ end rotations = [ 2pi/3 * (i-1) for i = 1:length(pixel_types) ] s = Scene(resolution = (100+100*length(pixel_types), 400), camera = campixel!) filename = Makie.assetpath("icon_transparent.png") - marker_image = FileIO.load(filename) + marker_image = load(filename) for (i, (rot, pxtype)) in enumerate(zip(rotations, pixel_types)) marker = convert.(pxtype, marker_image) p = Point2f((i-1) * 100 + 100, 200) diff --git a/ReferenceTests/src/tests/updating.jl b/ReferenceTests/src/tests/updating.jl index 7b5118e17aa..89f91ccee57 100644 --- a/ReferenceTests/src/tests/updating.jl +++ b/ReferenceTests/src/tests/updating.jl @@ -64,7 +64,7 @@ function load_frames(video, dir) mkdir(framedir) Makie.extract_frames(video, framedir) return map(readdir(framedir; join=true)) do path - return convert(Matrix{RGB{N0f8}}, FileIO.load(path)) + return convert(Matrix{RGB{N0f8}}, load(path)) end end @@ -127,3 +127,43 @@ end sleep(1.0) f end + +@reference_test "interactive colorscale - mesh" begin + brain = load(assetpath("brain.stl")) + color = [abs(tri[1][2]) for tri in brain for i in 1:3] + f, ax, m = mesh(brain; color, colorscale=identity) + mesh(f[1, 2], brain; color, colorscale=log10) + st = Stepper(f) + Makie.step!(st) + m.colorscale = log10 + Makie.step!(st) +end + +@reference_test "interactive colorscale - heatmap" begin + data = exp.(abs.(randn(20, 20))) + f, ax, hm = heatmap(data, colorscale=log10, axis=(; title="log10")) + Colorbar(f[1, 2], hm) + ax2, hm2 = heatmap(f[1, 3], data, colorscale=log10, axis=(; title="log10")) + st = Stepper(f) + Makie.step!(st) + hm2.colorscale = identity + ax2.title = "identity" + Makie.step!(st) + hm.colorscale = identity + ax.title = "identity" + Makie.step!(st) +end + +@reference_test "interactive colorscale - hexbin" begin + x = randn(1_000) + y = randn(1_000) + f = Figure() + hexbin(f[1, 1], x, y; axis=(aspect=DataAspect(), title="identity")) + ax, hb = hexbin(f[1, 2], x, y; colorscale=log, axis=(aspect=DataAspect(), title="log")) + Colorbar(f[1, end+1], hb) + st = Stepper(f) + Makie.step!(st) + hb.colorscale = identity + ax.title = "identity" + Makie.step!(st) +end