diff --git a/Project.toml b/Project.toml index f0093ce..8592228 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LayeredLayouts" uuid = "f4a74d36-062a-4d48-97cd-1356bad1de4e" authors = ["Frames White and contributors"] -version = "0.2.9" +version = "0.2.10" [deps] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/src/graph_properties.jl b/src/graph_properties.jl index fe455dd..bc1a96c 100644 --- a/src/graph_properties.jl +++ b/src/graph_properties.jl @@ -7,7 +7,7 @@ sinks(graph) = findall(iszero, outdegree(graph)) function longest_paths(graph, roots) dag_or_error(graph) - dists = zeros(nv(graph)) + dists = zeros(Int, nv(graph)) pending = [0 => r for r in roots] while(!isempty(pending)) depth, node = pop!(pending) diff --git a/src/layering.jl b/src/layering.jl index b514232..4f7859d 100644 --- a/src/layering.jl +++ b/src/layering.jl @@ -3,7 +3,11 @@ function layer_by_longest_path_to_source(graph, force_layer) dists = longest_paths(graph, sources(graph)) force_layers!(graph, dists, force_layer) - layer_groups = collect.(IterTools.groupby(i->dists[i], sort(vertices(graph), by=i->dists[i]))) + layer_groups = [Int[] for d in 1:maximum(dists)] + for (ii, d) in enumerate(dists) + push!(layer_groups[d], ii) + end + return layer_groups end diff --git a/src/zarate.jl b/src/zarate.jl index 79a26fb..b48f9ab 100644 --- a/src/zarate.jl +++ b/src/zarate.jl @@ -42,8 +42,10 @@ different nodes as x and y coordinates. Optional arguments: `force_layer`: Vector{Pair{Int, Int}} - specifies the layer for each node - e.g. [3=>1, 5=>5] specifies layer 1 for node 3 and layer 5 to node 5 + specifies the layer for each node e.g. [3=>1, 5=>5] specifies layer 1 for node 3 and + layer 5 to node 5. If not specified, layer indices are calculated by longest path to + source vertices, with child vertex' layers following parents', and with layer indices + assigned consecutively from 1. `force_order`: Vector{Pair{Int, Int}} this vector forces the ordering of the nodes in each layer, @@ -278,6 +280,7 @@ function assign_coordinates(layout, graph, layer2nodes; node2y = Dict{Int, VariableRef}() for (layer, nodes) in enumerate(layer2nodes) + isempty(nodes) && continue # skip empty layers first_node, other_nodes = Iterators.peel(nodes) prev_y = node2y[first_node] = @variable(m, base_name="y_$first_node") for node in other_nodes diff --git a/test/demos.jl b/test/demos.jl index 281030a..af63b63 100644 --- a/test/demos.jl +++ b/test/demos.jl @@ -78,4 +78,17 @@ end test_example(layout, :two_lines_flipped_vertex_order; force_equal_layers=[1=>3]) #test_example(layout, :large_depgraph) # too big #test_example(layout, :extra_large_depgraph) # too big + + # laying out a graph with specified layering values - which intentionally skips the 16th + # layer entirely - while also using `force_equal_layers` relative to this layering set + test_example(layout, :disconnected_components_graph; + force_layer = [ # note that the 16th layer is skipped + 1=>1, 2=>1, 3=>2, 4=>2, 5=>3, 6=>4, 7=>4, 8=>5, 9=>6, 10=>6, 11=>7, 12=>7, + 13=>8, 14=>8, 15=>9, 16=>9, 17=>10, 18=>10, 19=>11, 20=>12, 21=>12, 22=>13, + 23=>14, 24=>14, 25=>15, 26=>15, 27=>17, 28=>18, 29=>18, 30=>19, 31=>19, 32=>20, + 33=>20, 34=>21, 35=>22, 36=>22, 37=>23, 38=>24, 39=>24, 40=>25, 41=>25, 42=>26, + 43=>26, 44=>27, 45=>27, 46=>28, 47=>28, 48=>29, 49=>30, 50=>30, 51=>31, 52=>31], + force_equal_layers = [ + 1=>7, 1=>9, 1=>15, 3=>5, 3=>11, 3=>13, 17=>21, 17=>23, 17=>29, 19=>25, 19=>27, + 19=>31]) end diff --git a/test/examples.jl b/test/examples.jl index 4f430f9..90d29e3 100644 --- a/test/examples.jl +++ b/test/examples.jl @@ -488,6 +488,66 @@ module Examples 2 => 7 2 => 24 ])) + + # a graph with disconnected components + disconnected_components_graph = SimpleDiGraph(Edge.([ + 1 => 3 + 2 => 4 + 3 => 5 + 4 => 5 + 5 => 6 + 5 => 7 + 6 => 8 + 7 => 8 + 8 => 9 + 8 => 10 + 9 => 11 + 10 => 12 + 11 => 13 + 12 => 14 + 13 => 16 + 14 => 15 + 15 => 18 + 16 => 17 + 17 => 19 + 18 => 19 + 19 => 20 + 19 => 21 + 20 => 22 + 21 => 22 + 22 => 23 + 22 => 24 + 23 => 26 + 24 => 25 + 27 => 28 + 27 => 29 + 28 => 30 + 29 => 31 + 30 => 32 + 31 => 33 + 32 => 34 + 33 => 34 + 34 => 35 + 34 => 36 + 35 => 37 + 36 => 37 + 37 => 38 + 37 => 39 + 38 => 41 + 39 => 40 + 40 => 43 + 41 => 42 + 42 => 44 + 43 => 45 + 44 => 46 + 45 => 47 + 46 => 48 + 47 => 48 + 48 => 49 + 48 => 50 + 49 => 52 + 50 => 51 + ])) end # module diff --git a/test/references/Zarate/direct/disconnected_components_graph_force_layer_force_equal_layers.png b/test/references/Zarate/direct/disconnected_components_graph_force_layer_force_equal_layers.png new file mode 100644 index 0000000..0a6cbb2 Binary files /dev/null and b/test/references/Zarate/direct/disconnected_components_graph_force_layer_force_equal_layers.png differ diff --git a/test/references/Zarate/paths/disconnected_components_graph_force_layer_force_equal_layers.png b/test/references/Zarate/paths/disconnected_components_graph_force_layer_force_equal_layers.png new file mode 100644 index 0000000..0a6cbb2 Binary files /dev/null and b/test/references/Zarate/paths/disconnected_components_graph_force_layer_force_equal_layers.png differ