diff --git a/README.md b/README.md index 75bde2b..2f02b50 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The environment variable `JULIA_NUM_THREADS` can be used to enable the multi-thr Please share your favorite fractals as `Fatou` snippet in the [discussion thread](https://discourse.julialang.org/t/ann-fatou-jl-easily-share-julia-fractals)! -## Basic Usage +## PyPlot.jl compatability features The program can be initialized with `using Fatou, PyPlot` or `ImageInTerminal`. @@ -88,6 +88,12 @@ basin(nf,2) ![D2(ϵ)](http://latex.codecogs.com/svg.latex?D_2(\epsilon)%20=%20\left\\{z\in\mathbb{C}:\left|\\,z%20-%20\frac{1}{\cos{\left%20(z%20\right%20)}}%20\left(1%20+%20i\right)%20\left(\sin{\left%20(z%20\right%20)}%20-%201\right)%20-%20\frac{\left(1%20+%20i\right)%20\left(\sin{\left%20(z%20-%20\frac{1}{\cos{\left%20(z%20\right%20)}}%20\left(1%20+%20i\right)%20\left(\sin{\left%20(z%20\right%20)}%20-%201\right)%20\right%20)}%20-%201\right)}{\cos{\left%20(z%20-%20\frac{1}{\cos{\left%20(z%20\right%20)}}%20\left(1%20+%20i\right)%20\left(\sin{\left%20(z%20\right%20)}%20-%201\right)%20\right%20)}}%20-%20r_i\\,\right|%3C\epsilon,\\,\forall%20r_i(\\,f(r_i)=0%20)\right\\}) +## ImageInTerminal.jl compatibility + +When `using ImageInTerminal`, the display of a `Fatou.FilledSet` will be plotted automatically in the terminal. +The `orbit` method also has optional `UnicodePlots` compatibility. +Additional plotting support can be added via Pull-Request by adding another `Requires` script to the `__init__()` function definition. + ## Detailed Explanation View [Explore Fatou sets & Fractals](https://github.com/chakravala/Fatou.jl/wiki/Explore-Fatou-sets-&-fractals) in Wiki for detailed *examples*. diff --git a/src/Fatou.jl b/src/Fatou.jl index e5c8fa0..3558676 100644 --- a/src/Fatou.jl +++ b/src/Fatou.jl @@ -229,7 +229,7 @@ function newton(E; end # load additional functionality -include("internals.jl") +include("internals.jl"); include("orbitplot.jl") """ basin(::Fatou.Define, ::Integer) @@ -279,6 +279,7 @@ function __init__() println("Fatou detected $(Threads.nthreads()) julia threads.") @require PyPlot="d330b81b-6aea-500a-939a-2ce795aea3ee" include("pyplot.jl") @require ImageInTerminal="d8c32880-2388-543b-8c61-d9f865259254" include("term.jl") + @require UnicodePlots="b8865327-cd53-5732-bb35-84acbb429228" include("uniplots.jl") end end # module diff --git a/src/orbitplot.jl b/src/orbitplot.jl index 66cd9d1..b428a35 100644 --- a/src/orbitplot.jl +++ b/src/orbitplot.jl @@ -15,13 +15,12 @@ julia> juliafill("z^2-0.67",∂=[-1.25,1.5],x0=1.25,orbit=17,depth=3) |> orbit ``` """ function orbit(K::Define{FT,QT,CT}) where {FT,QT,CT} + !isdefined(Fatou,:UnicodePlots) && !isdefined(Fatou,:PyPlot) && throw(error("Requires `using PyPlot` or `using UnicodePlots`")) K.x0 == nothing ? (bi = K.∂[1:2]') : (bi = [K.∂[1:2]...,K.x0]') orbit(K.E,z->K.F(z,0),convert(Array{Float64},bi),K.orbit,K.depth,Int(K.n)) end -function orbit(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::Int=384; plt::Function=plot) - # prepare for next figure - figure() +function real_orb(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::Int=384) # initalize array to depth N = zeros(incr,depth+1) bis = zeros(3) @@ -34,8 +33,6 @@ function orbit(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::I for t ∈ 1:depth N[:,t+1] = broadcast(f,N[:,t]) end - # plot background lines - plot(x[:],N[:,1],"k--",x[:],N[:,2]) # initialize for orbit cobweb N2 = zeros(orb+1) N2[1] = bis[3]; @@ -53,29 +50,5 @@ function orbit(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::I orbit[1:3:siz,2] = N2[1:end-1] orbit[2:3:siz,2] = N2[2:end] orbit[3:3:siz,2] = N2[2:end] - # plot orbit cobweb path - plot(orbit[:,1],orbit[:,2],"r") - # plot f^2,f^3,f^4,... - for h ∈ 3:depth+1 - plot(x,N[:,h],lw=1) - end - if ~(orb == 0) - plt(range(bi[1],stop=bi[2],length=length(N2)),N2[:],"gray",marker="x",linestyle=":",lw=1) - funs = [latexstring("\\phi(x_{0:$orb})")] - funt = ", IC: \$ x_0 = $(bis[3])\$, \$ n\\in0:$orb\$" - else - funs = [] - funt = "" - end - # trim graph - d=1.07 - xlim(bi[1],bi[2]) - ylim(minimum([d*minimum(N[:,2]),0]),maximum([d*maximum(N[:,2]),0])) - # set title - fune = rdpm(Algebra.latex(E)) - title(latexstring("\$ x \\mapsto $fune\$$funt")) - # set legend - legend(vcat([L"$y=x$",L"$\phi(x)$",L"(x_n,\phi(x_n))"],[latexstring("\\phi^{$x}(x)") for x ∈ 2:depth],funs)) - tight_layout() - return + return x,N,N2,orbit,bis end diff --git a/src/pyplot.jl b/src/pyplot.jl index dfed0f4..8b5b6aa 100644 --- a/src/pyplot.jl +++ b/src/pyplot.jl @@ -29,4 +29,35 @@ function plot(K::FilledSet;c::String="",bare::Bool=false) end end -include("orbitplot.jl") +function orbit(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::Int=384; plt::Function=plot) + x,N,N2,orbit,bis = real_orb(E,f,bi,orb,depth,incr) + # prepare for next figure + figure() + # plot background lines + plot(x[:],N[:,1],"k--",x[:],N[:,2]) + # plot orbit cobweb path + plot(orbit[:,1],orbit[:,2],"r") + # plot f^2,f^3,f^4,... + for h ∈ 3:depth+1 + plot(x,N[:,h],lw=1) + end + if ~(orb == 0) + plt(range(bi[1],stop=bi[2],length=length(N2)),N2[:],"gray",marker="x",linestyle=":",lw=1) + funs = [latexstring("\\phi(x_{0:$orb})")] + funt = ", IC: \$ x_0 = $(bis[3])\$, \$ n\\in0:$orb\$" + else + funs = [] + funt = "" + end + # trim graph + d=1.07 + xlim(bi[1],bi[2]) + ylim(minimum([d*minimum(N[:,2]),0]),maximum([d*maximum(N[:,2]),0])) + # set title + fune = rdpm(Algebra.latex(E)) + PyPlot.title(latexstring("\$ x \\mapsto $fune\$$funt")) + # set legend + legend(vcat([L"$y=x$",L"$\phi(x)$",L"(x_n,\phi(x_n))"],[latexstring("\\phi^{$x}(x)") for x ∈ 2:depth],funs)) + tight_layout() + return +end diff --git a/src/term.jl b/src/term.jl index 58fe88d..521691f 100644 --- a/src/term.jl +++ b/src/term.jl @@ -3,6 +3,8 @@ using ImageInTerminal, ColorSchemes +nonan(x) = isnan(x) ? 0.0 : x + function Base.show(io::IO,K::FilledSet;c::String="",bare::Bool=false) # plot figure using imshow based in input preferences isempty(c) && (c = K.meta.cmap) @@ -10,12 +12,13 @@ function Base.show(io::IO,K::FilledSet;c::String="",bare::Bool=false) H = zeros(ColorSchemes.RGB{Float64},S...) C = getproperty(ColorSchemes, isempty(c) ? :balance : Symbol(c)) if K.meta.iter + M = length(C)/(max(K.iter...)+2) for x ∈ 1:S[1], y ∈ 1:S[2] - H[x,y] = C[K.iter[x,y]] + H[x,y] = C[round(Int,M*K.iter[x,y]+1)] end else for x ∈ 1:S[1], y ∈ 1:S[2] - H[x,y] = get(C,K.mix[x,y]) + H[x,y] = get(C,nonan(K.mix[x,y])) end end display(H) diff --git a/src/uniplots.jl b/src/uniplots.jl new file mode 100644 index 0000000..c5f09f7 --- /dev/null +++ b/src/uniplots.jl @@ -0,0 +1,32 @@ +# This file is part of Fatou.jl. It is licensed under the MIT license +# Copyright (C) 2019 Michael Reed + +using UnicodePlots + +function orbit(E,f::Function,bi::Matrix{Float64},orb::Int=0,depth::Int=1,incr::Int=384) + x,N,N2,orbit,bis = real_orb(E,f,bi,orb,depth,incr) + # trim graph + d=1.07 + xl = bi[1:2] + yl = [minimum([d*minimum(N[:,2]),0]),maximum([d*maximum(N[:,2]),0])] + # plot background lines + plt = lineplot(x[:],N[:,1],xlim=xl,ylim=yl,color=:magenta,name="y=real(z)") + lineplot!(plt,x[:],N[:,2],color=:blue,name="ϕ(real(z))") + # plot orbit cobweb path + scatterplot!(plt,orbit[:,1],orbit[:,2],color=:red,name="(zₙ,ϕ(zₙ))") + # set legend + leg = ["ϕ^{$x}(z)" for x ∈ 2:depth] + # plot f^2,f^3,f^4,... + for h ∈ 3:depth+1 + lineplot!(plt,x,N[:,h],color=isodd(h) ? :yellow : :green,name=leg[h-2]) + end + if ~(orb == 0) + lineplot!(plt,collect(range(bi[1],stop=bi[2],length=length(N2))),N2[:],color=:cyan,name="ϕ(z_{0:$orb})") + funt = ", IC: z₀ = $(bis[3]), n∈0:$orb" + else + funt = "" + end + # set title + UnicodePlots.title!(plt,"z ↦ $E$funt") + return plt +end