@@ -80,3 +80,146 @@ function _plot_coordinates(t::AbstractRootedTree,
80
80
81
81
return x, y
82
82
end
83
+
84
+ # We load Plots.distinguishable_colors via Requires.jl for older versions
85
+ # of Julia and as a package extension (weak dependency) on newer versions
86
+ # of Julia.
87
+ function _distinguishable_colors end
88
+
89
+ RecipesBase. @recipe function plot (t:: ColoredRootedTree )
90
+ # Compute x and y coordinates recursively
91
+ width = 2.0
92
+ height = 1.0
93
+ color_idx = unique (t. color_sequence)
94
+ if eltype (t. color_sequence) == Bool
95
+ color_val = [:white , :black ]
96
+ else
97
+ color_val = _distinguishable_colors (length (color_idx))
98
+ end
99
+ colormap = Dict {eltype(color_idx), eltype(color_val)} ()
100
+ for (idx, val) in zip (color_idx, color_val)
101
+ colormap[idx] = val
102
+ end
103
+ x, y, colors = _plot_coordinates (t, 0.0 , 0.0 , width, height, colormap)
104
+
105
+ # Series properties
106
+ linecolor --> :black
107
+ markercolor --> reshape (colors, 1 , :)
108
+ background_color --> " LightGray"
109
+ markershape --> :circle
110
+ markersize --> 6
111
+ linewidth --> 2
112
+
113
+ # Geometric properties
114
+ grid --> false
115
+ ticks --> false
116
+ foreground_color_border --> :white
117
+ legend --> :bottomright
118
+
119
+ # We need to `flatten` nested arrays
120
+ if ! isempty (t)
121
+ x_min, x_max = extrema (Iterators. flatten (x))
122
+ else
123
+ x_min = x_max = zero (eltype (eltype (x)))
124
+ end
125
+ if x_min ≈ x_max
126
+ xlims --> (x_min - width / 2 , x_max + width / 2 )
127
+ end
128
+
129
+ if ! isempty (t)
130
+ y_min, y_max = extrema (Iterators. flatten (y))
131
+ else
132
+ y_min = y_max = zero (eltype (eltype (x)))
133
+ end
134
+ if y_min ≈ y_max
135
+ ylims --> (y_min - height / 2 , y_max + height / 2 )
136
+ end
137
+
138
+ # Annotations
139
+ labels = ones (String, 1 , length (colors))
140
+ if ! isempty (t)
141
+ labels[1 ] = " tree " * string ((t. level_sequence, t. color_sequence))
142
+ end
143
+ label --> labels
144
+
145
+ x, y
146
+ end
147
+
148
+ function _plot_coordinates (t:: ColoredRootedTree ,
149
+ x_root:: T , y_root:: T ,
150
+ width:: T , height:: T ,
151
+ colormap) where {T}
152
+ # Initialize vectors of return values
153
+ x = Vector {Vector{T}} ()
154
+ y = Vector {Vector{T}} ()
155
+ colors = Vector {Vector{valtype(colormap)}} ()
156
+
157
+ if isempty (t)
158
+ return x, y, colors
159
+ end
160
+
161
+ push! (x, [x_root])
162
+ push! (y, [y_root])
163
+ color_root = colormap[first (t. color_sequence)]
164
+ push! (colors, [color_root])
165
+
166
+ # We cannot indicate a new line series by `NaN` since that doesn't work with
167
+ # colors
168
+ # ┌ Warning: Indices Base.OneTo(9) of attribute `seriescolor` does not match data indices 3:9.
169
+ # └ @ Plots ~/.julia/packages/Plots/AJMX6/src/utils.jl:132
170
+ # ┌ Info: Data contains NaNs or missing values, and indices of `seriescolor` vector do not match data indices.
171
+ # │ If you intend elements of `seriescolor` to apply to individual NaN-separated segments in the data,
172
+ # │ pass each segment in a separate vector instead, and use a row vector for `seriescolor`. Legend entries
173
+ # │ may be suppressed by passing an empty label.
174
+ # │ For example,
175
+ # └ plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], seriescolor=[1 2])
176
+ # ┌ Warning: Indices Base.OneTo(9) of attribute `linecolor` does not match data indices 3:9.
177
+ # └ @ Plots ~/.julia/packages/Plots/AJMX6/src/utils.jl:132
178
+ # ┌ Info: Data contains NaNs or missing values, and indices of `linecolor` vector do not match data indices.
179
+ # │ If you intend elements of `linecolor` to apply to individual NaN-separated segments in the data,
180
+ # │ pass each segment in a separate vector instead, and use a row vector for `linecolor`. Legend entries
181
+ # │ may be suppressed by passing an empty label.
182
+ # │ For example,
183
+ # └ plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], linecolor=[1 2])
184
+ # ┌ Warning: Indices Base.OneTo(9) of attribute `fillcolor` does not match data indices 3:9.
185
+ # └ @ Plots ~/.julia/packages/Plots/AJMX6/src/utils.jl:132
186
+ # ┌ Info: Data contains NaNs or missing values, and indices of `fillcolor` vector do not match data indices.
187
+ # │ If you intend elements of `fillcolor` to apply to individual NaN-separated segments in the data,
188
+ # │ pass each segment in a separate vector instead, and use a row vector for `fillcolor`. Legend entries
189
+ # │ may be suppressed by passing an empty label.
190
+ # │ For example,
191
+ # └ plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], fillcolor=[1 2])
192
+ # ┌ Warning: Indices Base.OneTo(9) of attribute `markercolor` does not match data indices 3:9.
193
+ # └ @ Plots ~/.julia/packages/Plots/AJMX6/src/utils.jl:132
194
+ # ┌ Info: Data contains NaNs or missing values, and indices of `markercolor` vector do not match data indices.
195
+ # │ If you intend elements of `markercolor` to apply to individual NaN-separated segments in the data,
196
+ # │ pass each segment in a separate vector instead, and use a row vector for `markercolor`. Legend entries
197
+ # │ may be suppressed by passing an empty label.
198
+ # │ For example,
199
+ # └ plot([1:2,1:3], [[4,5],[3,4,5]], label=["y" ""], markercolor=[1 2])
200
+
201
+ # Compute plot coordinates recursively
202
+ subtr = subtrees (t)
203
+
204
+ # Distribute children uniformly in x and at equal y coordinates
205
+ y_child = y_root + height
206
+ num_children = length (subtr)
207
+ distance = width * (num_children - 1 ) / 2
208
+
209
+ x_children = range (x_root - distance, x_root + distance, length = num_children)
210
+ for idx in eachindex (subtr)
211
+ x_child = x_children[idx]
212
+ push! (x, [x_root, x_child])
213
+ push! (y, [y_root, y_child])
214
+ push! (colors, [color_root, colormap[first (subtr[idx]. color_sequence)]])
215
+ x_recursive, y_recursive, colors_recursive = _plot_coordinates (subtr[idx],
216
+ x_child, y_child,
217
+ width / 3 , height,
218
+ colormap)
219
+ append! (x, x_recursive)
220
+ append! (y, y_recursive)
221
+ append! (colors, colors_recursive)
222
+ end
223
+
224
+ return x, y, colors
225
+ end
0 commit comments