In graph theory, a graph component refers to a subset of vertices in a graph, where each vertex is connected to every other vertex in the subset through a path of edges.
Let´s open an example graph and show the community detection per color:
open Graphoscope
open Cytoscape.NET
let componentExampleGraph =
let edgeSeq =
seq{
0,1,1
0,2,1
0,3,1
4,5,1
4,6,1
4,7,1
8,9,1
6,10,1
8,11,1
}
|> Seq.map(fun (s,t,w) ->
s,s,t,t,(float w)
)
AdjGraph.ofSeq edgeSeq
This graph is seperated into 3 distinct components.
Next we use a pre-generated color-pallet and Cytoscape.NET to visualise the graph and its components:
let colors =
[
"#3F51B5"
"#3F51B5"
"#3F51B5"
"#3F51B5"
"#FFC107"
"#FFC107"
"#FFC107"
"#FFC107"
"#FFEB3B"
"#FFEB3B"
"#FFEB3B"
"#FFEB3B"
]
let renderCyGraph (nodeLabelF) (graph:AdjGraph<'NodeKey,'NodeData,'EdgeData>) =
CyGraph.initEmpty ()
|> CyGraph.withElements [
for (sk,s,tk,t,el) in (AdjGraph.toSeq graph) do
let sk, tk = (string sk), (string tk)
yield Elements.node sk (nodeLabelF s )
yield Elements.node tk (nodeLabelF t )
yield Elements.edge (sprintf "%s_%s" sk tk) sk tk [ ]
]
|> CyGraph.withStyle "node"
[
CyParam.color "black"
CyParam.label =. CyParam.label
CyParam.Text.Align.center
CyParam.Text.Outline.width 0.5
CyParam.Background.color =. CyParam.color
CyParam.weight 100
]
|> CyGraph.withLayout (
Layout.initBreadthfirst(Layout.LayoutOptions.Generic())
)
|> CyGraph.withZoom(CytoscapeModel.Zoom.Init(ZoomingEnabled=false))
|> CyGraph.withSize(800, 400)
|> Cytoscape.NET.HTML.toGraphHTML()
renderCyGraph (fun x -> [CyParam.label x;CyParam.color colors.[x]]) componentExampleGraph
We can use Algorithms.Components to seperate the components from each other, where each components gets its own subgraph:
let components =
Algorithms.Components.getGraphComponentsOfAdjGraph componentExampleGraph
renderCyGraph (fun (x) -> [CyParam.label x;CyParam.color colors.[x]]) (components|>Seq.head)
namespace Graphoscope
namespace Cytoscape
namespace Cytoscape.NET
val componentExampleGraph: AdjGraph<int,int,float>
val edgeSeq: seq<int * int * int * int * float>
Multiple items
val seq: sequence: seq<'T> -> seq<'T>
<summary>Builds a sequence using sequence expression syntax</summary>
<param name="sequence">The input sequence.</param>
<returns>The result sequence.</returns>
<example id="seq-cast-example"><code lang="fsharp">
seq { for i in 0..10 do yield (i, i*i) }
</code></example>
--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
<summary>An abbreviation for the CLI type <see cref="T:System.Collections.Generic.IEnumerable`1" /></summary>
<remarks>
See the <see cref="T:Microsoft.FSharp.Collections.SeqModule" /> module for further operations related to sequences.
See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/sequences">F# Language Guide - Sequences</a>.
</remarks>
module Seq
from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.seq`1" />.</summary>
val map: mapping: ('T -> 'U) -> source: seq<'T> -> seq<'U>
<summary>Builds a new collection whose elements are the results of applying the given function
to each of the elements of the collection. The given function will be applied
as elements are demanded using the <c>MoveNext</c> method on enumerators retrieved from the
object.</summary>
<remarks>The returned sequence may be passed between threads safely. However,
individual IEnumerator values generated from the returned sequence should not be accessed concurrently.</remarks>
<param name="mapping">A function to transform items from the input sequence.</param>
<param name="source">The input sequence.</param>
<returns>The result sequence.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
<example id="item-1"><code lang="fsharp">
let inputs = ["a"; "bbb"; "cc"]
inputs |> Seq.map (fun x -> x.Length)
</code>
Evaluates to a sequence yielding the same results as <c>seq { 1; 3; 2 }</c></example>
val s: int
val t: int
val w: int
Multiple items
val float: value: 'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all
primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c>
with InvariantCulture settings. Otherwise the operation requires an appropriate
static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>
<example id="float-example"><code lang="fsharp"></code></example>
--------------------
[<Struct>]
type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>
--------------------
type float<'Measure> =
float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure.
The unit of measure is erased in compiled code and when values of this type
are analyzed using reflection. The type is representationally equivalent to
<see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
Multiple items
module AdjGraph
from Graphoscope
--------------------
type AdjGraph =
new: unit -> AdjGraph
static member addEdge: sourceKey: 'NodeKey -> targetKey: 'NodeKey -> data: 'EdgeData -> graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member addEdges: edgeSeq: seq<'NodeKey * 'NodeKey * 'EdgeData> -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member addElement: nk1: 'NodeKey -> nd1: 'NodeData -> nk2: 'NodeKey -> nd2: 'NodeData -> ed: 'EdgeData -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member addNode: nk: 'NodeKey -> nd: 'NodeData -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member addNodes: nodeSeq: seq<'NodeKey * 'NodeData> -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
static member containsEdge: v1: 'NodeKey -> v2: 'NodeKey -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> bool (requires comparison)
static member containsNode: vk: 'NodeKey -> g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> bool (requires comparison)
static member countEdges: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison)
static member countNodes: g: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison)
...
<summary>
Functions to operate on the AdjGraph representation
</summary>
--------------------
type AdjGraph<'NodeKey,'NodeData,'EdgeData (requires comparison)> = System.Collections.Generic.Dictionary<'NodeKey,('NodeData * System.Collections.Generic.Dictionary<'NodeKey,'EdgeData>)>
<summary>
Basic Adjacency Graph representation
</summary>
--------------------
new: unit -> AdjGraph
static member AdjGraph.ofSeq: edgelist: seq<'NodeKey * 'NodeData * 'NodeKey * 'NodeData * 'EdgeData> -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison)
val colors: string list
val renderCyGraph: nodeLabelF: ('NodeData -> CyParam.CyStyleParam list) -> graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> string (requires comparison and comparison and comparison)
val nodeLabelF: ('NodeData -> CyParam.CyStyleParam list) (requires comparison)
val graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison and comparison and comparison)
module CyGraph
from Cytoscape.NET
val initEmpty: unit -> CyGraph.CyGraph
val withElements: elems: seq<CytoscapeModel.Element> -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
val sk: 'NodeKey (requires comparison)
val s: 'NodeData (requires comparison)
val tk: 'NodeKey (requires comparison)
val t: 'NodeData (requires comparison)
val el: 'EdgeData (requires comparison)
static member AdjGraph.toSeq: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> seq<'NodeKey * 'NodeData * 'NodeKey * 'NodeData * 'EdgeData> (requires comparison and comparison and comparison)
val sk: string
val tk: string
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>
--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
module Elements
from Cytoscape.NET
val node: id: string -> dataAttributes: CyParam.CyStyleParam list -> Elements.Node
val edge: id: string -> sourceId: string -> targetId: string -> dataAttributes: CyParam.CyStyleParam list -> Elements.Edge
val sprintf: format: Printf.StringFormat<'T> -> 'T
<summary>Print to a string using the given format.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.sprintf</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatToStringThen``1" />) for examples.</example>
val withStyle: selector: string -> cyStyles: seq<CyParam.CyStyleParam> -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
module CyParam
from Cytoscape.NET
val color: v: 'a -> CyParam.CyStyleParam
val label: v: 'a -> CyParam.CyStyleParam
module Text
from Cytoscape.NET.CyParam
module Align
from Cytoscape.NET.CyParam.Text
val center: CyParam.CyStyleParam
module Outline
from Cytoscape.NET.CyParam.Text
val width: v: 'a -> CyParam.CyStyleParam
module Background
from Cytoscape.NET.CyParam
val weight: v: 'a -> CyParam.CyStyleParam
val withLayout: ly: Layout -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
Multiple items
module Layout
from Cytoscape.NET
--------------------
type Layout =
inherit DynamicObj
new: name: string -> Layout
member name: string
<summary>
Layout type inherits from dynamic object
</summary>
--------------------
new: name: string -> Layout
val initBreadthfirst: applyOption: (Layout -> Layout) -> Layout
<summary>
initializes a layout of type "breadthfirst" applying the givin layout option function.
The "breadthfirst" layout puts nodes in a hierarchy, based on a breadthfirst traversal of the graph. It is best suited to trees
and forests in its default top-down mode, and it is best suited to DAGs in its circle mode.
</summary>
Multiple items
type LayoutOptions =
new: unit -> LayoutOptions
static member Cose: ?Refresh: int * ?BoundingBox: 'a0 * ?NodeDimensionsIncludeLabels: bool * ?Randomize: bool * ?ComponentSpacing: int * ?NodeRepulsion: 'a1 * ?NodeOverlap: int * ?IdealEdgeLength: 'a2 * ?EdgeElasticity: 'a3 * ?NestingFactor: float * ?Gravity: int * ?NumIter: int * ?InitialTemp: int * ?CoolingFactor: float * ?MinTemp: float -> ('L -> 'L) (requires 'L :> Layout)
static member Generic: ?Positions: 'a * ?Zoom: 'b * ?Pan: 'c * ?Fit: bool * ?Padding: int * ?Animate: bool * ?AnimationDuration: int * ?AnimationEasing: 'd * ?AnimateFilter: 'e * ?AnimationThreshold: int * ?Ready: 'f * ?Stop: 'g * ?Transform: 'h -> ('L -> 'L) (requires 'L :> Layout)
<summary>
Functions provide the options of the Layout objects
</summary>
--------------------
new: unit -> Layout.LayoutOptions
static member Layout.LayoutOptions.Generic: ?Positions: 'a * ?Zoom: 'b * ?Pan: 'c * ?Fit: bool * ?Padding: int * ?Animate: bool * ?AnimationDuration: int * ?AnimationEasing: 'd * ?AnimateFilter: 'e * ?AnimationThreshold: int * ?Ready: 'f * ?Stop: 'g * ?Transform: 'h -> ('L -> 'L) (requires 'L :> Layout)
val withZoom: zoom: CytoscapeModel.Zoom -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
namespace Cytoscape.NET.CytoscapeModel
Multiple items
type Zoom =
inherit DynamicObj
new: unit -> Zoom
static member Init: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> Zoom
static member Update: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> (Zoom -> Zoom)
--------------------
new: unit -> CytoscapeModel.Zoom
static member CytoscapeModel.Zoom.Init: ?Level: float * ?Position: (int * int) * ?RenderedPosition: (int * int) * ?ZoomingEnabled: bool -> CytoscapeModel.Zoom
val withSize: width: int * height: int -> cy: CyGraph.CyGraph -> CyGraph.CyGraph
type HTML =
static member CreateGraphHTML: graphData: string * zooming: string * divId: string * cytoscapeReference: CytoscapeJSReference * ?Width: int * ?Height: int -> XmlNode list
static member CreateGraphScript: graphData: string * zooming: string * cytoscapeReference: CytoscapeJSReference -> XmlNode
static member Doc: graphHTML: XmlNode list * cytoscapeReference: CytoscapeJSReference * ?AdditionalHeadTags: XmlNode list -> XmlNode
static member show: cy: Cytoscape * ?DisplayOpts: DisplayOptions -> unit
static member toEmbeddedHTML: ?DisplayOpts: DisplayOptions -> (Cytoscape -> string)
static member toGraphHTML: ?DisplayOpts: DisplayOptions -> (Cytoscape -> string)
static member toGraphHTMLNodes: ?DisplayOpts: DisplayOptions -> (Cytoscape -> XmlNode list)
<summary>
HTML template for Cytoscape
</summary>
static member HTML.toGraphHTML: ?DisplayOpts: DisplayOptions -> (CytoscapeModel.Cytoscape -> string)
val x: int
val components: seq<AdjGraph<int,int,float>>
namespace Graphoscope.Algorithms
Multiple items
type Components =
new: unit -> Components
static member compute: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> seq<AdjGraph<'NodeKey,'NodeData,'EdgeData>> (requires comparison and comparison and comparison)
static member getComponentOfAdjGraphNode: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> nodeID: 'NodeKey -> AdjGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison and comparison and comparison)
static member getGraphComponentsOfAdjGraph: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> seq<AdjGraph<'NodeKey,'NodeData,'EdgeData>> (requires comparison and comparison and comparison)
static member getLargestWeakComponentOfDiGraph: g: DiGraph<'NodeKey,'NodeData,'EdgeData> -> DiGraph<'NodeKey,'NodeData,'EdgeData> (requires comparison and comparison)
static member getLargestWeakComponentSizeOfDiGraph: g: DiGraph<'NodeKey,'NodeData,'EdgeData> -> int (requires comparison and comparison)
static member getWeakComponentsOfDiGraph: g: DiGraph<'NodeKey,'NodeData,'EdgeData> -> Set<Set<'NodeKey * 'NodeData>> (requires comparison and comparison)
static member isWeakComponentOfDiGraph: g: DiGraph<'NodeKey,'NodeData,'EdgeData> -> bool (requires comparison)
--------------------
new: unit -> Algorithms.Components
static member Algorithms.Components.getGraphComponentsOfAdjGraph: graph: AdjGraph<'NodeKey,'NodeData,'EdgeData> -> seq<AdjGraph<'NodeKey,'NodeData,'EdgeData>> (requires comparison and comparison and comparison)
val head: source: seq<'T> -> 'T
<summary>Returns the first element of the sequence.</summary>
<param name="source">The input sequence.</param>
<returns>The first element of the sequence.</returns>
<exception cref="T:System.ArgumentNullException">Thrown when the input sequence is null.</exception>
<exception cref="T:System.ArgumentException">Thrown when the input does not have any elements.</exception>
<example id="head-1"><code lang="fsharp">
let inputs = ["banana"; "pear"]
inputs |> Seq.head
</code>
Evaluates to <c>banana</c></example>
<example id="head-2"><code lang="fsharp">
[] |> Seq.head
</code>
Throws <c>ArgumentException</c></example>