| 
54 | 54 |     xs, ys  | 
55 | 55 | end  | 
56 | 56 | 
 
  | 
 | 57 | +## Plot recipe  | 
 | 58 | +## define a heuristic to work around asymptotes  | 
 | 59 | +## just sort of successful  | 
 | 60 | +@recipe function f(pq::AbstractRationalFunction{T}, a=nothing, b=nothing) where {T}  | 
 | 61 | + | 
 | 62 | +    xlims = get(plotattributes, :xlims, (nothing, nothing))  | 
 | 63 | +    ylims = get(plotattributes, :ylims, (nothing, nothing))  | 
 | 64 | +    rational_function_trim(pq, a, b, xlims, ylims)      | 
 | 65 | + | 
 | 66 | +end  | 
 | 67 | + | 
 | 68 | +isapproxreal(x::Real) = true  | 
 | 69 | +isapproxreal(x::Complex{T}) where {T} = imag(x) <= sqrt(eps(real(T)))  | 
 | 70 | +function toobig(pq)  | 
 | 71 | +    x -> begin  | 
 | 72 | +        y = pq(x)  | 
 | 73 | +        isinf(y) && return true  | 
 | 74 | +        isnan(y) && return true  | 
 | 75 | +        abs(y) > 1e8 && return true  | 
 | 76 | +        return false  | 
 | 77 | +    end  | 
 | 78 | +end  | 
 | 79 | + | 
 | 80 | +function rational_function_trim(pq, a, b, xlims, ylims)  | 
 | 81 | + | 
 | 82 | +    p,q = lowest_terms(//(pq...), method=:numerical)  | 
 | 83 | +    dpq = derivative(p//q)  | 
 | 84 | +    p′,q′ = lowest_terms(dpq)  | 
 | 85 | + | 
 | 86 | +    λs = Multroot.multroot(q).values  | 
 | 87 | +    λs = isempty(λs) ? λs : real.(filter(isapproxreal, λs))  | 
 | 88 | + | 
 | 89 | +    cps = Multroot.multroot(p′).values  | 
 | 90 | +    cps = isempty(cps) ? cps : real.(filter(isapproxreal, cps))  | 
 | 91 | +    cps = isempty(cps) ? cps : filter(!toobig(pq), cps)  | 
 | 92 | + | 
 | 93 | +    a = isnothing(a) ? xlims[1] : a  | 
 | 94 | +    b = isnothing(b) ? xlims[2] : b  | 
 | 95 | + | 
 | 96 | +    if isnothing(a) && isnothing(b)  | 
 | 97 | +        u= poly_interval(p)  | 
 | 98 | +        v= poly_interval(q)  | 
 | 99 | +        a,b = min(first(u), first(v)), max(last(u), last(v))  | 
 | 100 | + | 
 | 101 | +        if !isempty(λs)  | 
 | 102 | +            a,b = min(a, real(minimum(λs))), max(b, real(maximum(λs)))  | 
 | 103 | +        end  | 
 | 104 | +        if !isempty(cps)  | 
 | 105 | +            a,b = min(a, real(minimum(cps))), max(b, real(maximum(cps)))  | 
 | 106 | +        end  | 
 | 107 | +        a *= (a > 0 ? 1/1.5 : 1.25)  | 
 | 108 | +        b *= (b < 0 ? 1/1.5 : 1.25)  | 
 | 109 | +    end  | 
 | 110 | + | 
 | 111 | +    n = 601  | 
 | 112 | +    xs = range(a,stop=b, length=n)  | 
 | 113 | +    ys = pq.(xs)  | 
 | 114 | +    Mcps = isempty(cps) ? 5 : 3*maximum(abs, pq.(cps))  | 
 | 115 | +    M = max(5, Mcps, 1.25*maximum(abs, pq.((a,b))))  | 
 | 116 | + | 
 | 117 | +    lo = isnothing(ylims[1]) ? -M : ylims[1]  | 
 | 118 | +    hi = isnothing(ylims[2]) ?  M : ylims[2]  | 
 | 119 | +    ys′ = [lo <= yᵢ <= hi ? yᵢ : NaN for yᵢ ∈ ys]  | 
 | 120 | +    xs, ys′  | 
 | 121 | + | 
 | 122 | +end  | 
57 | 123 | end  | 
0 commit comments