# Plotting a recursion graph for a function with 2 arguments

**URL:** <https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951>\
**Category:** Visualization\
**Tags:** plotting\
**Created:** [February 9, 2021, 7:33pm UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951 "2021-02-09T19:33:36Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![ash](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@ash](https://discourse.julialang.org/u/ash)\
**Post date:** [February 9, 2021, 7:33pm UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951/1 "2021-02-09T19:33:36Z")

</div>

I have a recursive function with 2 indices of the form:

```julia
function calc_rs(n,p)
    println("Calculating for ($n,$p)")
    if n != 1
        calc_rs(n-1, 1)
        calc_rs(n-1, p+1)
    end
end

```

It is called as:

```julia
calc_rs(N, 1)

```

then it recurses until it hits the base case with (1,p). For example, with N=3:

```julia
calc_rs(3, 1)
Calculating for (3,1)
Calculating for (2,1)
Calculating for (1,1)
Calculating for (1,2)
Calculating for (2,2)
Calculating for (1,1)
Calculating for (1,3)

```

I am trying to create a plot of this recursion. I have made this manually as:

```julia
using GraphRecipes, Plots
g = [0 1 1 0 0 0;
     0 0 0 1 1 0;
     0 1 0 1 0 1;
     0 0 0 0 0 0;
     0 0 0 0 0 0;
     0 0 0 0 0 0]

names=["(3,1)", "(2,1)", "(2,2)", "(1,1)", "(1,2)", "(1,3)"]
p = palette(:rainbow, 3)

graphplot(g, names=names, curvature_scalar=0, fontsize=12, nodeweights=[3,2,2,1,1,1], markercolor = [p[1],p[2],p[2],p[3],p[3],p[3]])

```

Which results in what I expect:

 ![CleanShot 2021-02-09 at 11.32.44@2x](https://global.discourse-cdn.com/julialang/original/3X/1/d/1d5ba2f022cf246b125ec2a0a1d4ad822b705e22.png)

Is there an easier way to do this using e.g. trees? It seems a little difficult to automate the process in this way, I just can’t wrap my head around it.

---

<div class="post-metadata">

**Author:** ![simonschoelly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonschoelly/32/21606_2.png) [@simonschoelly](https://discourse.julialang.org/u/simonschoelly)\
**Post date:** [February 9, 2021, 11:36pm UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951/2 "2021-02-09T23:36:36Z")

</div>

You could use an actual graph:

```julia
using LightGraphs, MetaGraphs, Plots, GraphRecipes
Plots.pyplot() # seems to be necessary to plot arrows for directed graphs

g = MetaDiGraph() # empty graph
set_indexingprop!(g, :name) # allows one to look up nodes by the attribute :name

function calc_rs(n, p, g)
    println("Calculating for ($n,$p)")
    if !haskey(g[:name], (n, p)) # if there is not already a node with name (n, p)
        # add a new vertex and set it's name to (n, p)
        # the most recent added vertex always has the index nv(g)
        add_vertex!(g) 
        set_prop!(g, nv(g), :name, (n, p))
     end
     if n != 1
        # recurse as usual but with also passing g
         calc_rs(n-1, 1, g)
         calc_rs(n-1, p+1, g)

         # at this point, the vertices with the names (n, p), (n-1, 1) and (n-1, p+1) already exist
         # so we look them up by their name
         v1 = g[(n, p), :name]
         v2 = g[(n-1, 1), :name]
         v3 = g[(n-1, p+1), :name]
               
         # add edges (n, p) -> (n-1, 1) and (n, p) -> (n-1, p+1)
         add_edge!(g, v1, v2)
         add_edge!(g, v1, v3)
    end
    return nothing
end

calc_rs(3, 1)
graphplot(g, names = [string(get_prop(g, v, :name)) for v in vertices(g)], arrow=:arrow)

```

![image](https://global.discourse-cdn.com/julialang/original/3X/0/d/0deccb2259033b7e6313e0c222474a8bc664be1f.png)

Otherwise, `graphplot` seem also be able to draw trees: [https://docs.juliaplots.org/latest/graphrecipes/examples/#AbstractTrees-Trees](https://docs.juliaplots.org/latest/graphrecipes/examples/#AbstractTrees-Trees)

---

<div class="post-metadata">

**Author:** ![ash](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@ash](https://discourse.julialang.org/u/ash)\
**Post date:** [February 10, 2021, 12:39am UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951/3 "2021-02-10T00:39:05Z")

</div>

Brilliant! Thank you so much! I edited the example a little bit to get the following:

 ![CleanShot 2021-02-09 at 16.37.48@2x](https://global.discourse-cdn.com/julialang/original/3X/9/1/91720812f676c9315cd43ed5800a6476eec2f067.jpeg)

```julia
using LightGraphs, MetaGraphs, Plots, GraphRecipes

g = MetaDiGraph() # empty graph
set_indexing_prop!(g, :name) # allows one to look up nodes by the attribute :name
size = []
col = []

function calc_rs(n, p, g, N, pal, size, col)
    println("Calculating for ($n,$p) with order $N")
    if !haskey(g[:name], (n, p)) # if there is not already a node with name (n, p)
        # add a new vertex and set it's name to (n, p)
        # the most recent added vertex always has the index nv(g)
        add_vertex!(g) 
        set_prop!(g, nv(g), :name, (n, p))
        push!(size, N)
        push!(col, pal[N])
     end
     if n != 1
        # recurse as usual but with also passing g
         calc_rs(n-1, 1, g, N-1, pal, size, col)
         calc_rs(n-1, p+1, g, N-1, pal, size, col)

         # at this point, the vertices with the names (n, p), (n-1, 1) and (n-1, p+1) already exist
         # so we look them up by their name
         v1 = g[(n, p), :name]
         v2 = g[(n-1, 1), :name]
         v3 = g[(n-1, p+1), :name]
               
         # add edges (n, p) -> (n-1, 1) and (n, p) -> (n-1, p+1)
         add_edge!(g, v1, v2)
         add_edge!(g, v1, v3)
    end
    return nothing
end

N = 4
pal = palette([:red, :yellow, :lightblue], N)
calc_rs(N, 1, g, N, pal, size, col)
graphplot(g, names = [string(get_prop(g, v, :name)) for v in vertices(g)], arrow=:arrow, nodeshape=:circle, curvature_scalar=0.01, nodeweights=size, markercolor=col, fontsize=14, markersize=0.05)

```

---

<div class="post-metadata">

**Author:** ![simonschoelly](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonschoelly/32/21606_2.png) [@simonschoelly](https://discourse.julialang.org/u/simonschoelly)\
**Post date:** [February 10, 2021, 3:34pm UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951/4 "2021-02-10T15:34:23Z")

</div>

You could also add `:col` and `size` as additional vertex properties to your graph:

```julia
using LightGraphs, MetaGraphs, Plots, GraphRecipes

g = MetaDiGraph() # empty graph
set_indexing_prop!(g, :name) # allows one to look up nodes by the attribute :name

function calc_rs(n, p, g, N, pal)
    println("Calculating for ($n,$p) with order $N")
    if !haskey(g[:name], (n, p)) # if there is not already a node with name (n, p)
        # add a new vertex and set it's name to (n, p)
        # the most recent added vertex always has the index nv(g)
        add_vertex!(g) 
        set_prop!(g, nv(g), :name, (n, p))
        set_prop!(g, nv(g), :size, N)
        set_prop!(g, nv(g), :col, pal[N])
    end
    if n != 1
        # recurse as usual but with also passing g
        calc_rs(n-1, 1, g, N-1, pal)
        calc_rs(n-1, p+1, g, N-1, pal)
       
        # at this point, the vertices with the names (n, p), (n-1, 1) and (n-1, p+1) already exist
        # so we look them up by their name
        v1 = g[(n, p), :name]
        v2 = g[(n-1, 1), :name]
        v3 = g[(n-1, p+1), :name]
                      
        # add edges (n, p) -> (n-1, 1) and (n, p) -> (n-1, p+1)
        add_edge!(g, v1, v2)
        add_edge!(g, v1, v3)
    end
    return nothing
end

pal = palette([:red, :yellow, :lightblue], N)

calc_rs(N, 1, g, N, pal)

graphplot(g,
    names=[string(get_prop(g, v, :name)) for v in vertices(g)],
    arrow=:arrow,
    nodeshape=:circle,
    curvature_scalar=0.01,
    nodeweights=[get_prop(g, v, :size) for v in vertices(g)],
    markercolor=[get_prop(g, v, :col) for v in vertices(g)],
    fontsize=14,
    markersize=0.05)

```

---

<div class="post-metadata">

**Author:** ![ash](https://avatars.discourse-cdn.com/v4/letter/a/f19dbf/32.png) [@ash](https://discourse.julialang.org/u/ash)\
**Post date:** [February 10, 2021, 6:35pm UTC](https://discourse.julialang.org/t/plotting-a-recursion-graph-for-a-function-with-2-arguments/54951/5 "2021-02-10T18:35:17Z")

</div>

Again, brilliant, thank you! I have modified it a little bit and added it to my documentation [here](https://oashour.github.io/NonlinearSchrodinger.jl/dev/man/visualization/), with proper attribution of course. Thank you again, I would have never figured this out on my own.
