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

Bug fixes #3275

Merged
merged 5 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 1 addition & 21 deletions WGLMakie/src/particles.jl
Original file line number Diff line number Diff line change
Expand Up @@ -230,31 +230,13 @@ value_or_first(x) = x

function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.GlyphCollection, <:AbstractVector{<:Makie.GlyphCollection}}}})
glyphcollection = plot[1]
res = map(x->Vec2f(widths(x)), pixelarea(scene))
projview = scene.camera.projectionview
transfunc = Makie.transform_func_obs(plot)
pos = plot.position
space = plot.space
markerspace = plot.markerspace
offset = plot.offset

# TODO: This is a hack before we get better updating of plot objects and attributes going.
# Here we only update the glyphs when the glyphcollection changes, if it's a singular glyphcollection.
# The if statement will be compiled away depending on the parameter of Text.
# This means that updates of a text vector and a separate position vector will still not work if only the text
# vector is triggered, but basically all internal objects use the vector of tuples version, and that triggers
# both glyphcollection and position, so it still works
if glyphcollection[] isa Makie.GlyphCollection
# here we use the glyph collection observable directly
gcollection = glyphcollection
else
# and here we wrap it into another observable
# so it doesn't trigger dimension mismatches
# the actual, new value gets then taken in the below lift with to_value
gcollection = Observable(glyphcollection)
end
atlas = wgl_texture_atlas()
glyph_data = map(pos, gcollection, offset, transfunc, space) do pos, gc, offset, transfunc, space
glyph_data = map(pos, glyphcollection, offset, transfunc, space; ignore_equal_values=true) do pos, gc, offset, transfunc, space
Makie.text_quads(atlas, pos, to_value(gc), offset, transfunc, space)
end

Expand All @@ -281,10 +263,8 @@ function create_shader(scene::Scene, plot::Makie.Text{<:Tuple{<:Union{<:Makie.Gl
end
end

cam = scene.camera
plot_attributes = copy(plot.attributes)
plot_attributes.attributes[:calculated_colors] = uniform_color

uniforms = Dict(
:model => plot.model,
:shape_type => Observable(Cint(3)),
Expand Down
11 changes: 6 additions & 5 deletions src/basic_recipes/arrows.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ grid.

`arrows` can also work in three dimensions.

If a `Function` is provided in place of `u, v, [w]`, then it must accept
If a `Function` is provided in place of `u, v, [w]`, then it must accept
a `Point` as input, and return an appropriately dimensioned `Point`, `Vec`,
or other array-like output.

Expand Down Expand Up @@ -165,7 +165,8 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher

linesegments!(
arrowplot, headstart,
color = line_c, colormap = colormap, colorscale = colorscale, linestyle = linestyle,
color=line_c, colormap=colormap, colorscale=colorscale, linestyle=linestyle,
colorrange=arrowplot.colorrange,
linewidth=lift(lw -> lw === automatic ? 1.0f0 : lw, arrowplot, linewidth),
fxaa = fxaa_bool, inspectable = inspectable,
transparency = transparency, visible = visible,
Expand All @@ -176,7 +177,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher
marker=marker_head,
markersize = lift(as-> as === automatic ? theme(scene, :markersize)[] : as, arrowplot, arrowsize),
color = arrow_c, rotations = rotations, strokewidth = 0.0,
colormap = colormap, markerspace = arrowplot.markerspace,
colormap=colormap, markerspace=arrowplot.markerspace, colorrange=arrowplot.colorrange,
fxaa = fxaa_bool, inspectable = inspectable,
transparency = transparency, visible = visible
)
Expand Down Expand Up @@ -212,7 +213,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher
start, rotations = directions,
marker=marker_tail,
markersize = msize,
color = line_c, colormap = colormap, colorscale = colorscale,
color=line_c, colormap=colormap, colorscale=colorscale, colorrange=arrowplot.colorrange,
fxaa = fxaa_bool, ssao = ssao,
diffuse = diffuse,
specular = specular, shininess = shininess, inspectable = inspectable,
Expand All @@ -223,7 +224,7 @@ function plot!(arrowplot::Arrows{<: Tuple{AbstractVector{<: Point{N}}, V}}) wher
start, rotations = directions,
marker=marker_head,
markersize = markersize,
color = arrow_c, colormap = colormap, colorscale = colorscale,
color=arrow_c, colormap=colormap, colorscale=colorscale, colorrange=arrowplot.colorrange,
fxaa = fxaa_bool, ssao = ssao,
diffuse = diffuse,
specular = specular, shininess = shininess, inspectable = inspectable,
Expand Down
120 changes: 47 additions & 73 deletions src/figureplotting.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
struct AxisPlot
axis
axis::Any
plot::AbstractPlot
end

Expand All @@ -17,8 +17,7 @@ function _validate_nt_like_keyword(@nospecialize(kw), name)
The $name keyword argument received an unexpected value $(repr(kw)).
The $name keyword expects a collection of Symbol => value pairs, such as NamedTuple, Attributes, or AbstractDict{Symbol}.
The most common cause of this error is trying to create a one-element NamedTuple like (key = value) which instead creates a variable `key` with value `value`.
Write (key = value,) or (; key = value) instead."""
))
Write (key = value,) or (; key = value) instead."""))
end
end

Expand All @@ -28,35 +27,43 @@ function _disallow_keyword(kw, attributes)
end
end

function plot(P::PlotFunc, args...; axis = NamedTuple(), figure = NamedTuple(), kw_attributes...)

_validate_nt_like_keyword(axis, "axis")
_validate_nt_like_keyword(figure, "figure")

fig = Figure(; figure...)

axis = Dict(pairs(axis))
if haskey(axis, :type)
axtype = axis[:type]
pop!(axis, :type)
ax = axtype(fig; axis...)
@nospecialize
function get_axis(fig, P, axis_kw::Dict, plot_attr, plot_args)
if haskey(axis_kw, :type)
axtype = axis_kw[:type]
pop!(axis_kw, :type)
ax = axtype(fig; axis_kw...)
else
proxyscene = Scene()
attrs = Attributes(kw_attributes)
delete!(attrs, :show_axis)
delete!(attrs, :limits)
plot!(proxyscene, P, attrs, args...)
# We dont forward the attributes to the plot, since we only need the arguments to determine the axis type
# Remove arguments may not work with plotting into the scene
delete!(plot_attr, :show_axis)
delete!(plot_attr, :limits)
delete!(plot_attr, :color) # Color may contain Cycled(1), which needs the axis to get resolved to a color
plot!(proxyscene, P, Attributes(plot_attr), plot_args...)
if is2d(proxyscene)
ax = Axis(fig; axis...)
ax = Axis(fig; axis_kw...)
else
ax = LScene(fig; axis...)
ax = LScene(fig; axis_kw...)
end
empty!(proxyscene)
end
return ax
end
@specialize

function plot(P::PlotFunc, args...; axis=NamedTuple(), figure=NamedTuple(), kw_attributes...)
_validate_nt_like_keyword(axis, "axis")
_validate_nt_like_keyword(figure, "figure")

fig = Figure(; figure...)

axis = Dict(pairs(axis))
ax = get_axis(fig, P, axis, Dict{Symbol, Any}(kw_attributes), args)

fig[1, 1] = ax
p = plot!(ax, P, Attributes(kw_attributes), args...)
FigureAxisPlot(fig, ax, p)
return FigureAxisPlot(fig, ax, p)
end

# without scenelike, use current axis of current figure
Expand All @@ -66,16 +73,13 @@ function plot!(P::PlotFunc, args...; kw_attributes...)
isnothing(figure) && error("There is no current figure to plot into.")
ax = current_axis(figure)
isnothing(ax) && error("There is no current axis to plot into.")
plot!(P, ax, args...; kw_attributes...)
return plot!(P, ax, args...; kw_attributes...)
end

function plot(P::PlotFunc, gp::GridPosition, args...; axis = NamedTuple(), kwargs...)

function plot(P::PlotFunc, gp::GridPosition, args...; axis=NamedTuple(), kw_attributes...)
_validate_nt_like_keyword(axis, "axis")

f = get_top_parent(gp)

c = contents(gp, exact = true)
c = contents(gp; exact=true)
if !isempty(c)
error("""
You have used the non-mutating plotting syntax with a GridPosition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position:
Expand All @@ -88,42 +92,28 @@ function plot(P::PlotFunc, gp::GridPosition, args...; axis = NamedTuple(), kwarg
end

axis = Dict(pairs(axis))

if haskey(axis, :type)
axtype = axis[:type]
pop!(axis, :type)
ax = axtype(f; axis...)
else
proxyscene = Scene()
plot!(proxyscene, P, Attributes(kwargs), args...)
if is2d(proxyscene)
ax = Axis(f; axis...)
else
ax = LScene(f; axis...)
end
end
fig = get_top_parent(gp)
ax = get_axis(fig, P, axis, Dict{Symbol,Any}(kw_attributes), args)

gp[] = ax
p = plot!(P, ax, args...; kwargs...)
AxisPlot(ax, p)
p = plot!(P, ax, args...; kw_attributes...)
return AxisPlot(ax, p)
end

function plot!(P::PlotFunc, gp::GridPosition, args...; kwargs...)

c = contents(gp, exact = true)
c = contents(gp; exact=true)
if !(length(c) == 1 && can_be_current_axis(c[1]))
error("There needs to be a single axis-like object at $(gp.span), $(gp.side) to plot into.\nUse a non-mutating plotting command to create an axis implicitly.")
end
ax = first(c)
plot!(P, ax, args...; kwargs...)
return plot!(P, ax, args...; kwargs...)
end

function plot(P::PlotFunc, gsp::GridSubposition, args...; axis = NamedTuple(), kwargs...)

function plot(P::PlotFunc, gsp::GridSubposition, args...; axis=NamedTuple(), kw_attributes...)
_validate_nt_like_keyword(axis, "axis")

layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing = true)
c = contents(gsp, exact = true)
GridLayoutBase.get_layout_at!(gsp.parent; createmissing=true)
c = contents(gsp; exact=true)
if !isempty(c)
error("""
You have used the non-mutating plotting syntax with a GridSubposition, which requires an empty GridLayout slot to create an axis in, but there are already the following objects at this layout position:
Expand All @@ -136,41 +126,25 @@ function plot(P::PlotFunc, gsp::GridSubposition, args...; axis = NamedTuple(), k
end

fig = get_top_parent(gsp)

axis = Dict(pairs(axis))

if haskey(axis, :type)
axtype = axis[:type]
pop!(axis, :type)
ax = axtype(fig; axis...)
else
proxyscene = Scene()
plot!(proxyscene, P, Attributes(kwargs), args...)

if is2d(proxyscene)
ax = Axis(fig; axis...)
else
ax = LScene(fig; axis..., scenekw = (camera = automatic,))
end
end
ax = get_axis(fig, P, axis, Dict{Symbol,Any}(kw_attributes), args)

gsp.parent[gsp.rows, gsp.cols, gsp.side] = ax
p = plot!(P, ax, args...; kwargs...)
AxisPlot(ax, p)
p = plot!(P, ax, args...; kw_attributes...)
return AxisPlot(ax, p)
end

function plot!(P::PlotFunc, gsp::GridSubposition, args...; kwargs...)

layout = GridLayoutBase.get_layout_at!(gsp.parent, createmissing = false)
layout = GridLayoutBase.get_layout_at!(gsp.parent; createmissing=false)

gp = layout[gsp.rows, gsp.cols, gsp.side]

c = contents(gp, exact = true)
c = contents(gp; exact=true)
if !(length(c) == 1 && can_be_current_axis(c[1]))
error("There is not just one axis at $(gp).")
end
ax = first(c)
plot!(P, ax, args...; kwargs...)
return plot!(P, ax, args...; kwargs...)
end

update_state_before_display!(f::FigureAxisPlot) = update_state_before_display!(f.figure)
Expand Down
1 change: 0 additions & 1 deletion src/makielayout/blocks/axis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,6 @@ function Makie.plot!(

_disallow_keyword(:axis, allattrs)
_disallow_keyword(:figure, allattrs)

cycle = get_cycle_for_plottype(allattrs, P)
add_cycle_attributes!(allattrs, P, cycle, la.cycler, la.palette)

Expand Down
2 changes: 1 addition & 1 deletion src/makielayout/blocks/colorbar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function extract_colormap(@nospecialize(plot::AbstractPlot))
end
end

function extract_colormap(plot::StreamPlot)
function extract_colormap(plot::Union{Arrows, StreamPlot})
return extract_colormap(plot.plots[1])
end

Expand Down
1 change: 1 addition & 0 deletions src/utilities/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ attr_broadcast_length(x::ScalarOrVector) = x.sv isa Vector ? length(x.sv) : 1
attr_broadcast_getindex(x::NativeFont, i) = x
attr_broadcast_getindex(x::VecTypes, i) = x # these are our rules, and for what we do, Vecs are usually scalars
attr_broadcast_getindex(x::AbstractVector, i) = x[i]
attr_broadcast_getindex(x::AbstractArray{T, 0}, i) where T = x[1]
attr_broadcast_getindex(x::AbstractPattern, i) = x
attr_broadcast_getindex(x, i) = x
attr_broadcast_getindex(x::Ref, i) = x[] # unwrap Refs just like in normal broadcasting, for protecting iterables
Expand Down
9 changes: 9 additions & 0 deletions test/pipeline.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,12 @@ end
@test p.xmax === xmax
fig
end

@testset "Cycled" begin
# Test for https://github.com/MakieOrg/Makie.jl/issues/3266
f, ax, pl = lines(1:4; color=Cycled(2))
cpalette = ax.palette[:color][]
@test pl.calculated_colors[] == cpalette[2]
pl2 = lines!(ax, 1:4; color=Cycled(1))
@test pl2.calculated_colors[] == cpalette[1]
end
50 changes: 50 additions & 0 deletions test/primitives.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@testset "ablines" begin
# Test ablines with 0 dim arrays
f, ax, pl = ablines(fill(0), fill(1))
reset_limits!(ax)
points = pl.plots[1][1]
@test points[] == [Point2f(0), Point2f(10)]
limits!(ax, 5, 15, 6, 17)
@test points[] == [Point2f(5), Point2f(15)]
end


@testset "arrows" begin
# Test for:
# https://github.com/MakieOrg/Makie.jl/issues/3273
directions = decompose(Point2f, Circle(Point2f(0), 1))
points = decompose(Point2f, Circle(Point2f(0), 0.5))
color = range(0, 1, length=length(directions))
fig, ax, pl = arrows(points, directions; color=color)
cbar = Colorbar(fig[1, 2], pl)
@test cbar.limits[] == Vec2f(0, 1)
pl.colorrange = (0.5, 0.6)
@test cbar.limits[] ≈ Vec2f(0.5, 0.6)
end


# TODO, test all primitives and argument conversions

# text()
# fig, ax, p = meshscatter(1:5, (1:5) .+ 5, rand(5))
# fig, ax, p = scatter(1:5, rand(5))
# fig, ax, p = mesh(Sphere(Point3f(0), 1.0))
# fig, ax, p = linesegments(1:5, rand(5))
# fig, ax, p = lines(1:5, rand(5))
# fig, ax, p = surface(rand(4, 7))
# fig, ax, p = volume(rand(4, 4, 4))
# begin
# fig, ax, p = heatmap(rand(4, 4))
# scatter!(Makie.point_iterator(p) |> collect, color=:red, markersize=10)
# display(fig)
# end

# fig, ax, p = image(rand(4, 5))
# scatter!(Makie.point_iterator(p) |> collect, color=:red, markersize=10)
# display(fig)

# begin
# fig, ax, p = scatter(1:5, rand(5))
# linesegments!(Makie.data_limits(ax.scene), color=:red)
# display(fig)
# end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ using Makie: volume
@test all(hi .>= (8,8,10))
end

include("primitives.jl")
include("pipeline.jl")
include("record.jl")
include("scenes.jl")
Expand Down
Loading
Loading