microsoft / automatic-graph-layout

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

[Question] Node labels #251

Closed ghost closed 4 years ago

ghost commented 4 years ago

When constructing a Drawing.Node, is it possible to have an Id separate from a label? We have graphs where many labels duplicate their display name, but their ID is unique (such that we can draw a -> b -> different_a). I tried manually setting a.Label.Text after Node creation, but this causes an exception when performing layout.

Going through the samples, I am trying to find something that utilises clustering (potentially refered to as subgraph) such that we can layout a graph similar to https://graphviz.org/Gallery/directed/cluster.html

Could someone point me to an example of how to do this? I am limited by not having a windows PC to try some of the tools. Edit, removed question about clustering, I found that sugiyama does not layout subgraphs (based on https://github.com/microsoft/automatic-graph-layout/issues/182).

levnach commented 4 years ago

According to https://github.com/microsoft/automatic-graph-layout/issues/182 clusters are supported. Label.Text can be set arbitrarily.

ghost commented 4 years ago

Sorry I must have completely misread that! It has been difficult to put Drawing.Graph into the right 'state' so that layout runs without crashing, ill give it another crack

ghost commented 4 years ago

based on #182, it seems that similar to Drawing.Graph.Edges, CreateGeometryGraph does not set the geometry correctly on subgraph components. I have used a extension method to prevent layout from bombing out:

    type Microsoft.Msagl.Drawing.Graph with
        member this.DoLayout() =
            this.CreateGeometryGraph()

            // Geometry is only drawn after call to CreateGeometryGraph
            // so we need to loop over the edges again and fill in some missing
            // values from the edge so that we can perform layout correctly.
            let fixEdgeForGeo (e:Edge) =
                e.SourceNode.Attr.Shape <- Shape.DrawFromGeometry
                e.TargetNode.Attr.Shape <- Shape.DrawFromGeometry
                let rectangle width height =
                    CurveFactory.CreateRectangle(
                        Rectangle(Height=height,Width=width,Center=Point())
                    )
                let rect (n:Core.Layout.Node) = // hack attempt to fix box around label being too small
                    let width, height =
                        try
                            n.Width, n.Height // get_Width can throw an exn??
                        with _ ->
                            try
                                (float e.LabelText.Length * e.Label.FontSize) * 2.0, e.Label.FontSize * 2.0
                            with _ -> 70.0, 23.0
                    rectangle width height

                e.GeometryEdge.Source.BoundaryCurve <- rect e.GeometryEdge.Source
                e.TargetNode.GeometryNode.BoundaryCurve <- rect e.TargetNode.GeometryNode

            this.RootSubgraph.Subgraphs |> Seq.iter (fun e -> e.Edges |> Seq.iter fixEdgeForGeo)
            this.Edges |> Seq.iter fixEdgeForGeo

            let layoutSettings = pickLayoutAlgorithmSettings (float this.EdgeCount) (float this.NodeCount)
            LayoutHelpers.CalculateLayout(this.GeometryGraph, layoutSettings, null)

I still have to work out how to ensure the subgraph color is drawn to SVG, but I feel there is progress afoot! Thank you for your help