Skip to main content

pymyIO

PyPI version Python versions PyPI downloads License

Python bindings for myIO — the d3.js-based interactive chart library originally shipped as an R package.

pymyIO is feature-equivalent to the R package: every R export is reachable from Python, every chart type renders identically, and the JSON config the Python builder produces matches what R emits, byte for byte where possible. Both packages drive the same d3 engine (myIOapi.js), wired in via a git submodule so there is one canonical source of truth — no duplicated JS to drift.

Status: alpha. API is settled and matches R's setMargin/setBrush/ etc. surface. All 20 registry transforms are implemented, including loess, smooth, density, survfit, fit_distribution, and pairwise_test (scipy-backed, Python-native — numeric output may differ from the R package's stats-based versions).

Installation

pip install pymyio

For development:

git clone --recurse-submodules https://github.com/mortonanalytics/pymyIO
cd pymyIO
pip install -e ".[dev]"
pytest

If you cloned without --recurse-submodules, fetch the engine afterwards:

git submodule update --init --recursive

Quickstart

import pandas as pd
from pymyio import MyIO

mtcars = pd.DataFrame({
    "wt":  [2.62, 2.875, 2.32, 3.215, 3.44, 3.46],
    "mpg": [21.0, 21.0, 22.8, 21.4, 18.7, 18.1],
})

(
    MyIO(data=mtcars)
    .add_layer(type="point", label="points",
               mapping={"x_var": "wt", "y_var": "mpg"}, color="#E69F00")
    .add_layer(type="line", label="trend", transform="lm",
               mapping={"x_var": "wt", "y_var": "mpg"}, color="red")
    .set_axis_format(x_label="Weight (1000 lbs)", y_label="MPG")
)

In a Jupyter cell, the trailing expression renders as an interactive widget. Outside notebooks, call .render() to get a MyIOWidget, or .to_config() for the underlying JSON spec.

Where pymyIO runs

Host Tier Render idiom
JupyterLab 1 trailing expression in a cell
VS Code (Jupyter extension) 1 trailing expression in a cell
Shiny for Python 1 from pymyio.shiny import render_myio, output_myio
Classic Notebook 7.x 2 trailing expression
Google Colab 2 trailing expression
marimo 2 mo.ui.anywidget(MyIO(...).render())
Panel 2 pn.pane.IPyWidget(MyIO(...).render())
Solara 2 solara.display(MyIO(...).render())
Quarto (HTML) 2 interactive HTML only; PDF/docx not supported
static HTML / email / Quarto PDF workaround — pymyio.to_standalone_html(chart)

Tier 1 hosts are covered by CI and release-block on regressions. Tier 2 hosts are documented best-effort and verified on the pre-release smoke checklist.

Shiny for Python

from shiny import App, ui
from pymyio.shiny import render_myio, output_myio, reactive_brush, example_app

# Copy-paste the whole app:
app = example_app()

The pymyio.shiny submodule ships thin aliases over shinywidgets so R-myIO users get renderMyIO/myIOOutput muscle memory, plus reactive_brush/reactive_annotated/reactive_rollover helpers that wrap shinywidgets.reactive_read(widget, trait_name).

Install with pip install 'pymyio[shiny]' (pulls shinywidgets >= 0.8.0 and shiny >= 1.0). Don't import shinywidgets directly in vanilla Jupyter notebooks — it installs a process-wide callback that breaks widget construction outside a Shiny session. pymyio's top-level never touches shinywidgets; the submodule is opt-in for exactly this reason.

Static HTML export (Quarto, nbconvert, email embeds)

from pymyio import to_standalone_html

html = to_standalone_html(MyIO(data=df).add_layer(...))
open("chart.html", "w").write(html)

include_assets="inline" (default) produces one self-contained HTML string; include_assets="bundled" returns (html_str, assets_dict) for publishing pipelines that prefer sidecar assets. Interactive-only features (set_brush, set_annotation, drag_points) emit a MyIOStaticWarning — the chart renders, but round-trip callbacks need a live Python kernel.

Supported chart types (34 total)

line, point, bar, groupedBar, area, histogram, heatmap, hexbin, treemap, gauge, donut, candlestick, waterfall, sankey, boxplot, violin, ridgeline, rangeBar, text, regression, bracket, comparison, qq, lollipop, dumbbell, waffle, beeswarm, bump, radar, funnel, parallel, survfit, histogram_fit, calendarHeatmap.

R → Python function map

R export Python equivalent
myIO() MyIO()
addIoLayer() MyIO.add_layer()
setMargin() MyIO.set_margin()
setAxisFormat() MyIO.set_axis_format()
setAxisLimits() MyIO.set_axis_limits()
setColorScheme() MyIO.set_color_scheme()
setReferenceLines() MyIO.set_reference_lines()
setTheme() MyIO.set_theme()
setTransitionSpeed() MyIO.set_transition_speed()
setToolTipOptions() MyIO.set_tooltip_options()
defineCategoricalAxis() MyIO.define_categorical_axis()
flipAxis() MyIO.flip_axis()
suppressLegend() MyIO.suppress_legend()
suppressAxis() MyIO.suppress_axis()
setBrush() MyIO.set_brush()
setAnnotation() MyIO.set_annotation()
setExportOptions() MyIO.set_export_options()
setFacet() MyIO.set_facet()
setLayerOpacity() MyIO.set_layer_opacity()
setSlider() MyIO.set_slider()
setToggle() MyIO.set_toggle()
setLinkedCursor() MyIO.set_linked_cursor()
dragPoints() MyIO.drag_points()
linkCharts() pymyio.link_charts() (module-level)
setLinked() n/a — Crosstalk-specific; use link_charts()
myIO_last_error() MyIOWidget.last_error traitlet
myIOOutput/renderMyIO n/a — Shiny-specific

Reading interactions back into Python

chart = MyIO(data=mtcars).add_layer(...).set_brush().render()
chart                            # display in a cell
chart.brushed                    # last brush selection (dict, syncs from JS)
chart.annotated                  # last annotation event
chart.last_error                 # most recent JS render error, if any
chart.observe(handler, names=["brushed"])  # react to selections

Architecture: one engine, two wrappers

mortonanalytics/myIO          (R package)
  └── inst/htmlwidgets/myIO/  ← canonical engine source
        ├── myIOapi.js
        ├── style.css
        └── lib/d3*.js

mortonanalytics/pymyIO        (this repo)
  ├── vendor/myIO/            ← git submodule pinned to a myIO commit
  └── src/pymyio/static/      ← symlinks pointing into vendor/myIO/

Wheels built by python -m build follow the symlinks and ship real files, so end-users pip-install a self-contained package. Developers and CI work against the submodule directly. To pull in upstream chart fixes:

git submodule update --remote vendor/myIO
git add vendor/myIO && git commit -m "bump myIO engine to <sha>"

Roadmap

ID Item Disposition
PYMYIO-DOC Sphinx docs site Out of scope for 0.1.0

License

MIT. See LICENSE. The vendored myIO engine is also MIT-licensed (see vendor/myIO/LICENSE).

Release files for pymyio 0.4.0

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

Source distribution (sdist)

Source distribution for pymyio 0.4.0
File Size Uploaded
pymyio-0.4.0.tar.gz 849.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pymyio 0.4.0
File Interpreter ABI Platform
pymyio-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / pymyio-0.4.0.tar.gz

Download URL pymyio-0.4.0.tar.gz
Size 849.0 kB
Tags Source
SHA-256 checksum
How to use checksums
9b88bf32df5b75f23e21d07a8199a2dc10e557521bf427bd9915751ce22c8290
BLAKE2b-256 checksum
How to use checksums
68e79229ea11fb8c70674c2bfd1ffeb28bbc4513195c9ec7fe0582b2a881d98a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Jul 29, 2026.

Transparency log

Release files / pymyio-0.4.0-py3-none-any.whl

Download URL pymyio-0.4.0-py3-none-any.whl
Size 457.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0875e0c8dbe67ed3c8d4e5a6cdacf2a223ae0f323f294e119f7de28c4fb997c1
BLAKE2b-256 checksum
How to use checksums
057fcbe63f62d10fb6440e8a30eabe5669d4a8cc787ff4e490b8b831c412092e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Jul 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

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