using Makie, MakieRecipes

The simplest example model

using MakieRecipes.RecipesBase

struct T end

RecipesBase.@recipe function plot(::T, n = 1; customcolor = :green)
    markershape --> :auto        # if markershape is unset, make it :auto
    markercolor :=  customcolor  # force markercolor to be customcolor
    xrotation   --> 45           # if xrotation is unset, make it 45
    zrotation   --> 90           # if zrotation is unset, make it 90
    rand(10,n)                   # return the arguments (input data) for the next recipe
end

recipeplot(T(); seriestype = :path)

AbstractPlotting.save("basic.svg", AbstractPlotting.current_scene()); nothing #hide

Testing out series decomposition

sc = Scene()
recipeplot!(sc, rand(10, 2); seriestype = :scatter)
recipeplot!(sc, 1:10, rand(10, 1); seriestype = :path)

AbstractPlotting.save("series.svg", AbstractPlotting.current_scene()); nothing #hide

Differential Equations

using OrdinaryDiffEq, StochasticDiffEq, DiffEqNoiseProcess

A simple exponential growth model

f(u,p,t) = 1.01.*u
u0 = [1/2, 1]
tspan = (0.0,1.0)
prob = ODEProblem(f,u0,tspan)
sol = solve(prob, Tsit5(), reltol=1e-8, abstol=1e-8)

recipeplot(sol)

AbstractPlotting.save("exp.svg", AbstractPlotting.current_scene()); nothing #hide

Matrix DiffEq

A  = [1. 0  0 -5
      4 -2  4 -3
     -4  0  0  1
      5 -2  2  3]
u0 = rand(4,2)
tspan = (0.0,1.0)
f(u,p,t) = A*u
prob = ODEProblem(f,u0,tspan)
sol = solve(prob, Tsit5(), reltol=1e-8, abstol=1e-8)

recipeplot(sol)

AbstractPlotting.save("mat.svg", AbstractPlotting.current_scene()); nothing #hide

Stochastic DiffEq

f(du,u,p,t) = (du .= u)
g(du,u,p,t) = (du .= u)
u0 = rand(4,2)

W = WienerProcess(0.0,0.0,0.0)
prob = SDEProblem(f,g,u0,(0.0,1.0),noise=W)
sol = solve(prob,SRIW1())

recipeplot(sol)

AbstractPlotting.save("stochastic.svg", AbstractPlotting.current_scene()); nothing #hide

Animating a differential equation solution

You can update arguments and attributes arbitrarily, and the recipe pipeline is rerun.

function lorenz(du, u, p, t)
    du[1] = p[1]*(u[2]-u[1])
    du[2] = u[1]*(p[2]-u[3]) - u[2]
    du[3] = u[1]*u[2] - p[3]*u[3]
end

prob = ODEProblem(lorenz, [1., 5., 10.], (0., 100.), (10.0, 28.0, 8/3))

ρ = Node(28.0)

sol = @lift solve(remake(prob; p = (10.0, $ρ, 8/3)), Tsit5())

sc = recipeplot(sol)

ylims!(sc, -30, 70) # avoid jitter when animating

record(sc, "lorenz.gif", LinRange(0, 35, 100)) do ρᵢ
    ρ[] = ρᵢ
end

Phylogenetic tree

using Phylo

assetpath = joinpath(dirname(pathof(MakieRecipes)), "..", "docs", "src", "assets")
hummers = open(t -> parsenewick(t, NamedPolytomousTree), joinpath(assetpath, "hummingbirds.tree"))

evolve(tree) = Phylo.map_depthfirst((val, node) -> val + randn(), 0., tree, Float64)

trait = evolve(hummers)

scp = recipeplot(
    hummers;
    treetype = :fan,
    line_z = trait,
    linewidth = 5,
    showtips = false,
    cgrad = :RdYlBu,
    seriestype = :path,
    scale_plot = false, # Makie attributes can be used here as well!
    show_axis = false
)
WARNING: using Phylo.Node in module ex-examples conflicts with an existing identifier.

Animation with different colormaps (changing attributes)

You can update arguments and attributes arbitrarily, and the recipe pipeline is rerun.

record(scp, "phylo_colormaps.gif", PlotUtils.cgradients(:colorcet), framerate = 3) do cmap
    scp.plots[1].cgrad[] = cmap
end
"phylo_colormaps.gif"

GraphRecipes

using GraphRecipes
using GraphRecipes: GraphPlot

In tis case, we don't need access to all of the functions which GraphRecipes provides - just the GraphPlot struct, which is used for recipe dispatch. The rest is handled by the GraphRecipes internals.

The simplest graph recipe

Because userplot is unsupported, we have to use the low-level interface to user plot recipes, by wrapping our arguments in the userplot type. Arguments must be supplied as a Tuple or some other iterable.

recipeplot(
    GraphPlot(
        (
        [0  1  1;
         1  0  1;
         1  1  0],
         )
    );
    show_axis = false,
    scale_plot = false
)

AbstractPlotting.save("simplegraph.svg", AbstractPlotting.current_scene()); nothing #hide

Undirected graph with node labels and sizes

n = 15
A = Float64[ rand() < 0.5 ? 0 : rand() for i=1:n, j=1:n]
for i=1:n
    A[i, 1:i-1] = A[1:i-1, i]
    A[i, i] = 0
end

recipeplot(
        GraphPlot((A,));
        markersize = 0.2,
        node_weights = 1:n,
        markercolor = range(colorant"yellow", stop=colorant"red", length=n),
        names = 1:n,
        fontsize = 10,
        linecolor = :darkgrey,
        show_axis = false,
        scale_plot = false
    )

AbstractPlotting.save("undigraph.svg", AbstractPlotting.current_scene()); nothing #hide

Multigraphs

recipeplot(GraphPlot(([[1,1,2,2],[1,1,1],[1]],)); names="node_".*string.(1:3), nodeshape=:circle, self_edge_size=0.25, show_axis = false, scale_plot = false)

AbstractPlotting.save("digraph.svg", AbstractPlotting.current_scene()); nothing #hide

Julia AST

code = quote
    function mysum(list)
        out = 0
        for value in list
            out += value
        end
        out
    end
end

recipeplot(code; fontsize = 12, shorten = 0.01, axis_buffer = 0.15, nodeshape = :rect)
AbstractPlotting.save("ast.svg", AbstractPlotting.current_scene()); nothing #hide

Type tree with GraphRecipes

recipeplot(AbstractFloat; method = :tree, fontsize = 10)
AbstractPlotting.save("typetree.svg", AbstractPlotting.current_scene()); nothing #hide


This page was generated using Literate.jl.