microsoft / automatic-graph-layout

A set of tools for graph layout and viewing
Other
1.35k stars 302 forks source link

Settings per Cluster for SugiyamaLayoutSettings #317

Closed Brains closed 2 years ago

Brains commented 2 years ago

Implementation for #80.

Need to assign LayerDirection per Cluster. Actually in my case, just Left-Right direction to RootCluster and Top-Bottom inside rest Clusters (opposite to directions in #80). Have Want
image image

Family of LayerConstraints methods seems to not work with Clusters. Neither applied to Clusters nor to Nodes directly.

  graph.Attr.LayerDirection = LayerDirection.TB;

  graph.LayerConstraints.AddSameLayerNeighbors(
      subgraph1,
      subgraph2;

  graph.LayerConstraints.AddSameLayerNeighbors(
      graph.FindNode("58"),
      graph.FindNode("70"));

  graph.LayerConstraints.AddUpDownVerticalConstraint(
      graph.FindNode("70"),
      graph.FindNode("71"));
Brains commented 2 years ago

After a long exploration have found:

Using InitialLayoutByCluster explicitly from a WPF project requires to configure everything manually or to change many methods, both are cumbersome.

An easier way was LayoutHelpers.ProcessSugiamaLayout. Currently, the same SugiyamaLayoutSettings is specified for all Clusters being processed:

static void ProcessSugiamaLayout(..., SugiyamaLayoutSettings sugiyamaLayoutSettings, ...)
    ...
    var initialBc =
        new InitialLayoutByCluster(
            geometryGraph,
            a => sugiyamaLayoutSettings);
    initialBc.Run(cancelToken);
    ...

Change to a simple selection:

new InitialLayoutByCluster(
    geometryGraph,
    //use different settings per each Cluster if available
    c => sugiyamaLayoutSettings.ClusterSettings.ContainsKey(c.UserData)
            ? sugiyamaLayoutSettings.ClusterSettings[c.UserData]
            : sugiyamaLayoutSettings);

has achieved the goal. Where SugiyamaLayoutSettings.ClusterSettings is

/// <summary>
/// Settings per Cluster for InitialLayoutByCluster used by LayoutHelpers.ProcessSugiamaLayout
/// </summary>
public Dictionary<object, LayoutAlgorithmSettings> ClusterSettings { get; set; } =
   new Dictionary<object, LayoutAlgorithmSettings>();
Brains commented 2 years ago

The problem happens after collapsed then expanded a Cluster. It resets to Right-Left direction.

Initial Expanded
image image

Subgraph.LayoutSettings was assigned of course.

var global = (SugiyamaLayoutSettings) graph.LayoutAlgorithmSettings;
var local  = (SugiyamaLayoutSettings) global.Clone();
local.Transformation = PlaneTransformation.Rotation(-Math.PI / 2);
subgraph2.LayoutSettings = local;   // for Collapsing\Expanding
global.ClusterSettings.Add(subgraph2, local);

Relayout is used on expanding, which uses same InitialLayoutByCluster under the hood. But this time it's not working. Have spent a lot of time trying to fix, with no luck.

Can you suggest something here?

Brains commented 2 years ago

Actually, when posting this PR, have noticed that after expanding the Outer node, its Subgraph.Transformation

subgraph2.LayoutSettings.Transformation // -PI / 2

is combined with global

graph.Attr.LayerDirection = LayerDirection.LR; // PI / 2

As result I got -PI after expanding

Seems like the key point why it works after the launch is LayoutHelpers.HandleTransformIsNotIdentity which is called from ProcessSugiamaLayout method. Without this workaround it not works in Relayout

levnach commented 2 years ago

I noticed that if I comment out the line https://github.com/microsoft/automatic-graph-layout/blob/47d30d63d73847492c796028a87fe08a6e7347a6/GraphLayout/Samples/WpfApplicationSample/WpfApplicationSample.cs#L315 then everything works fine. Maybe there is a bug related to this settings.

Brains commented 2 years ago

A little side note for history # There is Subgraph.LayoutSettings which looks more suitable for settings per Cluster. It's used only in Drawing.LayoutEditor: CollapseCluster, ExpandCluster:

var subgraph = cluster.UserData as Subgraph;
if (subgraph != null && subgraph.LayoutSettings != null)
    return subgraph.LayoutSettings;
else
    return viewer.Graph.LayoutAlgorithmSettings;

Unfortunatelly, Subgraph is not available in LayoutHelpers.ProcessSugiamaLayout, no way to employ Subgraph.LayoutSettings there.

#

From other side, using SugiyamaLayoutSettings.ClusterSettings instead of Subgraph.LayoutSettings to collapse\expand is not possible as well, because not all settings are instances of SugiyamaLayoutSettings. That's why should assign both:

var global = (SugiyamaLayoutSettings) graph.LayoutAlgorithmSettings;
var local  = (SugiyamaLayoutSettings) global.Clone();
local.Transformation = PlaneTransformation.Rotation(Math.PI / 2);
global.ClusterSettings.Add(subgraph1, subgraph1.LayoutSettings = local);
global.ClusterSettings.Add(subgraph2, subgraph2.LayoutSettings = local);