Polars-first financial statement Sankey visualization library
Project description
FinFlow Sankey
Polars-first financial statement Sankey visualization library.
Features
- Polars-first: Native support for
pl.DataFrameandpl.LazyFrame - Accounting-aware validation: Period/currency checks, reconciliation validation
- Role-based color palette: Revenue, costs, profit, cash flow each have distinct colors
- Customizable themes: default, monochrome, colorblind-safe, minimal, dark, plus custom YAML palettes
- Runtime palette override: Change colors via dict or YAML without modifying source
- Account mapping: Map raw account names to standard sections via dict or YAML
- Consistent line styles: Link widths proportional to values, but stroke widths uniform
- Node layout: Level-based horizontal positioning, including reconciliation side-by-side view
- Rich hover metadata: Original accounts, validation status, period, currency
- HTML export: One-line export helper
- Multi-period comparison: Compare two periods in a single Sankey
- Plotly renderer: Returns
plotly.graph_objects.Figurefor Jupyter, Streamlit, Dash, HTML export
Quickstart
import polars as pl
from finflow_sankey import FinancialSankey
df = pl.DataFrame({
"account": ["Revenue", "Cost of Revenue", "Operating Expenses", "Tax", "Net Income"],
"value": [100_000_000.0, -40_000_000.0, -30_000_000.0, -10_000_000.0, 20_000_000.0],
"period": ["FY2025"] * 5,
"currency": ["USD"] * 5,
"statement": ["income_statement"] * 5,
"section": ["revenue", "cost_of_revenue", "operating_expenses", "tax", "profit"],
})
fig = (
FinancialSankey
.income_statement(df, period="FY2025", currency="USD")
.validate()
.render(title="FY2025 Income Statement Flow")
)
fig.show()
Cash Flow Statement
df = pl.DataFrame({
"account": [
"Beginning Cash",
"Operating Cash Flow",
"Investing Cash Flow",
"Financing Cash Flow",
"FX Effect",
"Ending Cash",
],
"value": [50_000_000.0, 25_000_000.0, -10_000_000.0, -5_000_000.0, 2_000_000.0, 62_000_000.0],
"period": ["FY2025"] * 6,
"currency": ["USD"] * 6,
"statement": ["cash_flow_statement"] * 6,
"section": [
"beginning_cash",
"operating_cash_flow",
"investing_cash_flow",
"financing_cash_flow",
"fx_effect",
"ending_cash",
],
})
fig = (
FinancialSankey
.cash_flow_statement(df, period="FY2025", currency="USD")
.validate()
.render(title="FY2025 Cash Flow Bridge")
)
Balance Sheet Reconciliation
df = pl.DataFrame({
"account": [
"Current Assets",
"Non-current Assets",
"Current Liabilities",
"Non-current Liabilities",
"Equity",
],
"value": [60_000_000.0, 40_000_000.0, 30_000_000.0, 20_000_000.0, 50_000_000.0],
"period": ["2025-12-31"] * 5,
"currency": ["USD"] * 5,
"statement": ["balance_sheet"] * 5,
"section": [
"current_asset",
"non_current_asset",
"current_liability",
"non_current_liability",
"equity",
],
})
fig = (
FinancialSankey
.balance_sheet_reconciliation(df, as_of="2025-12-31", currency="USD")
.validate()
.render(title="Balance Sheet Reconciliation")
)
Multi-Period Comparison
df = pl.DataFrame({
"account": ["Revenue", "Revenue", "Operating Expenses", "Operating Expenses"],
"value": [100_000_000.0, 120_000_000.0, -40_000_000.0, -50_000_000.0],
"period": ["FY2024", "FY2025", "FY2024", "FY2025"],
"currency": ["USD"] * 4,
"statement": ["income_statement"] * 4,
"section": ["revenue", "revenue", "expense", "expense"],
})
fig = (
FinancialSankey
.multi_period_compare(df, currency="USD")
.validate()
.render(title="FY2024 vs FY2025")
)
Account Mapping
Map raw account names to standard sections via dict or YAML:
mapping = {
"revenue": ["Net Sales", "Sales Revenue"],
"cost_of_revenue": ["COGS", "Cost of Goods Sold"],
"operating_expenses": ["SG&A", "R&D"],
"tax": ["Income Tax Expense"],
"profit": ["Net Income"],
}
fig = FinancialSankey.income_statement(df, mapping=mapping).validate().render()
Themes & Palettes
# Built-in theme
fig = FinancialSankey.income_statement(df).validate().render(theme="colorblind_safe")
# Dark mode
fig = FinancialSankey.income_statement(df).validate().render(theme="dark")
# Custom YAML palette
fig = FinancialSankey.income_statement(df).validate().render(palette="./my_palette.yaml")
# Runtime dict override
fig = FinancialSankey.income_statement(df).validate().render(
palette={"revenue": "#0055FF", "profit": "#00AA55"}
)
HTML Export
(
FinancialSankey
.income_statement(df)
.validate()
.export_html("income_statement.html", title="FY2025 Income Statement")
)
Installation
pip install finflow-sankey
Development
pip install -e ".[dev]"
Development
python -m pytest tests/ -v
ruff check finflow_sankey tests
Project Structure
finflow_sankey/
core/ # schema, validation, normalization, graph, palette, mapper
templates/ # income_statement, cash_flow, balance_sheet, multi_period
renderers/ # plotly renderer
palettes/ # YAML color palettes
mappings/ # YAML account mappings
examples/ # usage examples
tests/ # pytest suite
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file finflow_sankey-0.1.13.tar.gz.
File metadata
- Download URL: finflow_sankey-0.1.13.tar.gz
- Upload date:
- Size: 29.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e0a029feb8db88c182fac70d19b361c7c64f1bf2ccf9f492e046c00fbd19596
|
|
| MD5 |
d56c54362fa9e33a45d568acdee82ed2
|
|
| BLAKE2b-256 |
2de0867039270ce36601c09ace37ee619865a4d013d748777a72166177f3ad06
|
Provenance
The following attestation bundles were made for finflow_sankey-0.1.13.tar.gz:
Publisher:
publish.yml on min9lin9/finflow-sankey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finflow_sankey-0.1.13.tar.gz -
Subject digest:
9e0a029feb8db88c182fac70d19b361c7c64f1bf2ccf9f492e046c00fbd19596 - Sigstore transparency entry: 1813206187
- Sigstore integration time:
-
Permalink:
min9lin9/finflow-sankey@cf222dfa39c9ee186af98ef7d25478648294bfc1 -
Branch / Tag:
refs/tags/v0.1.13 - Owner: https://github.com/min9lin9
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cf222dfa39c9ee186af98ef7d25478648294bfc1 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file finflow_sankey-0.1.13-py3-none-any.whl.
File metadata
- Download URL: finflow_sankey-0.1.13-py3-none-any.whl
- Upload date:
- Size: 36.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8a63c987ffd29b068e9e065abdb40146665f59ad3ff8f26b4b291bc4c82386f
|
|
| MD5 |
50522dcab28d6ef120d67ece6837419c
|
|
| BLAKE2b-256 |
52d917a1cc15c94f5942da6b8280746df3d4f6bcd90ebc3ea06f08359bd323c0
|
Provenance
The following attestation bundles were made for finflow_sankey-0.1.13-py3-none-any.whl:
Publisher:
publish.yml on min9lin9/finflow-sankey
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
finflow_sankey-0.1.13-py3-none-any.whl -
Subject digest:
b8a63c987ffd29b068e9e065abdb40146665f59ad3ff8f26b4b291bc4c82386f - Sigstore transparency entry: 1813206433
- Sigstore integration time:
-
Permalink:
min9lin9/finflow-sankey@cf222dfa39c9ee186af98ef7d25478648294bfc1 -
Branch / Tag:
refs/tags/v0.1.13 - Owner: https://github.com/min9lin9
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@cf222dfa39c9ee186af98ef7d25478648294bfc1 -
Trigger Event:
workflow_dispatch
-
Statement type: