1+ #=
2+ # Visualising Makie's `ComputeGraph`
3+ A `ComputeGraph` is Makies internal representation of the transformations that a
4+ plot performs on its input data to reach a representation that can be handed to
5+ backend for plotting.
6+
7+ In this example, we draw the topology of two `ComputeGraph`. Being able to visualise
8+ the interdependence of some calculations can sometimes help in debugging Makie recipes.
9+ =#
10+
11+ using CairoMakie
12+ CairoMakie. activate! (; type= " svg" ) # hide
13+ using GraphMakie
14+ using Graphs
15+ using NetworkLayout
16+
17+ # ## Converting the `ComputeGraph`
18+
19+ # First, we convert the `ComputeGraph`, which does not implement the `Graph` interface
20+ # to a bipartite `SimpleDiGraph` as well as some edge and node data
21+
22+ function convert_to_simple_graph (compute_graph)
23+ g = SimpleDiGraph ()
24+ labels = Any[]
25+ for (k, v) in compute_graph. inputs
26+ add_vertex! (g)
27+ push! (labels, (:input , k))
28+ end
29+ for (k, v) in compute_graph. outputs
30+ k in keys (compute_graph. inputs) && continue
31+ add_vertex! (g)
32+ push! (labels, (:output , k))
33+ end
34+ found_calculations = Any[]
35+ # # every output is the result of a computation, so no recursion needed.
36+ for (k, i) in compute_graph. outputs
37+ calc = i. parent
38+ if calc isa Makie. ComputePipeline. ComputeEdge
39+ if ! (calc in found_calculations)
40+ push! (found_calculations, calc)
41+ calc_id = (:calculation , calc. outputs[1 ]. name)
42+ add_vertex! (g)
43+ push! (labels, calc_id)
44+ for j in calc. inputs
45+ src_id = findfirst (labels) do label
46+ return label in [(:input , j. name), (:output , j. name)]
47+ end
48+ add_edge! (g, src_id, nv (g))
49+ end
50+ for j in calc. outputs
51+ dst_id = findfirst (labels) do label
52+ return label in [(:input , j. name), (:output , j. name), (:calculation , j. name)]
53+ end
54+ add_edge! (g, nv (g), dst_id)
55+ end
56+ end
57+ end
58+ end
59+ return (g, labels)
60+ end
61+ nothing # hide
62+
63+ # we define a function which does the conversion and plotting for us
64+
65+ function plot_compute_graph! (ax, compute_graph; kwargs... )
66+ g, labels = convert_to_simple_graph (compute_graph)
67+ node_colors = map (labels) do i
68+ if i[1 ] == :calculation
69+ :black
70+ elseif i[1 ] == :input
71+ :darkorange
72+ else
73+ :red
74+ end
75+ end
76+ plot = graphplot! (ax, g; node_color= node_colors,
77+ edge_color= [labels[e. src][1 ] == :calculation ? :orange : :darkgrey for e in edges (g)],
78+ nlabels= [i[1 ] == :calculation ? " " : string (i[2 ]) for i in labels],
79+ nlabels_align= (:center , :bottom ), kwargs... )
80+ return plot
81+ end
82+ nothing # hide
83+
84+ # ## Simple ComputeGraph
85+
86+ # First, we demonstrate a simple `ComputeGraph`, constructed from two inputs which map onto two outputs
87+
88+ graph = Makie. ComputeGraph ()
89+ Makie. add_input! (graph, :input1 , 1 )
90+ Makie. add_input! ((key, value) -> Float32 (value), graph, :input2 , 2 )
91+
92+ Makie. register_computation! (graph, [:input1 , :input2 ], [:output ]) do inputs, changed, cached
93+ input1, input2 = inputs
94+ return (input1[] + input2[],)
95+ end
96+
97+ Makie. register_computation! (graph, [:input1 , :output ], [:output2 ]) do inputs, changed, cached
98+ input1, output = inputs
99+ return (input1[]^ 2 * output,)
100+ end
101+
102+ # plotting the simple compute graph
103+
104+ f = Figure ()
105+ ax = Axis (f[1 , 1 ])
106+ g_plot = plot_compute_graph! (ax, graph; arrow_size= 20 , arrow_shift= 0.9 )
107+ f
108+
109+ # ## `ComputeGraph` of a the `graphplot!` recipe
110+
111+ # plotting the compute graph of the above `graphplot!` plot
112+
113+ f = Figure ()
114+ ax = Axis (f[1 , 1 ])
115+ plot_compute_graph! (ax, g_plot. attributes; nlabels_fontsize= 9 , layout= Spring (; C= 8.0 , iterations= 2000 ))
116+ f
0 commit comments