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

Accessing created Blocks/Plots for SpecApi objects #4354

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from

Conversation

SimonDanisch
Copy link
Member

This adds a virtual then field to the specapi objects to interact with the created axis (plot/gridlayout?) object:

import Makie.SpecApi as S 
ax =  S.Axis(...)
ax.then() do actual_axis_object
    hidedecorations!(actual_axis_object)
    return on(events(actual_axis_object).mouseposition) do mp 
        println("mouse: $(mp)")
    end
end

The problem is, that we need to clean up any changes for when we re-use axes, and then re-apply the then functions.
Right now, any observable ObserverFunction needs to be returned, so e.g. two on invocations need to be done like this:

ax.then() do ax
    obs1 = on(f1, events(ax).keyboardbutton)
    obs2 = on(f2, events(ax).mousebutton)
    return [obs1, obs2]
end

linkaxis! is also supported, since we just clear the axis links when re-using any axis, so one can do:

ax_spec1 = S.Axis(...)
ax_spec2 = S.Axis(...)
ax_spec1 .then(ax1-> ax_spec2 .then(ax2-> linkaxes!(ax1, ax2)))

It would be nice if we could make this stricter, ideally it would be impossible to leak any mutation from then.
But I'm not sure how we could do that, without making the API a pain to use or much harder to implement.

I'm happy to hear alternative approaches for how to register e.g. interactions with axis objects etc.

@SimonDanisch SimonDanisch changed the title Advanced SpecApi Accessing created Blocks/Plots for SpecApi objects Sep 13, 2024
@SimonDanisch SimonDanisch marked this pull request as draft September 13, 2024 11:35
@MakieBot
Copy link
Collaborator

MakieBot commented Sep 13, 2024

Compile Times benchmark

Note, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. All benchmark results are based on the mean time and negative percent mean faster than the base branch. Note, that GLMakie + WGLMakie run on an emulated GPU, so the runtime benchmark is much slower. Results are from running:

using_time = @ctime using Backend
# Compile time
create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @ctime Makie.colorbuffer(display(fig))
# Runtime
create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @benchmark Makie.colorbuffer(fig)
using create display create display
GLMakie 4.54s (4.43, 4.62) 0.08+- 112.40ms (108.17, 117.43) 3.94+- 485.63ms (458.91, 512.69) 19.73+- 9.34ms (8.94, 9.96) 0.37+- 26.55ms (26.42, 26.68) 0.11+-
master 4.50s (4.37, 4.65) 0.12+- 110.72ms (107.03, 120.51) 4.81+- 488.67ms (474.49, 519.64) 15.63+- 9.70ms (9.44, 10.15) 0.29+- 26.33ms (25.77, 26.77) 0.39+-
evaluation 0.99x invariant, 0.04s (0.36d, 0.51p, 0.10std) 0.99x invariant, 1.68ms (0.38d, 0.49p, 4.37std) 1.01x invariant, -3.04ms (-0.17d, 0.75p, 17.68std) 1.04x invariant, -0.36ms (-1.09d, 0.07p, 0.33std) 0.99x invariant, 0.22ms (0.77d, 0.19p, 0.25std)
CairoMakie 4.26s (4.22, 4.34) 0.04+- 109.92ms (106.74, 115.45) 2.79+- 171.42ms (169.33, 176.45) 2.45+- 9.66ms (9.47, 9.77) 0.13+- 1.14ms (1.14, 1.15) 0.01+-
master 4.25s (4.19, 4.32) 0.05+- 109.67ms (107.00, 116.16) 3.23+- 173.28ms (168.42, 178.58) 3.78+- 9.76ms (9.70, 9.80) 0.04+- 1.17ms (1.15, 1.20) 0.02+-
evaluation 1.00x invariant, 0.01s (0.25d, 0.65p, 0.04std) 1.00x invariant, 0.26ms (0.08d, 0.88p, 3.01std) 1.01x invariant, -1.86ms (-0.59d, 0.30p, 3.11std) 1.01x invariant, -0.1ms (-1.06d, 0.09p, 0.08std) 1.02x faster ✓, -0.02ms (-1.35d, 0.04p, 0.01std)
WGLMakie 4.76s (4.60, 4.92) 0.13+- 112.12ms (105.42, 124.38) 7.71+- 9.52s (9.24, 9.99) 0.26+- 11.86ms (11.30, 13.85) 0.95+- 123.76ms (112.59, 156.63) 14.78+-
master 4.71s (4.62, 4.85) 0.10+- 106.71ms (104.18, 109.28) 1.60+- 9.34s (9.20, 9.56) 0.13+- 11.74ms (11.06, 12.55) 0.47+- 117.94ms (113.46, 122.72) 4.02+-
evaluation 0.99x invariant, 0.04s (0.38d, 0.49p, 0.12std) 0.95x invariant, 5.41ms (0.97d, 0.12p, 4.65std) 0.98x invariant, 0.18s (0.89d, 0.13p, 0.19std) 0.99x invariant, 0.13ms (0.17d, 0.76p, 0.71std) 0.95x invariant, 5.82ms (0.54d, 0.35p, 9.40std)

@SimonDanisch
Copy link
Member Author

SimonDanisch commented Sep 24, 2024

Some Benchmarks:

using WGLMakie, Bonito
import Makie.SpecApi as S

function to_spec(data)
    axes = map(enumerate(data)) do (i, data)
        S.Axis(plots=[S.Heatmap(data)], title="Axis: $(i)")
    end
    return S.GridLayout(permutedims(axes))
end
data = [rand(Float32, 10, 10) for i in 1:3]

x = Observable(to_spec(data[1:1]))

f, ax = plot(x)
display(f)
msgs1, msg1 = Bonito.collect_messages() do
    x[] = to_spec(data[1:3])
end;
msgs2, msg2 = Bonito.collect_messages() do
    x[] = to_spec(data[1:1])
end;
msgs3, msg3 = Bonito.collect_messages() do
    x[] = to_spec(data[1:3])
end;
msgs4, msg4 = Bonito.collect_messages() do
    x[] = to_spec(reverse(data[1:3]))
end;

PR

Send 496 messages with a total size of 457.121 KiB
Send 55 messages with a total size of 8.041 KiB
Send 55 messages with a total size of 8.041 KiB <-----
Send 4 messages with a total size of 1.188 KiB

Master

Send 555 messages with a total size of 459.931 KiB
Send 57 messages with a total size of 8.833 KiB
Send 555 messages with a total size of 461.491 KiB
Send 4 messages with a total size of 1.186 KiB

The big improvement is obviously, when we go from 1 -> 3 axes that have been re-created previously.
The above is not yet perfect in all cases, since for e.g. reverse, it triggers some more changes, that we still need to get rid of.

@SimonDanisch
Copy link
Member Author

Another Benchmark for swapping axes:

using WGLMakie, Bonito, BenchmarkTools
import Makie.SpecApi as S
WGLMakie.activate!()
ax1 = S.Axis(; title="Title 1")
ax2 = S.Axis(; title="Title 2")
ax3 = S.Axis(; title="Title 3")
axis = [ax1, ax2, ax3]
gl = S.GridLayout(axis)
fig, _, pl = plot(gl)
display(fig)
msgs, msg = Bonito.collect_messages() do
    pl[1] = S.GridLayout(reverse!(axis))
end
@btime pl[1] = S.GridLayout(reverse!(axis))

PR

"Send 6 messages with a total size of 1024 bytes"
329.500 μs (2533 allocations: 152.05 KiB)

Master

"Send 14 messages with a total size of 2.472 KiB"
491.200 μs (2988 allocations: 182.78 KiB)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Work in progress
Development

Successfully merging this pull request may close these issues.

2 participants