diff --git a/Project.toml b/Project.toml index 585c3cb6..677d7fa5 100644 --- a/Project.toml +++ b/Project.toml @@ -7,7 +7,6 @@ version = "4.1.0" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" Setfield = "efcf1570-3423-57d1-acb7-fd33fddbac46" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" @@ -16,12 +15,14 @@ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" [extensions] PolynomialsChainRulesCoreExt = "ChainRulesCore" PolynomialsFFTWExt = "FFTW" PolynomialsMakieExt = "Makie" PolynomialsMutableArithmeticsExt = "MutableArithmetics" +PolynomialsRecipesBaseExt = "RecipesBase" [compat] Aqua = "0.8" @@ -51,9 +52,10 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Aqua", "ChainRulesCore", "DualNumbers", "FFTW", "LinearAlgebra", "MutableArithmetics", "SparseArrays", "OffsetArrays", "SpecialFunctions", "Test"] +test = ["Aqua", "ChainRulesCore", "DualNumbers", "FFTW", "LinearAlgebra", "MutableArithmetics", "SparseArrays", "OffsetArrays", "RecipesBase", "SpecialFunctions", "Test"] diff --git a/src/rational-functions/plot-recipes.jl b/ext/PolynomialsRecipesBaseExt.jl similarity index 56% rename from src/rational-functions/plot-recipes.jl rename to ext/PolynomialsRecipesBaseExt.jl index 04a3f7a0..02ef3e37 100644 --- a/src/rational-functions/plot-recipes.jl +++ b/ext/PolynomialsRecipesBaseExt.jl @@ -1,7 +1,64 @@ +module PolynomialsRecipesBaseExt + +using Polynomials +using Polynomials: domain +using RecipesBase + +function poly_interval(p::AbstractPolynomial) + + # use restricted domain, if finite + A,B = first(domain(p)), last(domain(p)) + if !isinf(A) && !isinf(B) + if isopen(domain(p)) + Delta = (B-A)/100 + A += Delta + B -= Delta + end + return A:(B-A)/100:B + end + + + # Find points of interest + zero_pts = roots(p) + crit_pts = roots(derivative(p, 1)) + infl_pts = roots(derivative(p, 2)) + pts = sort([ real(pt) for pt in [zero_pts; crit_pts; infl_pts] if isreal(pt) ]) + # Choose a range that shows all interesting points with some margin + min_x, max_x = length(pts) > 0 ? (pts[1], pts[end]) : (-1, 1) + d = max(max_x - min_x, 1) + a = min_x - d / 5 + b = max_x + d / 5 + + Delta = b - a + + return a:Delta/50:b +end + +poly_label(p::AbstractPolynomial) = sprint(printpoly, p) + +#@recipe function f(p::AbstractPolynomial, x = poly_interval(p)) +# label --> poly_label(p) +# x, p.(x) +#end + +@recipe function f(p::AbstractPolynomial) + label --> poly_label(p) + xlims --> extrema(poly_interval(p)) + x -> p(x) +end + +@recipe function f(p::AbstractPolynomial, a, b) + label --> poly_label(p) + step = (b - a) / 100 + xs = a:step:b + ys = p.(xs) + xs, ys +end + ## Plot recipe ## define a heuristic to work around asymptotes ## just sort of successful -@recipe function f(pq::AbstractRationalFunction{T}, a=nothing, b=nothing) where {T} +@recipe function f(pq::Polynomials.AbstractRationalFunction{T}, a=nothing, b=nothing) where {T} xlims = get(plotattributes, :xlims, (nothing, nothing)) ylims = get(plotattributes, :ylims, (nothing, nothing)) @@ -64,3 +121,4 @@ function rational_function_trim(pq, a, b, xlims, ylims) xs, ys′ end +end diff --git a/src/Polynomials.jl b/src/Polynomials.jl index e19cd5a0..6f12dd45 100644 --- a/src/Polynomials.jl +++ b/src/Polynomials.jl @@ -14,7 +14,6 @@ using OrderedCollections include("abstract.jl") include("show.jl") -include("plots.jl") include("contrib.jl") # Interface for all AbstractPolynomials @@ -55,7 +54,6 @@ include("rational-functions/common.jl") include("rational-functions/rational-function.jl") include("rational-functions/fit.jl") #include("rational-functions/rational-transfer-function.jl") -include("rational-functions/plot-recipes.jl") # compat; opt-in with `using Polynomials.PolyCompat` include("legacy/misc.jl") diff --git a/src/plots.jl b/src/plots.jl deleted file mode 100644 index 753479ed..00000000 --- a/src/plots.jl +++ /dev/null @@ -1,53 +0,0 @@ -## XXX todo: make this an extension when minimum Julia supports that -using RecipesBase - -function poly_interval(p::AbstractPolynomial) - - # use restricted domain, if finite - A,B = first(domain(p)), last(domain(p)) - if !isinf(A) && !isinf(B) - if isopen(domain(p)) - Delta = (B-A)/100 - A += Delta - B -= Delta - end - return A:(B-A)/100:B - end - - - # Find points of interest - zero_pts = roots(p) - crit_pts = roots(derivative(p, 1)) - infl_pts = roots(derivative(p, 2)) - pts = sort([ real(pt) for pt in [zero_pts; crit_pts; infl_pts] if isreal(pt) ]) - # Choose a range that shows all interesting points with some margin - min_x, max_x = length(pts) > 0 ? (pts[1], pts[end]) : (-1, 1) - d = max(max_x - min_x, 1) - a = min_x - d / 5 - b = max_x + d / 5 - - Delta = b - a - - return a:Delta/50:b -end - -poly_label(p::AbstractPolynomial) = sprint(printpoly, p) - -#@recipe function f(p::AbstractPolynomial, x = poly_interval(p)) -# label --> poly_label(p) -# x, p.(x) -#end - -@recipe function f(p::AbstractPolynomial) - label --> poly_label(p) - xlims --> extrema(poly_interval(p)) - x -> p(x) -end - -@recipe function f(p::AbstractPolynomial, a, b) - label --> poly_label(p) - step = (b - a) / 100 - xs = a:step:b - ys = p.(xs) - xs, ys -end diff --git a/test/StandardBasis.jl b/test/StandardBasis.jl index 3f45e594..409ad0f7 100644 --- a/test/StandardBasis.jl +++ b/test/StandardBasis.jl @@ -1687,22 +1687,6 @@ end @test printpoly_to_string(SparsePolynomial(Dict(.=>(-2:2, -1:3)))) == "-x^-2 + 1 + 2*x + 3*x^2" end -@testset "Plotting" begin - p = fromroots([-1, 1]) # x^2 - 1 - rec = apply_recipe(Dict{Symbol,Any}(), p) - @test rec[1].plotattributes[:label] == "-1 + x^2" - @test rec[1].plotattributes[:xlims] == (-1.4, 1.4) - - - rec = apply_recipe(Dict{Symbol,Any}(), p, -1, 1) - @test rec[1].plotattributes[:label] == "-1 + x^2" - - p = ChebyshevT([1,1,1]) - rec = apply_recipe(Dict{Symbol,Any}(), p) - @test !isnothing(match(r"T_0", rec[1].plotattributes[:label])) - @test rec[1].plotattributes[:xlims] == (-1.0, 1.0) # uses domain(p) -end - @testset "Promotion" begin # Test different types work together diff --git a/test/runtests.jl b/test/runtests.jl index 6fdde551..cab3dd79 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,7 +3,6 @@ using Test using LinearAlgebra using Polynomials using SpecialFunctions -using RecipesBase: apply_recipe import SparseArrays: sparse, nnz using OffsetArrays diff --git a/test/test-extensions.jl b/test/test-extensions.jl index 67780b23..1ccb96fd 100644 --- a/test/test-extensions.jl +++ b/test/test-extensions.jl @@ -1,3 +1,20 @@ using FFTW using Makie using ChainRulesCore +using RecipesBase: apply_recipe + +@testset "Plotting" begin + p = fromroots([-1, 1]) # x^2 - 1 + rec = apply_recipe(Dict{Symbol,Any}(), p) + @test rec[1].plotattributes[:label] == "-1 + x^2" + @test rec[1].plotattributes[:xlims] == (-1.4, 1.4) + + + rec = apply_recipe(Dict{Symbol,Any}(), p, -1, 1) + @test rec[1].plotattributes[:label] == "-1 + x^2" + + p = ChebyshevT([1,1,1]) + rec = apply_recipe(Dict{Symbol,Any}(), p) + @test !isnothing(match(r"T_0", rec[1].plotattributes[:label])) + @test rec[1].plotattributes[:xlims] == (-1.0, 1.0) # uses domain(p) +end