Basic Usage
To get a Sankey Chart use ChartType="ChartType.Sankey" to render the configured ChartSeries as Nodes and Edges.
@using MudBlazor.Charts <MudPaper Class="doc-section-component-container"> <MudChart ChartType="ChartType.Sankey" Width="650px" Height="350px" ChartSeries="@_series"/> </MudPaper>
@code { private List<ChartSeries<int>> _series = new() { new() { Name = "Income Flow", Data = new List<SankeyEdge<int>> { //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 SankeyChartOptions.
@using MudBlazor.Charts <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" ChartSeries="@_series" Width="@($"{_width}px")" Height="@($"{_height}px")" ChartOptions="@_options" /> </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="_options.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="_options.ShowNodeValues" /> </MudTooltip> <MudTooltip Text="Highlight on hover"> <MudToggleIconButton Icon="@Icons.Material.Filled.Highlight" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_options.HighlightOnHover" /> </MudTooltip> <MudTooltip Text="Hide nodes with no edges"> <MudToggleIconButton Icon="@Icons.Material.Filled.DisabledVisible" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_options.HideNodesWithNoEdges" /> </MudTooltip> <MudTooltip Text="Order nodes by value"> <MudToggleIconButton Icon="@Icons.Material.Filled.Sort" Color="@Color.Dark" ToggledColor="@Color.Primary" @bind-Toggled="_options.OrderNodesByValue" /> </MudTooltip> </MudButtonGroup> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_options.NodeWidth" Max="50" ValueLabel="true">Node width</MudSlider> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_options.MinVerticalSpacing" Max="30" ValueLabel="true">Min. vertical spacing</MudSlider> </MudItem> <MudItem xs="12" md="4"> <MudSlider @bind-Value="_options.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="@_options.HighlightColor" /> </MudItem> <MudItem xs="12" md="6"> <MudNumericField @bind-Value="_options.HideNodesSmallerThan" Label="Hide nodes smaller than" /> </MudItem> <MudItem xs="12" md="6"> <MudSelect @bind-Value="_options.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="_options.LabelPadding" Label="Label padding" /> </MudItem> </MudGrid>
@code { private List<SankeyNode> _nodes = []; private List<SankeyEdge<double>> _edges = []; private List<ChartSeries<double>> _series = []; private readonly SankeyChartOptions _options = 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 SankeyNode(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 SankeyEdge<double>(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.Weight <= 0); _series = new List<ChartSeries<double>>() { new() { Name = "Generated Data", Data = _edges } }; _options.NodeOverrides = _nodes; StateHasChanged(); } }
Events
The only event the Sankey Chart currently provides is the selected index one for nodes.
Node selected:
@using MudBlazor.Charts <MudPaper Class="doc-section-component-container"> <MudChart @ref="_mudChart" ChartType="ChartType.Sankey" ChartSeries="@Series.AsList()" Width="@_width" Height="@_height" @bind-SelectedIndex="_selectedIndex"/> </MudPaper> <MudGrid> <MudItem xs="12"> <MudText>Node selected: @(_selectedIndex >= 0 ? Chart.Nodes.ElementAt(_selectedIndex).Name : "")</MudText> </MudItem> </MudGrid>
@code { private MudChart<int> _mudChart = null!; private string _width = "650px"; private string _height = "350px"; private int _selectedIndex = -1; public Sankey<int> Chart => _mudChart.ChartReference as Sankey<int>; private readonly List<SankeyEdge<int>> _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), ]; private ChartSeries<int> Series => new() { Name = "Ball Catalog", Data = _edges }; }