Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
6 changes: 0 additions & 6 deletions .JuliaFormatter.toml

This file was deleted.

8 changes: 6 additions & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.3.6] unreleased
## [2.4.0] unreleased

### Added

* an extension to also perform the numerical checks plots with [`Makie.jl](https://https://makie.org/) (#272).

### Fixed

* (documentation of the `injectivity_radius` function now displays clearer instructions for the implementation of a radius linked to a user's own `AbstractRetractionMethod`. (#270)
* documentation of the `injectivity_radius` function now displays clearer instructions for the implementation of a radius linked to a user's own `AbstractRetractionMethod`. (#270)

## [2.3.5] 03/04/2026

Expand Down
9 changes: 7 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
name = "ManifoldsBase"
uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb"
version = "2.4.0"
authors = ["Seth Axen <seth.axen@gmail.com>", "Mateusz Baran <mateuszbaran89@gmail.com>", "Ronny Bergmann <manopt@ronnybergmann.net>", "Antoine Levitt <antoine.levitt@gmail.com>"]
version = "2.3.5"

[workspace]
projects = ["test", "docs", "tutorials"]

[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
Preferences = "21216c6a-2e73-6563-6e65-726566657250"
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[weakdeps]
Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Quaternions = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[extensions]
ManifoldsBaseMakieExt = "Makie"
ManifoldsBasePlotsExt = "Plots"
ManifoldsBaseQuaternionsExt = "Quaternions"
ManifoldsBaseRecursiveArrayToolsExt = "RecursiveArrayTools"
ManifoldsBaseStatisticsExt = "Statistics"

[compat]
LinearAlgebra = "1.6"
Makie = "0.24"
Markdown = "1.6"
Plots = "1"
Preferences = "1.4"
Printf = "1.6"
Quaternions = "0.7"
Random = "1.6"
RecursiveArrayTools = "2, 3, 4"
Quaternions = "0.7"
Statistics = "1.6"
julia = "1.10"
4 changes: 3 additions & 1 deletion docs/src/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# ManifoldsBase.jl

`ManifoldsBase.jl` is a lightweight interface for manifolds.
```@docs
ManifoldsBase.ManifoldsBase
```

This packages has two main purposes.
You can add it as a dependency if you plan to work on manifolds (generically) or if you plan to
Expand Down
63 changes: 63 additions & 0 deletions ext/ManifoldsBaseMakieExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
module ManifoldsBaseMakieExt

using ManifoldsBase
using Makie
using Printf: @sprintf
import ManifoldsBase: plot_slope, plot_check_geodesic

function ManifoldsBase.plot_slope(
::Val{:Makie}, x, y;
slope = 2, line_base = 0, a = 0, b = 2.0, i = 1, j = length(x),
)
fig = Makie.Figure()
# Setup the log log plot
ax = Makie.Axis(
fig[1, 1];
xscale = log10, yscale = log10, xlabel = "t", ylabel = L"E(t)", title = "Slope plot",
)
# Main error data
Makie.lines!(ax, x, y; label = L"E(t)", linewidth = 3, color = :lightblue)
# Reference slope
s_line = [exp10(line_base + t * slope) for t in log10.(x)]
Makie.lines!(
ax, x, s_line; label = "slope s=$slope",
linestyle = :dash, color = :black, linewidth = 2
)

# Best-fit slope segment if i and j are provided
if (i != 0) && (j != 0)
best_line = [exp10(a + t * b) for t in log10.(x[i:j])]
Makie.lines!(
ax, x[i:j], best_line;
label = "best slope $(@sprintf("%.4f", b))",
color = :blue, linestyle = :dot, linewidth = 2,
)
end
Makie.axislegend(ax; position = :lt)
return fig
end
function ManifoldsBase.plot_check_geodesic(::Val{:Makie}, T, N, e_norm, e_pt, e_alpha)
fig = Figure()
ax = Axis(
fig[1, 1];
xlabel = "t", ylabel = "error magnitude", title = "Geodesic checks",
)
# Speed deviation: |‖Xᵢ‖ − mean‖X‖|
Makie.lines!(
ax, T[1:(N - 1)], e_norm;
label = L"|\|X_i\| - \overline{\|X\|}|", linewidth = 3, color = :lightblue
)
# Parallel-transport mismatch (norm): ‖Xᵢ − PT_{i+1→i}(X_{i+1})‖
lines!(
ax, T[1:(N - 2)], e_pt;
label = "PT difference (norm)", linewidth = 3, color = :blue
)
# Parallel-transport mismatch (angle): |1 − cos∠(Xᵢ, PT_{i+1→i}X_{i+1})|
lines!(
ax, T[1:(N - 2)], e_alpha;
label = "PT difference (angle)", linewidth = 3, color = :green
)
axislegend(ax; position = :rt)
return fig
end
end
40 changes: 9 additions & 31 deletions ext/ManifoldsBasePlotsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,31 @@ module ManifoldsBasePlotsExt
using ManifoldsBase
using Plots
using Printf: @sprintf
import ManifoldsBase: plot_slope

function ManifoldsBase.plot_slope(
x,
y;
slope = 2,
line_base = 0,
a = 0,
b = 2.0,
i = 1,
j = length(x),
::Val{:Plots}, x, y;
slope = 2, line_base = 0, a = 0, b = 2.0, i = 1, j = length(x),
)
fig = plot(
x,
y;
xaxis = :log,
yaxis = :log,
label = "\$E(t)\$",
linewidth = 3,
legend = :topleft,
color = :lightblue,
x, y; xaxis = :log, yaxis = :log, label = "\$E(t)\$",
linewidth = 3, legend = :topleft, color = :lightblue,
)
s_line = [exp10(line_base + t * slope) for t in log10.(x)]
plot!(
fig,
x,
s_line;
label = "slope s=$slope",
linestyle = :dash,
color = :black,
linewidth = 2,
fig, x, s_line; label = "slope s=$slope",
linestyle = :dash, color = :black, linewidth = 2,
)
if (i != 0) && (j != 0)
best_line = [exp10(a + t * b) for t in log10.(x[i:j])]
plot!(
fig,
x[i:j],
best_line;
fig, x[i:j], best_line;
label = "best slope $(@sprintf("%.4f", b))",
color = :blue,
linestyle = :dot,
linewidth = 2,
color = :blue, linestyle = :dot, linewidth = 2,
)
end
return fig
end
function ManifoldsBase.plot_check_geodesic(T, N, e_norm, e_pt, e_alpha)
function ManifoldsBase.plot_check_geodesic(::Val{:Plots}, T, N, e_norm, e_pt, e_alpha)
fig = plot(
T[1:(N - 1)], e_norm;
# Deviation from constant speed: |‖Xᵢ‖ − mean‖X‖|
Expand Down
53 changes: 50 additions & 3 deletions src/ManifoldsBase.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
@doc """
🏔️ ManifoldsBase.jl: An interface for manifolds in Julia

* 📚 Documentation: [juliamanifolds.github.io/ManifoldsBase.jl/](https://juliamanifolds.github.io/ManifoldsBase.jl/)
* 📦 Repository: [github.com/JuliaManifolds/ManifoldsBase.jl](https://github.com/JuliaManifolds/ManifoldsBase.jl)
* 🎯 Issues: [github.com/JuliaManifolds/ManifoldsBase.jl/issues](https://github.com/JuliaManifolds/ManifoldsBase.jl/issues)
"""
module ManifoldsBase

import Base:
Expand All @@ -24,9 +31,11 @@ import Random: rand, rand!

using LinearAlgebra
using Markdown: @doc_str
using Preferences
using Printf: @sprintf
using Random


include("maintypes.jl")
include("numbers.jl")
include("Fiber.jl")
Expand Down Expand Up @@ -1219,6 +1228,41 @@ function zero_vector(M::AbstractManifold, p)
zero_vector!(M, X, p)
return X
end

#
#
# Internal function to set plotting backend

"""
set_plotting_backend!(backend::String; only_fallback = false)

Set the plotting backend to `backend`.
Currently supported: `"Plots"` and `"Makie"`.

An empty string resets to the default to use the last loaded one.
"""
function set_plotting_backend!(e::String)
(length(e) == 0) && (return Preferences.@delete_preferences!("PlottingBackend"))
# for the nonpersistent / fallback case, only set the value in the package
return Preferences.@set_preferences!("PlottingBackend" => e)
end

"""
get_plotting_backend()

Return the current plotting backend.
If none was set by the user, the last loaded one is returned. If none was loaded `nothing` is returned
"""
function get_plotting_backend()
def = nothing
# Choose a default – if both are loaded this order makes it Makie
!isnothing(Base.get_extension(ManifoldsBase, :ManifoldsBasePlotsExt)) && (def = "Plots")
!isnothing(Base.get_extension(ManifoldsBase, :ManifoldsBaseMakieExt)) && (def = "Makie")
# unless the user has set one
return Preferences.@load_preference("PlottingBackend", def)
end


include("errors.jl")
include("parallel_transport.jl")
include("vector_transport.jl")
Expand Down Expand Up @@ -1253,17 +1297,20 @@ function __init__()
#
return @static if isdefined(Base.Experimental, :register_error_hint) # COV_EXCL_LINE
Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs
if exc.f === plot_slope
if (exc.f === plot_slope) || (exc.f === plot_check_geodesic)
print(
io,
"""

`plot_slope` has to be implemented using your favourite plotting package.
A default is available when Plots.jl is added to the current environment.
`$(exc.f)` has to be implemented using your favourite plotting package.
A default is available when either `Plots.jl` or `Makie.jl` is loaded..
To then get the plotting functionality activated, do
""",
)
printstyled(io, "`using Plots`"; color = :cyan)
print(io, " or ")
printstyled(io, "`using CairoMakie`"; color = :cyan)
print(io, " or your favourite other Makie backend. You might have to add these to your environment first as well.")
end
if exc.f === find_best_slope_window
print(
Expand Down
Loading
Loading