Skip to content

Commit

Permalink
move plotting to package extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
daanhb committed Sep 20, 2024
1 parent 526001d commit 2e5d6fb
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 58 deletions.
16 changes: 11 additions & 5 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "BasisFunctions"
uuid = "4343a256-5453-507d-8aad-01a9d7189916"
authors = ["Daan Huybrechs <[email protected]>"]
version = "0.6.4"
version = "0.6.5"

[deps]
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
Expand All @@ -19,17 +19,23 @@ IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
ToeplitzMatrices = "c751599d-da0a-543b-9d20-d0a503d91d24"

[weakdeps]
PGFPlotsX = "8314cec4-20b6-5062-9cdb-752b83310925"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"

[extensions]
BasisFunctionsRecipesBaseExt = "RecipesBase"
BasisFunctionsPGFPlotsXExt = "PGFPlotsX"

[compat]
BlockArrays = "0.16"
CompositeTypes = "0.1.3"
Expand All @@ -52,7 +58,7 @@ Reexport = "1.0"
SpecialFunctions = "1.0, 2.0"
StaticArrays = "1.4"
ToeplitzMatrices = "0.7"
julia = "1.6"
julia = "1.9"

[extras]
Calculus = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
Expand All @@ -61,4 +67,4 @@ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[targets]
test = ["Plots", "Random", "Calculus", "DoubleFloats"]
test = ["PGFPlotsX", "Plots", "Random", "RecipesBase", "Calculus", "DoubleFloats"]
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
module BasisFunctionsPGFPlotsXExt

using BasisFunctions, PGFPlotsX

using PGFPlotsX
import PGFPlotsX: Plot, PlotInc, Options, Axis

using BasisFunctions:
plotgrid

for F in (:Expansion,)
@eval begin
Axis(F::$F, trailing...; opts...) =
Expand Down Expand Up @@ -29,12 +34,12 @@ for plot in (:Plot, :PlotInc)
if plot_complex
vals = F.(grid)
options = @pgf {options..., no_markers}
$(plot)(options, Table([grid, BasisFunctions.postprocess(dictionary(F), grid, real.(vals))])),
$(plot)(options, Table([grid, BasisFunctions.postprocess(dictionary(F), grid, imag.(vals))]))
$(plot)(options, Table([grid, BasisFunctions.plot_postprocess(dictionary(F), grid, real.(vals))])),
$(plot)(options, Table([grid, BasisFunctions.plot_postprocess(dictionary(F), grid, imag.(vals))]))
else
vals = real.(F.(grid))
options = @pgf {options..., no_markers}
$(plot)(options, Table([grid, BasisFunctions.postprocess(dictionary(F), grid, vals)]))
$(plot)(options, Table([grid, BasisFunctions.plot_postprocess(dictionary(F), grid, vals)]))
end
end

Expand All @@ -51,7 +56,9 @@ for plot in (:Plot, :PlotInc)
grid = plotgrid(dictionary(F), n)
vals = abs.(f.(grid) - F.(grid))
options = @pgf {options..., no_markers}
$(plot)(options, Table([grid, BasisFunctions.postprocess(dictionary(F), grid, vals)]))
$(plot)(options, Table([grid, BasisFunctions.plot_postprocess(dictionary(F), grid, vals)]))
end
end
end

end
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
module BasisFunctionsRecipesBaseExt

using BasisFunctions, RecipesBase

using BasisFunctions:
AbstractBasisFunction,
Domain2d,
plotgrid,
plot_postprocess

import BasisFunctions:
plotgrid,
plot_postprocess

## Plotting recipe for a setexpansion:
# - determine the plotting grid(depending on the basis)
# - evaluate the expansion in the gridpoints (fast if possible)
# - postprocess the data
# - plot_postprocess the data

@recipe function f(S::Expansion; plot_complex = false, n=200)
legend --> false
# title --> "Expansion"
grid = plotgrid(dictionary(S), n)
vals = plot_complex ? S.(grid) : real(S.(grid))
grid, postprocess(dictionary(S), grid, vals)
grid, plot_postprocess(dictionary(S), grid, vals)
end

# When a target function is provided, plot the error
Expand All @@ -19,7 +32,7 @@ end
# Determine the return type so we know where to sample
origvals = sample(grid, target, codomaintype(S))
vals = abs.(origvals - S.(grid))
dictionary(S), grid, postprocess(dictionary(S), grid, vals)
dictionary(S), grid, plot_postprocess(dictionary(S), grid, vals)
end
# 1D error plot
@recipe function f(S::Dictionary1d, grid::AbstractGrid, vals)
Expand All @@ -45,7 +58,7 @@ end
grid = plotgrid(F[i],n)
z = F[i].(grid)
vals = plot_complex ? z : real(z)
grid, postprocess(F[i],grid,vals)
grid, plot_postprocess(F[i],grid,vals)
end
end
nothing
Expand All @@ -57,46 +70,11 @@ end
grid = plotgrid(φ,n)
z = φ.(grid)
vals = plot_complex ? z : real(z)
grid, postprocess(φ,grid,vals)
grid, plot_postprocess(φ,grid,vals)
end
nothing
end

#
# For regular Expansions, no postprocessing is needed
function postprocess(S::Dictionary, grid, vals)
D = support(S)
I = grid .∉ Ref(D)
vals[I] .= Inf
vals
end

# For function subsets, revert to the underlying Dictionary for postprocessing
postprocess(S::Subdictionary, grid, vals) = postprocess(superdict(S), grid, vals)
postprocess::AbstractBasisFunction, grid, vals) = postprocess(dictionary(φ), grid, vals)

## Plotting grids
# Always plot on equispaced grids for the best plotting resolution
plotgrid(S::Dictionary1d, n) = EquispacedGrid(n, support(S))
# look at first element by default
plotgrid(S::MultiDict, n) = plotgrid(component(S,1), n)
plotgrid(S::DerivedDict, n) = plotgrid(superdict(S),n)
# NOTE: This only supports multi-dimensional tensor product dicts.
plotgrid(F::TensorProductDict2, n) = plotgrid(component(F,1),n)×plotgrid(component(F,2),n)
plotgrid(F::OperatedDict, n) = plotgrid(superdict(F), n)
plotgrid(F::Subdictionary, n) = plotgrid(superdict(F), n)
plotgrid::AbstractBasisFunction, n) = plotgrid(dictionary(φ), n)

# generic fallback for suitable plotting grids
plotgrid(S::Dictionary, n) = plotgrid_domain(n, support(S))
plotgrid_domain(n::Int, domain::AbstractInterval) = EquispacedGrid(n, domain)
plotgrid_domain(n::Int, domain::ProductDomain) =
productgrid(map(d->plotgrid_domain(n, d), factors(domain))...)
function plotgrid_domain(n::Int, domain)
box = boundingbox(domain)
g = plotgrid_domain(n, box)
MaskedGrid(g, domain)
end

## Split complex plots in real and imaginary parts
# 1D
Expand Down Expand Up @@ -140,7 +118,7 @@ end

@recipe function f(dom::Domain2d; n=300, distance=false, xlim=[-1,1], ylim=[-1,1])
seriescolor --> :tempo
seriestype --> :heatmap
seriestype --> :heatmap
aspect_ratio --> 1
colorbar --> false
# xrange = linspace(xlim[1],xlim[2],n)
Expand All @@ -153,3 +131,5 @@ end
plotdata = distance ? dist.(grid, Ref(dom)) : in.(grid, Ref(dom))
collect(xrange),collect(yrange),plotdata'
end

end
7 changes: 1 addition & 6 deletions src/BasisFunctions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ using DomainSets, DomainIntegrals
using CompositeTypes, CompositeTypes.Display

using QuadGK, Base.Cartesian
using RecipesBase

using Reexport

Expand Down Expand Up @@ -295,9 +294,6 @@ export ChebyshevT, ChebyshevU,
FastChebyshevTransform, InverseFastChebyshevTransform,
FastChebyshevTransformFFTW, InverseFastChebyshevTransformFFTW

# from util/recipes.jl
export plotgrid, postprocess

# from bases/poly/orthopoly.jl and friends
export Legendre, Jacobi, Laguerre, Hermite,
Monomials, GenericOPS,
Expand Down Expand Up @@ -416,8 +412,7 @@ include("bases/poly/ops/hermite.jl")
include("bases/poly/ops/generic_op.jl")
include("bases/poly/ops/specialOPS.jl")

include("util/display/recipes.jl")
include("util/display/pgfplots.jl")
include("util/plot.jl")

include("test/Test.jl")

Expand Down
40 changes: 40 additions & 0 deletions src/util/plot.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

"Return a grid suitable for plotting a function in the given dictionary."
function plotgrid end
"Process plotting data before it is visualized."
function plot_postprocess end

# For regular Expansions, no postprocessing is needed
function plot_postprocess(S::Dictionary, grid, vals)
D = support(S)
I = grid .∉ Ref(D)
vals[I] .= Inf
vals
end

# For function subsets, revert to the underlying Dictionary for postprocessing
plot_postprocess(S::Subdictionary, grid, vals) = plot_postprocess(superdict(S), grid, vals)
plot_postprocess::AbstractBasisFunction, grid, vals) = plot_postprocess(dictionary(φ), grid, vals)

## Plotting grids
# Always plot on equispaced grids for the best plotting resolution
plotgrid(S::Dictionary1d, n) = EquispacedGrid(n, support(S))
# look at first element by default
plotgrid(S::MultiDict, n) = plotgrid(component(S,1), n)
plotgrid(S::DerivedDict, n) = plotgrid(superdict(S),n)
# NOTE: This only supports multi-dimensional tensor product dicts.
plotgrid(F::TensorProductDict2, n) = plotgrid(component(F,1),n)×plotgrid(component(F,2),n)
plotgrid(F::OperatedDict, n) = plotgrid(superdict(F), n)
plotgrid(F::Subdictionary, n) = plotgrid(superdict(F), n)
plotgrid::AbstractBasisFunction, n) = plotgrid(dictionary(φ), n)

# generic fallback for suitable plotting grids
plotgrid(S::Dictionary, n) = plotgrid_domain(n, support(S))
plotgrid_domain(n::Int, domain::AbstractInterval) = EquispacedGrid(n, domain)
plotgrid_domain(n::Int, domain::ProductDomain) =
productgrid(map(d->plotgrid_domain(n, d), factors(domain))...)
function plotgrid_domain(n::Int, domain)
box = boundingbox(domain)
g = plotgrid_domain(n, box)
MaskedGrid(g, domain)
end
2 changes: 1 addition & 1 deletion test/test_plots.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using BasisFunctions, BasisFunctions.Test, DomainSets, GridArrays

using Test, LinearAlgebra, Plots
using Test, LinearAlgebra, PGFPlotsX, Plots

delimit("Plots")
@testset begin
Expand Down

4 comments on commit 2e5d6fb

@daanhb
Copy link
Member Author

@daanhb daanhb commented on 2e5d6fb Sep 20, 2024

Choose a reason for hiding this comment

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

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request created: JuliaRegistries/General/115558

Tip: Release Notes

Did you know you can add release notes too? Just add markdown formatted text underneath the comment after the text
"Release notes:" and it will be added to the registry PR, and if TagBot is installed it will also be added to the
release that TagBot creates. i.e.

@JuliaRegistrator register

Release notes:

## Breaking changes

- blah

To add them here just re-invoke and the PR will be updated.

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.6.5 -m "<description of version>" 2e5d6fbcd908576dd55a1c1b82b32b6340014a1f
git push origin v0.6.5

@daanhb
Copy link
Member Author

@daanhb daanhb commented on 2e5d6fb Sep 20, 2024

Choose a reason for hiding this comment

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

@JuliaRegistrator register

Release notes:

  • supporting routines for the Plots package have been moved to an extension conditional on loading RecipesBase
  • similarly, support for PGFPlotsX has moved to an extension

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

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

Registration pull request updated: JuliaRegistries/General/115558

Tagging

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.6.5 -m "<description of version>" 2e5d6fbcd908576dd55a1c1b82b32b6340014a1f
git push origin v0.6.5

Please sign in to comment.