From 4bd8ba0ee3a6359a2274a8c3da6606265c19d360 Mon Sep 17 00:00:00 2001 From: Eric <5846501+ericphanson@users.noreply.github.com> Date: Sat, 10 Aug 2019 12:54:18 +0100 Subject: [PATCH 1/3] Switch to Project.toml --- .gitignore | 1 + Project.toml | 31 +++++++++++++++++++++++++++++++ REQUIRE | 9 --------- test/REQUIRE | 3 --- 4 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 Project.toml delete mode 100644 REQUIRE delete mode 100644 test/REQUIRE diff --git a/.gitignore b/.gitignore index 8c960ec..0ee3d17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.jl.cov *.jl.*.cov *.jl.mem +Manifest.toml \ No newline at end of file diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..17cc72d --- /dev/null +++ b/Project.toml @@ -0,0 +1,31 @@ +name = "GraphRecipes" +uuid = "bd48cda9-67a9-57be-86fa-5b3c104eda73" +version = "0.4.1" + +[deps] +GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +NetworkLayout = "46757867-2c16-5918-afeb-47bfcb05e46a" +PlotUtils = "995b91a9-d308-5afd-9ec6-746e21dbc043" +RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[compat] +julia = "^1" + +[extras] +ImageMagick = "6218d12a-5da1-5696-b52f-db25d2ecc6d1" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +VisualRegressionTests = "34922c18-7c2a-561c-bac1-01e79b2c4c92" + +[targets] +test = ["VisualRegressionTests", "LinearAlgebra", "Plots", "ImageMagick", "Random", "SparseArrays", "Test"] diff --git a/REQUIRE b/REQUIRE deleted file mode 100644 index 2628eae..0000000 --- a/REQUIRE +++ /dev/null @@ -1,9 +0,0 @@ -julia 1.0 - -RecipesBase -NetworkLayout -LightGraphs -PlotUtils -NaNMath -GeometryTypes -Interpolations diff --git a/test/REQUIRE b/test/REQUIRE deleted file mode 100644 index a333d68..0000000 --- a/test/REQUIRE +++ /dev/null @@ -1,3 +0,0 @@ -Plots -VisualRegressionTests -ImageMagick From f1061f256b81342b1cb4601879ccc8a16a369a14 Mon Sep 17 00:00:00 2001 From: Eric <5846501+ericphanson@users.noreply.github.com> Date: Sat, 10 Aug 2019 16:13:54 +0100 Subject: [PATCH 2/3] Add `AbstractTrees` plotting --- Project.toml | 1 + README.md | 24 +++++++++++++ assets/julia_dict_tree.png | Bin 0 -> 40432 bytes src/GraphRecipes.jl | 1 + src/trees.jl | 60 +++++++++++++++++++++++++++++++++ test/generate_readme_images.jl | 15 +++++++++ test/readme.jl | 12 +++++++ 7 files changed, 113 insertions(+) create mode 100644 assets/julia_dict_tree.png create mode 100644 src/trees.jl diff --git a/Project.toml b/Project.toml index 17cc72d..2310cfe 100644 --- a/Project.toml +++ b/Project.toml @@ -3,6 +3,7 @@ uuid = "bd48cda9-67a9-57be-86fa-5b3c104eda73" version = "0.4.1" [deps] +AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" GeometryTypes = "4d00f742-c7ba-57c2-abde-4428a4b178cb" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" diff --git a/README.md b/README.md index 4f6769b..9605bc8 100644 --- a/README.md +++ b/README.md @@ -107,3 +107,27 @@ plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse) ``` ![](assets/julia_type_tree.png) + + +#### `AbstractTrees` Trees + +```julia +using AbstractTrees + +AbstractTrees.children(d::Dict) = [p for p in d] +AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2]) +function AbstractTrees.printnode(io::IO, p::Pair) + str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ") + print(io, str) +end + +d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0) + +using GraphRecipes +using Plots +default(size=(1000, 1000)) + +plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse) + +``` +![](assets/julia_dict_tree.png) \ No newline at end of file diff --git a/assets/julia_dict_tree.png b/assets/julia_dict_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..952a6eb579350a997a8690de220c4017059f0cfd GIT binary patch literal 40432 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 literal 0 HcmV?d00001 diff --git a/src/GraphRecipes.jl b/src/GraphRecipes.jl index 6b9e1a9..7d92225 100644 --- a/src/GraphRecipes.jl +++ b/src/GraphRecipes.jl @@ -18,5 +18,6 @@ include("utils.jl") include("graph_layouts.jl") include("graphs.jl") include("misc.jl") +include("trees.jl") end # module diff --git a/src/trees.jl b/src/trees.jl new file mode 100644 index 0000000..759c700 --- /dev/null +++ b/src/trees.jl @@ -0,0 +1,60 @@ +import AbstractTrees +using AbstractTrees: children + +export TreePlot + +""" + TreePlot(root) + +Wrap a tree-like object for plotting. Uses `AbstractTrees.children()` to recursively add children to the plot and `AbstractTrees.printnode()` to generate the labels. + +# Example + +```julia +using AbstractTrees, GraphRecipes +AbstractTrees.children(d::Dict) = [p for p in d] +AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2]) +function AbstractTrees.printnode(io::IO, p::Pair) + str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ") + print(io, str) +end + +d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0) + +plot(TreePlot(d)) +```` +""" +struct TreePlot{T} + root::T +end + +function add_children!(nodes, source, destiny, node, parent_idx) + for child in children(node) + push!(nodes, child) + child_idx = length(nodes) + push!(source, parent_idx) + push!(destiny, child_idx) + add_children!(nodes, source, destiny, child, child_idx) + end +end + +function string_from_node(node) + io = IOBuffer() + AbstractTrees.printnode(io, node) + String(take!(io)) +end + +# recursively build a graph of children of `tree_wrapper.root` +@recipe function f(tree_wrapper::TreePlot; namefunc = string_from_node ) + root = tree_wrapper.root + # recursively add children + nodes = Any[root] + source, destiny = Int[], Int[] + add_children!(nodes, source, destiny, root, 1) + + # set up the graphplot + names := map(namefunc, nodes) + method --> :buchheim + root --> :top + GraphPlot((source, destiny)) +end \ No newline at end of file diff --git a/test/generate_readme_images.jl b/test/generate_readme_images.jl index a37cf49..0ffac35 100644 --- a/test/generate_readme_images.jl +++ b/test/generate_readme_images.jl @@ -70,3 +70,18 @@ savefig("AST_example.png") plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse) savefig("julia_type_tree.png") + + +# `AbstractTrees` example +using AbstractTrees +AbstractTrees.children(d::Dict) = [p for p in d] +AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2]) +function AbstractTrees.printnode(io::IO, p::Pair) + str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ") + print(io, str) +end + +d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0) + +plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse) +savefig("julia_dict_tree.png") diff --git a/test/readme.jl b/test/readme.jl index 83bcabd..cdba250 100644 --- a/test/readme.jl +++ b/test/readme.jl @@ -4,6 +4,14 @@ using LinearAlgebra using SparseArrays using ImageMagick +using AbstractTrees +AbstractTrees.children(d::Dict) = [p for p in d] +AbstractTrees.children(p::Pair) = AbstractTrees.children(p[2]) +function AbstractTrees.printnode(io::IO, p::Pair) + str = isempty(AbstractTrees.children(p[2])) ? string(p[1], ": ", p[2]) : string(p[1], ": ") + print(io, str) +end + istravis = "TRAVIS" ∈ keys(ENV) default(show=false, reuse=true) @@ -68,4 +76,8 @@ cd("../assets") default(size=(1000, 1000)) @plottest plot(code, fontsize=10, shorten=0.01, axis_buffer=0.15, nodeshape=:rect) "AST_example.png" popup=!istravis tol=0.02 @plottest plot(AbstractFloat, method=:tree, fontsize=10, nodeshape=:ellipse) "julia_type_tree.png" popup=!istravis tol=0.2 + + d = Dict(:a => 2,:d => Dict(:b => 4,:c => "Hello"),:e => 5.0) + @plottest plot(TreePlot(d), method=:tree, fontsize=10, nodeshape=:ellipse) "julia_dict_tree.png" popup=!istravis tol=0.2 + end From 7ab96696b886420aa4d84c8857990fa339a83569 Mon Sep 17 00:00:00 2001 From: Eric <5846501+ericphanson@users.noreply.github.com> Date: Sun, 11 Aug 2019 14:03:25 +0100 Subject: [PATCH 3/3] Fix newlines and version --- .gitignore | 2 +- Project.toml | 2 +- src/trees.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0ee3d17..3f02ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.jl.cov *.jl.*.cov *.jl.mem -Manifest.toml \ No newline at end of file +Manifest.toml diff --git a/Project.toml b/Project.toml index 2310cfe..c976dc8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "GraphRecipes" uuid = "bd48cda9-67a9-57be-86fa-5b3c104eda73" -version = "0.4.1" +version = "0.5.0" [deps] AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" diff --git a/src/trees.jl b/src/trees.jl index 759c700..79c7dda 100644 --- a/src/trees.jl +++ b/src/trees.jl @@ -57,4 +57,4 @@ end method --> :buchheim root --> :top GraphPlot((source, destiny)) -end \ No newline at end of file +end