Skip to main content

Matplotlib with market-microstructure sanity: gap compression, LOD decimation, and trader-style interaction.

Project description

TradeAxis

Matplotlib with market-microstructure sanity.

TradeAxis is a thin wrapper that composes gap-compression, level-of-detail decimation, and trader-style mouse interaction onto a standard matplotlib Axes. No subclassing, no new API to learn -- your ax stays a normal ax.

Features

  • Gap compression -- Overnight/weekend gaps are detected automatically and removed. Session breaks are marked with clean dashed separators.
  • LOD decimation -- Millions of points render instantly. On zoom, the visible data is refined to full resolution. Min/max bucket downsampling ensures spikes are never hidden.
  • Trader-style interaction -- Left-drag to pan, right-drag to zoom, middle-click for a snap-to-data crosshair with datetime + value annotation. Press Escape to dismiss.

Installation

pip install tradeaxis

Or with Poetry (from source):

git clone https://github.com/youruser/tradeaxis.git
cd tradeaxis
poetry install

Quick start

import matplotlib.pyplot as plt
import numpy as np
import tradeaxis as ta

# Generate synthetic multi-day 1-min data
def make_day(date):
    base = np.datetime64(date)
    start = base + np.timedelta64(9 * 60 + 30, "m")
    end = base + np.timedelta64(16 * 60, "m")
    return np.arange(start, end, np.timedelta64(1, "m"))

timestamps = np.concatenate([make_day("2026-01-05"), make_day("2026-01-06")])
prices = 150 + np.cumsum(np.random.randn(len(timestamps)) * 0.02)

# One line to enhance the axes
fig, ax = plt.subplots(figsize=(14, 5))
chart = ta.wrap(ax, timestamps, prices)

# Everything below is normal matplotlib
ax.set_title("AAPL 1-min")
ax.set_ylabel("Price ($)")
ax.axhline(prices.mean(), color="red", ls="--", alpha=0.5, label="Mean")
ax.legend()
plt.show()

Interaction controls

Action Effect
Left-drag Pan along the x-axis
Right-drag up Zoom in (centered at cursor)
Right-drag down Zoom out (centered at cursor)
Middle-click Snap crosshair to nearest data point, show datetime + value
Escape Dismiss crosshair

API reference

tradeaxis.wrap(ax, timestamps, values, *, gap="auto", show_separators=True, interaction=True)

Enhance a standard matplotlib Axes with gap compression, LOD decimation, and interaction.

Parameters:

Name Type Default Description
ax matplotlib.axes.Axes -- The axes to enhance.
timestamps array[datetime64] -- Sorted timestamps.
values array[float] -- Y-values (prices, volumes, etc.).
gap "auto" / timedelta / callable "auto" Gap detection strategy. "auto" uses median heuristic. A timedelta sets a fixed threshold. A callable receives the timestamps array and returns a boolean mask.
show_separators bool True Draw dashed vertical lines at session breaks.
interaction bool True Enable pan/zoom/crosshair mouse handling.

Returns: Chart -- a handle for the enhanced chart. The ax is still a normal matplotlib Axes.

tradeaxis.plot_intraday(timestamps, values, *, gap="auto", show_separators=True, interaction=True, figsize=(14, 6))

Convenience function that creates a new figure + axes and calls wrap().

Chart methods

Method Description
chart.to_index(datetime) Convert a datetime to compressed index space (for adding custom annotations).
chart.to_datetime(idx) Convert a compressed index back to a datetime.
chart.detach() Remove all TradeAxis artifacts and restore the axes to vanilla matplotlib.

Working with compressed x-axis

The x-axis uses a compressed integer index, not wall-clock time. This means distances are proportional to number of data points, not elapsed time. When adding custom annotations:

# Convert a datetime to index space, then annotate normally
idx = chart.to_index(np.datetime64("2026-01-05T12:00"))
ax.axvline(x=idx, color="green", ls=":")

How it works

  1. TimeMapping detects gaps in the timestamp sequence (via median-heuristic or user-specified threshold) and remaps datetimes to a contiguous integer index. A FuncFormatter maps these integers back to readable time labels on the x-axis.

  2. LODRenderer decimates large datasets using min/max bucket downsampling. For each bucket of points, only the minimum and maximum values are kept (interleaved in x-order), preserving spikes. An LRU cache avoids recomputation during repeated pans.

  3. InteractionController implements a simple state machine (IDLE -> PAN / ZOOM) over matplotlib canvas events. The crosshair snaps to the nearest data point via binary search.

All of this is composed onto a user-owned Axes via callbacks and artist injection -- no subclassing, no monkey-patching.

Development

poetry install
poetry run pytest -v

Examples notebook:

poetry run jupyter notebook examples/showcase.ipynb

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tradeaxis-0.1.1.tar.gz (10.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tradeaxis-0.1.1-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file tradeaxis-0.1.1.tar.gz.

File metadata

  • Download URL: tradeaxis-0.1.1.tar.gz
  • Upload date:
  • Size: 10.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.3 CPython/3.11.9 Darwin/25.3.0

File hashes

Hashes for tradeaxis-0.1.1.tar.gz
Algorithm Hash digest
SHA256 22585d9bd6a30c4cdd47d2544eecb4915f1604f4bfd12137273063307f20ab11
MD5 b09177b5726992a88565ff02f33ccee8
BLAKE2b-256 4ba31690eabb31bd281a11ad2031c1de1ec43b0f7f449c53896d03bb8bf484be

See more details on using hashes here.

File details

Details for the file tradeaxis-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: tradeaxis-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.3 CPython/3.11.9 Darwin/25.3.0

File hashes

Hashes for tradeaxis-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 740504dc4cd3e70251bc1f4e28d92838a5df84288be2b8373a9949d687285c77
MD5 fc7f104ec31b8a0c5c6eb5bafe305774
BLAKE2b-256 445df0282c4fd5ac7d87687749b8a28fd2d3678bafe823d064e685c9dc924c57

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page