Skip to content

Commit 5def93b

Browse files
ericphansonJackDevine
authored andcommitted
Add AbstractTrees plotting (#80)
* Switch to Project.toml * Add `AbstractTrees` plotting * Fix newlines and version
1 parent a544318 commit 5def93b

File tree

10 files changed

+145
-12
lines changed

10 files changed

+145
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
*.jl.cov
22
*.jl.*.cov
33
*.jl.mem
4+
Manifest.toml

Project.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name = "GraphRecipes"
2+
uuid = "bd48cda9-67a9-57be-86fa-5b3c104eda73"
3+
version = "0.5.0"
4+
5+
[deps]
6+
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
7+
GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb"
8+
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
9+
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
10+
LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d"
11+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
12+
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
13+
NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a"
14+
PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043"
15+
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
16+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
17+
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
18+
19+
[compat]
20+
julia = "^1"
21+
22+
[extras]
23+
ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
24+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
25+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
26+
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
27+
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
28+
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
29+
VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92"
30+
31+
[targets]
32+
test = ["VisualRegressionTests", "LinearAlgebra", "Plots", "ImageMagick", "Random", "SparseArrays", "Test"]

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,27 @@ plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse)
107107

108108
```
109109
![](assets/julia_type_tree.png)
110+
111+
112+
#### `AbstractTrees` Trees
113+
114+
```julia
115+
using AbstractTrees
116+
117+
AbstractTrees.children(d::Dict) = [p for p in d]
118+
AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2])
119+
function AbstractTrees.printnode(io::IO, p::Pair)
120+
str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ")
121+
print(io, str)
122+
end
123+
124+
d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0)
125+
126+
using GraphRecipes
127+
using Plots
128+
default(size=(1000, 1000))
129+
130+
plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse)
131+
132+
```
133+
![](assets/julia_dict_tree.png)

REQUIRE

Lines changed: 0 additions & 9 deletions
This file was deleted.

assets/julia_dict_tree.png

39.5 KB
Loading

src/GraphRecipes.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ include("utils.jl")
1818
include("graph_layouts.jl")
1919
include("graphs.jl")
2020
include("misc.jl")
21+
include("trees.jl")
2122

2223
end # module

src/trees.jl

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import AbstractTrees
2+
using AbstractTrees: children
3+
4+
export TreePlot
5+
6+
"""
7+
TreePlot(root)
8+
9+
Wrap a tree-like object for plotting. Uses `AbstractTrees.children()` to recursively add children to the plot and `AbstractTrees.printnode()` to generate the labels.
10+
11+
# Example
12+
13+
```julia
14+
using AbstractTrees, GraphRecipes
15+
AbstractTrees.children(d::Dict) = [p for p in d]
16+
AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2])
17+
function AbstractTrees.printnode(io::IO, p::Pair)
18+
str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ")
19+
print(io, str)
20+
end
21+
22+
d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0)
23+
24+
plot(TreePlot(d))
25+
````
26+
"""
27+
struct TreePlot{T}
28+
root::T
29+
end
30+
31+
function add_children!(nodes, source, destiny, node, parent_idx)
32+
for child in children(node)
33+
push!(nodes, child)
34+
child_idx = length(nodes)
35+
push!(source, parent_idx)
36+
push!(destiny, child_idx)
37+
add_children!(nodes, source, destiny, child, child_idx)
38+
end
39+
end
40+
41+
function string_from_node(node)
42+
io = IOBuffer()
43+
AbstractTrees.printnode(io, node)
44+
String(take!(io))
45+
end
46+
47+
# recursively build a graph of children of `tree_wrapper.root`
48+
@recipe function f(tree_wrapper::TreePlot; namefunc = string_from_node )
49+
root = tree_wrapper.root
50+
# recursively add children
51+
nodes = Any[root]
52+
source, destiny = Int[], Int[]
53+
add_children!(nodes, source, destiny, root, 1)
54+
55+
# set up the graphplot
56+
names := map(namefunc, nodes)
57+
method --> :buchheim
58+
root --> :top
59+
GraphPlot((source, destiny))
60+
end

test/REQUIRE

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/generate_readme_images.jl

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,18 @@ savefig("AST_example.png")
7070

7171
plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse)
7272
savefig("julia_type_tree.png")
73+
74+
75+
# `AbstractTrees` example
76+
using AbstractTrees
77+
AbstractTrees.children(d::Dict) = [p for p in d]
78+
AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2])
79+
function AbstractTrees.printnode(io::IO, p::Pair)
80+
str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ")
81+
print(io, str)
82+
end
83+
84+
d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0)
85+
86+
plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse)
87+
savefig("julia_dict_tree.png")

test/readme.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ using LinearAlgebra
44
using SparseArrays
55
using ImageMagick
66

7+
using AbstractTrees
8+
AbstractTrees.children(d::Dict) = [p for p in d]
9+
AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2])
10+
function AbstractTrees.printnode(io::IO, p::Pair)
11+
str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ")
12+
print(io, str)
13+
end
14+
715
istravis = "TRAVIS" keys(ENV)
816

917
default(show=false, reuse=true)
@@ -68,4 +76,8 @@ cd("../assets")
6876
default(size=(1000, 1000))
6977
@plottest plot(code, fontsize=10, shorten=0.01, axis_buffer=0.15, nodeshape=:rect) "AST_example.png" popup=!istravis tol=0.02
7078
@plottest plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse) "julia_type_tree.png" popup=!istravis tol=0.2
79+
80+
d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0)
81+
@plottest plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse) "julia_dict_tree.png" popup=!istravis tol=0.2
82+
7183
end

0 commit comments

Comments
 (0)