Chord Chart

A chord diagram arranges entities (nodes) around a circular ring and draws curved ribbons between them to show relationships or flows. The width of each ribbon is proportional to the flow magnitude. Ideal for visualizing trade flows, communication patterns, dependencies, and any many-to-many relationship data.

The Chord chart uses a Data (nodes) + Links model, the same pattern as the Sankey Chart.

Basic Usage

<ArcadiaChordChart Data="@nodes" Links="@links"
                   Height="500" Width="500"
                   Title="Team Communication" />

@code {
    List<ChordNode> nodes = new()
    {
        new() { Id = "eng", Label = "Engineering" },
        new() { Id = "design", Label = "Design" },
        new() { Id = "pm", Label = "Product" },
        new() { Id = "sales", Label = "Sales" },
    };

    List<ChordLink> links = new()
    {
        new() { SourceId = "eng", TargetId = "design", Value = 80 },
        new() { SourceId = "eng", TargetId = "pm", Value = 60 },
        new() { SourceId = "design", TargetId = "pm", Value = 45 },
        new() { SourceId = "pm", TargetId = "sales", Value = 90 },
        new() { SourceId = "eng", TargetId = "sales", Value = 20 },
    };
}

Custom Colors

Override colors on individual nodes or links:

@code {
    List<ChordNode> nodes = new()
    {
        new() { Id = "us", Label = "US", Color = "#3b82f6" },
        new() { Id = "eu", Label = "EU", Color = "#22c55e" },
        new() { Id = "asia", Label = "Asia", Color = "#f59e0b" },
    };

    List<ChordLink> links = new()
    {
        new() { SourceId = "us", TargetId = "eu", Value = 120 },
        new() { SourceId = "us", TargetId = "asia", Value = 90,
                Color = "#ef4444" },  // override link color
        new() { SourceId = "eu", TargetId = "asia", Value = 75 },
    };
}

Palettes

<ArcadiaChordChart Data="@nodes" Links="@links"
                   Palette="ChartPalette.Vibrant" />

Available: Default, Cool, Warm, Monochrome, Pastel, Vibrant, Accessible.

Events

OnChordClick

Fired when a chord ribbon is clicked. Receives a ChordClickEventArgs:

<ArcadiaChordChart Data="@nodes" Links="@links"
                   OnChordClick="HandleClick" />

@code {
    void HandleClick(ChordClickEventArgs e)
    {
        Console.WriteLine($"{e.SourceLabel} <-> {e.TargetLabel}: {e.Value}");
    }
}
PropertyTypeDescription
SourceIdstringSource node ID
TargetIdstringTarget node ID
SourceLabelstringSource node display label
TargetLabelstringTarget node display label
ValuedoubleFlow value

Data Model

ChordNode

PropertyTypeDescription
IdstringUnique identifier for the node
LabelstringDisplay label (falls back to Id if null)
Colorstring?Optional color override
PropertyTypeDescription
SourceIdstringID of the source node
TargetIdstringID of the target node
ValuedoubleFlow magnitude (determines ribbon width). Must be > 0.
Colorstring?Optional color override (defaults to source node color)

Parameters

ParameterTypeDefaultDescription
DataIReadOnlyList<ChordNode>?nullThe nodes on the ring
LinksIReadOnlyList<ChordLink>?nullThe chord connections
Widthdouble0Chart width (0 = responsive)
Heightdouble300Chart height
InnerRadiusdouble?nullInner ring radius (null = 88% of outer)
OuterRadiusdouble?nullOuter ring radius (null = auto from dims)
PadAngledouble2.0Gap between arc segments in degrees
ChordOpacitydouble0.75Ribbon fill opacity
ChordHoverOpacitydouble1.0Ribbon fill opacity on hover
MinLabelAngledouble8Minimum arc degrees for label to render
Titlestring?nullChart title
Subtitlestring?nullSubtitle below title
ShowLabelsbooltrueShow labels on the outer ring
AnimateOnLoadbooltrueAnimate ribbons on first render
ShowToolbarbooltruePNG/SVG export toolbar
LoadingboolfalseLoading skeleton state
NoDataMessagestring?”No data available”Custom empty-state message
AriaLabelstring?nullScreen reader label
OnChordClickEventCallback<ChordClickEventArgs>Ribbon click event
PaletteChartPalette?nullColor palette

Plus all shared ChartBase parameters.

Layout Algorithm

  1. Total flow — Each node’s total flow = sum of all link values where that node is source or target.
  2. Angular allocation — The full circle (2PI) minus padding gaps is divided proportionally by each node’s total flow.
  3. Arc segments — Each node gets an annular arc segment on the outer ring.
  4. Chord sub-spans — For each link, angular sub-spans are allocated on both the source and target arcs, proportional to the link value relative to each node’s total.
  5. Ribbon paths — Quadratic bezier curves through the center connect the two arc sub-spans, forming the characteristic ribbon shape.

Input Validation

  • Negative or zero values — Links with Value <= 0 are skipped
  • Self-links — Links where SourceId == TargetId are skipped
  • Invalid node IDs — Links referencing non-existent nodes are skipped
  • Duplicate node IDs — Only the first node with a given ID is used
  • Null labels — Falls back to the node’s Id

Use Cases

  • Trade flows — Imports/exports between countries
  • Communication patterns — Message volume between teams or departments
  • Dependencies — Module or package interdependencies
  • Migration — Population movement between regions
  • Collaboration — Co-authorship or shared work between groups

Accessibility

  • role="figure" and aria-label on the SVG element
  • Hidden <table> with Source, Target, and Value columns for screen readers
  • Animations respect prefers-reduced-motion: reduce
  • FormatProvider support for localized number formatting