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)}"