Skip to content

Commit

Permalink
Some conversion related fixes (#4599)
Browse files Browse the repository at this point in the history
* add conversion for Vector of MultiLineString

* add VecTypes -> color conversions

* add padding converts for Label

* guard against NaN rotation and markersize in CairoMakie

* Update CHANGELOG.md
  • Loading branch information
ffreyer authored Dec 3, 2024
1 parent 3d6ede0 commit 23ee755
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
- Fix polygon rendering issue of `crossbar(..., show_notch = true)` in CairoMakie [#4587](https://github.com/MakieOrg/Makie.jl/pull/4587).
- Fix `colorbuffer(axis)` for `px_per_unit != 1` [#4574](https://github.com/MakieOrg/Makie.jl/pull/4574).
- Fix render order of Axis3 frame lines in CairoMakie [#4591](https://github.com/MakieOrg/Makie.jl/pull/4591)
- Added PointBased conversion for `Vector{MultiLineString}` [#4599](https://github.com/MakieOrg/Makie.jl/pull/4599)
- Added color conversions for tuples, Points and Vecs [#4599](https://github.com/MakieOrg/Makie.jl/pull/4599)
- Added conversions for 1 and 2 value paddings in `Label` and `tooltip` [#4599](https://github.com/MakieOrg/Makie.jl/pull/4599)
- Fixed `NaN` in scatter rotation and markersize breaking Cairo state [#4599](https://github.com/MakieOrg/Makie.jl/pull/4599)
- Fix color mapping between contourf and colorbar [#4618](https://github.com/MakieOrg/Makie.jl/pull/4618)
- Fixed an incorrect comparison in CairoMakie's line clipping code causing a line segment to disappear [#4631](https://github.com/MakieOrg/Makie.jl/pull/4631)
- Fixed heatmap cells being 0.5px/units too large in CairoMakie [4633](https://github.com/MakieOrg/Makie.jl/pull/4633)
Expand Down
3 changes: 2 additions & 1 deletion CairoMakie/src/primitives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ function draw_atomic_scatter(
markersize, strokecolor, strokewidth, m, mo, rotation

isnan(pos) && return
isnan(rotation) && return # matches GLMakie

scale = project_scale(scene, markerspace, markersize, size_model)
offset = project_scale(scene, markerspace, mo, size_model)
Expand All @@ -372,7 +373,7 @@ function draw_atomic_scatter(
# Setting a markersize of 0.0 somehow seems to break Cairos global state?
# At least it stops drawing any marker afterwards
# TODO, maybe there's something wrong somewhere else?
if !(norm(scale) 0.0)
if !(isnan(scale) || norm(scale) 0.0)
if m isa Char
draw_marker(ctx, m, best_font(m, font), pos, scale, strokecolor, strokewidth, offset, rotation)
else
Expand Down
10 changes: 10 additions & 0 deletions ReferenceTests/src/tests/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,13 @@
scatter(fig[1, 2], RNG.randn(20), color=colors, markersize=10, visible=false)
fig
end

@reference_test "(mesh)scatter with NaN rotation and markersize" begin
scene = Scene(size = (150, 300))
xs = [-0.6, 0.0, 0.6]
scatter!(scene, xs, fill( 0.75, 3), marker = :ltriangle, rotation = [0.5, NaN, -0.5], markersize = 50)
scatter!(scene, xs, fill( 0.25, 3), marker = :ltriangle, markersize = [50, NaN, 50])
meshscatter!(scene, xs, fill(-0.25, 3), marker = Rect2f(-0.5,-0.5,1,1), rotation = [0.5, NaN, -0.5], markersize = 0.2)
meshscatter!(scene, xs, fill(-0.75, 3), marker = Rect2f(-0.5,-0.5,1,1), markersize = [0.2, NaN, 0.2])
scene
end
13 changes: 2 additions & 11 deletions src/basic_recipes/tooltip.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,7 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}})

# Text

textpadding = map(p, p.textpadding) do pad
if pad isa Real
return (pad, pad, pad, pad)
elseif length(pad) == 4
return pad
else
@error "Failed to parse $pad as (left, right, bottom, top). Using defaults"
return (4, 4, 4, 4)
end
end
textpadding = map(to_lrbt_padding, p, p.textpadding)

text_offset = map(p, p.offset, textpadding, p.triangle_size, p.placement, p.align) do o, pad, ts, placement, align
l, r, b, t = pad
Expand Down Expand Up @@ -195,7 +186,7 @@ function plot!(p::Tooltip{<:Tuple{<:VecTypes}})

mesh!(
p, tri_points, [1 2 3], shading = NoShading, space = :pixel,
color = p.backgroundcolor, fxaa = false,
color = p.backgroundcolor, fxaa = false,
transparency = p.transparency, visible = p.visible,
overdraw = p.overdraw, depth_shift = p.depth_shift,
inspectable = p.inspectable, transformation = Transformation()
Expand Down
9 changes: 8 additions & 1 deletion src/conversions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ end
Takes an input `Array{LineString}` or a `MultiLineString` and decomposes it to points.
"""
function convert_arguments(PB::PointBased, linestring::Union{<:AbstractVector{<:LineString{N, T}}, MultiLineString{N, T}}) where {N, T}
function convert_arguments(PB::PointBased, linestring::Union{AbstractVector{<:LineString{N, T}}, MultiLineString{N, T}, AbstractVector{<:MultiLineString{N,T}}}) where {N, T}
T_out = float_type(T)
arr = Point{N, T_out}[]; n = length(linestring)
for idx in 1:n
Expand Down Expand Up @@ -920,6 +920,8 @@ end
to_color(c::Nothing) = c # for when color is not used
to_color(c::Real) = Float32(c)
to_color(c::Colorant) = convert(RGBA{Float32}, c)
to_color(c::VecTypes{3}) = RGBAf(c[1], c[2], c[3], 1)
to_color(c::VecTypes{4}) = RGBAf(c[1], c[2], c[3], c[4])
to_color(c::Symbol) = to_color(string(c))
to_color(c::String) = parse(RGBA{Float32}, c)
to_color(c::AbstractArray) = to_color.(c)
Expand Down Expand Up @@ -1980,3 +1982,8 @@ assemble_colors(::ShaderAbstractions.Sampler, color, plot) = Observable(el32conv
# BUFFER OVERLOAD

GeometryBasics.collect_with_eltype(::Type{T}, vec::ShaderAbstractions.Buffer{T}) where {T} = vec

# Used in Label, maybe useful elsewhere?
to_lrbt_padding(x::Real) = Vec4f(x)
to_lrbt_padding(xy::VecTypes{2}) = Vec4f(xy[1], xy[1], xy[2], xy[2])
to_lrbt_padding(pad::VecTypes{4}) = to_ndim(Vec4f, pad, 0)
6 changes: 4 additions & 2 deletions src/makielayout/blocks/label.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ function initialize_block!(l::Label)
textbb = Ref(BBox(0, 1, 0, 1))

onany(topscene, l.text, l.fontsize, l.font, l.rotation, word_wrap_width,
l.padding) do _, _, _, _, _, padding
l.padding) do _, _, _, _, _, pad
padding = to_lrbt_padding(pad)
textbb[] = Rect2f(boundingbox(t, :data))
autowidth = width(textbb[]) + padding[1] + padding[2]
autoheight = height(textbb[]) + padding[3] + padding[4]
Expand All @@ -29,7 +30,8 @@ function initialize_block!(l::Label)
return
end

onany(topscene, layoutobservables.computedbbox, l.padding) do bbox, padding
onany(topscene, layoutobservables.computedbbox, l.padding) do bbox, pad
padding = to_lrbt_padding(pad)
if l.word_wrap[]
tw = width(bbox) - padding[1] - padding[2]
else
Expand Down
2 changes: 2 additions & 0 deletions src/utilities/quaternions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ function quaternion_to_2d_angle(quat::Quaternion)
end

Base.isinf(q::Quaternion) = any(isinf, q.data)
Base.isnan(q::Quaternion) = any(isnan, q.data)
Base.isfinite(q::Quaternion) = all(isfinite, q.data)
Base.abs2(q::Quaternion) = mapreduce(*, +, q.data, q.data)
function Base.inv(q::Quaternion)
if isinf(q)
Expand Down
6 changes: 0 additions & 6 deletions test/conversions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,6 @@ end
@test Colors.alpha.(cs) == Float32.(LinRange(0, 1, 10))
end

@testset "colors" begin
@test to_color(["red", "green"]) isa Vector{RGBAf}
@test to_color(["red", "green"]) == [to_color("red"), to_color("green")]
end


@testset "heatmap from three vectors" begin
x = [2, 1, 2]
y = [2, 3, 3]
Expand Down
22 changes: 22 additions & 0 deletions test/convert_arguments.jl
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,25 @@ Makie.convert_arguments(::PointBased, ::MyConvVector) = ([Point(10, 20)],)
end
end
end

@testset "Explicit convert_arguments" begin
function nan_equal(a::Vector, b::Vector)
length(a) == length(b) || return false
for (x, y) in zip(a, b)
(isnan(x) && isnan(y)) || (x == y) || return false
end
return true
end

@testset "PointBased" begin
ps = Point2f.([1, 2], [1, 2])
ls1 = [LineString(ps) for _ in 1:2]
ls2 = MultiLineString(ls1)
ls3 = [ls2, ls2]
ps12 = [ps; [Point2f(NaN)]; ps]
ps3 = [ps12; [Point2f(NaN)]; ps12]
@test nan_equal(convert_arguments(PointBased(), ls1)[1], ps12)
@test nan_equal(convert_arguments(PointBased(), ls2)[1], ps12)
@test nan_equal(convert_arguments(PointBased(), ls3)[1], ps3)
end
end
30 changes: 26 additions & 4 deletions test/convert_attributes.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Makie: Mat, Mat3f, convert_attribute, uv_transform, automatic
using Makie: to_color
using Makie.Colors

@testset "uv_transform" begin
key = Makie.key"uv_transform"()
Expand All @@ -14,13 +16,13 @@ using Makie: Mat, Mat3f, convert_attribute, uv_transform, automatic
for wrap in (identity, x -> [x])
M = Mat{2, 3, Float32}(1,2,3,4,5,6)
@test convert_attribute(wrap(M), key) == wrap(M)

M3 = Mat3f(1,2,0, 3,4,0, 5,6,0)
@test convert_attribute(wrap(M3), key) == wrap(M)

# transformationmatrix-like
@test convert_attribute(wrap(Vec2f(2,3)), key) == wrap(Mat{2, 3, Float32}(2,0,0,3,0,0))
@test convert_attribute(wrap((Vec2f(-1,-2), Vec2f(2,3))), key) ==
@test convert_attribute(wrap((Vec2f(-1,-2), Vec2f(2,3))), key) ==
wrap(Mat{2, 3, Float32}(2,0,0,3,-1,-2))
@test convert_attribute(wrap(I), key) == wrap(Mat{2, 3, Float32}(1,0,0,1,0,0))

Expand All @@ -37,12 +39,32 @@ using Makie: Mat, Mat3f, convert_attribute, uv_transform, automatic
@test convert_attribute(wrap((:rotr90, :swap_xy)), key) == wrap(Mat{2, 3, Float32}(1, 0, 0, -1, 0, 1))
@test convert_attribute(wrap((:rotl90, (Vec2f(0.5, 0.5), Vec2f(0.5, 0.5)), :flip_y)), key) == wrap(Mat{2, 3, Float32}(0, 0.5, 0.5, 0, 0, 0.5))
end

@test convert_attribute(nothing, key) === nothing

# Not meant to be used via convert_attribute, util for uv_transform
@test uv_transform(:meshscatter)[Vec(1,2), Vec(1,2,3)] == convert_attribute(automatic, key, Makie.key"meshscatter"())
@test uv_transform(:mesh)[Vec(1,2), Vec(1,2,3)] == convert_attribute(automatic, key, Makie.key"mesh"())
@test uv_transform(:image)[Vec(1,2), Vec(1,2,3)] == convert_attribute(automatic, key, Makie.key"image"())
@test uv_transform(:surface)[Vec(1,2), Vec(1,2,3)] == convert_attribute(automatic, key, Makie.key"surface"())
end

@testset "to_color" begin
@test to_color(nothing) === nothing
@test to_color(1) == 1f0
@test to_color(17.0) == 17f0
@test to_color(colorant"blue") == RGBAf(0,0,1,1)
@test to_color(HSV(120, 1, 1)) == RGBAf(0,1,0,1)
@test to_color(RGB(1,0,0)) == RGBAf(1,0,0,1)
@test to_color(RGBA(1,0,0,0.5)) == RGBAf(1,0,0,0.5)
@test to_color(Vec3f(0.5, 0.6, 0.4)) == RGBAf(0.5, 0.6, 0.4, 1)
@test to_color(Vec4f(0.2, 0.3, 0.4, 0.5)) == RGBAf(0.2, 0.3, 0.4, 0.5)
@test to_color(:black) == RGBAf(0,0,0,1)
@test to_color("red") == RGBAf(1,0,0,1)
@test to_color([RGBf(0.5, 1, 0.5), :red, "blue"]) == [RGBAf(0.5, 1, 0.5, 1), RGBAf(1,0,0,1), RGBAf(0,0,1,1)]
@test to_color([HSV(0, 1, 1), HSV(120, 1, 1)]) == [RGBAf(1,0,0,1), RGBAf(0,1,0,1)]
@test to_color((:red, 0.5)) == RGBAf(1, 0, 0, 0.5)
@test to_color((RGBAf(0.2, 0.3, 0.4, 0.5), 0.5)) == RGBAf(0.2, 0.3, 0.4, 0.25)

# TODO: Pattern, Palette
end

0 comments on commit 23ee755

Please sign in to comment.