Skip to content

Basic Makie.jl support #165

New issue

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

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

Already on ? Sign in to your account

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open

Basic Makie.jl support #165

wants to merge 24 commits into from

Conversation

icweaver
Copy link

@icweaver icweaver commented Mar 9, 2025

Closes #164

Demo

using DynamicQuantities, GLMakie

fig = Figure()

y = 60:10:100

scatter(fig[1, 1], y * u"m")
scatter(fig[1, 2], QuantityArray(y, u"m"))
scatter(fig[2, 1], y * u"kg", y * u"m")
scatter(fig[2, 2], y * us"m/s/Hz")

fig

example

See docs for more examples using Makie's dimension conversion machinery

TODO

Future PR(s)?

  • Affine units?
  • Heatmap and Image support. Maybe with a recipe
  • Rich strings (Unitful example)

@github-actionsGitHub Actions
Copy link
Contributor

-actions bot commented Mar 9, 2025

Benchmark Results

main2d09a66...main / 2d09a66...
Quantity/creation/Quantity(x)3.1 ± 0.01 ns3.1 ± 0.01 ns0.997 ± 0.0045
Quantity/creation/Quantity(x, length=y)3.73 ± 0.01 ns3.73 ± 0.01 ns1 ± 0.0038
Quantity/with_numbers/*real2.79 ± 0.001 ns3.11 ± 0.01 ns0.9 ± 0.0029
Quantity/with_numbers/^int8.37 ± 1.6 ns8.68 ± 1.6 ns0.964 ± 0.25
Quantity/with_numbers/^int * real8.98 ± 1.6 ns8.98 ± 1.6 ns1 ± 0.25
Quantity/with_quantity/+y4.35 ± 0.001 ns4.35 ± 0.009 ns1 ± 0.0021
Quantity/with_quantity//y3.42 ± 0.01 ns3.42 ± 0.01 ns1 ± 0.0041
Quantity/with_self/dimension3.12 ± 0.01 ns2.79 ± 0 ns1.12 ± 0.0036
Quantity/with_self/inv3.11 ± 0.001 ns3.11 ± 0.001 ns1 ± 0.00046
Quantity/with_self/ustrip3.1 ± 0.01 ns2.79 ± 0.011 ns1.11 ± 0.0056
QuantityArray/broadcasting/multi_array_of_quantities0.0876 ± 0.00048 ms0.0875 ± 0.00069 ms1 ± 0.0097
QuantityArray/broadcasting/multi_normal_array0.0496 ± 0.0022 ms0.0478 ± 0.0023 ms1.04 ± 0.067
QuantityArray/broadcasting/multi_quantity_array0.053 ± 0.00018 ms0.053 ± 0.00022 ms1 ± 0.0054
QuantityArray/broadcasting/x^2_array_of_quantities14.6 ± 2.9 μs15.6 ± 3.4 μs0.933 ± 0.27
QuantityArray/broadcasting/x^2_normal_array2.27 ± 1 μs2.32 ± 0.88 μs0.975 ± 0.57
QuantityArray/broadcasting/x^2_quantity_array3.49 ± 0.15 μs3.52 ± 0.17 μs0.991 ± 0.064
QuantityArray/broadcasting/x^4_array_of_quantities0.0814 ± 0.00072 ms0.0812 ± 0.00051 ms1 ± 0.011
QuantityArray/broadcasting/x^4_normal_array0.0466 ± 0.00016 ms0.0466 ± 0.00012 ms1 ± 0.0043
QuantityArray/broadcasting/x^4_quantity_array0.0466 ± 0.0031 ms0.0467 ± 0.00012 ms0.997 ± 0.066
time_to_load0.2 ± 0.002 s0.198 ± 0.0033 s1.01 ± 0.02

Benchmark Plots

A plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR.
Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).

@icweaver
Copy link
Author

Just saw this really cool update from Julius on the AoG side of things!

MakieOrg/AlgebraOfGraphics.jl#619

https://aog.makie.org/v0.9.6/examples/scales/units#units

This also looks to address MakieOrg/Makie.jl#3890 in one fell swoop

@MilesCranmer
Copy link
Member

Cool!

Let me know (by tagging me) when you're ready for review

@icweaver
Copy link
Author

icweaver commented Mar 31, 2025

Hi @MilesCranmer, I think this should be just about ready for a first pass of reviews now.

The main additions are:

I'm not quite sure yet how I feel about Makie's choice to automatically change non-compound units for folks out from under them, so I kept that bit of machinery out for now. I do see the convenience of it though, it just seems to add a fair bit of complexity that we maybe don't need right now. Instead, this current design favors explicit over implicit unit handling, e.g.,

Unitful example (taken from ReferenceTests)

# Don't swallow units past the first
f, a, p = scatter((1:10) .* u"J/s")
# Don't simplify (assume the user knows better)
scatter(f[1, 2], (1:10) .* u"K", exp.(1:10) .* u"mm/m^2")
# Only change prefixes of simple units, not compound units
scatter(f[2, 1], 10 .^ (1:6) .* u"W/m^2", (1:6) .* 1000 .* u"nm")
# Only change units/prefixes for simple units when adding more plots
scatter(f[2, 2], (0:10) .* u"W/m^2", (0:10) .* u"g")
scatter!((0:10) .* u"kW/m^2", (0:10) .* u"kg")
f

unitful_example

Here the nanometer plot in the bottom left is auto-converted to microns without the user specifying that unit. In contrast:

This PR

using DynamicQuantities, Makie
const DQConversion = Base.get_extension(DynamicQuantities, :DynamicQuantitiesMakieExt).DQConversion

fig = Figure()

ax1 = Axis(fig[1, 1]; dim2_conversion=DQConversion(us"J/s"))
ax2 = Axis(fig[1, 2]; dim2_conversion=DQConversion(us"mm/m^2"))
ax3 = Axis(fig[2, 1]; dim1_conversion=DQConversion(us"W/m^2"), dim2_conversion=DQConversion(us"μm"))
ax4 = Axis(fig[2, 2]; dim1_conversion=DQConversion(us"W/m^2"))

scatter!(ax1, (1:10) .* u"J/s")
scatter!(ax2, (1:10) .* u"K", exp.(1:10) .* u"mm/m^2")
scatter!(ax3, 10 .^ (1:6) .* u"W/m^2", (1:6) .* 1000 .* u"nm")
scatter!(ax4, (0:10) .* u"W/m^2", (0:10) .* u"g")
scatter!(ax4, (0:10) .* u"kW/m^2", (0:10) .* u"kg")

fig

or with the appropriate use of SymbolicDimensions:

fig = Figure()

scatter(fig[1, 1], (1:10) .* us"J/s")
scatter(fig[1, 2], (1:10) .* u"K", exp.(1:10) .* us"mm/m^2")
scatter(fig[2, 1], 10 .^ (1:6) .* us"W/m^2", (1:6) .* 1000 .* u"nm"; axis=(; dim2_conversion=DQConversion(us"μm")))
scatter(fig[2, 2], (0:10) .* u"W/m^2", (0:10) .* u"g"; axis=(; dim1_conversion=DQConversion(us"W/m^2")))
scatter!(fig[2, 2], (0:10) .* u"kW/m^2", (0:10) .* us"kg")

fig

dq_example

Happy to save that kind of discussion for a separate PR though if it's starting to get too in the weeds for this basic functionality PR. Thanks again for taking a look!

@icweavericweaver marked this pull request as ready for review April 7, 2025 07:07
@bertini97
Copy link

This would be great for a project I'm working on right now. Can it be pushed?

@MilesCranmer
Copy link
Member

Sure let me review it; sorry i missed the earlier notification. I think I unsubscribed from the thread as it was a draft

Project.toml Outdated
DynamicQuantitiesMeasurementsExt = "Measurements"
DynamicQuantitiesScientificTypesExt = "ScientificTypes"
DynamicQuantitiesUnitfulExt = "Unitful"

[compat]
DisDoctor = "0.4"
LinearAlgebra = "1"
Makie = "0.22.2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you comment on why choose this version as a minimum compat?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was looking at Measurements.jl for prior art in adding Makie as a package extension when I was just getting started, and was just being conservative. Looking back, I think this could be relaxed to Makie v0.21.0 since it looks like that is when MakieOrg/Makie.jl#3226 was added

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 53 to +57
y0 = 10km
v0 = 250m/s
θ = deg2rad(60)
g = 9.81m/s^2
nothing # hide
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
y0 = 10km
v0 = 250m/s
θ = deg2rad(60)
g = 9.81m/s^2
nothing # hide
y0 = 10km
v0 = 250m/s
θ = deg2rad(60)
g = 9.81m/s^2;

A bit simpler. Can you also use ; rather than nothing elsewhere too

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, no dice just yet:

image

I noticed you mention this in your discussion with Abhro in #175, and I've wanted to try it out ever since. Is there something else that I could try? Found some relevant discussion here: JuliaDocs/Documenter.jl#1509

Comment on lines 32 to 49
DQConversion(unit=automatic; units_in_label=false)
Allows to plot arrays of DynamicQuantity objects into an axis.
# Arguments
- `unit=automatic`: sets the unit as conversion target. If left at automatic, the best unit will be chosen for all plots + values plotted to the axis (e.g. years for long periods, or km for long distances, or nanoseconds for short times).
- `units_in_label=true`: controls, whether plots are shown in the label_prefix of the axis labels, or in the tick labels
# Examples
```julia
using DynamicQuantities, CairoMakie
# DQConversion will get chosen automatically:
scatter(1:4, [1u"ns", 2u"ns", 3u"ns", 4u"ns"])
```
Fix unit to always use Meter & display unit in the xlabel:
```julia
# Temporary until this is upstreamed to Makie.jl
const DQConversion = Base.get_extension(DynamicQuantities, :DynamicQuantitiesMakieExt).DQConversion
dqc = DQConversion(us"m"; units_in_label=false)
scatter(1:4, [0.01u"km", 0.02u"km", 0.03u"km", 0.04u"km"]; axis=(dim2_conversion=dqc, xlabel="x (km)"))
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be spaced out a bit more

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

function M.convert_dim_observable(conversion::DQConversion, value_obs::M.Observable, deregister)
# TODO: replace with update_extrema
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be implemented?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so I think this ties into this bit of my comment here:

I'm not quite sure yet how I feel about MakieOrg/Makie.jl#4583 (comment) for folks out from under them, so I kept that bit of machinery out for now. I do see the convenience of it though, it just seems to add a fair bit of complexity that we maybe don't need right now. Instead, this current design favors explicit over implicit unit handling

So I've essentially side-stepped Makie's version of convert_dim_observable which calls to the best_unit business that I am not totally convinced about using

This issue that came up with using it (MakieOrg/Makie.jl#4940 (comment)) also makes me less inclined to use it. Idk though if you had any thoughts about this already?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: Added a comment in that issue to hopefully get some more discussion going

@icweaver
Copy link
Author

Hi @MilesCranmer, haha, I think I missed a notification too, sorry for the delay! Thanks for the comments, I think I have responded to all of them now for your review

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

Successfully merging this pull request may close these issues.

Potential Makie.jl support?
3 participants