npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hexane/plotlib

v0.4.0

Published

A React component library for building interactive scientific figures.

Readme

plotlib

A React component library for building interactive scientific figures. Plots are rendered as SVG, layout is solved by a Cassowary constraint engine, and interactivity (zoom, pan) is driven by Jotai atoms — giving a declarative, composable API that fits naturally into any React application.

Features

  • Declarative figure API — define scales once on <Figure>, reference them by name across any number of <Plot> panels; the layout engine keeps them aligned automatically
  • Constraint-based layout — panel sizing uses a Cassowary solver (@lume/kiwi), supporting proportional sizes, shared axis dimensions, and flexible multi-panel grids
  • Interactive zoom & pan — scroll to zoom, drag to pan, with configurable zoom extent, translate extent, and optional fixed aspect ratio
  • Composable marksPlotLine for line series, PlotImage for colormapped bitmap data
  • Color scaleslinear and log scales support numeric→color mapping via d3-interpolate piecewise interpolation
  • Colorbar — axis-aligned colorbar with configurable size and gradient stops
  • Scalebar — auto-ranging physical scale bar with SI prefix selection, zoom-aware
  • Theming — lightweight CSS-module-backed theme system; components accept style override props

Installation

npm install @hexane/plotlib

Peer dependencies — install these alongside plotlib if not already present:

npm install react react-dom jotai

Then import the default stylesheet once in your application:

import '@hexane/plotlib/styles.css';

Quick Start

import React from 'react';
import { Figure, Plot, PlotLine, layout } from '@hexane/plotlib';
import type { ScaleSpec } from '@hexane/plotlib';
import '@hexane/plotlib/styles.css';

const scales = new Map<string, ScaleSpec>([
    ['x', { domain: [0, 10], size: '400px' }],
    ['y', { domain: [0, 4], size: '200px' }],
]);

const xs = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const ys = xs.map(Math.sqrt);

export function MyFigure() {
    return (
        <Figure scales={scales} width="600px">
            <Plot xaxis="x" yaxis="y" zoom>
                <Plot.Clip>
                    <PlotLine xs={xs} ys={ys} />
                </Plot.Clip>
            </Plot>
        </Figure>
    );
}

Multi-Panel Figures

Axes declared on <Figure> are shared across panels by name. Placing two <Plot> components with the same xaxis key aligns them horizontally and links their zoom state.

const scales = new Map<string, ScaleSpec>([
    ['x',      { domain: [0, 10], size: '400px', show: 'one' }],
    ['signal', { domain: [-1, 1], size: '150px', show: 'one' }],
    ['error',  { domain: [0, 0.5], size: '150px', show: 'one' }],
]);

<Figure scales={scales} width="600px">
    <layout.FlexBox flexDirection="column" rowGap="8px">
        <Plot xaxis="x" yaxis="signal" zoom>
            <Plot.Clip><PlotLine xs={xs} ys={signal} /></Plot.Clip>
        </Plot>
        <Plot xaxis="x" yaxis="error" zoom>
            <Plot.Clip><PlotLine xs={xs} ys={error} /></Plot.Clip>
        </Plot>
    </layout.FlexBox>
</Figure>

show: 'one' suppresses duplicate axis labels when panels share an axis — only the outermost panel renders it.

Core Concepts

Axes

Each axis is declared as a ScaleSpec in the scales map passed to <Figure>:

| Property | Type | Description | |---|---|---| | domain | [number, number] | Data range | | size | string \| number | CSS length or solver variable expression | | show | boolean \| 'one' | Whether to render the axis; 'one' shows it only on the first/last panel in a grid | | translateExtent | [number, number] \| boolean | Pan boundary; true clamps to domain | | label | string | Axis label text |

Scales

Standalone scale constructors are available for use outside the component tree:

import { linear, log } from '@hexane/plotlib/scale';

const s = linear([0, 100], [0, 500]);   // data → pixels
s.transform(50);                         // → 250
s.ticks(5);                              // → [0, 25, 50, 75, 100]

const color = linear([0, 1], ['blue', 'red']);
color.transform(0.5);                    // → interpolated color string

Layout

The layout export exposes the constraint-based layout primitives directly, for building custom compositions:

| Component | Purpose | |---|---| | layout.FlexBox | Flex-like arrangement of child plots | | layout.MarginBox | Adds fixed or proportional margins | | layout.Centered | Centers content within parent bounds | | layout.Decorated | Attaches decorations (axis, label) to any edge | | layout.Constrained | SVG root; feeds container size into the solver |

Theming

Components ship with default styles via CSS modules. There are four ways to override them, from narrowest to broadest scope:

1. className / classNames props — per-instance overrides. Simple components accept className; compound components (e.g. Plot) also accept classNames to target named sub-elements:

<PlotLine xs={xs} ys={ys} className="my-line" />

<Plot xaxis="x" yaxis="y" classNames={{ box: 'custom-box' }}>

2. Global CSS via static prefix classes — every component receives a static plotlib-<Component>-<sub> class that can be targeted from any stylesheet without touching props:

.plotlib-PlotLine-root { stroke: steelblue; stroke-width: 2; }

3. ThemeProvider — applies classNames or defaultProps to all instances of a component within the subtree:

<ThemeProvider theme={{
    components: {
        PlotLine: { classNames: 'my-line' },
        Plot: { defaultProps: { zoom: true } },
    }
}}>
    <Figure scales={scales}>...</Figure>
</ThemeProvider>

4. unstyled — strips the default CSS-module class from a single component, leaving interactions and className props intact:

<PlotLine xs={xs} ys={ys} unstyled className="my-line" />

The classNamesPrefix option on ThemeProvider lets you change the plotlib- prefix to namespace classes for your application.

Components

PlotImage

Renders a colormapped bitmap image aligned to data coordinates. The image is drawn onto a canvas at the specified resolution and composited into the SVG.

const scales = new Map<string, ScaleSpec>([
    ['x', { domain: [0, 1], size: '400px' }],
    ['y', { domain: [0, 1], size: '400px' }],
    ['color', { scale: linear([0, 1], ['blue', 'red']) }],
]);

<Figure scales={scales}>
    <Plot xaxis="x" yaxis="y">
        <Plot.Clip>
            <PlotImage img={data} scale="color" width={256} height={256} />
        </Plot.Clip>
    </Plot>
</Figure>

| Prop | Type | Description | |---|---|---| | img | number[][] \| ArrayLike<number> | Row-major image data | | scale | string | Key of a color axis declared on <Figure> | | width | number | Canvas pixel width | | height | number | Canvas pixel height | | xlim | [number, number] | Data bounds along x; defaults to the x-axis domain | | ylim | [number, number] | Data bounds along y; defaults to the y-axis domain |

Colorbar

An axis-aligned colorbar that reads from a color axis declared on <Figure>. Place it inside a <Plot> or alongside one using layout.Decorated.

import { Figure, Plot, PlotImage } from '@hexane/plotlib';

<Figure scales={scales}>
    <Plot xaxis="x" yaxis="y" colorbar="color" zoom>
        <Plot.Clip>
            <PlotImage img={data} scale="color" width={256} height={256} />
        </Plot.Clip>
    </Plot>
</Figure>

TextBox

A rotatable SVG text element with alignment control. Used internally for axis labels; also available for annotations.

| Prop | Type | Description | |---|---|---| | ha | 'left' \| 'center' \| 'right' | Horizontal alignment; defaults to 'center' | | va | 'top' \| 'center' \| 'bottom' | Vertical alignment; defaults to 'center' | | rotation | number | Rotation in degrees about the element's centre |

ThemeProvider

Wraps a subtree with a custom theme. Components read style defaults from the nearest ThemeProvider.

import { ThemeProvider } from '@hexane/plotlib';

<ThemeProvider theme={{ components: { PlotLine: { defaultProps: { stroke: 'red' } } } }}>
    <Figure scales={scales}>...</Figure>
</ThemeProvider>

| Prop | Type | Description | |---|---|---| | theme | ThemeOverride | Partial theme to apply | | inherit | boolean | Whether to merge with the parent theme; defaults to true |

Development

# build the library
npm run build

# watch mode
npm run watch

# run tests
npm run test

# view storybook
npm run storybook

The examples/simple_plots directory contains a Vite app that imports from the local build and is a convenient testbed during development.

Further Reading

  • ARCHITECTURE.md — component hierarchy, scale system, layout engine, zoom system, and context/atom graph
  • TODO.md — planned features and known cleanup items