diff --git a/Project.toml b/Project.toml index 0880797..ddc1d8e 100644 --- a/Project.toml +++ b/Project.toml @@ -6,18 +6,14 @@ version = "1.1.0" [deps] DefaultKeywordArguments = "d739bc73-037a-4484-8212-e0e00e9ea6bf" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" -LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" [compat] DefaultKeywordArguments = "1" Distributions = "0.25" -LaTeXStrings = "1" LogExpFunctions = "0.3" -Plots = "1" Reexport = "1" julia = "1.9" diff --git a/docs/src/output_visualisation.md b/docs/src/output_visualisation.md index 3e0722d..5e65889 100644 --- a/docs/src/output_visualisation.md +++ b/docs/src/output_visualisation.md @@ -1,14 +1,11 @@ # Output visualisation -ConsensusBasedX.jl offers the `ConsensusBasedXPlots` submodule, which provides routines to visualise the output of `minimise` for problems in one or two dimensions. +The auxiliary package [ConsensusBasedXPlots.jl](https://github.com/PdIPS/ConsensusBasedXPlots.jl) provides routines to visualise the output of `minimise` for problems in one or two dimensions. These routines are kept as a separate package in order to minimise the dependencies of ConsensusBasedX.jl, since not every user will require visualisation tools. -Simply run `minimise` with `extended_output = true` (see [Extended output](@ref)), and then call the `plot_CBO` method: +To plot the output of CBO, simply run `minimise` with `extended_output = true` (see [Extended output](@ref)), and then call the `plot_CBO` method: ```julia out = minimise(f, D = 2, extended_output = true) -using ConsensusBasedX.ConsensusBasedXPlots +using ConsensusBasedXPlots plot_CBO(out) ``` Full-code examples in [one dimension](https://github.com/PdIPS/ConsensusBasedX.jl/blob/main/examples/advanced_usage/output_visualisation_1D.jl) and [two dimensions](https://github.com/PdIPS/ConsensusBasedX.jl/blob/main/examples/advanced_usage/output_visualisation_2D.jl). - -!!! compat - The developers of ConsensusBasedX.jl intend to segregate `ConsensusBasedXPlots` as a separate package in the future, in order to avoid having `Plots` as a dependency of `ConsensusBasedX`. diff --git a/examples/advanced_usage/output_visualisation_1D.jl b/examples/advanced_usage/output_visualisation_1D.jl index 99af35b..5895373 100644 --- a/examples/advanced_usage/output_visualisation_1D.jl +++ b/examples/advanced_usage/output_visualisation_1D.jl @@ -1,4 +1,4 @@ -using ConsensusBasedX, ConsensusBasedX.ConsensusBasedXPlots +using ConsensusBasedX, ConsensusBasedXPlots f(x) = ConsensusBasedX.Ackley(x, shift = 1) diff --git a/examples/advanced_usage/output_visualisation_2D.jl b/examples/advanced_usage/output_visualisation_2D.jl index 58ecd8f..3bf46f9 100644 --- a/examples/advanced_usage/output_visualisation_2D.jl +++ b/examples/advanced_usage/output_visualisation_2D.jl @@ -1,4 +1,4 @@ -using ConsensusBasedX, ConsensusBasedX.ConsensusBasedXPlots +using ConsensusBasedX, ConsensusBasedXPlots f(x) = ConsensusBasedX.Ackley(x, shift = 1) diff --git a/src/ConsensusBasedX.jl b/src/ConsensusBasedX.jl index 4c07c2d..5a05805 100644 --- a/src/ConsensusBasedX.jl +++ b/src/ConsensusBasedX.jl @@ -40,7 +40,5 @@ include("./CBS/CBS_method.jl") include("./ConsensusBasedXLowLevel.jl") export ConsensusBasedXLowLevel -include("./ConsensusBasedXPlots.jl") -export ConsensusBasedXPlots end diff --git a/src/ConsensusBasedXPlots.jl b/src/ConsensusBasedXPlots.jl deleted file mode 100644 index dc98108..0000000 --- a/src/ConsensusBasedXPlots.jl +++ /dev/null @@ -1,326 +0,0 @@ -module ConsensusBasedXPlots - -using Reexport -@reexport using LaTeXStrings, Plots - -import ..@expand, ..reverse_reshape - -const DEFAULT_PLOT_OPTIONS = - (; dpi = 150, fontfamily = "Computer Modern", widen = true, yflip = false) - -function plot_CBO(out::NamedTuple; keywords...) - D = out.particle_dynamic_cache.D - if D == 1 - return plot_CBO_1D(out; keywords...) - elseif D == 2 - return plot_CBO_2D(out; keywords...) - end - explanation = "The `plot_CBO` routine is only defined for problems in 1D or 2D." - throw(ArgumentError(explanation)) -end -export plot_CBO - -function plot_CBO_1D( - out::NamedTuple; - show_objective = true, - show_initial_particles = true, - show_final_particles = true, - show_ensemble_minimiser = true, - show_minimiser = true, - keywords..., -) - if show_initial_particles - initial_particles = reverse_reshape(out.initial_particles) - end - if show_final_particles - final_particles = reverse_reshape(out.final_particles) - end - ensemble_minimiser = out.ensemble_minimiser - minimiser = out.minimiser - - @expand out.particle_dynamic_cache D N M - if show_initial_particles && show_final_particles - ranges = get_range_by_dimension(initial_particles, final_particles) - elseif show_initial_particles - ranges = get_range_by_dimension(initial_particles) - elseif show_final_particles - ranges = get_range_by_dimension(final_particles) - else - ranges = [(0.9 * minimiser[d] - 1, 1.1 * minimiser[d] + 1) for d ∈ 1:D] - end - - colours = (M <= 16) ? palette(:default) : palette(:default, M) - markersize_min = 2 - markersize_max = 8 - markeralpha_min = 0.5 - markeralpha_max = 1 - markersize = markersize_min + (markersize_max - markersize_min) * exp(-N / 10) - markeralpha = - markeralpha_min + (markeralpha_max - markeralpha_min) * exp(-N / 10) - - plt = - plot(xlabel = L"x", ylabel = L"f(x)"; DEFAULT_PLOT_OPTIONS..., keywords...) - - f(x) = out.method.f([x]) - - if show_objective - x_vec = range(ranges[1]..., length = 200) - plot!(x_vec, f, c = :black, label = L"f(x)", keywords...) - end - - if show_initial_particles - for m ∈ 1:M - scatter!( - initial_particles[1, :, m], - f.(initial_particles[1, :, m]), - c = colours[m], - markershape = :x, - label = ""; - markersize, - markeralpha, - keywords..., - ) - end - scatter!( - [], - [], - label = "Initial particles", - c = colours[1], - markershape = :x; - keywords..., - ) - end - - if show_final_particles - for m ∈ 1:M - scatter!( - final_particles[1, :, m], - f.(final_particles[1, :, m]), - c = colours[m], - markershape = :o, - label = ""; - markersize, - markeralpha, - keywords..., - ) - end - scatter!( - [], - [], - label = "Final particles", - c = colours[1], - markershape = :o; - keywords..., - ) - end - - if show_ensemble_minimiser - for m ∈ 1:M - scatter!( - [ensemble_minimiser[m][1]], - [f(ensemble_minimiser[m][1])], - c = colours[m], - markershape = :square, - label = "", - markersize = 2 * markersize; - keywords..., - ) - end - scatter!( - [], - [], - label = "Ensemble minimiser", - c = colours[1], - markershape = :square; - keywords..., - ) - end - - if show_minimiser - scatter!( - [minimiser[1]], - [f(minimiser[1])], - c = :white, - markershape = :star5, - label = "", - markersize = 2 * markersize; - keywords..., - ) - scatter!( - [], - [], - label = "Global minimiser", - c = :white, - markershape = :star5; - keywords..., - ) - end - - return plt -end - -function plot_CBO_2D( - out::NamedTuple; - show_objective = true, - show_initial_particles = true, - show_final_particles = true, - show_ensemble_minimiser = true, - show_minimiser = true, - keywords..., -) - if show_initial_particles - initial_particles = reverse_reshape(out.initial_particles) - end - if show_final_particles - final_particles = reverse_reshape(out.final_particles) - end - ensemble_minimiser = out.ensemble_minimiser - minimiser = out.minimiser - - @expand out.particle_dynamic_cache D N M - if show_initial_particles && show_final_particles - ranges = get_range_by_dimension(initial_particles, final_particles) - elseif show_initial_particles - ranges = get_range_by_dimension(initial_particles) - elseif show_final_particles - ranges = get_range_by_dimension(final_particles) - else - ranges = [(0.9 * minimiser[d] - 1, 1.1 * minimiser[d] + 1) for d ∈ 1:D] - end - - colours = (M <= 16) ? palette(:default) : palette(:default, M) - markersize_min = 2 - markersize_max = 8 - markeralpha_min = 0.5 - markeralpha_max = 1 - markersize = markersize_min + (markersize_max - markersize_min) * exp(-N / 10) - markeralpha = - markeralpha_min + (markeralpha_max - markeralpha_min) * exp(-N / 10) - - plt = plot(xlabel = L"x", ylabel = L"y"; DEFAULT_PLOT_OPTIONS..., keywords...) - - if show_objective - x_vec = range(ranges[1]..., length = 200) - y_vec = range(ranges[2]..., length = 200) - heatmap!( - x_vec, - y_vec, - (x, y) -> out.method.f([x, y]), - c = :nipy_spectral, - levels = 31, - colorbar_title = L"f(x,y)"; - keywords..., - ) - end - - if show_initial_particles - for m ∈ 1:M - scatter!( - initial_particles[1, :, m], - initial_particles[2, :, m], - c = colours[m], - markershape = :x, - label = ""; - markersize, - markeralpha, - keywords..., - ) - end - scatter!( - [], - [], - label = "Initial particles", - c = colours[1], - markershape = :x; - keywords..., - ) - end - - if show_final_particles - for m ∈ 1:M - scatter!( - final_particles[1, :, m], - final_particles[2, :, m], - c = colours[m], - markershape = :o, - label = ""; - markersize, - markeralpha, - keywords..., - ) - end - scatter!( - [], - [], - label = "Final particles", - c = colours[1], - markershape = :o; - keywords..., - ) - end - - if show_ensemble_minimiser - for m ∈ 1:M - scatter!( - [ensemble_minimiser[m][1]], - [ensemble_minimiser[m][2]], - c = colours[m], - markershape = :square, - label = "", - markersize = 2 * markersize; - keywords..., - ) - end - scatter!( - [], - [], - label = "Ensemble minimiser", - c = colours[1], - markershape = :square; - keywords..., - ) - end - - if show_minimiser - scatter!( - [minimiser[1]], - [minimiser[2]], - c = :white, - markershape = :star5, - label = "", - markersize = 2 * markersize; - keywords..., - ) - scatter!( - [], - [], - label = "Global minimiser", - c = :white, - markershape = :star5; - keywords..., - ) - end - - return plt -end - -function get_range_by_dimension(x::AbstractArray, y::AbstractArray) - range_x = get_range_by_dimension(x) - range_y = get_range_by_dimension(y) - range = map(s -> combine_ranges(s[1], s[2]), zip(range_x, range_y)) - return range -end - -function get_range_by_dimension(x::AbstractArray{<:Number, 3}) - max = maximum(x, dims = (2, 3))[:] - min = minimum(x, dims = (2, 3))[:] - range = map(s -> s, zip(min, max)) - return range -end - -function combine_ranges(x::Tuple{<:Real, <:Real}, y::Tuple{<:Real, <:Real}) - range = (min(x[1], y[1]), max(x[2], y[2])) - return range -end - -end