Skip to main content

ibcs-plotly

Interactive IBCS-compliant business charts on Plotly, with optional Streamlit components.

IBCS (International Business Communication Standards) fixes a small set of rules for business reports: current-period and comparison-period values get consistent colors, variance gets its own consistent colors, composition charts are sorted bars instead of pies, and comparable small multiples share one scale. This library gives you those chart types as plain functions that return a plotly.graph_objects.Figure, plus a thin Streamlit layer for KPI cards and the AC/PY/variance legend.

There's an existing IBCS-inspired Python package, clean_business_chart, built on matplotlib. This one targets interactive dashboards (Plotly + Streamlit) rather than static reports.

Install

pip install ibcs-plotly            # core: plotly + pandas + numpy
pip install ibcs-plotly[streamlit] # + Streamlit KPI cards / legend

Quick start: let an AI plan your charts

import pandas as pd
from ibcs_plotly.planner import build_plan, render_spec

df = pd.read_csv("sales.csv")
plan = build_plan(df, tier="STATS")      # the AI-readable plan: roles, calculations, chart specs
print(plan.to_markdown())
render_spec(df, plan.charts[0]).show()   # build the first chart locally, on the full data

Want an assistant to do this for you? Connect it over MCP.

Quick example

from ibcs_plotly import grouped_column, compare_periods

df_ac, df_py, py_year = compare_periods(df, period_col="year", current=2026)

fig = grouped_column(
    ac=df_ac.groupby("month")["revenue"].sum(),
    py=df_py.groupby("month")["revenue"].sum(),
    labels=month_names,
)
fig.show()

See examples/streamlit_demo.py for a full dashboard on synthetic data — run it with:

pip install -e ".[streamlit]"
streamlit run examples/streamlit_demo.py

Plan charts with AI (MCP)

ibcs_plotly.planner profiles a dataset, works out what can be calculated (variance AC-PY, variance %, share, rank, trend, rolling, YTD), and emits a plan of IBCS chart specs that a developer - or an agent - can build from. An MCP server exposes this to any MCP-capable assistant.

The operator decides how much of the data the AI may see; the AI can ask for less per call, never more:

Tier The AI receives
SCHEMA column names, dtypes, inferred roles (measure / dimension / time / period / id)
STATS + null %, min/max/mean, date ranges, top categories (groups under 5 rows are hidden; the leftover rows are reported as other_rows and never total fewer than 5, so subtraction cannot recover them)
SAMPLE + a small random row sample
FULL + all rows (capped). PII columns are masked in SAMPLE/FULL by default
pip install "ibcs-plotly[mcp]"
IBCS_MCP_DATA_DIR=./data IBCS_MCP_MAX_TIER=STATS ibcs-plotly-mcp

Tools: load_dataset, describe_dataset, plan_charts, llm_context_bundle, check_chart, render_chart. Charts are always rendered locally on the full data; the AI only gets back a file path. Without MCP, the same pieces work as a library:

from ibcs_plotly.planner import build_plan, render_spec
plan = build_plan(df, tier="STATS")
print(plan.to_markdown())
render_spec(df, plan.charts[0]).show()

Connect it to Claude or another assistant

Point the server at a folder of data files. The assistant can only read inside that folder, and only up to the tier you set.

Claude Code:

pip install "ibcs-plotly[mcp]"
claude mcp add ibcs -e IBCS_MCP_DATA_DIR=$PWD/data -e IBCS_MCP_MAX_TIER=STATS -- ibcs-plotly-mcp

Claude Desktop or any client that uses a JSON config:

{
  "mcpServers": {
    "ibcs": {
      "command": "ibcs-plotly-mcp",
      "env": { "IBCS_MCP_DATA_DIR": "/path/to/data", "IBCS_MCP_MAX_TIER": "STATS" }
    }
  }
}

Then ask, for example: "Load sales.csv and plan the charts that show how revenue compares with last year." The assistant loads the file, reads the plan, and asks for charts to be rendered. The images are written to your machine; the assistant never receives more than the tier allows. Optional settings: IBCS_MCP_MIN_GROUP, IBCS_MCP_PII_COLUMNS, IBCS_MCP_ALLOW_PII, IBCS_MCP_MAX_BYTES.

Exposure preview

streamlit run examples/exposure_preview.py shows exactly what an assistant would receive from your data at each tier, before you connect anything. Upload a file (or use the built-in sample), pick a tier, mark extra sensitive columns, and read the JSON, the plan and the charts. The last tab prints the matching MCP server settings. Nothing leaves your machine.

Exposure preview at the STATS tier

At the SAMPLE tier the email column is masked in every row:

Masked rows at the SAMPLE tier

LLM-ready export and compliance check

from ibcs_plotly.planner import llm_context, estimate_tokens, to_json
ctx = llm_context(df, tier="STATS", goal="revenue by region")  # instructions + data view + plan
print(estimate_tokens(ctx))        # check it fits the prompt before pasting
prompt_payload = to_json(ctx)

from ibcs_plotly import check_figure
for f in check_figure(fig):        # works on any Plotly figure
    print(f.severity, f.rule, f.message)

check_figure flags pies, 3D, truncated bar axes, unshared small-multiple scales, wrong AC/PY/variance colors, too many categories and color noise. It checks only what is mechanically verifiable from the figure; it cannot judge titles, units or message quality.

Tested on real data

Charts planned for real open datasets

Every chart above and below is the planner's own output for a real public dataset (nothing hand-drawn); each image carries its source and licence.

Chart Dataset What it shows
AC vs PY by month UCI Online Retail II 2011 against the same dates of 2010
Bars by country UCI Online Retail II ranked, AC over PY
Daily trend NYC taxi, Jan 2024 daily grain because the data spans one month
Small multiples NYC taxi, Jan 2024 one scale across panels
Bars by country, variance Our World in Data CO2 "World" and regional totals excluded
Row counts by district Chicago crimes no numeric column, so it counts events
AC vs PY by month Seattle weather 2015 against 2014

What was tested

The test suites are kept out of this repository (unit tests, seed data, the downloaded datasets, the harnesses and their reports all live in git-ignored tests/ and testdata/), and were run locally before release. CI runs lint, an import check of every module, and an end-to-end smoke test of plan, render and lint.

Suite Data Checks Covers
Unit tests small crafted frames 114 roles, tiers, plans, rendering, lint, MCP session, HTML escaping
Synthetic harness 53 generated files 2,351 edge cases: negatives, nulls, infinities, 500k rows, 200 columns, a dozen date formats, hidden and obvious PII, prompt-injection text, path escapes, bad files
Real-data harness 26 open datasets (below) 1,069 all four exposure tiers; no cell text at SCHEMA; small groups hidden at STATS and not recoverable by subtraction; PII never exposed; chart totals re-computed with plain pandas; plausibility review
MCP end to end stdio server 1 script all six tools, tier ceiling, path-traversal refusals
Assistant test real Claude sessions using the MCP server, no other tools 12 prompts tier ceilings respected, PII masked, small groups hidden, prompt injection in the data not obeyed, path escape refused
Dataset Licence Rows Stresses
UCI Online Retail II CC BY 4.0 1,067,371 cancellations and returns, mixed-type invoice ids, missing customer ids
NYC TLC yellow taxi, Jan 2024 open data 2,964,624 stray dates from 2002/2009/2023, negative fares, float counts with NaN
NYC 311, Jan 2024 public domain 100,000 street addresses, free text, many sparse columns
Chicago crimes 2023 (sample) public domain 100,000 code columns, coordinates, no numeric measure
Our World in Data CO2 CC BY 4.0 50,411 79 columns, heavy missing data, regional totals beside countries
Movies, cars, gapminder, stocks vega-datasets 406 to 3,201 text dates, JSON, nulls
Seattle weather, flights, titanic, penguins, diamonds NOAA, seaborn-data 144 to 53,940 month names, small groups, no time column
COVID-19 by country (JHU), World Bank GDP CC BY 4.0 13,979 to 161,568 running totals, aggregates beside countries, ISO country codes
SF building permits, LA parking citations (samples) public domain 50,000 each addresses and owner names, zero-padded lot codes, sparse columns
US employment, unemployment by industry, population, Iowa electricity, planets, health expenditure, tips, S&P 500 list vega-datasets, seaborn-data, datahub 51 to 19,000 period columns, year/month beside a date, negative changes, a table with no measure

Real data found problems synthetic data did not, all fixed and covered by unit tests: code columns such as zip, district and iucr read as measures or dates; invoice ids with cancellation prefixes turned into numbers and blanked; latitude and longitude summed; regional totals double counted; stray dates picked as the comparison year; a part-year compared with a full year; monthly lines for one month of data; street addresses missed as PII; ID-like columns charted as categories; zero-padded codes such as lot 008 turned into numbers, and codes with a few letters silently blanked.

Not covered: charts are never judged for meaning (only for the rules listed above), PII detection is heuristic, and derived measures such as quantity times price are not built for you.

Charts built from CC BY datasets credit their sources in the image: Our World in Data, "CO2 and Greenhouse Gas Emissions" (CC BY 4.0); Chen, D. (2012), "Online Retail II", UCI Machine Learning Repository (CC BY 4.0).

What's included

  • grouped_column, horizontal_bar, variance_waterfall, small_multiples, line_comparison — chart primitives, framework-agnostic

  • compare_periods, safe_delta_pct — period-over-period comparison helpers

  • IBCSTheme — colors/layout as a dataclass you can override

  • ibcs_plotly.streamlit_ext — kpi_card, legend_html, inject_theme_css

  • ibcs_plotly.planner — dataset profiling, exposure tiers, chart plans, spec renderer, LLM export

  • ibcs_plotly.check_figure — IBCS compliance checker for any Plotly figure

  • ibcs_plotly.mcp_server — MCP server (ibcs-plotly-mcp) for AI-assisted chart planning

Not in scope yet: matplotlib/other backends, PDF/PPT export.

License

MIT

Metadata

Release files for ibcs-plotly 0.2.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ibcs-plotly 0.2.3
File Size Uploaded Provenance Actions
ibcs_plotly-0.2.3.tar.gz 1.9 MB With provenance Details for ibcs_plotly-0.2.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ibcs-plotly 0.2.3
File Interpreter ABI Platform Actions
ibcs_plotly-0.2.3-py3-none-any.whl Python 3 none any Details for ibcs_plotly-0.2.3-py3-none-any.whl

Total release size: 2.0 MB

Release files / ibcs_plotly-0.2.3.tar.gz

Download URL ibcs_plotly-0.2.3.tar.gz
Size 1.9 MB
Tags Source
SHA-256 checksum
How to use checksums
987b26ba3f40df2451cecd296dabc73b523da78b2bd49d42e2b27f5254b70d7e
BLAKE2b-256 checksum
How to use checksums
74b0115cd148c4d7ea09dccf762b30b82b52a499b403c1bdf42d91c4fd2ab347
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / ibcs_plotly-0.2.3-py3-none-any.whl

Download URL ibcs_plotly-0.2.3-py3-none-any.whl
Size 38.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d9443596ec84c089b6b03d0835dc3b931a6755fddca84428008b055039000834
BLAKE2b-256 checksum
How to use checksums
2d5b2463a2e5bdb635cc512438d8fdccc3c2e49ebb54a0892b7a72c17c56291d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for ibcs-plotly 0.2.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ibcs_plotly-0.2.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.3 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page