diff --git a/CHANGELOG.md b/CHANGELOG.md index e7a520b82bd..f3f2a2eac83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] +- Reduce updates for image/heatmap, improving performance [#4130](https://github.com/MakieOrg/Makie.jl/pull/4130). ## [0.21.7] - 2024-08-19 diff --git a/GLMakie/test/runtests.jl b/GLMakie/test/runtests.jl index 31173bd8d4c..9bb97615171 100644 --- a/GLMakie/test/runtests.jl +++ b/GLMakie/test/runtests.jl @@ -61,24 +61,21 @@ end rm(filename) end + f, a, p = scatter(rand(10)); filename = "$(tempname()).mp4" try - GLMakie.closeall() tick_record = Makie.Tick[] - @time record(_ -> push!(tick_record, events(f).tick[]), f, filename, 1:10, framerate = 30) + on(tick -> push!(tick_record, tick), events(f).tick) + record(_ -> nothing, f, filename, 1:10, framerate = 30) + + start = findfirst(tick -> tick.state == Makie.OneTimeRenderTick, tick_record) dt = 1.0 / 30.0 - i = 0 - for tick in tick_record - if tick.state !== Makie.OneTimeRenderTick - @warn "Unexpected tick during recording. Full tick record: $tick_record." maxlog = 1 - continue - end + for (i, tick) in enumerate(tick_record[start:end]) @test tick.state == Makie.OneTimeRenderTick - @test tick.count == i - @test tick.time ≈ dt * i + @test tick.count == i-1 + @test tick.time ≈ dt * (i-1) @test tick.delta_time ≈ dt - i += 1 end finally rm(filename) diff --git a/WGLMakie/src/imagelike.jl b/WGLMakie/src/imagelike.jl index 81a77a2b3a3..62d365ac929 100644 --- a/WGLMakie/src/imagelike.jl +++ b/WGLMakie/src/imagelike.jl @@ -162,7 +162,8 @@ function limits_to_uvmesh(plot, f32c) # Special path for ranges of length 2 which # can be displayed as a rectangle t = Makie.transform_func_obs(plot)[] - + px = lift(identity, plot, px; ignore_equal_values=true) + py = lift(identity, plot, py; ignore_equal_values=true) if px[] isa Makie.EndPoints && py[] isa Makie.EndPoints && Makie.is_identity_transform(t) rect = lift(plot, px, py) do x, y xmin, xmax = extrema(x) @@ -171,8 +172,9 @@ function limits_to_uvmesh(plot, f32c) end ps = lift(rect -> decompose(Point2f, rect), plot, rect) positions = Buffer(apply_transform_and_f32_conversion(plot, f32c, ps)) - faces = Buffer(lift(rect -> decompose(GLTriangleFace, rect), plot, rect)) - uv = Buffer(lift(decompose_uv, plot, rect)) + # UV + Faces stay the same for the rectangle + faces = Buffer(decompose(GLTriangleFace, rect[])) + uv = Buffer(decompose_uv(rect[])) else px = lift((x, z) -> xy_convert(x, size(z, 1)), px, pz; ignore_equal_values=true) py = lift((y, z) -> xy_convert(y, size(z, 2)), py, pz; ignore_equal_values=true) diff --git a/WGLMakie/src/meshes.jl b/WGLMakie/src/meshes.jl index 834236b679b..aaffa290452 100644 --- a/WGLMakie/src/meshes.jl +++ b/WGLMakie/src/meshes.jl @@ -22,7 +22,7 @@ function handle_color!(plot, uniforms, buffers, uniform_color_name = :uniform_co color = plot.calculated_colors minfilter = to_value(get(plot, :interpolate, true)) ? :linear : :nearest - convert_text(x) = permute_tex ? lift(permutedims, plot, x) : x + convert_texture(x) = permute_tex ? lift(permutedims, plot, x) : x if color[] isa Colorant uniforms[uniform_color_name] = color @@ -30,14 +30,14 @@ function handle_color!(plot, uniforms, buffers, uniform_color_name = :uniform_co buffers[:color] = Buffer(color) elseif color[] isa Makie.AbstractPattern uniforms[:pattern] = true - uniforms[uniform_color_name] = Sampler(convert_text(color); minfilter=minfilter) + uniforms[uniform_color_name] = Sampler(convert_texture(color); minfilter=minfilter) elseif color[] isa AbstractMatrix - uniforms[uniform_color_name] = Sampler(convert_text(color); minfilter=minfilter) + uniforms[uniform_color_name] = Sampler(convert_texture(color); minfilter=minfilter) elseif color[] isa Makie.ColorMapping if color[].color_scaled[] isa AbstractVector buffers[:color] = Buffer(color[].color_scaled) else - color_scaled = convert_text(color[].color_scaled) + color_scaled = convert_texture(color[].color_scaled) uniforms[uniform_color_name] = Sampler(color_scaled; minfilter=minfilter) end uniforms[:colormap] = Sampler(color[].colormap) diff --git a/WGLMakie/test/runtests.jl b/WGLMakie/test/runtests.jl index f6630c10dcb..5cad1aa584b 100644 --- a/WGLMakie/test/runtests.jl +++ b/WGLMakie/test/runtests.jl @@ -103,10 +103,13 @@ end filename = "$(tempname()).mp4" try tick_record = Makie.Tick[] - record(_ -> push!(tick_record, events(f).tick[]), f, filename, 1:10, framerate = 30) + on(tick -> push!(tick_record, tick), events(f).tick) + record(_ -> nothing, f, filename, 1:10, framerate = 30) + + start = findfirst(tick -> tick.state == Makie.OneTimeRenderTick, tick_record) dt = 1.0 / 30.0 - for (i, tick) in enumerate(tick_record) + for (i, tick) in enumerate(tick_record[start:end]) @test tick.state == Makie.OneTimeRenderTick @test tick.count == i-1 @test tick.time ≈ dt * (i-1) diff --git a/docs/src/reference/plots/datashader.md b/docs/src/reference/plots/datashader.md index d74da1cda67..df1fe1d2147 100644 --- a/docs/src/reference/plots/datashader.md +++ b/docs/src/reference/plots/datashader.md @@ -116,6 +116,8 @@ end axis=(; type=Axis, autolimitaspect = 1), figure=(;figure_padding=0, size=(1200, 600)) ) + # Zoom into the hotspot + limits!(ax, Rect2f(-74.175, 40.619, 0.5, 0.25)) # make image fill the whole screen hidedecorations!(ax) hidespines!(ax) @@ -144,7 +146,7 @@ points = Mmap.mmap(open(path, "r"), Vector{Point2f}); # For a big dataset its interesting to see how long each aggregation takes show_timings = true, # Use a local operation which is faster to calculate and looks good! - local_post=x-> log10(x + 1), + local_operation=x-> log10(x + 1), #= in the code we used to save the binary, we had the points in the wrong order. A good chance to demonstrate the `point_transform` argument, diff --git a/src/basic_recipes/datashader.jl b/src/basic_recipes/datashader.jl index 6423596b330..40adefaf7dc 100644 --- a/src/basic_recipes/datashader.jl +++ b/src/basic_recipes/datashader.jl @@ -288,8 +288,9 @@ For best performance, use `method=Makie.AggThreads()` and make sure to start jul """ @recipe DataShader (points,) begin """ - Can be `AggCount()`, `AggAny()` or `AggMean()`. User-extensible by overloading: - + Can be `AggCount()`, `AggAny()` or `AggMean()`. + Be sure, to use the correct element type e.g. `AggCount{Float32}()`, which needs to accomodate the output of `local_operation`. + User-extensible by overloading: ```julia struct MyAgg{T} <: Makie.AggOp end MyAgg() = MyAgg{Float64}() @@ -299,7 +300,7 @@ For best performance, use `method=Makie.AggThreads()` and make sure to start jul Makie.Aggregation.value(::MyAgg{T}, x::T) where {T} = x ``` """ - agg = AggCount() + agg = AggCount{Float32}() """ Can be `AggThreads()` or `AggSerial()` for threaded vs. serial aggregation. """ diff --git a/src/colorsampler.jl b/src/colorsampler.jl index fa8baecd560..49c73afd5c1 100644 --- a/src/colorsampler.jl +++ b/src/colorsampler.jl @@ -262,6 +262,7 @@ function _colormapping( raw_colormap = Observable(RGBAf[]; ignore_equal_values=true) mapping = Observable{Union{Nothing,Vector{Float64}}}(nothing; ignore_equal_values=true) colorscale = convert(Observable{Function}, colorscale) + colorscale.ignore_equal_values = true function update_colors(cmap, a) colors = to_colormap(cmap) @@ -300,7 +301,7 @@ function _colormapping( return Vec2f(apply_scale(scale, range)) end - color_scaled = lift(color_tight, colorscale) do color, scale + color_scaled = lift(color_tight, colorscale; ignore_equal_values=true) do color, scale return el32convert(apply_scale(scale, color)) end CT = ColorMapping{N,V,typeof(color_scaled[])} @@ -333,6 +334,7 @@ function ColorMapping( T = _array_value_type(color) color_tight = convert(Observable{T}, colors_obs)::Observable{T} + color_tight.ignore_equal_values = true _colormapping(color_tight, colors_obs, colormap, colorrange, colorscale, alpha, lowclip, highclip, nan_color, color_mapping_type) end