Overview

/

Benchmarks

Benchmarks

XY's large-data claim is about the representation sent to a fixed-size output, not about drawing every source row as an individual marker. The committed 0.1.0 launch baseline measures identical seeded scatter data at 900×420 pixels on an Apple M5 Pro with 64 GiB RAM. Each successful cell below is the mean of three isolated cold runs. The machine name and memory are copied verbatim from the committed environment record.

How to read this comparison. XY switches dense scatter output to a screen-bounded density representation, while the default Plotly and Matplotlib paths retain every marker. These results compare each library's default user-visible outcome at the same output size; they do not claim that the libraries send identical geometry to the renderer.

Snapshot at 10 million points

10M-point cold-render time

900×420 output · mean of three isolated runs · shared linear scale

XY
Matplotlib
Plotly
900×420 output contractXYMatplotlibPlotlyXY representation
Static CPU PNG0.0232 s2.7842 s9.5834 sdensity
Interactive first render, default GPU0.1797 s3.0029 s3.6434 sdensity + sample
Interactive first render, CPU fallback0.9920 s3.6735 s8.2152 sdensity + sample

These summary tables show means only; the linked launch report publishes the sample standard deviation for every successful timing cell. Small reversals in adjacent means, such as 100k versus 1M on the default interactive path, are within the observed three-run variation and should not be read as evidence that more rows are inherently faster.

The output contracts are intentionally separate. Static PNG rows compare validated CPU-rendered images. Interactive rows include figure construction, standalone HTML, a fresh browser, readiness, GPU completion, and a nonblank pixel check. Hardware-WebGL and SwiftShader results are never merged.

Time and memory across scale

The 10-million-point snapshot is one point on a larger curve. Static render time stays close to the output cost after XY switches to density, while the exact-marker paths continue to grow with the number of rows. Peak process-tree RSS tells the same practical story from a different angle.

Static render time by input size

Static 900×420 PNG · measured runs · × marks guarded failures

XY
Matplotlib
Plotly

10M static peak RSS

Static 900×420 PNG · complete process tree · GiB

At 10 million points, the static CPU output contract recorded:

Peak process-tree RSSXYMatplotlibPlotly / Kaleido
Static 900×420 PNG0.283 GiB0.834 GiB5.671 GiB

Plotly's static value includes the Kaleido and Chrome processes used by to_image(). RSS was sampled across each complete process tree every 50 ms, so very brief peaks may be missed. At one billion points, XY's successful static row peaked at 22.414 GiB; Matplotlib crossed the 36 GiB guardrail and Plotly did not produce a PNG on its first guarded attempt.

What scales with rows—and what does not

XY keeps exact source columns in Python. Ingest, range scans, binning, and line decimation still perform work that depends on the number of source rows. Once a large scatter has been reduced, however, the density grid and retained sample are bounded by the viewport rather than growing one marker per row. Long line output is similarly bounded after decimation.

That distinction is visible in the recorded sweep:

PointsNative static PNGInteractive, default GPUXY representation
10k0.0085 s0.1533 sdirect
100k0.0108 s0.1742 sdirect
1M0.0114 s0.1688 sdensity; density + sample interactive
10M0.0232 s0.1797 sdensity; density + sample interactive
1B1.1452 s1.2530 sdensity; density + sample interactive

At one billion points, XY ingested the rows and produced a validated density PNG and interactive density overview. It did not draw one billion markers. The exact-point Plotly and Matplotlib paths did not complete at that size within this run's 36 GiB process-tree and 180-second limits; those are local guarded outcomes, not universal limits.

What this benchmark does—and does not show

The recorded baseline showsIt does not establish
Cold time to a validated, nonblank 900×420 outputWarm-service throughput after browser or Kaleido startup is amortized
Peak process-tree RSS on one reference machineGPU memory or performance on every platform
Default large-scatter behavior for each libraryEquivalent rendered geometry after XY enters density mode
The effect of a screen-bounded representation at large sizesPerformance for every chart family, dashboard, or interaction

The result is strongest as an end-to-end product comparison: what a user gets from the default API under a fixed output contract. A separate like-for-like representation study is still useful when the question is about the cost of aggregation itself.

Next benchmark coverage

The repository already has harnesses for more than the launch scatter. Results will be published separately as their contracts and reference artifacts are frozen:

  • Adaptive peers: dense scatter against Datashader / HoloViews and long lines against Plotly Resampler, kept separate from exact-marker baselines.
  • Interaction and applications: pan and zoom refinement, selection, append/streaming updates, transport, and 10/20/50-chart dashboards.
  • More chart families: long lines and heatmaps, where decimation and fixed-resolution aggregation exercise different kernels.
  • Release and hardware tracking: immutable release directories plus clearly separated macOS hardware-WebGL and CI SwiftShader results.

Until those artifacts are published, this page intentionally keeps its headline claims scoped to the committed launch scatter.

Inspect and reproduce the evidence

The baseline records its source commit (7228f99), exact dependency lock, hardware, browser, raw samples, failure rows, and render oracles:

  • Launch report
  • Environment
  • Raw default-path results
  • Benchmark runbook

After completing the runbook setup, reproduce the frozen default-path sweep from the source revision recorded in the environment file:

One machine and three runs describe that recorded environment, not every machine or workload. New comparisons should retain chart type, data size, representation, backend, output target, and browser-TTFR status rather than shortening these results to a universal “faster than” claim. For the rendering model behind the numbers, read Large data and performance.

Built with Reflex