SANKEY

Excel Usage

=SANKEY(data, title, color_map)
  • data (list[list], required): Input data (Flows, Labels).
  • title (str, optional, default: null): Chart title.
  • color_map (str, optional, default: “viridis”): Color map for flows.

Returns (object): Matplotlib Figure object (standard Python) or base64 encoded PNG string (Pyodide).

Examples

Example 1: Energy flow with balanced inputs and outputs

Inputs:

data
2 Input A
1 Input B
-1.5 Output X
-1.5 Output Y

Excel formula:

=SANKEY({2,"Input A";1,"Input B";-1.5,"Output X";-1.5,"Output Y"})

Expected output:

"chart"

Example 2: Simple two-flow balance

Inputs:

data
1 In
-1 Out

Excel formula:

=SANKEY({1,"In";-1,"Out"})

Expected output:

"chart"

Example 3: Sankey with title

Inputs:

data title
5 Source Energy Distribution
-3 Use A
-2 Use B

Excel formula:

=SANKEY({5,"Source";-3,"Use A";-2,"Use B"}, "Energy Distribution")

Expected output:

"chart"

Example 4: Custom color map

Inputs:

data color_map
10 Revenue plasma
-6 Costs
-4 Profit

Excel formula:

=SANKEY({10,"Revenue";-6,"Costs";-4,"Profit"}, "plasma")

Expected output:

"chart"

Python Code

import sys
import matplotlib
IS_PYODIDE = sys.platform == "emscripten"
if IS_PYODIDE:
    matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.sankey import Sankey
import io
import base64
import numpy as np

def sankey(data, title=None, color_map='viridis'):
    """
    Create a Sankey flow diagram.

    See: https://matplotlib.org/stable/api/sankey_api.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        data (list[list]): Input data (Flows, Labels).
        title (str, optional): Chart title. Default is None.
        color_map (str, optional): Color map for flows. Valid options: Viridis, Plasma, Inferno, Magma, Cividis. Default is 'viridis'.

    Returns:
        object: Matplotlib Figure object (standard Python) or base64 encoded PNG string (Pyodide).
    """
    def to2d(x):
        return [[x]] if not isinstance(x, list) else x

    try:
        data = to2d(data)

        if not isinstance(data, list) or len(data) == 0:
            return "Error: Data must be a non-empty 2D list"

        # Extract flows and labels
        flows = []
        labels = []

        for row in data:
            if not isinstance(row, list) or len(row) < 1:
                continue

            try:
                flow = float(row[0])
                flows.append(flow)

                if len(row) > 1 and row[1]:
                    labels.append(str(row[1]))
                else:
                    labels.append("")
            except (TypeError, ValueError):
                continue

        if len(flows) == 0:
            return "Error: No valid flow data found"

        # Check if flows balance (sum should be close to zero)
        if abs(sum(flows)) > 1e-6:
            return "Error: Flows must balance (sum of inflows must equal sum of outflows)"

        # Create the figure
        fig = plt.figure(figsize=(8, 6))
        ax = fig.add_subplot(1, 1, 1)

        # Create Sankey diagram
        sankey = Sankey(ax=ax, scale=0.01, offset=0.2)

        # Get colormap
        try:
            cmap = plt.get_cmap(color_map)
            colors = [cmap(i / len(flows)) for i in range(len(flows))]
        except:
            colors = None

        sankey.add(flows=flows, labels=labels, orientations=[0]*len(flows), 
                   facecolor=colors[0] if colors else None)
        diagrams = sankey.finish()

        if title:
            plt.title(str(title))

        plt.tight_layout()

        if IS_PYODIDE:
            buf = io.BytesIO()
            plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
            buf.seek(0)
            img_base64 = base64.b64encode(buf.read()).decode('utf-8')
            plt.close(fig)
            return f"data:image/png;base64,{img_base64}"
        else:
            return fig
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator