Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add default colorscale attribute #2493

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
af19465
fix `Colorbar` `scale`
t-bltg Dec 13, 2022
6180d8d
fix axis scaled colormap
t-bltg Dec 22, 2022
915618d
fix colormap sampling
t-bltg Jan 5, 2023
f073f8c
implement `colorscale`
t-bltg Dec 22, 2022
2716a8f
modify recipes with default `colorscale`
t-bltg Dec 22, 2022
052591d
hexbin: replace `scale` with `colorscale` - add NEWS note
t-bltg Jan 5, 2023
a50451f
fix `per_face_colors`
t-bltg Dec 28, 2022
b9567cc
heatmap proof of concept for GLMakie
t-bltg Dec 28, 2022
4dc96cd
fix `Surface` primitive
t-bltg Dec 28, 2022
fb85b5d
conditional access `color_norm`
t-bltg Jan 5, 2023
7eb0289
`WGLMakie`: handle `colorscale` in upstream `interfaces.jl`
t-bltg Jan 5, 2023
8aa127a
update - precompiles
t-bltg Jan 5, 2023
e3790c6
revert handling in `interfaces`
t-bltg Jan 5, 2023
2bbf592
all backends precompile
t-bltg Jan 5, 2023
4c5478e
fix WGLMakie heatmap colorrange
t-bltg Jan 5, 2023
2b40929
cleanup
t-bltg Jan 5, 2023
44dfe13
fix GLMakie `scatter`
t-bltg Jan 5, 2023
7cc5455
fix WGLMAkie scatter
t-bltg Jan 5, 2023
f5fb2b8
fix WGLMakie `lines`
t-bltg Jan 5, 2023
66515a8
add `lines` & `scatter` ref examples
t-bltg Jan 5, 2023
ac4a350
add `hexbin` example
t-bltg Jan 5, 2023
46ea7b9
fix WGLMakie Volume
t-bltg Jan 6, 2023
8d0d78f
fix WGLMakie Mesh
t-bltg Jan 6, 2023
94b1f87
simplifications
t-bltg Jan 6, 2023
b99f98d
fix GLMakie Mesh
t-bltg Jan 6, 2023
cf57799
add `surface` test
t-bltg Jan 6, 2023
37195be
simplify imports
t-bltg Jan 6, 2023
6c292e4
remove unrelated changes
t-bltg Jan 7, 2023
fff22f2
simplify `Colorbar` checks
t-bltg Jan 7, 2023
9269b5e
add `poly` example
t-bltg Jan 7, 2023
95bf664
revert rename x -> plot | adapt to #2754
t-bltg Apr 1, 2023
0ae2786
fix interactivity bugs
t-bltg Apr 9, 2023
40d90e3
fix precompilation
t-bltg Apr 9, 2023
feacbea
fix WGLMakie
t-bltg Apr 9, 2023
bcbabbd
fix GLMakie
t-bltg Apr 9, 2023
25abda9
rework - all tests pass
t-bltg Apr 9, 2023
fd63175
rework WGLMakie interactivity
t-bltg Apr 9, 2023
45870ff
fix mesh
t-bltg Apr 15, 2023
659f3c6
add interactive tests
t-bltg Apr 16, 2023
a1b4326
Merge branch 'master' into log_cbar
SimonDanisch Apr 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CairoMakie/src/CairoMakie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -723,14 +723,15 @@ 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)
highclip = get_color_attr(plot, :highclip)
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
Expand Down Expand Up @@ -777,9 +778,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(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))

Expand All @@ -794,12 +796,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
Expand Down
20 changes: 11 additions & 9 deletions CairoMakie/src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,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)

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)

[get_rgba_pixel(pixel, colormap, colorrange, nan_color, lowclip, highclip) for pixel in 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)
Expand Down Expand Up @@ -224,7 +224,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
Expand All @@ -242,16 +242,18 @@ function per_face_colors(
if color isa AbstractVector{<: Colorant}
return FaceIterator(color, faces)
elseif color isa AbstractArray{<: Number}
low, high = extrema(colorrange)
scaled_colorrange = apply_scale(colorscale, colorrange)
low, high = extrema(scaled_colorrange)
cvec = map(color[:]) do c
if isnan(c) && nan_color !== nothing
scaled_c = apply_scale(colorscale, c)
if isnan(scaled_c) && nan_color !== nothing
return nan_color
elseif c < low && lowclip !== nothing
elseif scaled_c < low && lowclip !== nothing
return lowclip
elseif c > high && highclip !== nothing
elseif scaled_c > high && highclip !== nothing
return highclip
else
Makie.interpolated_getindex(colormap, c, colorrange)
Makie.interpolated_getindex(colormap, scaled_c, scaled_colorrange)
end
end
return FaceIterator(cvec, faces)
Expand Down
101 changes: 60 additions & 41 deletions GLMakie/src/drawing_primitives.jl
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -183,17 +183,36 @@ end

pixel2world(scene, msize::AbstractVector) = pixel2world.(scene, msize)

function handle_intensities!(attributes)
function handle_color_norm!(attributes, colorscale)
if haskey(attributes, :color_norm)
attributes[:color_norm] = lift(colorscale, attributes[:color_norm]) do colorscale, color_norm
apply_scale(colorscale, color_norm)
end
end
end

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(colorscale, color) do colorscale, color
convert(Vector{Float32}, apply_scale(colorscale, color))
end
handle_color_norm!(attributes, colorscale)
else
delete!(attributes, :intensity)
delete!(attributes, :color_map)
delete!(attributes, :color_norm)
end
end

function handle_colorscale!(p::AbstractPlot, attributes, x)
colorscale = get(p, :colorscale, Observable(nothing))
handle_color_norm!(attributes, colorscale)
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}))
return cached_robj!(screen, scene, x) do gl_attributes
# signals not supported for shading yet
Expand Down Expand Up @@ -250,7 +269,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, 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]
Expand Down Expand Up @@ -300,8 +319,7 @@ function draw_atomic(screen::Screen, scene::Scene, @nospecialize(x::Lines))
output
end
end

handle_intensities!(data)
handle_intensities!(data, get(x, :colorscale, nothing))
return draw_lines(screen, positions, data)
end
end
Expand Down Expand Up @@ -419,28 +437,22 @@ 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(x)
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
xpos = map(first, xypos)
ypos = map(last, xypos)
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
Expand Down Expand Up @@ -480,7 +492,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), gl_attributes, space)
return mesh_inner(screen, mesh, transform_func_obs(x), get(x, :colorscale, nothing), gl_attributes, space)
end
end

Expand All @@ -491,12 +503,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)
Expand All @@ -510,10 +523,18 @@ 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(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{<: 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(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)))")
end
Expand All @@ -526,12 +547,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!(meshplot, gl_attributes, scene.camera)
return mesh_inner(screen, meshplot[1], t, gl_attributes, space)
connect_camera!(x, gl_attributes, scene.camera)
return mesh_inner(screen, x[1], t, get(x, :colorscale, nothing), gl_attributes, space)
end
end

Expand All @@ -542,7 +563,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)
Expand All @@ -563,12 +584,15 @@ function draw_atomic(screen::Screen, scene::Scene, x::Surface)
gl_attributes[:shading] = to_value(get(gl_attributes, :shading, true))
connect_camera!(x, gl_attributes, scene.camera)

@assert to_value(x[3]) isa AbstractMatrix
mat = x[3]
@assert to_value(mat) isa AbstractMatrix
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)
end
if all(T -> T <: Union{AbstractMatrix, AbstractVector}, types)
t = Makie.transform_func_obs(x)
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)
Expand All @@ -589,16 +613,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
Expand Down
Loading