Browse documentation
aner.plot

Aner Plot

Compose native scientific charts, offline USA and world maps, reusable light, dark and company themes, and SVG outputs beside their notebook analysis.

Implemented in development

import aner.plot brings scientific charts, offline geographic maps, reusable themes and SVG export into the native Aner workflow. Compose immutable chart values with ordinary method chains, then display them beside the analysis they explain.

Development availability: this module requires a chart enabled native Aner 0.0.2-dev.1 build and development VS Code extension 0.1.46 for notebook display. The published 0.0.2 runtime and 0.1.45 extension predate this feature. Development packages are not offered on this website. A matching runtime remains necessary even when an extension is installed. See release and development status.

Start with the complete example

Download the Aner source or the VS Code notebook. With a compatible installed aner command, check and run the source:

sh
aner check plot_story.aner
aner run plot_story.aner

The source emits nine charts: a comparison line, scatter, bar, histogram, box, heatmap, a custom geographic join, world map and USA map. It needs no external dataset, connection or credentials. All values are synthetic teaching data. Command line execution emits the chart display data; use the notebook to view each chart beside its producing cell, or call .save("fresh-chart.svg") to export one.

Open the notebook in VS Code, select the compatible Aner runtime, restart the notebook session and choose Run All. The notebook also shows a dark version of the same comparison chart. Its setup cell stores values without drawing a chart. Subsequent chart expressions and .show() calls produce outputs below their own cells, including two separate outputs in the distribution cell.

API reference

Chart constructors return a Chart; the plot.geojson loader returns String text. Supply finite numeric List, Array, DynamicArray, NDArray or Tensor inputs. Series accept vectors; heatmaps accept a flat sequence with explicit dimensions or a matching matrix. Numeric lists may mix Int64 and Float64. Strings, Booleans, nulls and nonfinite values are rejected as numeric observations. Integers outside the exact Float64 range from negative 2^53 through positive 2^53 are rejected.

ConstructorInput and meaning
plot.line(x: Any, y: Any)Equal length coordinates, connected in supplied order
plot.scatter(x: Any, y: Any)Equal length coordinates, one point per observation
plot.bar(labels: List, values: Any)String categories and their supplied numeric values
plot.histogram(values: Any, bins: Int64)Counts in equal width bins; omitted bins defaults to 10
plot.box(values: Any)Observed median, quartiles, whiskers and outliers
plot.heatmap(values: Any, rows: Int64, columns: Int64)Numeric cells in row major order, matching the declared shape
plot.choropleth(geojson: String, property: String, keys: List, values: Any)Explicit String key join to supplied GeoJSON regions
plot.world(keys: List, values: Any)Offline world regions joined by Natural Earth ADM0_A3
plot.usa(keys: List, values: Any)Offline states and DC joined by uppercase postal code
plot.geojson(path: String)Read bounded local GeoJSON text for a custom choropleth
aner
import aner.plot
let weeks = List(1.0, 2.0, 3.0, 4.0)
let response = List(12.0, 15.0, 14.0, 19.0)
let trend = plot.line(x: weeks, y: response)
    .title("Response increased in this synthetic example")
    .labels(x: "Week", y: "Response (arbitrary units)")
    .caption("Synthetic measurements; four observations, no causal claim.")
    .annotate(x: 4.0, y: 19.0, text: "Last observation")
trend.show()

Construction snapshots the inputs. Later collection mutations do not change an existing chart. Sort time coordinates deliberately: a line follows the given order. Bars do not aggregate a table, and histograms report counts rather than probability density. Explicitly collect and filter the desired data before constructing a chart.

Axes and color scales disclose shared numeric offsets or powers of ten when close values have large magnitudes. Tooltips retain the full actual values so compact labels do not hide the supplied measurements.

Box quartiles use linear interpolation at sorted position (n - 1) * p. Whiskers reach observed values within 1.5 interquartile ranges; points beyond them are drawn individually. Whiskers describe sample spread, not confidence intervals. Histogram bins include their left boundary and exclude their right boundary, except the final bin includes the maximum.

Compose a clear scientific story

Every modifier returns another chart. Retain the result with an assignment or chain. There is no implicit current figure and no global plotting theme.

MethodResult
.title(text: String)Set a supported takeaway
.labels(x: String, y: String)Name variables and units
.caption(text: String)Record source, population, exclusions and uncertainty definition
.annotate(x: Float64, y: Float64, text: String)Mark a supplied data coordinate
.add_line(x: Any, y: Any, name: String)Add a named line to a line or scatter chart
.theme(theme: ChartTheme)Attach an immutable presentation snapshot
.size(width: Int64, height: Int64)Choose bounded SVG dimensions
.show()Emit one chart output for the current execution
.svg()Return the SVG as String
.summary()Return a plain text chart description
.save(path: String)Write a new SVG file; existing files are not replaced

Company theme and named comparison

Company theme: synthetic observed and reference responses, with labels, a legend and annotation

aner
let corporate = plot.theme("light").company(
    name: "Example Research",
    background: "#FFFFFF",
    foreground: "#17233B",
    colors: List("#007C91", "#C6601D", "#6950A1")
)
let comparison = trend
    .add_line(weeks, List(10.0, 12.0, 13.0, 14.0), name: "Reference")
    .theme(corporate)
comparison.show()

The gallery uses the six observations in the complete notebook; the shorter code above uses four. Reference values are supplied rather than fitted. The company name identifies the theme; it does not add a logo. Include the organization in the title or caption when the artwork must show it.

Light, dark and custom palettes

plot.theme("light"), plot.theme("dark") and plot.theme("auto") return ChartTheme. Explicit light and dark choices are stable presentation decisions; auto follows the host where supported. Attach a theme per chart so execution order does not silently change later figures.

aner
let dark = plot.theme("dark").palette(
    colors: List("#79D2E0", "#FFBC78", "#C6ACFF")
)
comparison.theme(dark).show()
comparison.theme(plot.theme("light")).show()

Dark theme: the same synthetic comparison with a dark background and custom palette

Theme colors use checked hexadecimal values. Palette and company modifiers return new theme values. Legends, labels and annotations should explain meaning alongside color. A valid hexadecimal palette is not a contrast certification or evidence of perceptual uniformity.

Light theme: a histogram with four bins and observed counts for six synthetic values

Offline USA and world maps

Bundled Natural Earth 1:110m boundaries require no online tiles, geocoding or map service. plot.world joins Natural Earth ADM0_A3 codes such as USA, CAN, FRA and NOR. These codes are not strictly ISO country codes; this source also includes KOS and SOL. Its 177 features follow the source geographic grouping rather than defining a sovereign country count.

aner
plot.world(keys: List("USA", "CAN", "FRA"), values: List(12.0, 9.0, 15.0))
    .title("Synthetic values on an offline world map")
    .caption("Synthetic values; boundaries: Natural Earth 1:110m.")
    .show()

World map: supplied synthetic values for USA, Canada and France, with all other regions marked as no data

plot.usa joins uppercase two letter postal codes for 50 states and the District of Columbia. Alaska and Hawaii retain their geographic positions; this is not a relocated inset map or county catalogue.

aner
plot.usa(keys: List("CA", "CO", "NY", "TX"), values: List(18.0, 12.0, 15.0, 9.0))
    .title("Synthetic values for four USA states")
    .caption("Synthetic values; other states have no data, not zero.")
    .theme(corporate)
    .show()

USA map: synthetic values for California, Colorado, New York and Texas in the company theme, with other states marked as no data

For custom boundaries, load licensed local GeoJSON with plot.geojson(path: "regions.geojson"), then join a stable String property with plot.choropleth. GeoJSON coordinates are longitude, latitude, in that order. Polygon holes and MultiPolygon parts are supported. Preserve identifiers with leading zeros. Confirm join coverage, denominators and geographic vintage before interpreting results. Missing regions are no data, never fabricated zeros.

The initial projection is an equirectangular preview with limited cartographic control. Do not infer area or distance. Supplied rings crossing the antimeridian must already be split; unsplit edges are rejected except the legitimate Antarctic pole boundary.

Boundary source and attribution

Made with Natural Earth, whose terms of use place the geographic data in the public domain. Credit includes Tom Patterson, Nathaniel Vaughn Kelso and contributors. The bundled source is fixed at commit ca96624a56bd078437bca8184e78163e5039ad19, June 2, 2022. The official 110m layer pages identify version 5.1.1; the repository version at that commit reads 5.2.0-pre.

Boundary fileFeaturesSHA256
world-110m.geojson1776866c877d39cba9c357620878839b336d569f8c662d3cfab4cb1dbe2d39c977f
usa-110m.geojson510067dec6a2c4f9c7a644bf7a9a46163d8d881595953326d0c67d89934190aefe

Notebook placement and export

Use .show() in the cell whose analysis the chart supports. Each call emits a separate output in execution order. In a shared native notebook session, a bare chart expression also displays; let stores a chart without displaying it. Inside loops and functions, call .show() explicitly. Put explanatory Markdown immediately before or after the producing cell.

Notebook outputs are saved historical results. Editing code or changing later values does not recompute a chart. Restart and run cells in order to verify a fresh analysis. Saving SVG outputs does not preserve live runtime variables. The optional native Jupyter adapter uses the same SVG through its MIME display mechanism.

For a shareable figure, call comparison.save("response-comparison.svg") with a fresh filename. SVG keeps marks and text scalable. Native PNG and PDF exporters, font embedding, animation and interactive selection are not implemented.

Errors, bounds and next steps

Mismatched lengths, unsupported ranks, invalid colors, nonfinite values and malformed geometry produce diagnostics. Data ingestion, table aggregation, fitting and uncertainty estimation remain explicit upstream decisions.

Limits are 100,000 observations, 32 series, 250 bar categories or histogram bins, 10,000 heatmap cells, 10,000 geographic features or joins, 100 annotations and 32 palette colors per chart. Text permits 4,096 UTF-8 bytes. Width ranges from 320 to 4,096 pixels, and height from 240 to 4,096 pixels. GeoJSON permits 8 MiB and 100,000 coordinates within parser limits. SVG output is bounded to 32 MiB; notebook envelopes additionally permit at most 64 charts and 4 MiB per cell. Exceeding a bound produces a diagnostic instead of silent sampling.

The implemented families are line, scatter, bar, histogram, box, heatmap and choropleth. World and USA are convenience constructors for choropleths. Figure grids, facets, temporal scales, statistical intervals, sequential and diverging scale controls, additional geographic projections, 3D and further exporters remain future work.

Aner documentation · Reference and guides