A plotting library written in MoonBit. Create figures, add charts and annotations, and export self-contained SVG for reports, documentation, and applications.
MoonPlot focuses on useful plotting features that can grow incrementally. Its API takes inspiration from Matplotlib, with typed MoonBit data and an SVG rendering pipeline.
View the SVG · Run this example
- Everyday charts: line, scatter, grouped/stacked bars, histogram, pie/donut, box, and violin plots.
- Scientific plots: error bars, filled regions, contours, triangulated meshes, vector fields, and stream plots.
- Polar plots: radial lines, scatter points, rose bars and closed radar outlines with category labels, angle direction, radial ticks, and circular clipping.
- Images and color: scalar and RGB(A) images, heatmaps, color maps, normalization, masks, and colorbars.
- Figure composition: multiple axes, shared axes, nested grids, secondary axes, titles, labels, legends, tables, and annotations.
- Axes and data: numeric scales, explicit ticks and formatters, date/time coordinates, time zones, and categorical labels.
- Editable lines: data updates, visibility, color, alpha, line width,
draw styles, dashes, and gap colors through
Line2Dhandles. - SVG output: render a figure to a string without a Python runtime.
- Rabbita components: an optional JS adapter provides real SVG DOM nodes, point and region hover, line x snapping, selection, legend buttons, reactive data updates, scoped SVG resources, and customizable semantic tooltips.
- Statistical interactions: error arms/caps, confidence and stacked-area interiors, and boxplot bodies/whiskers/outliers expose typed ranges and statistics. See the statistics guide.
- Matrix and bin interactions: nearest scalar images and flat rectangular meshes expose original row, column, value and data intervals across whole cells; 2D histograms expose both bin intervals and their original counts. See the mesh guide.
- Distribution interactions: hexagonal bins expose counts and aggregation values across their actual faces; violin bodies expose KDE samples and statistical strokes. See the hexbin and violin guides.
Support varies by chart and option. See the usage guide for examples and the current capabilities and API behavior notes for detailed boundaries.
MoonPlot uses the Lampese/mathplotlib@0.18.0 module. See publication status and installation instructions.
From your application's module directory, add it with:
moon add Lampese/mathplotlib@0.18.0Import Lampese/mathplotlib for static plotting, and add
Lampese/mathplotlib/rabbita when composing browser components. Both packages
come from the same installation. The package alias @mathplotlib and plotting
method names stay the same. Installing this module resolves its declared
Rabbita dependencies too; the core plotting packages do not import UI types.
Install the MoonBit toolchain. The native example also requires a working C compiler.
git clone https://github.com/moonbit-community/moonplot.git
cd moonplot
moon run cmd/preview --target native > chart.svg
moon build rabbita/cmd/demo --target js
python3 -m http.server 8765 --bind 127.0.0.1Open chart.svg in a browser or SVG viewer. Open
the interactive example for hover, selection,
legend toggles and data updates. Serve the repository root so the example can
load its built JavaScript; stop the server with Ctrl+C.
Moon resolves the declared dependencies when building. Run moon update if
your local registry index needs refreshing.
The checked-in PNG above is a preview of the SVG output. MoonPlot does not currently provide standalone PNG export.
The project is named MoonPlot and its module ID is Lampese/mathplotlib.
When migrating from the earlier source release, replace the old
mathplotlib/mathplotlib prefix with Lampese/mathplotlib. Existing
@mathplotlib calls remain valid; see the path migration notes.
A package using the library imports the root plotting API in moon.pkg:
///|
import {
"Lampese/mathplotlib",
}Create a figure, choose its axes, add data, and request SVG output. This compact example uses explicit limits and ticks:
///|
fn main raise {
let fig = @mathplotlib.figure(width=640, height=400)
fig.set_title("A MoonPlot chart")
fig.set_x_label("Sample")
fig.set_y_label("Value")
fig.set_x_limits(0.0, 4.0)
fig.set_y_limits(0.0, 20.0)
fig.set_x_ticks([0.0, 1.0, 2.0, 3.0, 4.0])
fig.set_y_ticks([0.0, 5.0, 10.0, 15.0, 20.0])
fig.set_x_tick_labels(["0", "1", "2", "3", "4"])
fig.set_y_tick_labels(["0", "5", "10", "15", "20"])
fig.plot(
[0.0, 1.0, 2.0, 3.0, 4.0],
[3.0, 7.0, 5.0, 13.0, 17.0],
color="#2563eb",
label="Measurements",
)
fig.legend(fig.legend_entries())
println(fig.to_svg_checked())
}Use the object API for individual figures and axes, or the
pyplot package for a stateful facade.
For mutable line data and appearance, plot_line returns a Line2D handle.
The complete two-series example is in cmd/preview.
The checked rendering APIs propagate data, tick, and layout errors so callers can handle them. The first usable milestone records the workflows checked for basic SVG output; more complex combinations continue to evolve.
moon run cmd/gallery --target native > gallery.svgThis example combines line, scatter, and categorical bar charts with automatic
ranges and ticks. Set a legend corner with
axes.set_legend_position(@mathplotlib.LegendPosition::UpperLeft).
UpperRight (the default), LowerLeft, and LowerRight are also available.
Figure::to_drawing() prepares the SVG and data-point hit locations together.
The rabbita package turns that snapshot into composable
Rabbita Html using public SVG node constructors. Add it to your application's
moon.pkg with an explicit alias:
///|
import {
"Lampese/mathplotlib",
"Lampese/mathplotlib/rabbita" @plot_dom,
"moonbit-community/rabbita",
}The application owns hover, selection, visibility and data state. The browser
package declares supported_targets = "js"; the core facade, Scene, Drawing
and static renderer keep their platform-independent interfaces. No separate
adapter module or local workspace is needed. See the component guide
for a complete view and the DOM notes for tested behavior.
The tooltip guide covers full-bar hit regions, line samples selected by horizontal position, histogram bins and pie slices, and application-defined units, dates, labels and styling. Run the six-chart example:
moon build rabbita/cmd/tooltips --target jsWith the repository served as above, open
the tooltip examples.
Use hit_mode=XNearest to opt into line x snapping; existing calls keep nearest-point picking.
moon build rabbita/cmd/distributions --target jsOpen the four-chart distribution example to inspect counts, custom reductions, KDE density samples and statistical parts. Version 0.7.0 also corrects the earlier hexbin partition: point assignment and polygon vertices now share the same hexagonal lattice. Hexbin centers, counts, aggregation groups and SVG geometry can change; see the compatibility details.
moon build rabbita/cmd/discrete --target jsOpen the four-chart discrete example to switch step alignment and stairs orientation, inspect weighted CDF/CCDF jumps, and try independent legends and data updates. Tooltips retain original samples, directed intervals and the probabilities returned by the existing ECDF calculation. See the step, stairs and ECDF guides for exact identities and supported geometry.
moon build rabbita/cmd/stems --target jsOpen the three-chart stem example to inspect original samples along a rod or at its head. Vertical and horizontal stems retain signed values and nonzero baselines; missing samples keep their original indices. The example also combines stems with a confidence band. See the stem guide for source identities and clipping.
moon build rabbita/cmd/vectors --target jsOpen the vector example to inspect original X/Y positions and signed U/V components along the actual shaft and both arrow wings. Zero vectors preserve later input indices; clipped strokes retain the original source position. A second chart overlays vectors on a reference band. See the Quiver guide.
moon build rabbita/cmd/barbs --target jsOpen the wind example to inspect the shaft, feathers, filled flags and calm disks. Tooltips retain original input positions, indices and signed U/V, including nonzero vectors rounded to calm. The second card switches the existing anchor, feather direction and calm visibility options. See the Barbs guide.
moon build rabbita/cmd/contours --target jsOpen the contour example to inspect regular-grid and triangular level curves. Actual visible strokes expose the exact level and original series, including both fragments around inline labels. The contour guide explains generated path indices, clipping and geometry midpoint anchors.
moon build rabbita/cmd/filled_contours --target jsOpen the filled contour example to inspect nested bands and separate islands. Tooltips show the scalar interval, representative value and original series. Whole-region picking preserves holes, the original band slots and the space between islands through data and mask updates. See the filled contour guide.
moon build rabbita/cmd/triangles --target jsOpen the triangular mesh example to inspect original face values or vertex arithmetic means. Whole-face picking preserves masked gaps, original face indices and ordered vertex triples through normalization, data and visibility updates. Default and Chinese custom tooltips share the same typed metadata. See the tripcolor guide.
moon build rabbita/cmd/streamlines --target jsOpen the streamplot example to inspect U/V field samples along continuous body strokes. The same frame retains the original seed and generated-edge indices, with optional raw color values before normalization. Default and Chinese custom tooltips update with the field and style grids. See the streamplot guide for generated midpoint semantics and the static arrow boundary.
moon build rabbita/cmd/polar --target jsOpen the polar and radar example
to change data, switch angle direction, toggle each series, and remount both
charts. Figure::add_polar_axes accepts raw angles in radians and nonnegative
radii. Radar profiles retain their original categories and share one radial
scale. Both SVG and Rabbita DOM use a true circular clip in rectangular panels.
Hover or click anywhere inside a filled rose sector to read its original
angle and radius. PolarAxes::bar takes an explicit angular width in radians.
Line/scatter and radar observations use physical sample proximity; all picking
stays inside the actual circle. See the polar guide.
- SVG is the static output backend; Rabbita DOM is an optional browser component. Standalone PNG/PDF export and a desktop GUI backend are not available.
- Interactive picking includes line/scatter anchors, bar and histogram regions, pie/donut sectors, matrix cells, statistical areas, distribution parts, discrete curves, stems, quiver arrows, wind barbs, line contours, filled contour bands, triangular faces, continuous streamline bodies and original polar samples. Touch gestures, zoom/pan, and keyboard navigation remain future work.
- 3D plotting, animation, and full mathtext/TeX and font layout are not available.
- The library is not a drop-in Matplotlib implementation. Python's dynamic argument forms and every chart parameter are not reproduced.
- SVG text uses the viewer's fonts; full text measurement and typography remain limited.
- Documentation index
- Detailed usage and API examples
- Current capabilities and milestone acceptance
- Installation, module paths and release status
- M2 interactive plotting and source-release history
- Filled contour regions and holes: completed M12
- Triangular face values and vertex means: completed M13
- Continuous streamline field samples: completed M14
- Polar plots and radar outlines: completed M15
- Delivered M16: original polar values and circular picking
- Polar bars and rose plots: 0.18.0 acceptance
- Four capability goals
- Rabbita interactive DOM and acceptance
- Dependencies and integration notes
- Third-party licenses and attribution
The root package provides the common plotting facade. Implementation packages
include scene for figure and artist state, ticker for axes and date handling,
transforms for geometry, and backend/svg for rendering.
The facade is kept in api.mbt, consumer tests in tests/api,
and isolated configuration tests in tests/integration.
See the source organization guide for package boundaries,
generated resources, and reference fixtures.
From the repository root:
python3 tools/check_structure.py
moon check --target all
moon test --target all
python3 tools/update_interfaces.py
moon fmtTests include unit tests, public API examples, SVG checks, and source-reference
fixtures. Guides under testdata/ describe their supported domains
and reproduction steps. Python is used by some fixture generators, not by the
plotting runtime.
When changing public APIs, review the generated pkg.generated.mbti diffs.
Keep examples and capability notes aligned with the behavior that is tested.
Licensed under the Apache License 2.0.
Some algorithms and behavior are adapted from the pinned Matplotlib v3.11.2 source and retain its license. Other dependencies and bundled data retain their own licenses; see Third-Party Notices.












