Basic Usage
To get a Sankey Chart use ChartType="ChartType.Sankey" to render the configured Nodes and Edges.
<MudPaper Class="doc-section-component-container"> <MudChart ChartType="ChartType.Sankey" Nodes="@_nodes" Edges="@_edges" Width="650px" Height="350px"/> </MudPaper>
@code { private readonly List<SankeyChartNode> _nodes = [ new("Income", 0), // Income new("Expenses", 1), new("Savings", 1), // Expenses new("Housing", 2), new("Food", 2), new("Insurance", 2), new("Mobility", 2), new("Travel", 2), new("Leisure", 2), // Savings new("Interest", 2), new("Stocks", 2), // Housing new("Rent", 3), new("Other", 3), // Insurance new("Home insurance", 3), new("Car insurance", 3), new("Health insurance", 3), // Travel new("Car", 3), new("Public transport", 3), ]; private readonly List<SankeyChartEdge> _edges = [ // Income new("Income", "Expenses", 2800), new("Income", "Savings", 400), // Expenses new("Expenses", "Housing", 1200), new("Expenses", "Food", 500), new("Expenses", "Insurance", 250), new("Expenses", "Mobility", 125), new("Expenses", "Travel", 425), new("Expenses", "Leisure", 300), // Savings new("Savings", "Interest", 10), new("Savings", "Stocks", 390), // Housing new("Housing", "Rent", 950), new("Housing", "Other", 250), // Insurance new("Insurance", "Home insurance", 50), new("Insurance", "Car insurance", 75), new("Insurance", "Health insurance", 125), // Travel new("Travel", "Car", 300), new("Travel", "Public transport", 125), ]; }
Customization
The Sankey Chart can be further customised using ChartOptions, NodeChartOptions or the options within the
SankeyChartNode class.
<MudStack Row="true" Justify="Justify.Center" Class="mud-width-full"> <MudPaper Class="pa-4"> <MudStack Row="true"> <MudNumericField @bind-Value="_nodeCount" Label="Nodes" Min="2" Max="500"/> <MudNumericField @bind-Value="_columnCount" Label="Columns" Min="2" Max="5"/> <MudButton OnClick="@(() => GenerateData())" StartIcon="@Icons.Material.Outlined.Refresh" Color="Color.Primary" Variant="Variant.Outlined">Generate</MudButton> </MudStack> </MudPaper> </MudStack> <MudPaper Class="doc-section-component-container"> <MudChart ChartType="ChartType.Sankey" Nodes="@_nodes" Edges="@_edges" Width="@($"{_width}px")" Height="@($"{_height}px")" ChartOptions="@_options" NodeChartOptions="_nodeChartOptions"/> </MudPaper> <MudGrid> <MudItem xs="12" Class="d-flex justify-center"> <MudButtonGroup Color="Color.Primary" Variant="Variant.Outlined" Class="pt-4"> <MudTooltip Text="Show edge values"> <MudToggleIconButton Icon="@Icons.Material.Filled.ShortText" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_nodeChartOptions.ShowEdgeLabels"/> </MudTooltip> <MudTooltip Text="Show labels"> <MudToggleIconButton Icon="@Icons.Material.Filled.Textsms" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_options.ShowLabels"/> </MudTooltip> <MudTooltip Text="Show node values"> <MudToggleIconButton Icon="@Icons.Material.Filled.Money" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_nodeChartOptions.ShowNodeValues"/> </MudTooltip> <MudTooltip Text="Highlight on hover"> <MudToggleIconButton Icon="@Icons.Material.Filled.Highlight" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_nodeChartOptions.HighlightOnHover"/> </MudTooltip> <MudTooltip Text="Hide nodes with no edges"> <MudToggleIconButton Icon="@Icons.Material.Filled.DisabledVisible" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_nodeChartOptions.HideNodesWithNoEdges"/> </MudTooltip> <MudTooltip Text="Order nodes by value"> <MudToggleIconButton Icon="@Icons.Material.Filled.Sort" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_nodeChartOptions.OrderNodesByValue"/> </MudTooltip> </MudButtonGroup> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_nodeChartOptions.NodeWidth" Max="50" ValueLabel="true">Node width</MudSlider> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_nodeChartOptions.MinVerticalSpacing" Max="30" ValueLabel="true">Min. vertical spacing</MudSlider> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_nodeChartOptions.EdgeOpacity" Step="0.01" Max="1" ValueLabel="true">Edge opacity</MudSlider> </MudItem> <MudItem xs="12" md="6"> <MudSlider @bind-Value="_width" ValueLabel="true" Max="2000">Chart width</MudSlider> </MudItem> <MudItem xs="12" md="6"> <MudSlider @bind-Value="_height" ValueLabel="true" Max="2000">Chart height</MudSlider> </MudItem> <MudItem xs="12" md="6"> <MudColorPicker Label="Highlighting color" @bind-Text="@_nodeChartOptions.HighlightColor"/> </MudItem> <MudItem xs="12" md="6"> <MudNumericField @bind-Value="_nodeChartOptions.HideNodesSmallerThan" Label="Hide nodes smaller than"/> </MudItem> <MudItem xs="12" md="6"> <MudSelect @bind-Value="_nodeChartOptions.LabelFontSize" Label="Label font size"> <MudSelectItem Value="@("0.25rem")">0.25rem</MudSelectItem> <MudSelectItem Value="@("0.33rem")">0.33rem</MudSelectItem> <MudSelectItem Value="@("0.5rem")">0.5rem</MudSelectItem> <MudSelectItem Value="@("0.66rem")">0.66rem</MudSelectItem> <MudSelectItem Value="@("0.75rem")">0.75rem</MudSelectItem> <MudSelectItem Value="@("1rem")">1rem</MudSelectItem> <MudSelectItem Value="@("1.25rem")">1.25rem</MudSelectItem> </MudSelect> </MudItem> <MudItem xs="12" md="6"> <MudNumericField @bind-Value="_nodeChartOptions.LabelPadding" Label="Label padding"/> </MudItem> </MudGrid>
@code { private List<SankeyChartNode> _nodes = []; private List<SankeyChartEdge> _edges = []; private readonly ChartOptions _options = new(); private readonly NodeChartOptions _nodeChartOptions = new() { NodeWidth = 5, MinVerticalSpacing = 5, LabelFontSize = "0.33rem", LabelPadding = 2, OrderNodesByValue = true, HideNodesSmallerThan = 1 }; private int _width = 650; private int _height = 650; private int _nodeCount = 50; private int _columnCount = 3; protected override void OnAfterRender(bool firstRender) { base.OnAfterRender(firstRender); if (firstRender) GenerateData(); } private void GenerateData(double minEdgePercentage = 0.15, double maxEdgePercentage = 0.7) { var rnd = new Random(); _nodes = []; _edges = []; var nodesPerColumn = (int)Math.Ceiling((double)_nodeCount / _columnCount); for (var col = 0; col < _columnCount; col++) { var nodesInCurrentColumn = Math.Min(nodesPerColumn, _nodeCount - _nodes.Count); for (var i = 0; i < nodesInCurrentColumn; i++) { var nodeName = $"Node_{col}_{i}"; _nodes.Add(new SankeyChartNode(nodeName, col)); } } var nodesByColumn = _nodes.GroupBy(n => n.Column) .OrderBy(g => g.Key) .Select(g => g.ToList()) .ToList(); var nodeOutputs = new Dictionary<string, double>(); var nodeInputs = new Dictionary<string, double>(); foreach (var node in _nodes) { nodeOutputs[node.Name] = 0; nodeInputs[node.Name] = 0; } for (var colI = 0; colI < nodesByColumn.Count - 1; colI++) { var sourceNodes = nodesByColumn[colI]; var targetNodes = nodesByColumn[colI + 1]; if (colI == 0) { foreach (var sourceNode in sourceNodes) { nodeOutputs[sourceNode.Name] = rnd.Next(1, 1000); } } foreach (var sourceNode in sourceNodes) { var remainingEdgeValue = nodeOutputs[sourceNode.Name]; var edgeCount = rnd.Next(1, Math.Min(targetNodes.Count, 3) + 1); var selectedTargets = targetNodes.OrderBy(_ => rnd.Next()).Take(edgeCount).ToList(); for (var i = 0; i < selectedTargets.Count; i++) { var targetNode = selectedTargets[i]; double edgeValue; if (i == selectedTargets.Count - 1) { edgeValue = remainingEdgeValue; } else { var maxEdgeValue = remainingEdgeValue - (selectedTargets.Count - i - 1) * 10; edgeValue = rnd.NextDouble() * maxEdgeValue * maxEdgePercentage + maxEdgeValue * minEdgePercentage; remainingEdgeValue -= edgeValue; } _edges.Add(new SankeyChartEdge(sourceNode.Name, targetNode.Name, Math.Round(edgeValue))); nodeInputs[targetNode.Name] += edgeValue; } } foreach (var targetNode in targetNodes) { nodeOutputs[targetNode.Name] = nodeInputs[targetNode.Name]; } } _edges.RemoveAll(e => e.Value <= 0); StateHasChanged(); } }
Events
The only event the Sankey Chart currently provides is the selected index one for nodes.
Node selected:
<MudPaper Class="doc-section-component-container"> <MudChart ChartType="ChartType.Sankey" Nodes="@_nodes" Edges="@_edges" Width="@_width" Height="@_height" @bind-SelectedIndex="_SelectedIndex"/> </MudPaper> <MudGrid> <MudItem xs="12"> <MudText>Node selected: @(_SelectedIndex >= 0 ? _nodes[_SelectedIndex].Name : "")</MudText> </MudItem> </MudGrid>
@code { private string _width = "650px"; private string _height = "350px"; private int _SelectedIndex = -1; private readonly List<SankeyChartNode> _nodes = [ new("Balls", 0), new("Soccer ball", 1), new("Football", 1), new("Tennis ball", 1), new("Good condition", 2), new("Bad condition", 2), ]; private readonly List<SankeyChartEdge> _edges = [ new("Balls", "Soccer ball", 20), new("Balls", "Football", 10), new("Balls", "Tennis ball", 30), new("Soccer ball", "Good condition", 17), new("Soccer ball", "Bad condition", 3), new("Football", "Good condition", 5), new("Football", "Bad condition", 5), new("Tennis ball", "Good condition", 10), new("Tennis ball", "Bad condition", 20), ]; }