windowsforms-devexpress-dot-xtracharts-dot-sankey-dot-sankeydiagramcontrol-832e604d.md
Specifies Sankey layout algorithm settings.
Namespace : DevExpress.XtraCharts.Sankey
Assembly : DevExpress.XtraCharts.v25.2.UI.dll
NuGet Package : DevExpress.Win.Charts
public SankeyLayoutAlgorithmBase LayoutAlgorithm { get; set; }
Public Property LayoutAlgorithm As SankeyLayoutAlgorithmBase
| Type | Description |
|---|---|
| SankeyLayoutAlgorithmBase |
Contains Sankey layout algorithm settings.
|
You can use the predefined linear layout algorithm. Cast the LayoutAlgorithm property value to SankeyLinearLayoutAlgorithm to change default settings. Use the SankeyLinearLayoutAlgorithm.NodeAlignment property to specify the node alignment.
The following example aligns nodes to the bottom of the SankeyDiagramControl:
SankeyLinearLayoutAlgorithm layoutAlgorithm = (SankeyLinearLayoutAlgorithm)sankey.LayoutAlgorithm;
layoutAlgorithm.NodeAlignment = SankeyNodeAlignment.Near;
Dim layoutAlgorithm As SankeyLinearLayoutAlgorithm = CType(sankey.LayoutAlgorithm, SankeyLinearLayoutAlgorithm)
layoutAlgorithm.NodeAlignment = SankeyNodeAlignment.Near
To implement a custom layout, create a descendant of the SankeyLayoutAlgorithmBase class. Override the SankeyLayoutAlgorithmBase.CalculateNodeBounds method to specify node bounds:
using DevExpress.Charts.Sankey;
using DevExpress.XtraCharts.Sankey;
using System;
using System.Collections.Generic;
using System.Linq;
private void Form1_Load(object sender, EventArgs e) {
SankeyDiagramControl sankeyDiagramControl1 = new SankeyDiagramControl();
this.Controls.Add(sankeyDiagramControl1);
List<SankeyItem> data = new List<SankeyItem> {
new SankeyItem { Source = "France", Target = "UK", Value = 53 },
new SankeyItem { Source = "Australia", Target = "UK", Value = 72 },
new SankeyItem { Source = "France", Target = "Canada", Value = 81 },
new SankeyItem { Source = "China", Target = "Canada", Value = 96 },
new SankeyItem { Source = "UK", Target = "France", Value = 61 },
new SankeyItem { Source = "Canada", Target = "France", Value = 89 }
};
sankeyDiagramControl1.DataSource = data;
sankeyDiagramControl1.SourceDataMember = "Source";
sankeyDiagramControl1.TargetDataMember = "Target";
sankeyDiagramControl1.WeightDataMember = "Value";
sankeyDiagramControl1.LayoutAlgorithm = new MyLayoutAlgorithm();
sankeyDiagramControl1.Width = 640;
sankeyDiagramControl1.Height = 360;
}
public class SankeyItem {
public string Source { get; set; }
public string Target { get; set; }
public double Value { get; set; }
}
public class MyLayoutAlgorithm : SankeyLayoutAlgorithmBase {
void SpreadLevelIndex(ISankeyNodeLayoutItem node, int startingLevelIndex = 0) {
node.LevelIndex = startingLevelIndex;
if (node.OutputLinks == null)
return;
foreach (var outputLink in node.OutputLinks)
SpreadLevelIndex(outputLink.Target, startingLevelIndex + 1);
}
public override void CalculateNodeBounds(IEnumerable<ISankeyNodeLayoutItem> nodes, DevExpress.Utils.DXRectangle bounds) {
foreach (var node in nodes)
if (node.InputLinks == null || node.InputLinks.Count == 0)
SpreadLevelIndex(node);
int nodeWidth = bounds.Width / 10;
int nodeHeight = bounds.Height / 10;
int levelCount = nodes.Max(node => node.LevelIndex) + 1;
int spaceBetweenLevels = (bounds.Width - nodeWidth) / (levelCount - 1);
int maxNodeCountInALevel = nodes.GroupBy(node => node.LevelIndex).Max(group => group.Count());
int spaceBetweenNodes = (bounds.Height - nodeHeight) / (maxNodeCountInALevel - 1);
Dictionary<int, int> levelNodeCountPairs = new Dictionary<int, int>();
foreach (var node in nodes) {
if (!levelNodeCountPairs.TryGetValue(node.LevelIndex, out int nodeCount))
levelNodeCountPairs.Add(node.LevelIndex, 0);
levelNodeCountPairs[node.LevelIndex]++;
node.Bounds = new DevExpress.Utils.DXRectangle(bounds.Left + node.LevelIndex * spaceBetweenLevels, bounds.Top + nodeCount * spaceBetweenNodes, nodeWidth, nodeHeight);
}
}
}
Imports DevExpress.Charts.Sankey
Imports DevExpress.Utils
Imports DevExpress.XtraCharts.Sankey
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sankeyDiagramControl1 As SankeyDiagramControl = New SankeyDiagramControl()
Me.Controls.Add(sankeyDiagramControl1)
Dim data As List(Of SankeyItem) = New List(Of SankeyItem) From {
New SankeyItem With {
.Source = "France",
.Target = "UK",
.Value = 53
},
New SankeyItem With {
.Source = "Australia",
.Target = "UK",
.Value = 72
},
New SankeyItem With {
.Source = "France",
.Target = "Canada",
.Value = 81
},
New SankeyItem With {
.Source = "China",
.Target = "Canada",
.Value = 96
},
New SankeyItem With {
.Source = "UK",
.Target = "France",
.Value = 61
},
New SankeyItem With {
.Source = "Canada",
.Target = "France",
.Value = 89
}
}
sankeyDiagramControl1.DataSource = data
sankeyDiagramControl1.SourceDataMember = "Source"
sankeyDiagramControl1.TargetDataMember = "Target"
sankeyDiagramControl1.WeightDataMember = "Value"
sankeyDiagramControl1.LayoutAlgorithm = New MyLayoutAlgorithm()
sankeyDiagramControl1.Width = 640
sankeyDiagramControl1.Height = 360
End Sub
Public Class SankeyItem
Public Property Source As String
Public Property Target As String
Public Property Value As Double
End Class
Public Class MyLayoutAlgorithm
Inherits SankeyLayoutAlgorithmBase
Private Sub SpreadLevelIndex(ByVal node As ISankeyNodeLayoutItem, ByVal Optional startingLevelIndex As Integer = 0)
node.LevelIndex = startingLevelIndex
If node.OutputLinks Is Nothing Then Return
For Each outputLink In node.OutputLinks
SpreadLevelIndex(outputLink.Target, startingLevelIndex + 1)
Next
End Sub
Public Overrides Sub CalculateNodeBounds(ByVal nodes As IEnumerable(Of ISankeyNodeLayoutItem), ByVal bounds As DevExpress.Utils.DXRectangle)
For Each node In nodes
If node.InputLinks Is Nothing OrElse node.InputLinks.Count = 0 Then SpreadLevelIndex(node)
Next
Dim nodeWidth As Integer = bounds.Width / 10
Dim nodeHeight As Integer = bounds.Height / 10
Dim levelCount As Integer = nodes.Max(Function(node) node.LevelIndex) + 1
Dim spaceBetweenLevels As Integer = (bounds.Width - nodeWidth) / (levelCount - 1)
Dim maxNodeCountInALevel As Integer = nodes.GroupBy(Function(node) node.LevelIndex).Max(Function(group) group.Count())
Dim spaceBetweenNodes As Integer = (bounds.Height - nodeHeight) / (maxNodeCountInALevel - 1)
Dim levelNodeCountPairs As Dictionary(Of Integer, Integer) = New Dictionary(Of Integer, Integer)()
Dim nodeCount As Integer = Nothing
For Each node In nodes
If Not levelNodeCountPairs.TryGetValue(node.LevelIndex, nodeCount) Then levelNodeCountPairs.Add(node.LevelIndex, 0)
levelNodeCountPairs(node.LevelIndex) += 1
node.Bounds = New DXRectangle(bounds.Left + node.LevelIndex * spaceBetweenLevels, bounds.Top + nodeCount * spaceBetweenNodes, nodeWidth, nodeHeight)
Next
End Sub
End Class
End Class
See Also