On this page
inklet API reference¶
Public names exported by inklet, in package order, with signatures and short
descriptions. Use help(inklet.link), for example, to read the full docstring.
The stable subpackages inklet.volume, inklet.selection,
inklet.project and inklet.editor follow; import inklet does not import
them, so import each one you use.
Numeric drawing lengths use millimetres. Many dimension arguments also
accept strings such as "89mm" or "2in"; pt(9) converts 9 points to
millimetres. Composition preserves child handles: combinators wrap drawings
in parent nodes, so handles created before layout still resolve in the figure.
One-call charts¶
class Chart(*, width=None, height=None, style='scientific.modern', font_pt=None, palette=None, title=None, xlabel=None, ylabel=None, xlim=None, ylim=None, xscale='linear', yscale='linear', legend='auto', grid=None, xticks=None, yticks=None, xminor=None, yminor=None, xformat=None, yformat=None, aspect=None)¶
One plot: marks on shared axes, with a size and a preset.
line(data=None, x=None, y=None, *, color=None, name=None, markers=False, error_y=None, dash=None, linewidth=None, sort=True, gaps='break', secondary_y=None, simplify='auto', marker_size=None, marker=None, **style)-- Lines through (x, y), one percolorgroup or perycolumn.scatter(data=None, x=None, y=None, *, color=None, size=None, name=None, marker='circle', palette=None, error_y=None, text=None, secondary_y=None, raster=None, **style)-- Points at (x, y). A numericcolorcolumn with many values is a ramp.bar(data=None, x=None, y=None, *, color=None, name=None, orient='v', stacked=False, error_y=None, labels=None, agg=None, points=False, **style)-- Bars ofyat eachxcategory;colorgroups side by side or stacked.hist(data=None, x=None, *, color=None, bins=20, density=False, name=None, cumulative=False, **style)-- Histogram ofx; one overlaid histogram percolorgroup.kde(data=None, x=None, *, color=None, fill=False, name=None, **style)-- Kernel density estimate ofx, one curve percolorgroup.ecdf(data=None, x=None, *, color=None, name=None, **style)-- Empirical cumulative distribution ofx, one step percolorgroup.boxplot(data=None, x=None, y=None, *, color=None, points=False, **style)-- Box plot ofyin eachxcategory;orient='h'lays the boxes across.violin(data=None, x=None, y=None, *, color=None, points=False, **style)-- Violin plot ofyin eachxcategory;orient='h'lays the violins across.strip(data=None, x=None, y=None, *, color=None, **style)-- Jittered points ofyin eachxcategory;orient='h'lays them across.area(data=None, x=None, y=None, *, color=None, stacked=True, **style)-- Filled areas undery; groups stack unlessstacked=False.regression(data=None, x=None, y=None, *, color=None, method='linear', confidence=0.95, equation=False, name=None, **style)-- Points with a fitted line and its confidence band, percolorgroup.heatmap(data=None, x=None, y=None, z=None, *, palette='viridis', center=None, colorbar=True, colorbar_title=None, **style)-- A matrix of colour cells.colorbaris True, False or the bar's title.survival(data=None, time=None, event=None, *, color=None, at_risk=True, pvalue=True, band='log-log', confidence=0.95, censors=True, **style)-- Kaplan-Meier survival curves:timedurations andeventflags, one curve percolorgroup.volcano(data=None, x=None, y=None, *, label=None, labels=None, highlight=None, q=None, **style)-- A volcano plot:xthe log2 fold change,ythe raw p-value, one point per row.forest(data=None, label=None, estimate=None, lower=None, upper=None, *, weight=None, summary=None, left=('label',), right=('ci',), log=False, null=None, limits=None, measure='Estimate', digits=2, **style)-- A forest plot: one row per study, with its estimate and confidence interval.pie(data=None, names=None, values=None, *, hole=0, labels='percent')-- A pie chart: one slice per row, sized byvalues, in row order.lollipop(data=None, x=None, y=None, *, color=None, orient='v', **style)-- One value per category as a dot on a stem from zero: a lighter bar chart.dumbbell(data=None, y=None, x=None, **style)-- Two values per category joined by a line: before and after, for instance.waterfall(data=None, x=None, y=None, *, totals=(), labels=True, **style)-- Changes as bars floating on a running total: a waterfall chart.slope(data=None, x=None, y=None, group=None, *, labels='both', format=None, highlight=None, **style)-- Each group's values at two or more time points, joined by a straight line.labels(*, x=None, y=None, title=None, y2=None)-- Set axis titles and the chart title (all optional).colorbar(**options)-- Draw the colour bar, or update the one already drawn.legend(**options)-- Draw the key, or update the key already recorded.twin_y(*args, **kwargs)-- Not on a quick chart: usesecondary_y=for a right-hand axis.twin_x(*args, **kwargs)-- Refused, for the same reason astwin_y: a quick chart has one x axis.size(width=None, height=None)-- Width as 'single', 'double', 'slide' or millimetres; height in mm.plot(width=None, profile=None, rotate=False, colours=None, slots=None, title=None, shared_key=False, lettered=False, cell=None)-- ThePlotSpecwith axes, legend and title applied, for a document cell.document(rotate=frozenset(), below=frozenset())-- ADocumentholding this chart, sized and styled; add cells to grow it.compile()-- Measure and place everything; returns aCompiledFigure.report(**options) -> 'str'-- Layout and print diagnostics: overlaps, clipped text, small type.save(*paths, **options)-- Save to each path; the extension picks SVG, PDF or PNG.show(path=None)-- Display in a notebook, or write an SVG and print where it went.to_pdf(**options) -> 'bytes'to_png(**options) -> 'bytes'to_svg(**options) -> 'str'
class Layout(direction, items, *, width=None, style=None, letters=True, columns=None, palette=None, font_pt=None, grid=None)¶
Charts side by side (a | b) or stacked (a / b), with panel letters.
options(**settings)-- Set this layout's options and return it:(a | b).options(style='scientific.nature', palette='okabe-ito', font_pt=8).charts()document(rotate=frozenset(), below=frozenset())-- ADocumentwith one lettered cell per chart.hline(y, *, data=None, **options)-- A horizontal reference line in every panel, or a value per facet; returns the layout.vline(x, *, data=None, **options)-- A vertical reference line in every panel, or a value per facet; returns the layout.compile()-- Measure and place everything; returns aCompiledFigure.report(**options) -> 'str'-- Layout and print diagnostics: overlaps, clipped text, small type.save(*paths, **options)-- Save to each path; the extension picks SVG, PDF or PNG.show(path=None)-- Display in a notebook, or write an SVG and print where it went.to_pdf(**options) -> 'bytes'to_png(**options) -> 'bytes'to_svg(**options) -> 'str'
class LayoutWarning¶
A saved chart has layout problems; the message is its lint report.
chart(**options) -> 'Chart'¶
An empty chart to add marks to: inklet.chart(title='...').line(...).
line(data=None, *args, **options)¶
Lines through (x, y), one per color group or per y column.
scatter(data=None, *args, **options)¶
Points at (x, y). A numeric color column with many values is a ramp.
bar(data=None, *args, **options)¶
Bars of y at each x category; color groups side by side or stacked.
hist(data=None, *args, **options)¶
Histogram of x; one overlaid histogram per color group.
boxplot(data=None, *args, **options)¶
Box plot of y in each x category; orient='h' lays the boxes across.
violin(data=None, *args, **options)¶
Violin plot of y in each x category; orient='h' lays the violins across.
strip(data=None, *args, **options)¶
Jittered points of y in each x category; orient='h' lays them across.
kde(data=None, *args, **options)¶
Kernel density estimate of x, one curve per color group.
ecdf(data=None, *args, **options)¶
Empirical cumulative distribution of x, one step per color group.
area(data=None, *args, **options)¶
Filled areas under y; groups stack unless stacked=False.
heatmap(data=None, *args, **options)¶
A matrix of colour cells. colorbar is True, False or the bar's title.
regression(data=None, *args, **options)¶
Points with a fitted line and its confidence band, per color group.
survival(data=None, *args, **options)¶
Kaplan-Meier survival curves: time durations and event flags, one curve per color group.
volcano(data=None, *args, **options)¶
A volcano plot: x the log2 fold change, y the raw p-value, one point per row.
pie(data=None, *args, **options)¶
A pie chart: one slice per row, sized by values, in row order.
lollipop(data=None, *args, **options)¶
One value per category as a dot on a stem from zero: a lighter bar chart.
dumbbell(data=None, *args, **options)¶
Two values per category joined by a line: before and after, for instance.
waterfall(data=None, *args, **options)¶
Changes as bars floating on a running total: a waterfall chart.
slope(data=None, *args, **options)¶
Each group's values at two or more time points, joined by a straight line.
from_matplotlib(figure, *, width=None, style='scientific.modern', palette=None, keep_colors=False, letters=True)¶
Convert a matplotlib Figure (or one Axes) into an inklet chart or layout.
class MatplotlibWarning¶
Parts of a matplotlib figure that the bridge did not convert.
rendering_capabilities()¶
Declared format support; no renderer is selected implicitly.
class RenderScene(root: 'SceneNode', bbox: 'Rect', stats: 'Mapping', changes: 'tuple[SceneChange, ...]', _nodes: 'Mapping', _resources: 'Mapping', _images: 'Mapping', _fonts: 'Mapping') -> None¶
A compiled native scene shared by SVG, PDF and PNG exports.
walk()validate_fonts()font_manifest()-- Return the captured font inventory without rereading font files.sources_current()-- Check external inputs when a document considers reusing a snapshot.to_svg(**options)to_pdf(**options)to_png(**options)to_html(*, title='Inklet figure', backend='auto', **options)-- Offline HTML viewer; WebGL2 filled markers, Canvas fallback, SVG art.damage_bounds(previous: 'RenderScene')-- Conservative old/new ink union for changed placements, in page mm.
compile_scene(root: 'Diagram | RenderScene', *, previous: 'RenderScene | None' = None) -> 'RenderScene'¶
Resolve a drawing for all native backends, reusing an optional revision.
class FontEmbeddingWarning¶
A PDF asked for live text drew some of it as outlines.
class Suite(name: 'str', *, base: 'object' = 'scientific.nature', font: 'str' = 'Helvetica, Arial, Liberation Sans, sans-serif', allowed_fonts: 'tuple[str, ...] | None' = None, ink: 'str | None' = None, paper: 'str' = '#ffffff', type: 'TypeScale' = <factory>, lines: 'LineWeights' = <factory>, markers: 'MarkerStyle' = <factory>, letters: 'LetterStyle' = <factory>, text: 'TextRules' = <factory>, palettes: 'Mapping[str, object]' = <factory>, ramps: 'Mapping[str, object]' = <factory>, widths: 'Mapping[str, float]' = <factory>, export: 'Export' = <factory>, lint: 'Mapping[str, object]' = <factory>) -> None¶
A figure set's house style: fonts, type, line weights, markers, colours, letters, text rules, widths, export and lint. Build one with suite().
customize(**changes) -> "'Suite'"-- A copy with fields replaced. A dict for one of the nested style fields (type,lines,markers,letters,text,export) merges into it:customize(lines={"data": 0.5})keepsfitandaxis.palettes,ramps,widthsandlintare replaced whole.font_families(*, allowed: 'bool' = False) -> 'tuple[str, ...]'-- The families infont(orallowed_fonts), generic names dropped.fonts() -> 'dict[str, dict]'-- How each face the suite sets resolves on this machine: file, family, and whether a PDF can embed it as live text.size(role: 'str') -> 'float'-- A type size in mm: 'tick', 'label', 'key', 'note' or 'letter'.stroke(tier: 'str' = 'data') -> 'float'-- A line weight in mm by tier name ('data', 'fit', 'axis' or an extra).width(name: 'str | float' = 'double') -> 'float'-- A named page width in mm ('single', 'double', ...), or a number as is.palette(name: 'str')-- A categorical palette as given: {key: colour} or a tuple.color(key: 'str', palette: 'str | None' = None) -> 'str'-- The colour ofkey: frompalette, or the first palette that has it; a colour string is returned unchanged.ramp(name: 'str') -> 'Callable[[float], str]'-- A sequential map as a function of t in [0, 1]. Ordinal dict ramps are sampled along their keys in order.stops(name: 'str') -> 'dict'-- An ordinal ramp's fixed {key: colour} stops.text_color(color: 'str') -> 'str'--colordeepened along its own lightness until text in it reachestext.label_contraston the paper; hue is kept. A grey becomes ink.mark_color(color: 'str') -> 'str'-- A marker colour:color(a palette key or a colour) deepened tomarkers.min_contraston the paper, or unchanged at 1.0.line(color: 'str', tier: 'str' = 'data', **style) -> 'dict'--Panel.linekeywords: the colour (a palette key or a colour) and the tier's weight.mark(color: 'str', *, hollow: 'bool' = False, size: 'float | None' = None, **style) -> 'dict'--Panel.scatterkeywords for the house marker: filled without an outline, or open as a ring in the series colour.marker(shape: 'str', color: 'str', *, hollow: 'bool' = False, size: 'float | None' = None) -> 'Diagram'-- One placed or key marker in the house style (seemark).panel(width: 'float', height: 'float', **kwargs)--inklet.panelbuilt under this suite's theme.axes(p, x=None, y=None, **kwargs)--Panel.axesat the suite's tick and label sizes and axis weight.label(text: 'str', *, role: 'str' = 'note', color: 'str | None' = None, **kwargs) -> 'Diagram'-- A text node at a role's size, never bold, in ink or the deepened colour ofcolor.end_labels(p, labels: 'Mapping[str, tuple[float, float]]', *, colors: 'Mapping[str, str] | None' = None, gap: 'float' = 0.4, dx: 'float' = 1.0, anchor: 'str' = 'w', role: 'str' = 'note')-- Direct series labels at line ends, spread so none overlap.mosaic(layout, panels, *, height: 'float', width: 'str | float' = 'double', **kwargs) -> 'Diagram'--inklet.panel_mosaicwith the suite's letters (size, gap, case).letter(text: 'str') -> 'Diagram'-- A panel letter on its own, for hand-built layouts: the suite's size, bold, baseline-aligned like the mosaic's (header_text).figure(width: 'str | float' = 'double', **kwargs)--inklet.figureon the suite's theme and paper, at a named width.document(width: 'str | float' = 'double', **kwargs)-- The suite preset's liveDocumentat a named width: the suite's font, type sizes and paper. Its panel letters follow the base preset's letter style, notletters.lint_rules()-- The suite's house rules asHouseRulesforlint(house=...).lint_options() -> 'dict'-- Thelint()keywordscheckuses: the base preset's limits, the suite's fonts, paper and house rules, thenlint.check(figure, **kwargs)-- Lint diagnostics for a figure under the suite's limits and house rules. Takes a Figure, compiled Document, Document or Diagram.page(item, width=None)--itemas something that saves and lints: a Figure or compiled Document passes through, a Document is compiled, and a Diagram or Panel is put on a suite figure as wide as it (orwidth).save(item, name: 'str', *, out: 'str | Path' = '.', width=None, report: 'bool' = False) -> "'SaveResult'"-- Writeout/name.{formats}and lint them. Returns aSaveResult.build(figures: 'Mapping[str, object] | Iterable[tuple[str, object]]', *, out: 'str | Path', only: 'Sequence[str] | None' = None, inputs: 'Mapping[str, Sequence] | None' = None, depends: 'Sequence[str | Path]' = (), force: 'bool' = False, isolate: 'bool' = True, report: 'bool' = True) -> "'BuildReport'"-- Build a set of figures, skip the unchanged ones, lint them all.
suite(name: 'str', **options) -> 'Suite'¶
A house style for a figure set; see Suite for every field. Nested fields take dicts: suite("lab", lines={"data": 0.6, "fit": 0.75}).
current_suite() -> 'Suite | None'¶
The suite of the innermost with suite: block, or None.
blend(node, mode='multiply')¶
Blend an isolated group with the artwork behind it, natively in SVG/PDF.
mask(content, stencil, *, mode='luminance', dpi=300)¶
Apply a same-coordinate stencil as a recorded raster layer.
class LinearGradient(stops: tuple, start: tuple = (0.0, 0.0), end: tuple = (1.0, 0.0)) -> None¶
Opaque colour stops from start to end in fractions of the shape bounds.
class RadialGradient(stops: tuple, center: tuple = (0.5, 0.5), radius: float = 0.5) -> None¶
Concentric opaque gradient in shape-bound fractions; circles become ellipses on rectangular bounds.
class Hatch(color: str = '#666666', spacing: float = 2.0, stroke: float = 0.2, angle: float = 45.0, background: str | None = None) -> None¶
Parallel vector strokes with spacing/width in local millimetres.
paint(node, brush)¶
Fill a shape or shape group with a vector gradient or hatch; retain text and authored strokes.
class SceneRender(diagram: inklet.core.diagram.Diagram, metadata: dict, cache_hit: bool, passes: object = <factory>) -> None¶
A rendered snapshot, its provenance and whether cached pixels were reused.
project(point, *, depth_bias=0.001)-- Project a world point into centred millimetres; test visibility with depth.path3d(points, *, hidden='omit', depth_bias=0.001, step_px=1.0, max_samples=200000, **style)-- Create an aligned vector path with occluded sections omitted, dashed or shown.annotate3d(point, text, *, side='n', clear=2.0, hidden='omit', depth_bias=0.001, leader=True, head='none', size=None, avoid=(), leader_style=None, **text_style)-- Label a world point; omit hidden targets or dash their screen-space leader.dimension3d(a, b, text=None, *, scale=1.0, unit='scene units', precision=3, offset=0.0, hidden='omit', depth_bias=0.001, size=None, tick=1.2, witness=True, plate=True, **style)-- Dimension projected endpoints, labelled with their true 3D distance.arrow3d(a, b, *, hidden='omit', depth_bias=0.001, head='triangle', head_size=1.6, step_px=1.0, max_samples=200000, **style)-- Depth-test a world-space shaft with a constant page-size arrowhead.angle3d(a, vertex, b, text=None, *, radius=None, precision=1, hidden='omit', depth_bias=0.001, side='n', clear=2.0, size=None, step_px=1.0, max_samples=200000, **style)-- Measure the 3D angle a-vertex-b and project an arc in its world plane.object_mask(*names)-- Return an aligned stencil for named objects; request object_id first.
class ScenePass(name: str, pixels: tuple[int, int], channels: int, width_mm: float, height_mm: float, data: bytes) -> None¶
Immutable little-endian float32 pixels, in top-left row order.
value(x, y)-- Read one pixel without NumPy; normals return an XYZ tuple.to_numpy()-- Return a read-only H×W or H×W×3 NumPy view; requires inklet[images].save(path)-- Save numeric data as .npy without losing precision or changing axes.to_diagram(*, value_range=None)-- Visualize a pass with transparent background; requires inklet[images].object_mask(ids)-- Make a white alpha stencil for object IDs, aligned with the scene.
class ProjectedPoint(point: inklet.core.geom.Vec2, depth: float, in_frame: bool, visible: bool | None) -> None¶
A world point in centred figure millimetres, with camera visibility.
class BlendSceneSpec(path: object, options: dict = <factory>, _dependencies: tuple = ()) -> None¶
Deferred scene rendering with file and live-data cache invalidation.
signature(trail=())render(context, width=None, height=None)
render_blend(path, *, width, height=None, camera=None, scene=None, frame=None, dpi=None, engine=None, samples=None, seed=0, transparent=True, landmarks=None, objects=None, collections=None, bindings=None, assets=(), cache=None, blender=None, timeout=900, threads=4, max_pixels=40000000, view_layer=None, passes=(), quality=None, denoise=None, noise_threshold=None, style='authored', device='AUTO', devices=None, fallback='cpu', progress=None, cancel=None)¶
Render an existing .blend file without modifying it.
blend_scene(path, **options)¶
A complete Blender scene as a Diagram; see render_blend for options.
blend_scene_spec(path, **options)¶
Create a live scene panel that responds to asset and data changes.
scene_templates()¶
Return a fresh JSON-compatible catalogue; Blender is not required.
create_scene(template, path, *, parameters=None, blender=None, overwrite=False, timeout=90, progress=None, cancel=None)¶
Create an editable .blend from laboratory, product or architecture.
class RenderQuality(name: str, dpi: float, samples: int, denoise: bool, noise_threshold: float) -> None¶
Physical resolution and Cycles sampling settings for scene renders.
render_quality(name='preview', **overrides)¶
Get immutable draft, preview or final settings, with validated overrides.
inspect_blend(path, *, blender=None, timeout=30)¶
List authored scenes, cameras, view layers, objects and materials without rendering.
render_devices(*, blender=None, timeout=30, refresh=False)¶
List Cycles backends, device IDs and discovery errors without rendering.
class RenderQueue(max_workers=2, *, max_gpu_jobs=1)¶
Schedule scene renders with worker and GPU concurrency limits.
submit(path, **options)-- Queue render_blend arguments and return a cancellable RenderJob.shutdown(*, wait=True, cancel=False)-- Stop accepting jobs; optionally cancel pending and running renders.
class RenderJob()¶
A queued or running scene render with cancellation and its latest update.
cancel()-- Request cancellation, including for running Blender processes.done()result(timeout=None)-- Wait for a SceneRender; timeout only limits this wait, not the render.
class RenderProgress(phase: str, message: str, fraction: float | None = None) -> None¶
One render update; fraction is optional and refers to the current phase.
class RenderCancelled¶
Rendering was cancelled before a complete snapshot was committed.
to_png(root, *, dpi=150, **options)¶
Return PNG bytes at physical DPI, without Chrome or a display server.
save_png(root, path, **options)¶
Save a Diagram as PNG; see to_png for physical DPI and backgrounds.
rasterize(node, *, dpi=300, reason='explicit raster layer')¶
Freeze one expensive layer as pixels, preserving its size and anchors.
Live documents¶
class PublicationProfile(name: str, width: float, font_pt: float = 8, small_font_pt: float = 7, stroke_mm: float = 0.18, min_font_pt: float = 6, min_stroke_mm: float = 0.1, min_dpi: float = 300, dpi: float = 300, text: str = 'embed', base_theme: inklet.themes.theme.Theme | str = 'nature', title_font_pt: float | None = None, max_font_pt: float | None = None, max_height_mm: float | None = None, letter_font_pt: float | None = None, max_letter_pt: float | None = None, expected_fonts: tuple[str, ...] | None = None) -> None¶
An editable set of physical page, typography, stroke and export defaults.
document(**options)-- Create a document with this profile's theme, checks and export defaults.
publication(name='double-column', **options)¶
Choose single-column (89 mm), double-column (183 mm), or slide (254 mm).
class FigureFormat(name: 'str', width: 'float', height: 'float | None' = None) -> None¶
Physical page dimensions in millimetres; None height fits the content.
class PlotDefaults(grid: 'str' = 'none', legend_side: 'str' = 'bottom', tick_count: 'int' = 5, bar_fill: 'str' = 'neutral', axes: 'str' = 'open') -> None¶
Defaults for live plot recipes; explicit recipe options take precedence.
class GuidelineSource(title: 'str', url: 'str', reviewed_on: 'str | None', status: 'str', scope: 'str') -> None¶
Journal guidance provenance, distinguishing reviewed and unverified sources.
class Preset(name: 'str', description: 'str', format: 'FigureFormat', publication: 'PublicationProfile', plot: 'PlotDefaults' = PlotDefaults(grid='none', legend_side='bottom', tick_count=5, bar_fill='neutral', axes='open'), margin: 'float' = 4, gap: 'float' = 6, letter_style: 'str' = 'bold-lower', sources: 'tuple[GuidelineSource, ...]' = (), letter_pad: 'float | None' = None) -> None¶
An immutable figure style, format, plot policy and publication profile.
customize(**options) -> 'Preset'-- Return a preset with explicit overrides; dimensions use millimetres.document(**options)-- Create a live document, retaining explicit page overrides on preset switches.as_dict()-- Return a JSON-compatible record of resolved settings and source guidance.
preset(name='scientific.general', *, format=None, **overrides) -> 'Preset'¶
Choose a scientific, educational or marketing preset and physical format.
preset_names(family=None) -> 'tuple[str, ...]'¶
List built-in presets, optionally restricted to one family.
format_names() -> 'tuple[str, ...]'¶
List built-in physical formats accepted by preset().
subfigure(*, width=180, height=None, columns=1, margin=0, gap=6, row_gap=None, share_plot_margins=False, stretch=True)¶
Create a nested grid. Children inherit the enclosing document theme.
class Composition(width: 'float', height: 'float', unit: 'float' = 1, fit_top: 'bool' = False, _parts: 'list' = <factory>, _constraints: 'list' = <factory>, _links: 'list' = <factory>, _annotations: 'list' = <factory>, bindings: 'dict' = <factory>, _ports: 'dict' = <factory>) -> None¶
A figure assembled from named children and measured expressions.
measure(name, dimension='width')-- Reference a child's measured width or height, in composition units.point(name, anchor='center')-- Reference a placed child's compass point or registered port.add(name, item, *, x=0, y=0, anchor=None, width=None, height=None, scale=1)replace(name, item)-- Replace a child while preserving its placement and dependent references.slot(name, **placement)-- Declare a required content input with the same placement options as add().copy()-- Copy nested compositions, plots, modules and component instructions.instantiate(**items)-- Create an independent recipe, filling required slots and replacing defaults.configure(*, width=None, height=None, unit=None, fit_top=None)-- Atomically update authored page dimensions or coordinate units.place(name, **placement)-- Edit a child's placement without replacing its content or named links.layout_overrides(reference)-- Capture changed layout, named labels and supported styles against a reference.with_layout_overrides(value, *, missing='error')-- Return an independent edited recipe and a reconciliation report.port(name, target)-- Expose a child's name:anchor as a reusable composition attachment point.constrain(value, *, minimum=0, message='composition needs more space')-- Require an expression to meet a minimum; fail before drawing.link(source, target, **options)-- Route a branch or return between named children (name:port).annotate(target, text, **options)-- Place a measured callout; a unique name enables saved label editing.signature(trail=())render(context, width=None, height=None)
class LayoutValue(operation: 'str', args: 'tuple') -> None¶
A scalar layout expression evaluated after its dependencies are measured.
composition(width, height, *, unit=1, fit_top=False)¶
Create a measured composition; see Composition for coordinate semantics.
class ModuleSpec(label: object, min_width: float = 20, min_height: float = 12, pad: float = 3, max_height: float | None = None, ports: dict = <factory>, text_style: dict = <factory>, box_style: dict = <factory>, label_offset: tuple = (0, 0), max_width: float | None = None) -> None¶
A label-sized module. Port coordinates are fractions of its box.
configure(label=None, **options)signature(trail=())render(context, width=None, height=None)
module(label, **options)¶
Create a measured module with fractional ports.
class Document(width: 'float' = 180, height: 'float | None' = None, columns: 'object' = 1, margin: 'float' = 4, gap: 'float' = 6, row_gap: 'float | None' = None, theme: 'object' = 'nature', publication: 'object' = None, preset: 'object' = None, share_plot_margins: 'bool | str' = False, stretch: 'bool' = True, pack: 'bool' = False, _preset_overrides: 'dict' = <factory>, _cells: 'list' = <factory>, _links: 'list' = <factory>, _letters: 'dict' = <factory>, _cache: 'dict' = <factory>, _last: 'object' = None, _labels: 'dict' = <factory>) -> None¶
A physical page containing named, live figure definitions.
add(name, item, *, row=None, column=0, rowspan=1, colspan=1, min_width=None, min_height=None, align='center', grow=True)-- Place a named cell; align fixed artwork by a compass point.configure(**options)-- Validate page changes together before applying them.use_preset(selected, *, format=None, keep_overrides=True, **options)-- Switch presets and remeasure live content, preserving explicit page options.replace(name, item)-- Replace a cell definition while retaining its layout constraints.link(source, target, **kwargs)-- Connect named cells, optionallycell:anchor, after layout.letters(names=None, *, start='a', anchor='content', **options)-- Measure panel letters with the cells, reserving room before placement.label(*, x: 'str | None' = None, y: 'str | None' = None, **unknown)-- Name the grid once:xunder its bottom row,ybeside its left column.signature(trail=())render(context, width=None, height=None)compile()-- Measure dependencies and return a cached CompiledFigure snapshot.export(directory, **kwargs)save(*paths, **kwargs)
class CompiledFigure(_state: 'CompiledState', cells: 'Mapping', diagnostics: 'tuple', metadata: 'Mapping', stats: 'Mapping') -> None¶
A resolved snapshot; later authoring changes cannot alter its exports.
build()-- Return the retained drawing and read-only resolved placements.lint(**kwargs)report(**kwargs)layout_report() -> 'str'-- Which cells set each row's height, unused space per cell, and the alternative kept for eachchoose()cell.to_svg(*, text=None, **kwargs)to_pdf(*, text=None, **kwargs)to_png(*, dpi=None, **kwargs)save(*paths, **kwargs)export(directory, **kwargs)
class LayoutError¶
A document cannot satisfy its declared physical layout constraints.
document(*, width=180, height=None, columns=1, margin=4, gap=6, row_gap=None, theme='nature', publication=None, share_plot_margins=False, pack=False)¶
Create a live document; optionally share plot furniture across the grid.
class PlotSpec(width: 'float' = 40, height: 'float' = 30, options: 'dict' = <factory>, _steps: 'list' = <factory>, _findings: 'list' = <factory>, _width_given: 'bool' = False) -> None¶
A live plot recipe. Construct with plot_spec().
copy()-- Copy instructions and nested plots, retaining explicit live dependencies.extend(other, *, prefix=None)-- Append an independent copy of another plot's recorded instructions.style(key, **options)-- Merge keyword options into a named instruction without replacing data.replace(key, *args, **kwargs)-- Replace arguments of an instruction recorded withkey=....remove(key)configure(*, width=None, height=None, **options)-- Validate physical dimensions together before applying configuration.annotate(x, y, text, *, avoid_marks=True, key=None, **options)-- Place a callout after marks, insets and brackets have been measured.group_labels(categories, *, key=None, **kwargs)series(series, *, kind='line', uncertainty=True, key=None, **style)-- Draw a shared Series definition, including its name and uncertainty.twin_y(scale=None, **options)-- Record a second y-axis; returned instructions share the parent area.twin_x(scale=None, **options)-- Record a second x-axis; returned instructions share the parent area.signature(trail=())render(context, width=None, height=None)
class ComponentSpec(factory: 'object', args: 'tuple' = (), kwargs: 'dict' = <factory>, responsive: 'bool' = False) -> None¶
A diagram factory with explicit, versioned arguments and dependencies.
configure(*args, **kwargs)signature(trail=())render(context, width=None, height=None)
class Choice(options: 'tuple', names: 'tuple') -> None¶
Alternative definitions of one cell. Construct with choose().
signature(trail=())render(context, width=None, height=None)
plot_spec(width=None, height=30, **options)¶
Defer Panel drawing instructions until a document is compiled.
component(factory, *args, responsive=False, **kwargs)¶
Rebuild a component under its document theme when its arguments change.
choose(*options, **named)¶
Offer a document cell several layouts; the page keeps the shortest.
class Dataset(columns, *, units=None, source: 'Source | None' = None, name='data')¶
An equal-length column table with explicit updates and a revision number.
update(**columns)column(name)points(x, y)
class DataRef(table: 'Dataset', names: 'tuple') -> None¶
DataRef(table: 'Dataset', names: 'tuple')
evaluate()
class Source(citation: 'str', method: 'str' = 'measured', path: 'str | None' = None) -> None¶
Data origin and construction method carried into an export manifest.
class Series(name: 'str', x: 'object', y: 'object', color: 'str', lower: 'object' = None, upper: 'object' = None) -> None¶
Shared name, colour, values and optional absolute uncertainty bounds.
draw(panel, *, kind='line', uncertainty=True, **style)
class SharedScale(columns: 'tuple', padding: 'float' = 0.05, include_zero: 'bool' = False, kind: 'str' = 'linear') -> None¶
One live numeric domain computed from all supplied column references.
evaluate()
dataset(columns, *, units=None, source=None, name='data')¶
Create a versioned Dataset with units and an optional source record.
read_csv(path, *, types, units=None, name='data', citation=None, method='measured', encoding='utf-8-sig', delimiter=',')¶
Read a local CSV into a Dataset with explicit types and source provenance.
shared_scale(*columns, padding=0.05, include_zero=False, kind='linear')¶
Share a live numeric domain across plots, rejecting incompatible units.
class CategoryEncoding(definition: 'object', selected: 'tuple | None' = None) -> None¶
A live selection of a CategorySet shared by marks, axes and legends.
select(keys)evaluate()scale(*, reverse=False, gap=1.0, padding=0.1, outer=None)
class FileRef(path: 'object') -> None¶
An explicit file dependency for component factories such as asset.
evaluate()
class DerivedData(factory: 'object', inputs: 'tuple') -> None¶
A deterministic transformation of explicit live inputs.
evaluate()
derive(factory, *inputs)¶
Derive live values, such as filtered rows or stacked series, from inputs.
Authoring¶
text(content: 'str', *, size: 'float | str | None' = None, font: 'str | None' = None, weight: 'str | None' = None, align: 'str' = 'center', width: 'float | str | None' = None, line_height: 'float | None' = None, features: 'dict[str, bool | int] | None' = None, markup: 'bool' = True, angle: 'float' = 0.0, kind: 'str' = 'text', bounds: 'str' = 'font', **style) -> 'Diagram'¶
Return shaped text as a diagram with bounds based on its ink extent.
label(content: 'str', **kwargs) -> 'Diagram'¶
Text for annotations, using the theme's small font size by default.
title(content: 'str', **kwargs) -> 'Diagram'¶
text at the theme's large size, tagged as a title.
box(content: 'str | Diagram | None' = None, *, pad: 'float | str | None' = None, radius: 'float | str | None' = None, shape_: 'str' = 'rect', width: 'float | str | None' = None, height: 'float | str | None' = None, **style) -> 'Diagram'¶
A labelled container that sizes itself to what is inside it.
circle(content: 'str | Diagram | None' = None, **kwargs) -> 'Diagram'¶
box with an elliptical outline, taking the same keywords.
asset(path: 'str | Path', *, width: 'float | str | None' = None, height: 'float | str | None' = None, cutout: 'Cutout | str | bool | None' = 'auto', cutout_tolerance: 'float | None' = None, lineart: 'LineArt | str | bool | None' = False, palette: 'Harmonize | Sequence[str] | float | bool | None' = None, palette_strength: 'float | None' = None, anchors: 'Mapping[str, Sequence[float]] | None' = None, outline: 'bool' = True, outline_tolerance: 'float' = 0.35, outline_max_points: 'int' = 96, outline_resolution: 'int' = 512, license: 'str | None' = None, attribution: 'str | None' = None, source_url: 'str | None' = None, sidecar: 'bool' = True, cache_dir: 'str | Path | None' = None, name: 'str | None' = None) -> 'Diagram'¶
Place an image as a diagram that knows its own silhouette.
escape_markup(text: 'str') -> 'str'¶
text with every markup character made literal.
strip_markup(text: 'str') -> 'str'¶
Return text with its markup removed.
text_on_path(content: 'str | Diagram', along, **kwargs) -> 'Diagram'¶
Set a line of text along a curve, one shaping cluster per station.
text_on_arc(content: 'str | Diagram', radius: 'float', angle: 'float', **kwargs) -> 'Diagram'¶
Set a line of text around a circle, centred on the bearing angle.
baseline(source: 'object' = (), *, curves: 'Sequence[Sequence[object]] | None' = None, closed: 'bool' = False) -> 'Baseline'¶
A Baseline from whatever describes the curve.
baseline_arc(radius: 'float', start: 'float', end: 'float', centre: 'object' = None, *, center: 'object' = None) -> 'Baseline'¶
The circular arc from bearing start to bearing end, exactly.
class Baseline(points: 'tuple[Vec2, ...]', tangents: 'tuple[Vec2, ...]', lengths: 'tuple[float, ...]') -> None¶
A curve to set type along, resampled as one arclength axis.
at(station: 'float') -> 'tuple[Vec2, Vec2]'-- The point and unit tangentstationmm along, from the start.offset(distance: 'float') -> 'Baseline'-- The parallel curvedistancemm to the right of the direction of travel -- which for text setside="above"is below the letters.reversed() -> 'Baseline'-- The same curve walked the other way: stations measured from the far end, tangents turned round. Setting a run on it is what puts the type on the other side of the line without mirroring a single glyph.
Drawing¶
arrow(points, *, smooth: 'float' = 0.5, head: 'str' = 'triangle', head_length: 'float | str' = 2.0, head_width: 'float | str | None' = None, both: 'bool' = False, color: 'str | None' = None, stroke_width: 'float | str' = 0.35, **style) -> 'Diagram'¶
Draw an arrow through waypoints, or along an existing single open path.
tag(content: 'str | Diagram', *, size=None, font=None, weight=None, color: 'str | None' = None, fill: 'str | None' = None, pad=(0.9, 0.35), radius=0.3, stroke='none', stroke_width=0.15, markup: 'bool' = True) -> 'Diagram'¶
A label plate sized from shaped text, with no font stretching.
path(points: 'Iterable[Point]' = (), *, closed: 'bool' = False, curves: 'Sequence[Sequence[Point]] | None' = None, holes: 'Sequence[Iterable[Point]]' = (), filled: 'bool | None' = None, fill_rule: 'str' = 'nonzero', kind: 'str' = 'path', **style) -> 'Diagram'¶
One subpath, exactly as given -- plus any rings cut out of it.
polyline(points: 'Iterable[Point]', **kwargs) -> 'Diagram'¶
An open run of straight segments.
polygon(points: 'Iterable[Point]', **kwargs) -> 'Diagram'¶
A closed run of straight segments, fillable.
curve(points: 'Iterable[Point]', *, smooth: 'float' = 0.5, closed: 'bool' = False, **kwargs) -> 'Diagram'¶
Return a Catmull-Rom spline through every point as cubic Bézier segments.
arc(radius: 'float | str', start: 'float', end: 'float', *, closed: 'bool' = False, kind: 'str' = 'path', **style) -> 'Diagram'¶
Approximate a circular arc from start to end degrees with cubic Bézier segments.
sector(radius: 'float | str', start: 'float', end: 'float', *, inner: 'float | str' = 0.0, kind: 'str' = 'path', **style) -> 'Diagram'¶
The wedge between two angles: a pie slice, or a ring segment with inner set. Filled by default, since a sector is an area.
marker(kind: 'str' = 'circle', size: 'float | str | None' = None, **style) -> 'Diagram'¶
One data glyph, centred on its own origin so place() lands it on the point it stands for.
place(items: 'Iterable[tuple[Point, Diagram] | Diagram]', *, anchor: 'str' = 'center', origin: 'Point | None' = None, kind: 'str' = 'place', **style) -> 'Diagram'¶
Put children at explicit coordinates, in millimetres.
window(items: 'Diagram | Iterable[Diagram]', region: 'Rect | Sequence[Point]', *, kind: 'str' = 'window', **style) -> 'Diagram'¶
Crop painted content to a fixed convex window, in local millimetres.
clip(items: 'Diagram | Iterable[Diagram]', region: 'Rect | Sequence[Point]', *, kind: 'str' = 'clip', strict: 'bool' = False, **style) -> 'Diagram'¶
Cut items down to region, in the coordinate frame you pass it in.
encoded(kind: 'str' = 'path') -> 'str'¶
Mark a kind as one whose stroke width is data rather than design.
drawn(items: 'Diagram | Iterable[Diagram]', *, kind: 'str' = 'place', **style) -> 'Diagram'¶
Absolute-coordinate geometry, back in the coordinates it was drawn in.
as_drawn(node: 'Diagram') -> 'Diagram'¶
Put a drawn node back at the coordinates it was drawn in.
placed_anchor(item: 'Diagram', anchor: 'str' = 'center') -> 'Vec2'¶
An item's named anchor, in the coordinates of whoever holds it.
plot_area(node: 'Diagram') -> 'Rect | None'¶
Where a panel keeps its data, or None for a node that is not one.
Annotating¶
annotate(target: 'Diagram | AnchorRef', text: 'str | Diagram', *, side: 'str' = 'n', clear: 'float | str' = 2.0, leader: 'bool' = True, avoid: 'Sequence[Diagram | Rect]' = (), within: 'Diagram | None' = None, size: 'float | str | None' = None, align: 'str' = 'center', name: 'str | None' = None, head: 'str' = 'none', shoulder: 'float | str | None' = None, through: 'Sequence[Diagram]' = (), leader_style: 'dict | None' = None, search: 'bool' = True, keep: 'Rect | None' = None, **style) -> 'Diagram'¶
Put text outside target, clear millimetres off it, with a leader.
annotation_side(node: 'Diagram | str') -> 'str | None'¶
Which side an annotate label actually landed on.
bracket(a, b, *, side: 'str' = 'n', text: 'str | Diagram | None' = None, tick: 'float | str' = 1.0, clear: 'float | str' = 0.0, pad: 'float | str | None' = None, size: 'float | str | None' = None, within: 'Diagram | None' = None, kind: 'str' = 'bracket', **style) -> 'Diagram'¶
The grouping bracket over two things, with text centred on it.
dimension(a, b, text: 'str | Diagram | None' = None, *, offset: 'float | str' = 0.0, tick: 'float | str' = 1.2, witness: 'bool' = True, plate: 'bool' = True, size: 'float | str | None' = None, within: 'Diagram | None' = None, kind: 'str' = 'dimension', **style) -> 'Diagram'¶
A dimension line from a to b, ticked at both ends and labelled.
scalebar(length: 'float', text: 'str | Diagram | None' = None, *, panel=None, over: 'Diagram | None' = None, corner: 'str' = 'sw', pad: 'float | str | None' = None, thickness: 'float | str | None' = None, plate: 'bool | None' = None, axis: 'str' = 'x', ink: 'str | None' = None, kind: 'str' = 'scalebar', **style) -> 'Diagram'¶
A scale bar, with its length written under it.
letters(items: 'Iterable', *, start: 'str' = 'a', style: 'str' = 'bold-lower', corner: 'str' = 'nw', pad: 'float | str | None' = None, inside: 'bool' = False, size: 'float | str | None' = None, **text_style) -> 'list[Diagram]'¶
a, b, c on the corner of each item, as diagrams you can stack.
label_slot(target: 'Diagram | AnchorRef', body: 'Diagram', *, side: 'str' = 'n', clear: 'float | str' = 2.0, within: 'Diagram | None' = None, placements: 'Mapping[str, Placement] | None' = None) -> 'Rect'¶
The rectangle annotate would put this label in, without building it.
label_specs(node: 'Diagram') -> 'tuple[LabelSpec, ...]'¶
Every annotate request recorded anywhere in node, in call order.
label_column(labels, targets, *, x, bounds, side='right', gap=1, leader_color='#777777', leader_width=0.2) -> 'Diagram'¶
Place measured label Diagrams beside points without vertical overlap.
place_labels(art: 'Diagram', *, sides: 'Sequence[str]' = ('n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'), radii: 'Sequence[float] | None' = None, weights: 'LabelWeights | None' = None, clearance: 'float | str | None' = None, method: 'str' = 'greedy') -> 'Diagram'¶
Re-place every annotate label in art, deciding all of them at once.
label_plan(art: 'Diagram', *, sides: 'Sequence[str]' = ('n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'), radii: 'Sequence[float] | None' = None, weights: 'LabelWeights | None' = None, clearance: 'float | str | None' = None, method: 'str' = 'greedy') -> 'tuple[LabelChoice, ...]'¶
What place_labels would do, without doing it.
class LabelChoice(target: 'str', side: 'str', clear: 'float', score: 'float', asked: 'str', overlap: 'float' = 0.0, crossings: 'int' = 0, length: 'float' = 0.0, unresolved: 'bool' = False) -> None¶
Where one label ended up, and what it cost.
class LabelWeights(overlap: 'float' = 1.0, crossing: 'float' = 4.0, length: 'float' = 0.3) -> None¶
What the placer is trading off, in units it can actually compare.
Scientific diagram components¶
database(content, *, width=None, height=None, pad=None, **style)¶
A labelled cylinder with input/output ports on its vertical sides.
feature_matrix(values, *, row_labels=None, column_labels=None, cell=4, ramp=None, label=None, highlight_rows=(), gap=None, **style)¶
A matrix with text/diagram headers and named row/column connection points.
sequence(items, *, pitch=None, gap=None, stem=0, baseline=False, **style)¶
A row of text or diagram symbols with item-0, ... and input/output ports.
value_table(rows, *, headers=None, font_size=3, header_size=None, font=None, pad=(1, 0.7), min_cell_width=0, min_cell_height=0, fill='white', header_fill='#eeeeee', color='#222222', stroke='#cccccc', stroke_width=0.15, formatter=<class 'str'>)¶
A compact numeric/text table with measured, glyph-centered cells.
Plotting¶
panel(width: 'float | str', height: 'float | str', *, x=None, y=None, nice: 'bool' = False, clip: 'bool' = False) -> 'Panel'¶
A plot area of a fixed size, with scales fitted to it.
class Panel(width: 'float', height: 'float', x: 'Scale', y: 'Scale', clip: 'bool' = False, _under: 'list[Diagram]' = <factory>, _content: 'list[Diagram]' = <factory>, _over: 'list[Diagram]' = <factory>, _title: 'tuple[Diagram, str, float] | None' = None, _built: 'Diagram | None' = None, _parent: "'Panel | None'" = None, _scale_domain: 'Scale | None' = None, _ramp: 'object | None' = None, _matrix: 'bool' = False, _brackets: 'list[Diagram]' = <factory>, _keys: 'list[SeriesKey]' = <factory>, _spans: 'list' = <factory>, _insets: 'list' = <factory>, _inset_state: 'tuple' = (), _deferred: 'dict' = <factory>, _sizes: 'object | None' = None, _widths: 'object | None' = None, _ternary: 'object | None' = None, _survival: 'list' = <factory>, _side_stacks: 'dict' = <factory>, _key_at: 'list' = <factory>) -> None¶
A drawing region plus the scales that map data into it.
point(x, y) -> 'Vec2'-- One data point in panel coordinates, in millimetres.map(points: 'Iterable[Sequence]') -> 'tuple[Vec2, ...]'--point()over a sequence: data pairs in, millimetres out.region(x0, y0, x1, y1) -> 'Rect'-- Map two data corners to a normalized rectangle in panel coordinates.draw(*items: 'Diagram', clip: 'bool | None' = None) -> "'Panel'"-- Add content already expressed in panel coordinates.place(items, *, clip: 'bool | None' = None) -> "'Panel'"--draw.place()in data coordinates:((x, y), diagram)pairs, or bare diagrams that already know where they go.marks(item: 'Diagram', points: 'Iterable[Sequence]', *, name: 'str | None' = None, **style) -> "'Panel'"-- A copy ofitemcentred on every data point.matrix(values: 'Sequence[Sequence[float]]', *, ramp=None, scale: 'Scale | None' = None, center: 'float | None' = None, x: 'Sequence | None' = None, y: 'Sequence | None' = None, overlap: 'float | None' = None, missing: 'str | None' = None, vector: 'str' = 'cells', interpolation: 'str' = 'nearest', samples: 'int' = 4, raster: 'bool | str' = 'auto', **style) -> "'Panel'"-- A 2D array of values, one coloured cell each.line(points: 'Iterable[Sequence]', *, smooth: 'float' = 0.0, closed: 'bool' = False, name: 'str | None' = None, err=None, err_style: 'str' = 'band', simplify: 'float | str | None' = None, **style) -> "'Panel'"-- A path through data points: straight by default, curved withsmooth.band(x: 'Sequence', lo, hi, *, name: 'str | None' = None, color: 'str | None' = None, **style) -> "'Panel'"-- The shaded envelope between two edges over shared x.scatter(points: 'Iterable[Sequence]', *, size=None, color=None, ramp=None, scale: 'Scale | None' = None, marker: 'str' = 'circle', name: 'str | None' = None, hollow: 'bool' = False, raster: 'bool' = False, dpi: 'float' = 300, **style) -> "'Panel'"-- Markers at data points, with size and colour that may be data too.bars(at: 'Sequence', heights, *, width: 'float' = 0.8, baseline: 'float' = 0.0, orient: 'str' = 'v', stacked: 'bool | None' = None, grouped: 'bool | None' = None, gap: 'float' = 0.12, color=None, bar_colors=None, name: 'str | Sequence[str] | None' = None, labels=None, label_position: 'str' = 'auto', label_options: 'dict | None' = None, normalize: 'bool' = False, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'Panel'"-- A rectangle per value, standing on a baseline.hist(values: 'Sequence[float]', bins: 'int | Sequence[float]' = 10, *, range: 'tuple[float, float] | None' = None, density: 'bool' = False, baseline: 'float' = 0.0, orient: 'str' = 'v', color=None, name: 'str | None' = None, histtype: 'str | None' = None, cumulative: 'bool' = False, prebinned: 'bool' = False, colors=<deprecated: use color=>, **style) -> "'Panel'"-- Binned counts as touching rectangles.errorbars(points: 'Iterable[Sequence]', *, yerr=None, xerr=None, cap: 'float | None' = None, floor: 'str' = 'arrow', **style) -> "'Panel'"-- Whiskers through each point, in the data's own units.fill(points: 'Iterable[Sequence]', *, baseline: 'float' = 0.0, orient: 'str' = 'v', name: 'str | None' = None, **style) -> "'Panel'"-- The area between a series and a baseline.fill_between(x: 'Sequence', y0, y1, *, name: 'str | None' = None, **style) -> "'Panel'"-- The band between two curves over shared x -- a confidence envelope.stackarea(x: 'Sequence', values, *, baseline=0.0, color=None, name: 'str | Sequence[str] | None' = None, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'Panel'"-- Stack non-negative series over shared x values, in supplied order.step(points: 'Iterable[Sequence]', *, where: 'str' = 'post', name: 'str | None' = None, **style) -> "'Panel'"-- A staircase through the points, for a quantity that changes at instants rather than continuously.boxplot(groups, *, at=None, width: 'float' = 0.6, orient: 'str' = 'v', whisker: 'float' = 1.5, outliers: 'bool' = True, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- Quartile boxes with Tukey whiskers, one per group.violin(groups, *, at=None, width: 'float' = 0.8, orient: 'str' = 'v', bandwidth: 'float | None' = None, samples: 'int' = 64, cut: 'float' = 2.0, median: 'bool' = True, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- Mirrored kernel densities, one per group.hline(y, *, span: 'tuple | None' = None, front: 'bool | None' = None, label: 'str | Diagram | None' = None, label_side: 'str | None' = None, label_offset: 'float | None' = None, name: 'str | None' = None, **style) -> "'Panel'"-- A horizontal rule at one data value of y.vline(x, *, span: 'tuple | None' = None, front: 'bool | None' = None, label: 'str | Diagram | None' = None, label_side: 'str | None' = None, label_offset: 'float | None' = None, name: 'str | None' = None, **style) -> "'Panel'"-- A vertical rule at one data value of x -- stimulus onset, a dose, a cut point.span=(y0, y1)clips it in data coordinates.vspan(x0, x1, *, front: 'bool' = False, name: 'str | None' = None, **style) -> "'Panel'"-- A shaded stripe between two data values of x, full height.hspan(y0, y1, *, front: 'bool' = False, name: 'str | None' = None, **style) -> "'Panel'"-- A shaded stripe between two data values of y, full width.rect(x0, y0, x1, y1, *, front: 'bool' = False, **style) -> "'Panel'"-- A rectangle whose four sides are data values -- a gated region, the extent of an inset, a box round a cluster.under(*items: 'Diagram', clip: 'bool | None' = None) -> "'Panel'"-- Content that paints beneath everything else -- a backdrop, anything the data should sit on top of.over(*items: 'Diagram', clip: 'bool | None' = None) -> "'Panel'"-- Content that paints above everything else, like an annotation.background(**style) -> "'Panel'"-- Fill the plot area, beneath everything already in it.outline(**style) -> "'Panel'"-- A rectangle around the area, drawn over the data.grid(*, x: 'bool' = True, y: 'bool' = True, count: 'int' = 5, x_options: 'dict | None' = None, y_options: 'dict | None' = None, **style) -> "'Panel'"-- Rules at the tick positions, under the data.axis(side: 'str' = 'bottom', *, at=None, **kwargs) -> "'Panel'"-- Hang an axis off one edge, built from this panel's own scale.axes(x: 'str | None' = None, y: 'str | None' = None, *, x_options: 'dict | None' = None, y_options: 'dict | None' = None, **kwargs) -> "'Panel'"-- Bottom and left axes with shared and per-axis options.twin_y(scale=None, *, side: 'str' = 'right', label: 'str | Diagram | None' = None, color: 'str | None' = None, axis: 'bool' = True, **kwargs) -> "'Panel'"-- A second y scale over the same area, and a handle that draws in it.twin_x(scale=None, *, side: 'str' = 'top', label: 'str | Diagram | None' = None, color: 'str | None' = None, axis: 'bool' = True, **kwargs) -> "'Panel'"-- A second x scale over the same area -- wavelength above frequency, or a second time base.twin_yexplains the shape of it.title(content: 'str | Diagram', *, align: 'str' = 'center', pad: 'float | str | None' = None) -> "'Panel'"-- A heading over the panel, clear of whatever is already in it.legend(*, corner: 'str | None' = 'ne', side: 'str | None' = None, entries: 'Sequence[tuple[str, object]] | None' = None, columns: 'int | str | None' = None, max_width: 'float | str | None' = None, swatch: 'float | str | None' = None, pad: 'float | str | None' = None, plate: 'bool | None' = None, title: 'str | None' = None, markup: 'bool' = True, order: 'str' = 'row', col_gap: 'float | str | None' = None, row_gap: 'float | str | None' = None, names: 'Sequence[str] | None' = None, **style) -> "'Panel'"-- A key built from the series this panel actually drew.key_diagram(*, names: 'Sequence[str] | None' = None, columns: 'int | str' = 1, max_width: 'float | str | None' = None, font_size: 'float | str | None' = None, swatch: 'float | str | None' = None, order: 'str' = 'row', title: 'str | None' = None, markup: 'bool' = True, **style) -> 'Diagram'-- The key of this panel's named series as a diagram of its own.colorbar(*, side: 'str' = 'right', source=None, corner: 'str | None' = None, scale: 'Scale | None' = None, length: 'float | str | None' = None, pad: 'float | str | None' = None, plate: 'bool' = False, title: 'str | None' = None, **kwargs) -> "'Panel'"-- The ramp this panel's matrix was coloured through, as a key beside it.text(x, y, content: 'str | Diagram', *, anchor: 'str' = 'center', offset: 'Sequence[float]' = (0.0, 0.0), size: 'float | str | None' = None, markup: 'bool' = True, front: 'bool' = True, decorative: 'bool' = False, **style) -> "'Panel'"-- Words at one data point.arrow(a: 'Sequence', b: 'Sequence', *, head: 'str' = 'triangle', label: 'str | Diagram | None' = None, front: 'bool' = True, **style) -> "'Panel'"-- An arrow from one data point to another.annotate(x, y, text: 'str | Diagram', *, side: 'str' = 'n', clear: 'float | str | None' = None, leader: 'bool' = True, inside: 'bool' = True, dot: 'bool' = False, front: 'bool' = True, **kwargs) -> "'Panel'"-- A callout on one data point: a label clear of it, with a leader.placed(x, y) -> 'Diagram'-- Build with the data rectangle's top-left at page(x, y)in mm.guide(a, b, *, label=None, at=0.5, offset=1.0, label_style=None, **style) -> "'Panel'"-- A straight data guide with a label following its displayed direction.build() -> 'Diagram'-- The panel as a diagram, centred like everything else, with itsoriginanchor on the centre of the plot area.inset(sub, **kwargs) -> "'Panel'"-- Put a smaller panel in a corner of this one. Seeplot.inset.bracket(x0, x1, y=None, **kwargs) -> "'Panel'"-- A grouping or significance bracket across a data span.ribbon(a, b, **kwargs) -> "'Panel'"-- A Sankey band from data pointato data pointb.break_marks() -> "'Panel'"-- Draw the break glyph wherever ainklet.brokenscale interrupts.swarm(groups, *, at=None, width: 'float' = 0.8, max_width: 'float | str | None' = None, orient: 'str' = 'v', size: 'float | str | None' = None, gap: 'float | str | None' = None, marker: 'str' = 'circle', hollow: 'bool' = False, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- Every observation as its own dot, nudged sideways until none hides another.dumbbell(at: 'Sequence', values, *, orient: 'str' = 'v', size: 'float | str | None' = None, color=None, name: 'str | Sequence[str] | None' = None, marker: 'str' = 'circle', connector: 'dict | None' = None, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'Panel'"-- Two or more dots per category joined by a line: a dumbbell plot.lollipop(at: 'Sequence', values: 'Sequence', *, baseline: 'float' = 0.0, orient: 'str' = 'v', size: 'float | str | None' = None, color: 'str | None' = None, marker: 'str' = 'circle', stem: 'dict | None' = None, name: 'str | None' = None, **style) -> "'Panel'"-- One value per category as a dot on a stem frombaseline.ecdf(values: 'Sequence[float]', *, weights: 'Sequence[float] | None' = None, complementary: 'bool' = False, normalize: 'bool' = True, extend: 'bool' = True, name: 'str | None' = None, **style) -> "'Panel'"-- The empirical cumulative distribution ofvaluesas a step line.ridgeline(groups, *, at=None, overlap: 'float' = 1.5, bandwidth: 'float | None' = None, samples: 'int' = 96, scale: 'str' = 'shared', fit: 'bool' = True, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- Overlapping kernel densities, one per category: a ridgeline plot.raincloud(groups, *, at=None, orient: 'str' = 'h', width: 'float' = 0.9, bandwidth: 'float | None' = None, samples: 'int' = 64, cut: 'float' = 2.0, whisker: 'float' = 1.5, points: 'str | None' = 'jitter', size: 'float | str | None' = None, seed: 'int' = 0, box: 'bool' = True, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- A half violin, a narrow box and the observations, per group.label_points(points: 'Iterable[Sequence]', labels: 'Sequence[str]', **kwargs) -> "'Panel'"-- Label many data points at once, clear of the marks and each other.label_lines(name: 'str | Sequence[str] | None' = None, **kwargs) -> "'Panel'"-- Name curves at the curves themselves instead of in a legend.dendrogram(tree, *, labels: 'Sequence | None' = None, orient: 'str' = 'v', threshold: 'float | None' = None, color=None, colors=<deprecated: use color=>, **style) -> "'Panel'"-- The merge tree of a hierarchical clustering, drawn as elbows.clusters(groups: 'Sequence', *, color: 'str | None' = None, highlight=None, highlight_color: 'str | None' = None, width: 'float | str | None' = None, labels: 'bool' = False, size: 'float | str | None' = None, min_size: 'int' = 1, **style) -> "'Panel'"-- Boxes on the diagonal of a matrix, one per cluster.correlogram(r, name: 'Sequence[str] | None' = None, *, triangle: 'str' = 'lower', shape: 'str' = 'circle', ramp=None, values=False, labels: 'bool' = True, size: 'float | str | None' = None, **style) -> "'Panel'"-- A correlation matrix as a triangle of glyphs sized and coloured by r.ternary(points: 'Iterable[Sequence[float]]', *, labels: 'Sequence[str] | None' = None, ticks: 'int' = 5, grid: 'bool' = True, total: 'float' = 100, format=None, color=None, size=None, marker: 'str' = 'circle', name: 'str | None' = None, **style) -> "'Panel'"-- Compositions of three parts as points in a triangle.treemap(data, *, color=None, highlight=None, highlight_color: 'str | None' = None, padding: 'float | str | None' = None, header: 'bool | None' = None, labels: 'bool' = True, values=None, sort: 'bool' = True, size: 'float | str | None' = None, **style) -> "'Panel'"-- A squarified treemap: each leaf a rectangle with area proportional to its value, filling the plot area.icicle(data, *, orient: 'str' = 'h', root: 'bool | None' = None, gap: 'float | str | None' = None, spacing: 'float | str | None' = None, links: 'bool | None' = None, color=None, highlight=None, highlight_color: 'str | None' = None, labels='fit', levels: 'bool' = False, counts: 'bool' = False, sort: 'bool' = False, size: 'float | str | None' = None, **style) -> "'Panel'"-- An icicle (partition) chart: one band per level of a hierarchy, each node spanning its share of its parent.sunburst(data, *, inner: 'float' = 0.3, start: 'float' = -90.0, color=None, highlight=None, highlight_color: 'str | None' = None, labels: 'bool' = True, center: 'str | None' = None, sort: 'bool' = False, size: 'float | str | None' = None, **style) -> "'Panel'"-- A sunburst: an icicle chart bent into rings about the centre of the plot area, the first level innermost.network(nodes, edges, *, layout: 'str' = 'circular', order=None, size=None, top: 'float | None' = None, diameter: 'float | str | None' = None, floor: 'float | str | None' = None, shape: 'str' = 'circle', shapes=None, groups=None, color=None, labels='auto', label_size: 'float | str | None' = None, weights=None, width: 'float | str | None' = None, width_floor: 'float | str | None' = None, edge_color=None, bend: 'float | None' = None, arrows: 'bool' = False, opacity: 'float' = 0.85, gap: 'float | str | None' = None, iterations: 'int' = 300, **style) -> "'Panel'"-- A weighted network: node area from a value, edge width from a weight, colours from categories, fitted into the plot area.width_key(source=None, *, side: 'str' = 'right', corner: 'str | None' = None, values: 'Sequence[float] | None' = None, count: 'int' = 3, format=None, title: 'str | None' = None, color: 'str | None' = None, length: 'float | str | None' = None, pad: 'float | str | None' = None, plate: 'bool' = False) -> "'Panel'"-- Reference lines with their weights: the key to an edge-width encoding.chord(matrix, name: 'Sequence[str] | None' = None, *, color=None, gap: 'float' = 2.0, start: 'float' = -90.0, directed: 'bool' = False, sort: 'bool' = False, thickness: 'float | str | None' = None, pad: 'float | str | None' = None, labels: 'bool' = True, opacity: 'float' = 0.72, color_by: 'str' = 'source', size: 'float | str | None' = None, **style) -> "'Panel'"-- A chord diagram: groups as arcs around a ring, flows between them as ribbons through the middle, fitted into the plot area.arc_diagram(nodes, edges, *, size=None, top: 'float | None' = None, diameter: 'float | str | None' = None, floor: 'float | str | None' = None, shape: 'str' = 'circle', shapes=None, groups=None, color=None, labels: 'bool' = True, rotate: 'float | None' = None, weights=None, width: 'float | str | None' = None, width_floor: 'float | str | None' = None, edge_color=None, directed: 'bool' = False, opacity: 'float' = 0.8, label_size: 'float | str | None' = None, **style) -> "'Panel'"-- An arc diagram: nodes in a row, each edge a half-ellipse arc above them whose width is the edge weight.volcano(fold: 'Sequence[float]', p: 'Sequence[float]', *, labels: 'Sequence[str] | None' = None, top: 'int | None' = None, fold_threshold: 'float' = 1.0, p_threshold: 'float' = 0.05, color=None, name=None, size: 'float | None' = None, thresholds: 'bool' = True, label_options: 'dict | None' = None, highlight: 'Sequence[str] | None' = None, q: 'Sequence[float] | None' = None, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'Panel'"-- A volcano plot: log2 fold change on x against -log10 p on y.ma(mean: 'Sequence[float]', fold: 'Sequence[float]', p: 'Sequence[float] | None' = None, *, labels: 'Sequence[str] | None' = None, top: 'int' = 10, fold_threshold: 'float' = 1.0, p_threshold: 'float' = 0.05, color=None, name=None, size: 'float | None' = None, log: 'bool' = True, zero: 'bool' = True, **style) -> "'Panel'"-- An MA plot: mean expression on x against log2 fold change on y.dotplot(sizes: 'Sequence[Sequence[float]] | None' = None, colors=None, *, x: 'Sequence | None' = None, y: 'Sequence | None' = None, top: 'float | None' = None, diameter: 'float | str | None' = None, ramp=None, scale: 'Scale | None' = None, center: 'float | None' = None, color=None, size: 'Sequence[Sequence[float]] | None' = None, **style) -> "'Panel'"-- A dot plot: a circle per cell, its area one value, its colour another.size_key(source=None, *, side: 'str' = 'right', corner: 'str | None' = None, values: 'Sequence[float] | None' = None, count: 'int' = 3, format=None, title: 'str | None' = None, orient: 'str | None' = None, pad: 'float | str | None' = None, plate: 'bool' = False, **style) -> "'Panel'"-- Reference circles with their values: the key to a size encoding.kaplan_meier(data, *, confidence: 'float' = 0.95, band: 'str | None' = 'log-log', shade: 'bool' = True, censors: 'bool' = True, color=None, pvalue: 'float | str | None' = None, pvalue_corner: 'str' = 'sw', colors=<deprecated: use color=>, **style) -> "'Panel'"-- Kaplan-Meier survival curves, with censor ticks and confidence bands.at_risk(*, ticks: 'Sequence | None' = None, count: 'int' = 5, title: 'str | None' = 'Number at risk', font_size: 'float | str | None' = None, pad: 'float | str | None' = None, **kwargs) -> "'Panel'"-- The number-at-risk table under the x axis of akaplan_meierplot.split_violin(first, second, *, at=None, orient: 'str' = 'v', width: 'float' = 0.8, bandwidth: 'float | None' = None, samples: 'int' = 64, cut: 'float' = 2.0, scale: 'str' = 'shared', median: 'bool' = True, quartiles: 'bool' = False, color=None, name: 'Sequence[str] | None' = None, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'Panel'"-- Two conditions per category as the two halves of one violin.embedding(points: 'Iterable[Sequence]', clusters: 'Sequence', *, color=None, size=None, labels: 'bool' = True, center: 'str' = 'median', label_size: 'float | str | None' = None, arrows=None, shuffle: 'bool' = True, seed: 'int' = 0, raster: 'bool' = False, outline=None, outline_core: 'float' = 0.8, colors=<deprecated: use color=>, centre=<deprecated: use center=>, **style) -> "'Panel'"-- A UMAP or t-SNE style scatter, coloured and named by cluster.brackets(comparisons: 'Sequence', *, format='stars', hide_ns: 'bool' = False, stars=None, ns: 'str' = 'ns', **kwargs) -> "'Panel'"-- Significance brackets for many pairs of groups, stacked clear of each other.kde(values, *, bandwidth='scott', adjust: 'float' = 1.0, cut: 'float' = 3.0, samples: 'int' = 200, fill: 'bool' = False, stat: 'str' = 'density', orient: 'str' = 'v', color=None, name: 'str | None' = None, baseline: 'float' = 0.0, **style) -> "'Panel'"-- A kernel density curve, or one per group.kde2d(points: 'Iterable[Sequence]', *, levels=5, fill: 'bool' = False, bandwidth='scott', adjust: 'float' = 1.0, gridsize: 'int' = 96, color=None, ramp=None, name: 'str | None' = None, **style) -> "'Panel'"-- Contours of a 2D kernel density: lines, or filled levels.contour(x: 'Sequence[float]', y: 'Sequence[float]', z, *, levels=None, hdr=None, color=None, ramp=None, name: 'str | None' = None, **style) -> "'Panel'"-- Lines where a field gridded onxandyreaches each level.hexbin(points: 'Iterable[Sequence]', *, gridsize: 'int' = 24, min_count: 'int' = 1, ramp=None, scale: 'Scale | None' = None, log: 'bool' = False, **style) -> "'Panel'"-- Points counted in hexagons, each coloured by its count.hist2d(points: 'Iterable[Sequence]', bins=20, *, range=None, density: 'bool' = False, min_count: 'float' = 1, ramp=None, scale: 'Scale | None' = None, log: 'bool' = False, **style) -> "'Panel'"-- A 2D histogram: points counted in rectangular bins on continuous axes, each bin coloured by its count.density_scatter(points: 'Iterable[Sequence]', *, bandwidth: 'float | None' = None, ramp=None, size=None, sort: 'bool' = True, raster: 'bool' = False, dpi: 'float' = 300, marker: 'str' = 'circle', **style) -> "'Panel'"-- A scatter coloured by how crowded each point's neighbourhood is.regression(points: 'Iterable[Sequence]', *, method: 'str' = 'linear', confidence: 'float | None' = 0.95, prediction: 'bool' = False, scatter: 'bool' = True, frac: 'float' = 0.6666666666666666, iterations: 'int' = 3, span: 'tuple | None' = None, equation: 'bool | str' = False, color: 'str | None' = None, size=None, name: 'str | None' = None, **style) -> "'Panel'"-- Points with a fitted line and its confidence band.residuals(points: 'Iterable[Sequence]', *, method: 'str' = 'linear', frac: 'float' = 0.6666666666666666, iterations: 'int' = 3, smooth: 'bool' = False, color: 'str | None' = None, size=None, name: 'str | None' = None, **style) -> "'Panel'"-- The residuals of a fit against x, with a zero line.qq(values: 'Sequence[float]', *, dist='normal', line: 'str | None' = 'quartiles', color: 'str | None' = None, size=None, name: 'str | None' = None, **style) -> "'Panel'"-- A normal quantile-quantile plot: sample against theoretical quantiles, with a reference line.pp(values: 'Sequence[float]', *, dist='normal', color: 'str | None' = None, size=None, name: 'str | None' = None, **style) -> "'Panel'"-- A probability-probability plot against a fitted normal.bland_altman(a: 'Sequence[float]', b: 'Sequence[float]', *, z: 'float' = 1.96, percent: 'bool' = False, confidence: 'float | None' = None, labels: 'bool' = True, format: 'str' = '{:.2f}', color: 'str | None' = None, size=None, name: 'str | None' = None, **style) -> "'Panel'"-- A Bland-Altman (mean-difference) plot of two methods' agreement.boxen(groups, *, at=None, width: 'float' = 0.8, orient: 'str' = 'v', depth='tukey', outliers: 'bool' = True, color=None, size=None, **style) -> "'Panel'"-- Letter-value (boxen) plots: nested boxes out into the tails.strip(groups, *, at=None, width: 'float' = 0.8, jitter: 'float' = 0.5, orient: 'str' = 'v', size=None, seed: 'int' = 0, color=None, marker: 'str' = 'circle', **style) -> "'Panel'"-- A strip plot: each group's observations, jittered across its slot.sina(groups, *, at=None, width: 'float' = 0.8, orient: 'str' = 'v', bandwidth='scott', adjust: 'float' = 1.0, size=None, seed: 'int' = 0, color=None, marker: 'str' = 'circle', **style) -> "'Panel'"-- A sina plot: points jittered within their group's density.waterfall(at: 'Sequence', values: 'Sequence', *, totals=(), baseline: 'float' = 0.0, orient: 'str' = 'v', width: 'float' = 0.6, color=None, connectors: 'bool' = True, labels=None, name: 'Sequence[str] | None' = None, **style) -> "'Panel'"-- A waterfall chart: signed changes as bars floating on a running total.slope(values: 'Mapping[str, Sequence[float]]', *, at: 'Sequence | None' = None, labels: 'str' = 'both', format=None, color=None, highlight=None, size: 'float | str | None' = None, name: 'bool' = True, **style) -> "'Panel'"-- A slope chart: each series' values at a few time points, joined.bump(values: 'Mapping[str, Sequence[float]]', *, at: 'Sequence | None' = None, ranked: 'bool' = False, labels: 'str' = 'both', color=None, highlight=None, size: 'float | str | None' = None, numbers: 'bool' = False, **style) -> "'Panel'"-- A bump chart: the rank of each series at each time point.stem(points: 'Iterable[Sequence]', *, baseline: 'float' = 0.0, orient: 'str' = 'v', color: 'str | None' = None, marker: 'str' = 'circle', size: 'float | str | None' = None, hollow: 'bool' = False, rule: 'bool' = True, name: 'str | None' = None, **style) -> "'Panel'"-- A stem plot: a stem frombaselineto a dot at each(x, y).likert(at: 'Sequence', counts: 'Sequence[Sequence[float]]', *, neutral: 'int | None' = None, normalize: 'bool' = True, orient: 'str' = 'h', width: 'float' = 0.7, color=None, name: 'str | Sequence[str] | None' = None, labels=None, zero: 'bool' = True, **style) -> "'Panel'"-- Diverging stacked bars for Likert-scale responses, centred on neutral.diverging_bars(at: 'Sequence', left, right, *, orient: 'str' = 'h', width: 'float' = 0.7, color=None, name: 'str | Sequence[str] | None' = None, reference=None, titles: 'Sequence[str] | None' = None, zero: 'bool' = True, **style) -> "'Panel'"-- Two quantities per category, back to back: left of zero and right.pyramid(at: 'Sequence', left, right, *, titles: 'Sequence[str] | None' = None, color=None, width: 'float' = 0.92, **kwargs) -> "'Panel'"-- A population pyramid:diverging_barswith touching bars.waffle(values: 'Sequence[float]', *, rows: 'int' = 10, columns: 'int' = 10, total: 'float | None' = None, color=None, name: 'str | Sequence[str] | None' = None, gap: 'float' = 0.18, order: 'str' = 'column', **style) -> "'Panel'"-- A waffle chart: shares of a whole as cells of a grid.mosaic(at: 'Sequence', values, *, color=None, name: 'str | Sequence[str] | None' = None, gap: 'float | str' = 0.6, labels=None, categories: 'bool' = True, **style) -> "'Panel'"-- A mosaic (Marimekko) chart: stacked bars as wide as their totals.streamgraph(x: 'Sequence', values, *, offset: 'str' = 'wiggle', order: 'str' = 'input', color=None, name: 'str | Sequence[str] | None' = None, smooth: 'float' = 0.5, **style) -> "'Panel'"-- A streamgraph: stacked areas around a moving baseline.parallel(rows, *, dimensions: 'Sequence | None' = None, ranges=None, color=None, groups: 'Sequence | None' = None, count: 'int' = 4, format=None, labels: 'bool' = True, **style) -> "'Panel'"-- Parallel coordinates: an axis per variable and a line per record.bullet(at: 'Sequence', values: 'Sequence[float]', *, targets=None, ranges=None, baseline: 'float' = 0.0, orient: 'str' = 'h', width: 'float' = 0.7, color: 'str | None' = None, **style) -> "'Panel'"-- Bullet charts: a measure bar against a target and qualitative ranges.gantt(tasks: 'Sequence[Sequence]', *, groups: 'Sequence | None' = None, color=None, width: 'float' = 0.6, labels: 'bool' = False, **style) -> "'Panel'"-- A Gantt chart: a bar per task from its start to its end.timeline(events: 'Sequence[Sequence]', *, at: 'float | None' = None, color: 'str | None' = None, size: 'float | str | None' = None, levels: 'Sequence[int] | None' = None, line: 'bool' = True, **style) -> "'Panel'"-- An event timeline: labelled stems off a base line.calendar(values: 'Mapping', *, start=None, end=None, ramp=None, scale: 'Scale | None' = None, center: 'float | None' = None, week_start: 'str | int' = 'monday', gap: 'float | str' = 0.25, labels: 'bool' = True, **style) -> "'Panel'"-- A calendar heatmap: a square per day, a column per week.barplot(at: 'Sequence', data, *, estimator: 'str' = 'mean', error='sem', points: 'bool' = True, width: 'float' = 0.8, gap: 'float' = 0.12, orient: 'str' = 'v', color=None, name: 'str | Sequence[str] | None' = None, size: 'float | str | None' = None, cap: 'float | str | None' = None, baseline: 'float' = 0.0, **style) -> "'Panel'"-- Bars of the mean with error bars and every observation as a dot.
row(panels: 'Iterable[Panel | Diagram]', gap: 'float | str | None' = None, align: 'str' = 'center') -> 'Diagram'¶
Panels side by side, their plot areas on one line.
column(panels: 'Iterable[Panel | Diagram]', gap: 'float | str | None' = None, align: 'str' = 'center') -> 'Diagram'¶
Panels stacked, their plot areas on one vertical line.
axis(scale: 'Scale', *, side: 'str' = 'bottom', label: 'str | Diagram | None' = None, ticks: 'Sequence | None' = None, count: 'int' = 5, format: 'Callable[[object], str] | str | None' = None, si: 'bool' = False, length: 'float | str | None' = None, tick_size: 'float | str | None' = None, tick_pad: 'float | str | None' = None, label_pad: 'float | str | None' = None, spine: 'bool' = True, thin: 'bool | None' = None, labels: 'bool' = True, rotate: 'float' = 0.0, tnum: 'bool' = True, markup: 'bool | None' = None, offset: 'bool | str | None' = None, minor: 'bool | int' = False, minor_size: 'float | str | None' = None, tick_font_size: 'float | str | None' = None, label_font_size: 'float | str | None' = None, kind: 'str' = 'axis', **style) -> 'Diagram'¶
One axis of a plot.
colorbar(source, *, domain: 'tuple[float, float]' = (0.0, 1.0), scale: 'Scale | None' = None, length: 'float | str | None' = None, thickness: 'float | str | None' = None, side: 'str' = 'right', label: 'str | None' = None, ticks: 'Sequence | None' = None, count: 'int' = 5, format: 'Callable[[object], str] | None' = None, steps: 'int' = 128, outline: 'bool' = True, thin: 'bool | None' = None, tick_font_size: 'float | str | None' = None, label_font_size: 'float | str | None' = None, kind: 'str' = 'colorbar', **style) -> 'Diagram'¶
A continuous ramp with an axis against it.
legend(entries: 'Sequence[tuple[str, object]]', *, columns: 'int | str' = 1, max_width: 'float | str | None' = None, font_size: 'float | str | None' = None, swatch: 'float | str | None' = None, gap: 'float | str | None' = None, row_gap: 'float | str | None' = None, col_gap: 'float | str | None' = None, order: 'str' = 'row', title: 'str | None' = None, markup: 'bool' = True, kind: 'str' = 'legend', **style) -> 'Diagram'¶
Swatches and their names.
linear(domain: 'tuple[float, float]' = (0.0, 1.0), range: 'Range' = (0.0, 1.0), *, clamp: 'bool' = False, nice: 'bool' = False) -> 'Linear'¶
A proportional scale. nice=True rounds the domain out to whole ticks.
log(domain: 'tuple[float, float]' = (1.0, 10.0), range: 'Range' = (0.0, 1.0), *, base: 'float' = 10.0, clamp: 'bool' = False) -> 'Log'¶
A logarithmic scale. The domain must not span or touch zero.
symlog(domain: 'tuple[float, float]' = (-1.0, 1.0), range: 'Range' = (0.0, 1.0), *, linthresh: 'float' = 1.0, base: 'float' = 10.0) -> 'SymLog'¶
Logarithmic away from zero, linear across it.
band(categories: 'Sequence', range: 'Range' = (0.0, 1.0), *, padding: 'float' = 0.1, outer: 'float | None' = None) -> 'Band'¶
A categorical scale: one evenly spaced slot per category.
grouped_band(groups: 'Sequence[Sequence] | Mapping', range: 'Range' = (0.0, 1.0), *, gap: 'float' = 1.0, padding: 'float' = 0.1, outer: 'float | None' = None, reverse: 'bool' = False) -> 'GroupedBand'¶
A band scale with gaps between groups, measured in category slots.
broken(domain: 'tuple[float, float]' = (0.0, 1.0), range: 'Range' = (0.0, 1.0), *, breaks: 'Sequence[Sequence[float]]' = (), gap: 'float | None' = None, weights: 'Sequence[float] | None' = None) -> 'Broken'¶
A linear scale with breaks cut out of it.
dates(domain=('1970-01-01', '1970-01-02'), range: 'Range' = (0.0, 1.0), *, clamp: 'bool' = False, nice: 'bool' = False) -> 'Time'¶
A time axis over (start, end).
class Scale()¶
Data to millimetres. Subclasses fill in map, invert and ticks.
map(value)-- One data value to its millimetre position along this scale.invert(position: 'float')-- The reverse ofmap: millimetres back to a data value.ticks(count: 'int' = 5) -> 'tuple'-- Aboutcountround values to label, chosen to suit the scale.with_range(lo: 'float', hi: 'float') -> "'Scale'"-- The same scale measuring into a different span of millimetres.tick_labels(ticks: 'Sequence') -> 'tuple[str, ...]'-- Labels for a set of ticks, formatted against their own spacing.minor_ticks(majors: 'Sequence', count: 'int | None' = None, clear: 'float' = 0.0) -> 'tuple'-- Unlabelled subdivisions between the major ticks.positions(values: 'Sequence') -> 'tuple[float, ...]'--mapover a sequence of values.
ramp(stops: 'str | Palette | Sequence[str]', *, space: 'str' = 'lab') -> 'Ramp'¶
A ramp from a palette, the name of one, or a list of colours.
class Ramp(stops: 'tuple[str, ...]', space: 'str' = 'lab') -> None¶
A colour ramp, sampled at t in 0..1. Call it, or ask it for n stops.
sample(count: 'int') -> 'tuple[str, ...]'--countcolours spanning the ramp, ends included.reversed() -> "'Ramp'"-- The same colours end to end, for a scale that runs the other way.
class CategorySet(_entries: 'tuple', _groups: 'tuple' = ()) -> None¶
An immutable colour mapping. Use categories() to construct one.
subset(keys)-- Select categories in their original order; reject unknown/empty selections.scale(range=(0.0, 1.0), *, reverse=False, gap=1.0, padding=0.1, outer=None)-- A categorical axis;reverse=Truereads top to bottom on y.group_labels(panel, *, side='bottom', pad=None, **style)-- Add group brackets outside a panel, after its axes have been added.get(key, default=None)-- D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.items()-- D.items() -> a set-like object providing a view on D's itemskeys()-- D.keys() -> a set-like object providing a view on D's keysvalues()-- D.values() -> an object providing a view on D's values
categories(colors: 'Mapping', *, labels: 'Mapping | None' = None, groups: 'Mapping | None' = None) -> 'CategorySet'¶
Define category colours and order once for scales, bars, keys and groups.
inset(panel, sub, *, corner: 'str' = 'ne', width: 'float | None' = 0.35, pad: 'float | str | None' = None, side: 'str | None' = None, align: 'str' = 'center', zoom: 'Sequence[float] | None' = None, plate: 'bool' = True, connect: 'bool' = True, connector: 'dict | None' = None, **style)¶
Put sub inside panel's plot area, on a plate, and return panel.
ribbon(a: 'Point', b: 'Point', *, width0: 'float', width1: 'float | None' = None, along: 'Point | None' = None, ease: 'float' = 0.55, align: 'str' = 'center', kind: 'str' = 'mark', **style) -> 'Diagram'¶
A band from a to b, width0 wide at one end and width1 at the other.
facets(panels: 'Sequence[Panel | Diagram]', *, cols: 'int | None' = None, share_x: 'bool' = True, share_y: 'bool' = True, x_label: 'str | Diagram | None' = None, y_label: 'str | Diagram | None' = None, gap: 'float | str | None' = None, row_gap: 'float | str | None' = None, axes: 'bool' = True, label_pad: 'float | str | None' = None, **axis_kwargs) -> 'Diagram'¶
A grid of panels with one set of axes between them.
histogram(values: 'Sequence[float]', bins: 'int | Sequence[float]' = 10, *, range: 'tuple[float, float] | None' = None, density: 'bool' = False) -> 'tuple[tuple[float, ...], tuple[float, ...]]'¶
Bin edges and the height of each bin: (edges, heights).
upset(data, *, sets: 'Sequence[str] | None' = None, sort: 'str' = 'size', sort_sets: 'bool' = True, min_size: 'float' = 1, max_intersections: 'int | None' = None, empty: 'bool' = False, set_sizes: 'bool' = True, width: 'float | str | None' = None, height: 'float | str' = 26, matrix_height: 'float | str | None' = None, set_width: 'float | str' = 16, color: 'str | None' = None, labels=None, stripes: 'bool' = True, bar_label: 'str | None' = 'intersection size', set_label: 'str | None' = 'set size', gap: 'float | str | None' = None, count: 'int' = 4) -> 'Diagram'¶
An UpSet plot: intersection sizes as bars over a membership matrix.
forest(rows: 'Sequence', *, log: 'bool' = False, limits: 'tuple[float, float] | None' = None, null: 'float | None' = None, left: 'Sequence' = ('label',), right: 'Sequence' = ('ci',), headers: 'bool' = True, measure: 'str' = 'Estimate', digits: 'int' = 2, label: 'str | None' = None, ticks: 'Sequence[float] | None' = None, width: 'float | str' = 36, row_height: 'float | str | None' = None, color: 'str | None' = None, summary_color: 'str | None' = None, size: 'float | str | None' = None, summary_line: 'bool' = False, gap: 'float | str | None' = None, count: 'int' = 5, text_size: 'float | str | None' = None) -> 'Diagram'¶
A forest plot: one estimate and confidence interval per row, with aligned text columns beside it.
pairplot(data: 'Mapping[str, Sequence[float]]', *, vars: 'Sequence[str] | None' = None, groups: 'Sequence | None' = None, cell: 'float | str' = 26, diag: 'str | None' = 'auto', lower: 'str | None' = 'scatter', upper: 'str | None' = 'scatter', corner: 'bool' = False, bins: 'int' = 12, log: 'Sequence[str]' = (), labels: 'Mapping[str, str] | None' = None, color=None, size=None, legend: 'bool' = True, gap: 'float | str | None' = None, count: 'int' = 4, **style) -> 'Diagram'¶
Every pair of variables against each other, in one aligned grid.
jointplot(points: 'Sequence[Sequence[float]]', *, kind: 'str' = 'scatter', marginal: 'str' = 'hist', groups: 'Sequence | None' = None, width: 'float | str' = 50, ratio: 'float' = 4.0, x=None, y=None, x_log: 'bool' = False, y_log: 'bool' = False, bins: 'int' = 20, x_label: 'str | None' = None, y_label: 'str | None' = None, color=None, size=None, legend: 'bool' = True, gap: 'float | str | None' = None, count: 'int' = 5, **style) -> 'Diagram'¶
One pair of variables with both marginal distributions.
clustermap(values, *, rows: 'Sequence[str] | None' = None, columns: 'Sequence[str] | None' = None, method: 'str' = 'average', metric='euclidean', row_cluster: 'bool' = True, col_cluster: 'bool' = True, row_linkage=None, col_linkage=None, standardize: 'str | None' = None, k: 'int | None' = None, highlight=None, row_color: 'Mapping | None' = None, col_color: 'Mapping | None' = None, ramp=None, scale=None, center: 'float | None' = None, width: 'float | str' = 50, height: 'float | str | None' = None, tree: 'float | str' = 8, strip: 'float | str' = 2.0, label: 'str | None' = None, row_labels: 'bool | None' = None, col_labels: 'bool | None' = None, colorbar: 'bool' = True, gap: 'float | str | None' = None) -> 'Diagram'¶
A matrix reordered by hierarchical clustering, with row and column dendrograms, annotation strips and a colorbar.
manhattan(chromosome: 'Sequence', position: 'Sequence[float]', p: 'Sequence[float]', *, labels: 'Sequence[str] | None' = None, top: 'int' = 5, threshold: 'float | None' = 5e-08, suggestive: 'float | None' = 1e-05, window: 'float' = 1000000.0, order: 'Sequence[str] | None' = None, color: 'str | Sequence[str] | None' = None, highlight=None, highlight_color: 'str | None' = None, bands: 'bool' = False, width: 'float | str' = 120, height: 'float | str' = 40, ymax: 'float | None' = None, size: 'float | None' = None, gap: 'float' = 0.008, raster: 'bool' = False, **style)¶
A Manhattan plot as a panel with its axes, ready for more layers.
polar(radius: 'float | str' = 30.0, *, r=None, theta=None, zero: 'float | str | None' = None, winding: 'str | None' = None, unit: 'str' = 'deg', hole: 'float | str' = 0.0, clip: 'bool' = False, nice: 'bool' = False) -> 'PolarPanel'¶
A polar plot area of a given rim radius.
class PolarPanel(radius: 'float', r: 'Scale', theta: 'Theta', hole: 'float' = 0.0, clip: 'bool' = False, _under: 'list[Diagram]' = <factory>, _content: 'list[Diagram]' = <factory>, _over: 'list[Diagram]' = <factory>, _title: 'tuple[Diagram, float] | None' = None, _built: 'Diagram | None' = None, _keys: 'list[SeriesKey]' = <factory>, _spokes: 'list[float]' = <factory>, _ring: 'list[tuple[float, Rect]]' = <factory>, _pie: 'tuple | None' = None, _free: 'tuple[bool, bool]' = (False, False), _journal: 'list' = <factory>, _depth: 'int' = 0, _replayable: 'bool' = True, _ring_values: 'tuple | None' = None, _radar_data: 'list' = <factory>, _breakout_clear: 'tuple | None' = None, _theta_axes: 'list' = <factory>) -> None¶
A disc, or a fan of one, plus the scales that map data into it.
angle(theta: 'float') -> 'float'-- One data angle in page degrees -- east is 0, clockwise is positive.reach(r: 'float') -> 'float'-- One data radius in millimetres from the pole.point(theta, r) -> 'Vec2'-- One data point in panel coordinates, in millimetres.map(points: 'Iterable[Sequence]') -> 'tuple[Vec2, ...]'--point()over a sequence:(theta, r)pairs in, millimetres out.draw(*items: 'Diagram', clip: 'bool | None' = None) -> "'PolarPanel'"-- Add content already expressed in panel coordinates.under(*items: 'Diagram', clip: 'bool | None' = None) -> "'PolarPanel'"-- Add content beneath the data.over(*items: 'Diagram', clip: 'bool | None' = None) -> "'PolarPanel'"-- Add content above the data.place(items, *, clip: 'bool | None' = None) -> "'PolarPanel'"--draw.place()in data coordinates:((theta, r), diagram)pairs.background(**style) -> "'PolarPanel'"-- Fill the data region, beneath everything already in it.spine(*, rim: 'bool' = True, edges: 'bool | None' = None, **style) -> "'PolarPanel'"-- The rim, and for a fan the two straight edges, drawn over the data.outline(*, rim: 'bool' = True, edges: 'bool | None' = None, **style) -> "'PolarPanel'"-- The rim, and for a fan the two straight edges, drawn over the data.grid(*, r: 'bool' = True, theta: 'bool' = True, r_count: 'int' = 4, theta_count: 'int' = 8, r_ticks: 'Sequence | None' = None, theta_ticks: 'Sequence | None' = None, **style) -> "'PolarPanel'"-- Rings at the r ticks and spokes at the theta ticks, under the data.theta_axis(*, count: 'int' = 8, ticks: 'Sequence | None' = None, labels: 'bool' = True, format=None, label: 'str | Diagram | None' = None, spine: 'bool' = True, tick_size: 'float | str | None' = None, pad: 'float | str | None' = None, label_pad: 'float | str | None' = None, thin: 'bool' = True, curved: 'bool' = False, kind: 'str' = 'axis', **style) -> "'PolarPanel'"-- Ticks round the rim, their angles written outside it.r_axis(*, at: 'float | None' = None, count: 'int' = 4, ticks: 'Sequence | None' = None, labels: 'bool' = True, format=None, si: 'bool' = False, label: 'str | Diagram | None' = None, side: 'str | None' = None, spine: 'bool' = False, plate: 'bool | None' = None, tick_size: 'float | str | None' = None, pad: 'float | str | None' = None, label_pad: 'float | str | None' = None, kind: 'str' = 'axis', **style) -> "'PolarPanel'"-- The radial scale, written along one spoke.title(content: 'str | Diagram', *, pad: 'float | str | None' = None) -> "'PolarPanel'"-- A heading over the panel, clear of whatever is already in it.line(points: 'Iterable[Sequence]', *, closed: 'bool | None' = None, interpolate: 'bool' = True, name: 'str | None' = None, **style) -> "'PolarPanel'"-- A path through(theta, r)points -- a tuning curve, a radiation pattern, a profile round a cell.scatter(points: 'Iterable[Sequence]', *, size=None, color=None, marker: 'str' = 'circle', name: 'str | None' = None, **style) -> "'PolarPanel'"-- Markers at(theta, r)points, with size and colour that may be data too. The rectangularPanel.scatterin polar coordinates: the same call, through this panel's ownpoint().marks(item: 'Diagram', points: 'Iterable[Sequence]', *, name: 'str | None' = None, **style) -> "'PolarPanel'"-- A copy ofitemcentred on every(theta, r)point.band(theta: 'Sequence', low, high, *, closed: 'bool | None' = None, interpolate: 'bool' = True, name: 'str | None' = None, color: 'str | None' = None, **style) -> "'PolarPanel'"-- The region between two radii at each angle: a spread round a curve.rose(heights: 'Sequence[float]', *, at: 'Sequence[float] | None' = None, width: 'float' = 1.0, base: 'float | None' = None, name: 'str | None' = None, color: 'str | None' = None, **style) -> "'PolarPanel'"-- Sector bars: the wind rose, and every circular histogram there is.radar(values: 'Sequence[float]', *, name: 'str | None' = None, color: 'str | None' = None, fill: 'bool' = True, markers: 'bool' = True, size: 'float | str | None' = None, **style) -> "'PolarPanel'"-- One series of a radar chart: a closed polygon with a value per spoke.radar_grid(categories: 'Sequence[str]', *, rings=None, shape: 'str' = 'polygon', labels: 'bool' = True, values: 'bool' = False, **style) -> "'PolarPanel'"-- The rings, spokes and category names of a radar chart.pie(values: 'Sequence[float]', *, name: 'Sequence[str] | None' = None, color=None, labels='percent', label_options: 'dict | None' = None, separator: 'bool' = True, names=<deprecated: use name=>, colors=<deprecated: use color=>, **style) -> "'PolarPanel'"-- A pie chart, or a donut on a panel made withhole=.breakout(slices, parts: 'Sequence[float] | None' = None, *, color=None, name: 'Sequence[str] | None' = None, labels='percent', label_options: 'dict | None' = None, side: 'str' = 'right', width: 'float | str | None' = None, height: 'float | str | None' = None, gap: 'float | str | None' = None, title: 'str | None' = None, title_side: 'str' = 'top', connector: 'dict | None' = None, separator: 'bool' = True, colors=<deprecated: use color=>, names=<deprecated: use name=>, **style) -> "'PolarPanel'"-- Expand slices of the pie into a stacked bar beside it.mean_vector(angles: 'Sequence[float]', weights: 'Sequence[float] | None' = None, *, r: 'float | None' = None, order: 'int' = 1, head: 'str' = 'triangle', label: 'str | Diagram | None' = None, name: 'str | None' = None, color: 'str | None' = None, **style) -> "'PolarPanel'"-- The circular mean ofangles, drawn as an arrow from the pole.text(theta, r, content: 'str | Diagram', *, anchor: 'str' = 'center', offset: 'Sequence[float]' = (0.0, 0.0), size: 'float | str | None' = None, markup: 'bool' = True, **style) -> "'PolarPanel'"-- Writing at one data point,anchorof it on that point.legend(*, corner: 'str | None' = 'ne', side: 'str | None' = None, entries: 'Sequence[tuple[str, object]] | None' = None, columns: 'int' = 1, swatch: 'float | str | None' = None, pad: 'float | str | None' = None, plate: 'bool | None' = None, title: 'str | None' = None, markup: 'bool' = True, names: 'Sequence[str] | None' = None, **style) -> "'PolarPanel'"-- A key built from the series this panel actually drew.build() -> 'Diagram'-- The panel as a diagram, with itsoriginanchor on the pole.
theta_ticks(low: 'float', high: 'float', count: 'int' = 8, *, unit: 'str' = 'deg', closed: 'bool' = False) -> 'tuple[float, ...]'¶
Return readable angular tick values between low and high.
circular_mean(angles: 'Sequence[float]', weights: 'Sequence[float] | None' = None, *, unit: 'str' = 'deg', order: 'int' = 1) -> 'tuple[float, float]'¶
The mean direction of a set of angles, and how concentrated they are.
circular_histogram(angles: 'Sequence[float]', bins: 'int' = 12, *, unit: 'str' = 'deg', domain: 'tuple[float, float] | None' = None, density: 'bool' = False) -> 'tuple[tuple[float, ...], tuple[float, ...]]'¶
Bin angles into equal sectors: (centres, heights) for rose().
class AnatomyView(view: 'View', width: 'float', height: 'float', _layers: 'list' = <factory>) -> None¶
A fixed viewport with named surfaces, paths and markers in one camera.
surface(name, mesh, **style)paths(name, lines, **style)markers(name, points, **style)style(name, **changes)-- Restyle one named layer without refitting its geometry or siblings.zoom(focus, *, width, height, pad=1, layers=None)-- Reframe selected layers in the same camera orientation and projection.window(detail)-- The detail's full viewport, expressed in this overview's coordinates.lighting(direction=(-0.4, -0.6, -1), *, levels=16, smooth=80)-- Set one smooth-lighting treatment across all current surfaces.cut(normal, offset=0)-- Section all layers in source coordinates without changing the camera.build(*, depth='layers')-- Render all layers into a clipped, fixed-size native vector viewport.inset(focus, *, width, height, corner='ne', side=None, gap=2, layers=None, **style)-- Overview plus a registered inset or external detail, with locator lines.
anatomy_view(reference, *, width, height, camera='front', pad=1)¶
Fit one camera to a reference mesh and author layers without projections.
model(source: 'str | Path | Mesh', *, width: 'float | str | None' = None, height: 'float | str | None' = None, view: 'Camera | View | str | tuple[float, float] | None' = None, style: 'str' = 'lineart', shading: 'str | None' = None, sort: 'str' = 'auto', opacity: 'float' = 1.0, occlusion: 'float' = 0.0, backend: 'str' = 'builtin', crease: 'float' = 30.0, ridges: 'bool | Mapping[str, bool]' = True, hidden: 'bool' = True, cull: 'bool | None' = None, smooth: 'bool | float | None' = None, up_axis: 'str' = 'z', at: 'Sequence[float] | Vec3 | None' = None, spin: 'Any' = None, scale: 'float | Sequence[float] | None' = None, transform: 'Mat4 | None' = None, repair: 'bool' = False, ink: 'str | None' = None, color: 'str | None' = None, colors: 'Mapping[str, str] | None' = None, stroke_width: 'float | str | None' = None, stroke_widths: 'Mapping[str, float | str] | None' = None, creases: 'Mapping[str, float] | None' = None, light: 'Vec3 | None' = None, levels: 'int | None' = None, depth_cue: 'float | None' = None, lift: 'float | None' = None, shade: 'float | None' = None, anchors: 'Mapping[str, Sequence[float]] | None' = None, groups: 'bool' = True, options: 'Sequence[tuple[str, Any]]' = (), name: 'str | None' = None) -> 'Diagram'¶
Draw a mesh -- from a file or already in hand -- as vector line art.
solid(kind: 'str' = 'cube', *, tolerance: 'float | None' = 0.06, **options) -> 'Diagram'¶
A parametric solid, with no asset file involved.
scene(parts, *, width: 'float | str | None' = None, height: 'float | str | None' = None, view: 'Camera | str | tuple[float, float] | None' = None, order: 'str' = 'parts', assert_order: 'Sequence[tuple[str, str]]' = (), name: 'str' = 'scene', **shared) -> 'Diagram'¶
Several meshes in one projection, painted back to front.
axes(*, width: 'float | str' = 26.0, view: 'Camera | str | tuple[float, float] | None' = 'isometric', labels: 'Sequence[str] | None' = ('x', 'y', 'z'), style: 'str' = 'shaded', length: 'float' = 1.0, thickness: 'float' = 1.0, gap: 'float | None' = None, label_size: 'float | str | None' = None, name: 'str' = 'axes', tolerance: 'float | None' = 0.06, **options) -> 'Diagram'¶
Draw three coordinate arrows and their labels.
cartoon(chain: 'Chain', *, name: 'str' = 'cartoon', group: 'str | None' = None, sides: 'int' = 12, steps: 'int' = 6) -> 'Mesh'¶
The whole chain: one ribbon per continuous segment, merged.
class Mesh(vertices: 'tuple[Vec3, ...]', faces: 'tuple[tuple[int, int, int], ...]', groups: 'tuple[str, ...]' = (), name: 'str' = '', _derived: 'dict' = <factory>) -> None¶
Mesh(vertices: 'tuple[Vec3, ...]', faces: 'tuple[tuple[int, int, int], ...]', groups: 'tuple[str, ...]' = (), name: 'str' = '', _derived: 'dict' =
from_arrays(vertices, faces, *, groups=(), name='')-- Build from iterable XYZ coordinates and triangle indices.clipped(normal, offset=0)-- Keep the half-space normal·point >= offset, with an open cut boundary.simplified(target_faces: 'int')-- Return a quadric-error display approximation with fewer triangles.rough_vertices(degrees: 'float') -> 'frozenset[int]'-- Vertices with a fold, a border or a branch somewhere around them.group_center(name: 'str') -> 'Vec3'-- Centroid of the vertices belonging to a named group, area-weighted by nothing: a plain average of the distinct vertices the group touches. Area weighting would drag the point toward whichever end of a part happened to be finely tessellated.transformed(matrix: 'Mat4') -> 'Mesh'-- Move the mesh. A mirroring transform reverses every winding, because the alternative is a solid whose normals all point inward and whose silhouette comes out inside-out.merged(*others: 'Mesh') -> 'Mesh'-- Concatenate, keeping each part's group names.grouped(name: 'str') -> 'Mesh'-- The same geometry with every face labelled, formergedto keep.centered() -> 'Mesh'scaled_to_fit(size: 'float') -> 'Mesh'-- Uniformly scale so the longest bounding-box side issize.drill(axis: 'str | Sequence[float] | Vec3' = 'z', *, radius: 'float', at: 'Sequence[float] | Vec3 | None' = None, segments: 'int' = 20, group: 'str | None' = None) -> 'Mesh'-- A cylindrical hole straight through the solid, both sides open.subtract(tool: 'Mesh') -> 'Mesh'-- This mesh withtoolremoved. Needs trimesh;drilldoes not.coplanar_patches(faces: 'Sequence[int]') -> 'list[tuple[int, ...]]'-- Group a subset of faces into maximal flat, connected patches.
class Vec3(x: 'float' = 0.0, y: 'float' = 0.0, z: 'float' = 0.0) -> None¶
Vec3(x: 'float' = 0.0, y: 'float' = 0.0, z: 'float' = 0.0)
dot(other: 'Vec3') -> 'float'cross(other: 'Vec3') -> 'Vec3'normalized() -> 'Vec3'lerp(other: 'Vec3', t: 'float') -> 'Vec3'min(other: 'Vec3') -> 'Vec3'max(other: 'Vec3') -> 'Vec3'as_tuple() -> 'tuple[float, float, float]'
class Mat4(ax: 'float' = 1.0, bx: 'float' = 0.0, cx: 'float' = 0.0, dx: 'float' = 0.0, ay: 'float' = 0.0, by: 'float' = 1.0, cy: 'float' = 0.0, dy: 'float' = 0.0, az: 'float' = 0.0, bz: 'float' = 0.0, cz: 'float' = 1.0, dz: 'float' = 0.0) -> None¶
A 3x4 affine map, written as three rows of four.
translation(v: 'Vec3') -> 'Mat4'scaling(sx: 'float', sy: 'float | None' = None, sz: 'float | None' = None) -> 'Mat4'rotation(axis: 'Vec3', degrees: 'float') -> 'Mat4'-- Right-handed rotation about an arbitrary axis (Rodrigues).basis(x: 'Vec3', y: 'Vec3', z: 'Vec3', origin: 'Vec3' = Vec3(x=0.0, y=0.0, z=0.0)) -> 'Mat4'-- The map that sends the unit axes onto these three vectors.apply(p: 'Vec3') -> 'Vec3'apply_vector(v: 'Vec3') -> 'Vec3'-- Directions ignore translation.normal_matrix_apply(n: 'Vec3') -> 'Vec3'-- Transform a surface normal.
anchor3d(node: 'Diagram', name: 'str', point: 'Sequence[float] | Sequence[Sequence[float]]', *, pick: 'str' = 'centroid') -> 'Diagram'¶
Add an anchor at a 3D point, after the fact. Returns the node.
outline_of(part: 'Diagram | Mesh', view: 'View | None' = None, *, crease: 'float' = 30.0, ridges: 'bool' = True, smooth: 'bool | float | None' = None)¶
A part's projected outline: ((points, closed), ...) in its own frame.
panel_mosaic(layout, panels, *, width, height, gap=4, margin=4, row_weights=None, column_weights=None, titles=None, letters=True, label_size=4, label_gap=2, header_bounds='band')¶
Build a page from a rectangular matrix of panel names ('.' is empty).
place_in_clear_space(item, *, within, avoid=(), pad=1, clearance=0.5, steps=9)¶
Place a Diagram inside a Rect, clear of supplied drawing geometry.
hstack(items: 'Iterable[Diagram]', gap: 'Length' = 0.0, align: 'str' = 'center') -> 'Diagram'¶
Left to right. align is "top"/"n", "center"/"c", "bottom"/"s", "baseline", or "origin" to line up the drawn frames.
vstack(items: 'Iterable[Diagram]', gap: 'Length' = 0.0, align: 'str' = 'center') -> 'Diagram'¶
Top to bottom. align is "left"/"w", "center"/"c", "right"/"e", or "origin" to line up the drawn frames.
stack(items: 'Iterable[Diagram]', direction: 'Vec2', gap: 'Length' = 0.0, align: 'str' = 'center') -> 'Diagram'¶
Pack items along direction, each one gap past the last.
grid(items: 'Iterable[Diagram]', cols: 'int | None' = None, rows: 'int | None' = None, gap: 'Length' = 0.0, col_gap: 'Length | None' = None, row_gap: 'Length | None' = None, align: 'str' = 'center', valign: 'str' = 'center') -> 'Diagram'¶
Arrange items in a row-major grid with shared column widths and row heights.
flow(items: 'Iterable[Diagram]', columns: 'int' = 2, gap: 'Length' = 0.0, col_gap: 'Length | None' = None, align: 'str' = 'left') -> 'Diagram'¶
Pack items down columns rather than across rows.
overlay(items: 'Iterable[Diagram]', align: 'str' = 'center') -> 'Diagram'¶
Stack items on top of each other, first one at the bottom.
pad(item: 'Diagram', top: 'Length', right: 'Length | None' = None, bottom: 'Length | None' = None, left: 'Length | None' = None) -> 'Diagram'¶
Grow the space an item occupies, CSS shorthand order.
frame(content: 'Diagram', pad: 'Length' = 0.0, radius: 'Length | None' = None, shape: 'str' = 'rect', min_width: 'Length | None' = None, min_height: 'Length | None' = None, kind: 'str' = 'frame') -> 'Diagram'¶
Draw a shape around content, behind it.
spacer(width: 'Length' = 0.0, height: 'Length' = 0.0) -> 'Diagram'¶
Empty space that is really there: a phantom box, centred on its origin.
beside(a: 'Diagram', b: 'Diagram', direction: 'Vec2', gap: 'Length' = 0.0) -> 'Diagram'¶
b placed alongside a in direction, centred across the axis.
align_to(item: 'Diagram', anchor: 'str') -> 'Diagram'¶
Move an item so its named anchor lands on the origin.
fit(build: 'Callable[[float], Diagram]', width: 'Length | None' = None, height: 'Length | None' = None, *, guess: 'float | None' = None, tries: 'int' = 10, tolerance: 'Length' = 0.05, exact: 'bool' = True, with_extras: 'bool' = False)¶
Call build with sizes until what it returns fits the target.
graph(nodes, edges: 'Iterable' = (), *, layout: 'str' = 'layered', direction: 'str' = 'down', gap: 'Length | None' = None, rank_gap: 'Length | None' = None, lane: 'Length | None' = None, roots: 'Sequence | None' = None, iterations: 'int' = 300, route: 'str' = 'auto', sweeps: 'int' = 4, ports: 'bool' = True, fit: 'Length | None' = None, name: 'str | None' = None) -> 'Graph'¶
Lay out a graph from its edges, and hand back the diagram and the arrows.
class Graph(diagram: 'Diagram', nodes: 'tuple[Diagram, ...]', edges: 'tuple[GraphEdge, ...]', layout: 'str', ranks: 'tuple[int, ...]', keys: 'Mapping[str, int]' = <factory>) -> None¶
What inklet.graph() returns: a laid-out diagram plus its edges.
add_to(figure, **overrides) -> 'list[Link]'-- Put the graph on a figure and route every edge. The usual spelling.build(*, min_arrow_size=None, min_stroke_width=None) -> 'Diagram'-- Build a self-contained static diagram, including all routed edges.
class GraphEdge(source: 'Diagram', target: 'Diagram', label: 'Diagram | None' = None, route: 'str' = 'straight', span: 'int' = 0, options: 'Mapping[str, object]' = <factory>) -> None¶
One edge, resolved: the two node diagrams, and how to draw the arrow.
link_kwargs() -> 'dict[str, object]'-- Everything but the endpoints, ready to splat intofig.link.
class GraphError¶
A graph that cannot be laid out as asked.
sankey(flows: 'Iterable[Sequence]', *, nodes: 'Iterable' = (), labels: 'Mapping | Callable[[object], str] | None' = None, length: 'Length | None' = None, breadth: 'Length | None' = None, node_width: 'Length | None' = None, gap: 'Length | None' = None, label_gap: 'Length | None' = None, direction: 'str' = 'right', order: 'str' = 'barycentre', sweeps: 'int' = 4, relax: 'int' = 6, ease: 'float | None' = None, color: 'Mapping | Callable[[object], str] | None' = None, tint: 'str' = 'source', opacity: 'float' = 0.55, halo: 'float | None' = None, name: 'str | None' = None) -> 'Sankey'¶
Lay out a Sankey from its flows and draw it.
class Sankey(diagram: 'Diagram', nodes: 'tuple[SankeyNode, ...]', flows: 'tuple[SankeyFlow, ...]', crossings: 'int', unit: 'float', keys: 'Mapping[object, int]' = <factory>) -> None¶
What inklet.sankey() returns: the drawing, and everything it decided.
add_to(figure) -> 'Diagram'-- Put the drawing on a figure. Nothing to route: a ribbon is content.node(key) -> 'SankeyNode'-- The full record for a node, rank and value included.
class SankeyError¶
A flow diagram that cannot be laid out as asked.
class SankeyFlow(source: 'SankeyNode', target: 'SankeyNode', value: 'float', diagram: 'Diagram') -> None¶
One ribbon, resolved: its two nodes, its value, and the band drawn.
class SankeyNode(key: 'object', label: 'str', rank: 'int', order: 'int', value: 'float', box: 'Rect', diagram: 'Diagram') -> None¶
One bar: what it is, where the layout put it, and how much goes through.
connect(source: 'Diagram', target: 'Diagram', *, within: 'Diagram | None' = None, **kwargs) -> 'Diagram'¶
Connect two placed shapes, clipping the ends to their actual boundaries.
link(source, target, **kwargs) -> 'Link'¶
Declare a connector. Nothing is measured until route().
class Link(source: 'Diagram | AnchorRef | Sequence[Diagram | AnchorRef]', target: 'Diagram | AnchorRef | Sequence[Diagram | AnchorRef]', through: 'Sequence[Diagram | AnchorRef]' = (), kind: 'str' = 'arrow', route: 'str' = 'straight', label: 'Diagram | None' = None, label_side: 'str' = 'center', label_offset: 'float' = 1.0, standoff: 'float' = 0.0, arrow_size: 'float | None' = None, style: 'Style' = Style(fill=None, stroke=None, stroke_width=None, stroke_dash=None, stroke_linecap=None, stroke_linejoin=None, opacity=None, fill_opacity=None, stroke_opacity=None, corner_radius=None, font_family=None, font_size=None, font_weight=None, font_style=None, text_fill=None, line_height=None, halo=None, halo_color=None), name: 'str | None' = None, head: 'str | None' = None, corner: 'float' = 0.0, shoulder: 'float | None' = None, waypoints: 'Sequence[Vec2 | tuple[float, float] | AnchorRef | tuple[AnchorRef, float, float]]' = (), port: 'float' = 0.0, target_port: 'float' = 0.0, offset: 'float' = 0.0, loop: 'str | None' = None, loop_size: 'float | None' = None, stem: 'float | None' = None) -> None¶
An arrow that has not been drawn yet.
route(link: 'Link', placements: 'Mapping[str, Placement]', obstacles: 'Sequence[Rect | Obstacle]' = (), drawn: 'Sequence[tuple[Vec2, Vec2]]' = ()) -> 'Diagram'¶
Turn a spec into geometry: shaft, heads and label, in world coordinates.
route_all(links: 'Iterable[Link]', placements: 'Mapping[str, Placement]', obstacles: 'Sequence[Rect | Obstacle] | None' = None) -> 'Diagram'¶
Route links in declaration order, reserving each shaft and label.
figure(width: 'float | str' = 89.0, **kwargs) -> 'Figure'¶
A page to put content on. See Figure for everything it can do.
class Figure(width: 'float' = 89.0, height: 'float | None' = None, theme: 'Theme' = <factory>, margin: 'float' = 2.0, background: 'str | None' = None, _content: 'list[Diagram]' = <factory>, _links: 'list[Link]' = <factory>, _built: 'tuple[Diagram, dict[str, Placement]] | None' = None) -> None¶
Figure(width: 'float' = 89.0, height: 'float | None' = None, theme: 'Theme' =
add(*diagrams: 'Diagram') -> 'Diagram'-- Stack content vertically. Returns the last item for chaining.link(source, target, *, label: 'str | Diagram | None' = None, label_plate: 'bool' = True, **kwargs) -> 'Link'-- Connect two things. The link module works in geometry alone, so a string label is shaped here, where the theme is known.build() -> 'tuple[Diagram, dict[str, Placement]]'-- Lay out the content, route the links over it, put it on the page.page_rect(content_box: 'Rect | None' = None) -> 'Rect'-- The finished page, in millimetres.lint(**kwargs) -> 'list[Diagnostic]'-- Every rule, run over the built figure. Seeinklet.lint.report(**kwargs) -> 'str'-- Returnlint()diagnostics formatted as text.to_svg(*, text: 'str' = 'names', **kwargs) -> 'str'-- The figure as SVG text, page frame and background included.to_pdf(*, text: 'str' = 'outline', **kwargs) -> 'bytes'-- The figure as PDF bytes, on the same page asto_svgputs it.to_png(*, dpi=150, **kwargs) -> 'bytes'-- Render PNG at physical DPI with optional resvg, without a browser.export(directory: 'str | Path', *, name: 'str' = 'figure', dpi: 'float' = 150, text: 'str' = 'embed', compare_pdf: 'bool' = True, png_backend: 'str' = 'resvg', compare_to=None) -> 'dict[str, Path]'-- Write SVG, PDF, PNG, diagnostics and a local HTML review page.save(*paths: 'str | Path', **kwargs) -> 'dict[str, bool]'-- Write the figure to SVG, PDF or PNG, following each filename suffix.
Theming¶
theme(name: 'str' = 'nature') -> 'Theme'¶
Look up a theme by name. The default is the one built for print.
class Theme(name: 'str', ink: 'str', paper: 'str', muted: 'str', accent: 'str', grid: 'str', palette: 'tuple[str, ...]', font_family: 'str', font_mono: 'str', font_size: 'float', font_size_small: 'float', font_size_large: 'float', line_height: 'float', stroke: 'float', hairline: 'float', thick: 'float', radius: 'float', space: 'tuple[float, ...]', arrow_size: 'float', link_radius: 'float' = 0.0, axis_ink: 'str | None' = None, axis_text: 'str | None' = None) -> None¶
A complete set of design tokens.
with_palette(palette: "'str | Palette | tuple[str, ...]'") -> "'Theme'"-- This theme with other series colours, given by name, as aPaletteor as a sequence of colours:NATURE.with_palette("inklet").style_for(role: 'str') -> 'Style'-- TheStylefor a semantic role.color(index: 'int') -> 'str'-- The categorical colour for seriesindex.text_on(background: 'str', min_ratio: 'float' = 4.5) -> 'str'-- Ink that stays readable onbackground.ink_color(index: 'int', min_ratio: 'float' = 3.0) -> 'str'--color(index), darkened towardsinkuntil it clearsmin_ratioagainstpaper.text_color(index: 'int', min_ratio: 'float' = 4.5) -> 'str'--color(index), darkened along its own hue until it can carry text.gap(step: 'int | str') -> 'float'-- A spacing value, by name ('xs' 's' 'm' 'l' 'xl') or by index.scaled(factor: 'float') -> "'Theme'"-- The same design at a different physical size.
THEMES = {'nature': Theme(name='nature', ink='#1a1a1a', paper='#ffffff', muted='#5f6b7a', accent='#0072b2', grid='#e4e4e7', palette=('#1d57a0', '#df913e', '#418368', '#93190a', '#8bc4e5', '#56254c', '#fbe673', '#ad7591'), font_family='Helvetica Neue, Helvetica, Arial, sans-serif', font_mono='SF Mono, Menlo, Consolas, monospace', font_size=2.469444444444444, font_size_small=2.1166666666666663, font_size_large=2.822222222222222, line_height=1.25, stroke=0.25, hairline=0.13, thick=0.5, radius=1.0, space=(0.5, 1.0, 2.0, 3.0, 5.0, 8.0, 13.0), arrow_size=1.6, link_radius=0.0, axis_ink=None, axis_text=None), 'slides': Theme(name='slides', ink='#111418', paper='#ffffff', muted='#4b5563', accent='#4477aa', grid='#d4d4d8', palette=('#4477aa', '#ee6677', '#228833', '#ccbb44', '#66ccee', '#aa3377', '#bbbbbb'), font_family='Inter, Helvetica Neue, Helvetica, Arial, sans-serif', font_mono='JetBrains Mono, SF Mono, Menlo, monospace', font_size=4.938888888888888, font_size_small=3.880555555555555, font_size_large=7.055555555555555, line_height=1.3, stroke=0.6, hairline=0.3, thick=1.2, radius=2.0, space=(1.0, 2.0, 4.0, 6.0, 10.0, 16.0, 26.0), arrow_size=3.6, link_radius=0.0, axis_ink=None, axis_text=None), 'notebook': Theme(name='notebook', ink='#1f2328', paper='#fcfcfa', muted='#57606a', accent='#332288', grid='#e6e4e0', palette=('#1d57a0', '#df913e', '#418368', '#93190a', '#8bc4e5', '#56254c', '#fbe673', '#ad7591'), font_family='Inter, Segoe UI, Roboto, Helvetica, sans-serif', font_mono='JetBrains Mono, SF Mono, Menlo, monospace', font_size=3.175, font_size_small=2.645833333333333, font_size_large=4.2333333333333325, line_height=1.4, stroke=0.35, hairline=0.18, thick=0.7, radius=1.8, space=(0.5, 1.5, 3.0, 4.5, 7.0, 11.0, 18.0), arrow_size=2.2, link_radius=0.0, axis_ink=None, axis_text=None)}¶
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
use_theme(name: 'str | Theme') -> 'Theme'¶
Set the theme new content is built against.
current_theme() -> 'Theme'¶
The theme new nodes are being styled with right now.
contrast_ratio(a: 'str | Sequence[float]', b: 'str | Sequence[float]') -> 'float'¶
WCAG contrast ratio, 1.0 (identical) to 21.0 (black on white).
mix(a: 'str | Sequence[float]', b: 'str | Sequence[float]', t: 'float') -> 'str'¶
Blend a towards b; t=0 returns a, t=1 returns b.
lighten(color: 'str | Sequence[float]', amount: 'float') -> 'str'¶
Move amount of the way towards white.
darken(color: 'str | Sequence[float]', amount: 'float') -> 'str'¶
Move amount of the way towards black.
readable(color: 'str | Sequence[float]', on: 'str | Sequence[float]', min_ratio: 'float' = 4.5) -> 'str'¶
The nearest colour to color, along its own lightness, that can be read on on.
Inspection and output¶
class FigureReview(diagram: 'Diagram', findings: 'tuple[Diagnostic, ...]', highlighted: 'int', source: 'Diagram | None' = None) -> None¶
All findings plus a numbered overlay, without altering the source figure.
as_dict()-- JSON-ready findings with stable node references and page coordinates.save(prefix)-- Write a numbered SVG overlay and matching JSON finding list.save_bundle(directory, *, reference=None, sources=(), panels=None, reference_regions=None, dpi=180, caption='Figure comparison')-- Export original art, diagnostics, source hashes and an HTML comparison.
review_figure(art, *, max_highlights=100, **checks)¶
Run figure checks and return an inspectable numbered diagnostic overlay.
lint(root: 'Diagram', *, page: 'Rect | None' = None, rules: 'Iterable[str] | Mapping[str, Rule] | None' = None, min_font_pt: 'float' = 5.0, min_stroke_mm: 'float' = 0.088, min_dpi: 'float' = 300.0, placements: 'Mapping[str, Placement] | None' = None, page_fill: 'str' = '#ffffff', min_clearance_mm: 'float' = 1.0, min_overlap_fraction: 'float' = 0.08, max_stroke_widths: 'int' = 3, max_font_pt: 'float | None' = None, max_height_mm: 'float | None' = None, max_letter_pt: 'float | None' = None, expected_fonts: 'Sequence[str] | None' = None, expect: 'Iterable[str]' = (), house: 'HouseRules | None' = None) -> 'list[Diagnostic]'¶
Check a figure and return its diagnostics, deterministically ordered.
abutting(kind: 'str' = 'group') -> 'str'¶
Declare that the parts inside this subtree touch by design.
crossing(stroke: "'Diagram'", *through: "'Diagram'") -> "'Diagram'"¶
Declare that stroke is drawn through through on purpose.
class Diagnostic(code: 'str', severity: 'str', message: 'str', targets: 'tuple[str, ...]', where: 'Rect | Vec2 | None', hint: 'str | None' = None) -> None¶
One actionable finding. where is figure-space, in millimetres.
format_report(diags: 'Sequence[Diagnostic]', *, color: 'bool' = False) -> 'str'¶
Compact report. Returns a single string with no trailing newline.
to_svg(root: 'Diagram | RenderScene', *, width: 'float | str | None' = None, height: 'float | str | None' = None, margin: 'float' = 0.0, background: 'str | None' = None, precision: 'int' = 3, title: 'str | None' = None, compact: 'bool | str' = 'auto', text: 'str' = 'names', ids: 'str' = 'nodes') -> 'str'¶
Render a diagram tree to a self-contained SVG document.
save_svg(root: 'Diagram | RenderScene', path: 'str', *, width: 'float | str | None' = None, height: 'float | str | None' = None, margin: 'float' = 0.0, background: 'str | None' = None, precision: 'int' = 3, title: 'str | None' = None, compact: 'bool | str' = 'auto', text: 'str' = 'names', ids: 'str' = 'nodes') -> 'None'¶
Write root to path as SVG. to_svg is the same thing as a string.
to_pdf(root: 'Diagram | RenderScene | Sequence[Diagram | RenderScene]', *, width: 'float | str | None' = None, height: 'float | str | None' = None, margin: 'float' = 0.0, background: 'str | None' = None, precision: 'int' = 3, title: 'str | None' = None, compress: 'bool' = True, text: 'str' = 'outline') -> 'bytes'¶
Render one diagram tree, or a sequence of them, to a PDF document.
save_pdf(root: 'Diagram | RenderScene | Sequence[Diagram | RenderScene]', path: 'str | Path', **kwargs) -> 'None'¶
Write root to path as PDF. to_pdf is the same thing as bytes.
outline_text(root: 'Diagram') -> 'Diagram'¶
Return root with every shaped text block replaced by its glyph outlines.
shape(text: 'str', *, font: 'str | FontFace' = 'sans', size: 'float | str' = 2.469444444444444, weight: 'str' = 'regular', align: 'str' = 'center', line_height: 'float' = 1.25, width: 'float | str | None' = None, features: 'dict[str, bool | int] | None' = None, markup: 'bool' = True, colors: 'Mapping[str, str] | None' = None) -> 'TextPrim'¶
Measure a string into a fully-shaped TextPrim.
measure(text: 'str', **options) -> 'Rect'¶
The block's local bounding box, centred on the origin like the prim itself.
apply_theme(root: 'Diagram', theme: 'Theme') -> 'Diagram'¶
Slide theme styles underneath whatever the author set explicitly.
resolve(root: 'Diagram', base: 'Affine' = Affine(a=1.0, b=0.0, c=0.0, d=1.0, e=0.0, f=0.0), base_style: 'Style' = Style(fill=None, stroke=None, stroke_width=None, stroke_dash=None, stroke_linecap=None, stroke_linejoin=None, opacity=None, fill_opacity=None, stroke_opacity=None, corner_radius=None, font_family=None, font_size=None, font_weight=None, font_style=None, text_fill=None, line_height=None, halo=None, halo_color=None)) -> 'dict[str, Placement]'¶
Flatten the tree into world transforms, keyed by node id.
Core types and units¶
class Diagram(prim: 'Prim | None' = None, children: "tuple['Diagram', ...]" = (), transform: 'Affine' = Affine(a=1.0, b=0.0, c=0.0, d=1.0, e=0.0, f=0.0), style: 'Style' = Style(fill=None, stroke=None, stroke_width=None, stroke_dash=None, stroke_linecap=None, stroke_linejoin=None, opacity=None, fill_opacity=None, stroke_opacity=None, corner_radius=None, font_family=None, font_size=None, font_weight=None, font_style=None, text_fill=None, line_height=None, halo=None, halo_color=None), kind: 'str' = 'g', name: 'str | None' = None, id: 'str' = '', envelope_override: 'Envelope | None' = None, attached_to: 'tuple[str, ...]' = (), anchors: 'dict[str, Vec2]' = <factory>, notes: 'dict[str, object]' = <factory>, clip_region: 'tuple[Vec2, ...]' = (), _cache: 'dict' = <factory>) -> None¶
Diagram(prim: 'Prim | None' = None, children: "tuple['Diagram', ...]" = (), transform: 'Affine' = Affine(a=1.0, b=0.0, c=0.0, d=1.0, e=0.0, f=0.0), style: 'Style' = Style(fill=None, stroke=None, stroke_width=None, stroke_dash=None, stroke_linecap=None, stroke_linejoin=None, opacity=None, fill_opacity=None, stroke_opacity=None, corner_radius=None, font_family=None, font_size=None, font_weight=None, font_style=None, text_fill=None, line_height=None, halo=None, halo_color=None), kind: 'str' = 'g', name: 'str | None' = None, id: 'str' = '', envelope_override: 'Envelope | None' = None, attached_to: 'tuple[str, ...]' = (), anchors: 'dict[str, Vec2]' =
extent(direction: 'Vec2') -> 'float'-- How far this reaches along a direction, in the parent's frame. This is what stacking asks, and why a rotated shape packs tighter than its bbox.anchor(name: 'str', at: 'tuple[float, float] | Vec2') -> "'Diagram'"-- Register a named point. A tuple is read as fractions of the local bounding box, (0, 0) being its top-left corner -- the natural way to point at an ear in a photograph.anchor_point(name: 'str' = 'center') -> 'Vec2'-- Local coordinates of a named or compass anchor.registered_point(name: 'str') -> 'Vec2 | None'-- A registered anchor's coordinates in this node's frame, or None.note(key: 'str', value: 'object') -> "'Diagram'"-- Record something about this node that core has no opinion on.carry_notes(source: "'Diagram'") -> "'Diagram'"-- Copysource's notes onto this node, re-expressed in this frame.at(name: 'str') -> "'AnchorRef'"placed(transform: 'Affine') -> "'Diagram'"-- Wrap in a positioned parent, leaving this node untouched so callers keep a working handle on it.translated(dx: 'float', dy: 'float' = 0.0) -> "'Diagram'"rotated(degrees: 'float') -> "'Diagram'"scaled(factor: 'float', factor_y: 'float | None' = None) -> "'Diagram'"centered() -> "'Diagram'"-- Shift so the envelope's centre sits on the origin.styled(**kwargs) -> "'Diagram'"named(name: 'str') -> "'Diagram'"copy() -> "'Diagram'"-- Fresh identities throughout, for placing the same shape twice.walk() -> "Iterator['Diagram']"find(name: 'str') -> "'Diagram'"
class DiagramError¶
Common base class for all non-exit exceptions.
class Style(fill: 'str | None' = None, stroke: 'str | None' = None, stroke_width: 'float | None' = None, stroke_dash: 'tuple[float, ...] | None' = None, stroke_linecap: 'str | None' = None, stroke_linejoin: 'str | None' = None, opacity: 'float | None' = None, fill_opacity: 'float | None' = None, stroke_opacity: 'float | None' = None, corner_radius: 'float | None' = None, font_family: 'str | None' = None, font_size: 'float | None' = None, font_weight: 'str | None' = None, font_style: 'str | None' = None, text_fill: 'str | None' = None, line_height: 'float | None' = None, halo: 'float | None' = None, halo_color: 'str | None' = None) -> None¶
Style(fill: 'str | None' = None, stroke: 'str | None' = None, stroke_width: 'float | None' = None, stroke_dash: 'tuple[float, ...] | None' = None, stroke_linecap: 'str | None' = None, stroke_linejoin: 'str | None' = None, opacity: 'float | None' = None, fill_opacity: 'float | None' = None, stroke_opacity: 'float | None' = None, corner_radius: 'float | None' = None, font_family: 'str | None' = None, font_size: 'float | None' = None, font_weight: 'str | None' = None, font_style: 'str | None' = None, text_fill: 'str | None' = None, line_height: 'float | None' = None, halo: 'float | None' = None, halo_color: 'str | None' = None)
over(base: 'Style | None') -> 'Style'-- Resolve self against an inherited style, self winning where set.with_(**kwargs) -> 'Style'
class StyleError¶
Inappropriate argument value (of correct type).
class Vec2(x: 'float' = 0.0, y: 'float' = 0.0) -> None¶
Vec2(x: 'float' = 0.0, y: 'float' = 0.0)
dot(other: 'Vec2') -> 'float'cross(other: 'Vec2') -> 'float'normalized() -> 'Vec2'perp() -> 'Vec2'-- Rotated a quarter turn. Used for arrow heads and label offsets.angle() -> 'float'
class Rect(x0: 'float', y0: 'float', x1: 'float', y1: 'float') -> None¶
Rect(x0: 'float', y0: 'float', x1: 'float', y1: 'float')
from_size(width: 'float', height: 'float', center: 'Vec2' = Vec2(x=0.0, y=0.0)) -> 'Rect'hull(points) -> 'Rect'union(other: 'Rect') -> 'Rect'pad(top: 'float', right: 'float | None' = None, bottom: 'float | None' = None, left: 'float | None' = None) -> 'Rect'-- CSS shorthand order.overlap(other: 'Rect') -> 'Rect | None'contains(p: 'Vec2') -> 'bool'transform(t: 'Affine') -> 'Rect'-- Exact axis-aligned bounds of this rectangle after an affine map.
class Affine(a: 'float' = 1.0, b: 'float' = 0.0, c: 'float' = 0.0, d: 'float' = 1.0, e: 'float' = 0.0, f: 'float' = 0.0) -> None¶
SVG's matrix(a b c d e f): x' = ax + cy + e, y' = bx + dy + f.
translation(dx: 'float', dy: 'float') -> 'Affine'scaling(sx: 'float', sy: 'float | None' = None) -> 'Affine'rotation(degrees: 'float') -> 'Affine'apply(p: 'Vec2') -> 'Vec2'apply_vector(v: 'Vec2') -> 'Vec2'-- Directions ignore translation.transpose_linear(v: 'Vec2') -> 'Vec2'-- Apply the transpose of the linear part. This is what pulls a query direction back through a transform when evaluating an envelope.inverse() -> 'Affine'uniform_scale() -> 'float'-- Return the geometric mean scale factor.
mm(value: 'float | int | str') -> 'float'¶
Coerce a length to millimetres. Bare numbers are already mm.
pt(value: 'float') -> 'float'¶
Points to millimetres, for font sizes and hairline strokes.
COLUMN_SINGLE = 89.0¶
Numeric constant.
COLUMN_DOUBLE = 183.0¶
Numeric constant.
Stable subpackages¶
These packages are covered by the same
compatibility policy as top-level
inklet. Before 4.3 they lived under inklet.experimental; those paths still
work and return the same objects (see migration).
inklet.volume¶
Calibrated microscopy volumes, sections, slabs, channels and measurements.
class Volume(data: object, spacing_zyx: tuple[float, float, float], unit: str, origin_xyz: tuple[float, float, float] = (0.0, 0.0, 0.0), source_id: str = '') -> None¶
An immutable scalar snapshot with explicit voxel calibration and identity.
world(index_zyx)-- Convert a finite fractional voxel index to a physical X,Y,Z position.report()slice(axis, index)-- An axis-aligned physical section, with the second axis pointing up.crop(start_zyx, stop_zyx)-- Half-open voxel bounds; preserve the original physical coordinate frame.reslice(plane, *, kind)-- Sample an explicit physical plane: linear intensities or nearest labels.project_slab(slab, *, reduction, region=None)-- Project physical intensity samples, optionally restricted to a shared region.measure(label)-- Voxel-count volume, centroid and boundary status of one integer label.surface(label, *, allow_clipped=False, step_size=1)-- Marching-cubes surface of one label, in calibrated world coordinates.
class Slice(volume: inklet.volume._volume.Volume, axis: str, index: int) -> None¶
Slice(volume: inklet.volume._volume.Volume, axis: str, index: int)
project(world_xyz, *, width)-- Image-centred mm (+y down); accepts points in this voxel slab only.diagram(*, width, window)-- A greyscale slice with an explicit shared display window and no resampling.scalebar(length, *, width)-- A separate vector key; place beside the image without further scaling.
class Plane(centre_xyz: tuple[float, float, float], right_xyz: tuple[float, float, float], up_xyz: tuple[float, float, float], shape_yx: tuple[int, int], spacing_yx: tuple[float, float], unit: str) -> None¶
A rectangular sampling plane; output rows run downward, columns rightward.
world(row, column)-- Physical XYZ for a fractional output pixel index; index 0 is a centre.project(world_xyz, *, width)-- Project an on-plane point to image-centred page mm, with +y downward.scalebar(length, *, width)-- A separate vector key in physical units; scale together with the image.report()
class SampledSection(plane: inklet.volume._sections.Plane, volume: inklet.volume._volume.Volume, kind: str, data: object, valid: object) -> None¶
An immutable resampled array plus an explicit source-coverage mask.
report()contours(label)-- Exact sampled-label pixel edges, with source-coverage limits kept separate.measure(label)-- Sampled label area, not 3D volume or a native-resolution measurement.diagram(*, width, window)-- Windowed greyscale RGBA image; out-of-volume samples are transparent.
reslice(volume, plane, *, kind)¶
Resample a plane; labels preserve exact integer IDs, including uint64.
class Slab(plane: inklet.volume._sections.Plane, thickness: float, samples: int) -> None¶
A finite thickness about a Plane, sampled at equal-width bin midpoints.
face(offset)-- A parallel plane at a signed physical distance along the normal.report()
class SlabProjection(slab: inklet.volume._slabs.Slab, volume: inklet.volume._volume.Volume, reduction: str, data: object, counts: object, region: inklet.volume._regions.BoxRegion | None = None) -> None¶
Immutable intensity projection and count of contributing samples at each pixel.
report()diagram(*, width, window)-- Windowed image; pixels with no contributing samples are transparent.
project_slab(volume, slab, *, reduction, region=None)¶
Reduce intensity samples with O(output pixels) working memory.
class BoxRegion(selection_id: str, lower_xyz: tuple[float, float, float], upper_xyz: tuple[float, float, float], unit: str) -> None¶
An axis-aligned world XYZ box with a stable, caller-assigned identity.
report()mask(plane)-- Immutable YX membership of section pixel centres, independent of source coverage.intersection(plane)-- World XYZ polygon of box/plane intersection, clipped to the image extent.outline(plane, *, width, **style)-- Vector outline in the same image-centred page coordinates as Plane.project.measure(volume, *, label)-- Count an exact integer label within the box on the supplied source grid.
class Channel(name: str, sampled: inklet.volume._sections.SampledSection | inklet.volume._slabs.SlabProjection, color: str, window: tuple[float, float], weight: float = 1.0) -> None¶
One sampled intensity signal and its explicit display mapping.
report()
class Composite(channels: tuple[inklet.volume._channels.Channel, ...], coverage: str) -> None¶
Additive display RGB from channels sharing exactly the same sampling geometry.
report()diagram(*, width)legend(*, size=2.822222222222222)-- Vector color keys recording channel names, windows and display weights.
class LabelContour(section: inklet.volume._sections.SampledSection, label: int) -> None¶
Boundary segments of one exact label ID on a sampled section grid.
report()world_segments(*, include_coverage=False)-- Physical XYZ edge pairs for use with saved-camera vector paths.diagram(*, width, stroke, stroke_width=0.25, coverage='omit')-- Vector boundaries aligned with the section image; coverage edges are explicit.
class LabelMeasurements(_payload: str) -> None¶
A reproducible long-form table; report and row access return fresh copies.
report()to_json()to_csv()-- Long-form CSV; retain label_id as text when importing large IDs.
measure_labels(labels, channels, *, label_ids=None, region=None, coverage='intersection')¶
Measure source intensities without display windows, weights or RGB conversion.
class TiffImage(names: tuple[str, ...], volumes: tuple[inklet.volume._volume.Volume, ...], _provenance: str) -> None¶
Named immutable scalar volumes plus import provenance.
report()
read_tiff(path, *, spacing_zyx, unit, source_id, channel_names=None, origin_xyz=(0.0, 0.0, 0.0), series=0, time_index=None, axes=None)¶
Read a calibrated ZYX volume per channel from a local TIFF series.
inklet.selection¶
Immutable keyed tables and portable selection states.
class KeyedTable(name, columns, *, key='id')¶
Snapshot scalar columns with a stable table name and unique string key.
from_pandas(name, frame, *, key='id', columns=None, time_columns=None)-- Snapshot a pandas DataFrame; ignore its index and require a string key.from_polars(name, frame, *, key='id', columns=None, time_columns=None)-- Snapshot an eager Polars DataFrame with an explicit string key.subset(ids)-- Return columns in source order, rejecting IDs absent from this table.
class SelectionState(table: 'str', data_digest: 'str', selected_ids: 'tuple[str, ...]' = (), visible_ids: 'tuple[str, ...] | None' = None) -> None¶
A selection and optional visibility filter tied to exact table contents.
for_table(table, *, selected=(), visible=None)validate(table)visible(table)rebase(table, *, missing='error')-- Bind to revised contents; report removed IDs when explicitly dropping.to_json()from_json(payload)
class RebasedSelection(state: 'SelectionState', removed_selected: 'tuple[str, ...]', removed_visible: 'tuple[str, ...]') -> None¶
The result of SelectionState.rebase: the rebound state and dropped IDs.
inklet.project¶
Reproducible figure projects with verified assets and explicit correspondence.
class Asset(id: str, path: str, sha256: str, size: int, source: str, license: str, role: str = 'data', unit: str | None = None) -> None¶
One source file with author-supplied provenance and optional physical units.
class AssetManifest(assets: tuple[inklet.project.assets.Asset, ...] = ()) -> None¶
Immutable inventory. Capture explicitly chosen files; verify before reuse.
capture(root, entries)-- Capture dictionaries with id/path/source/license and optional role/unit.verify(root)-- Return verified file paths by asset ID; reject missing or changed bytes.to_dict()from_dict(value)
class EntityMap(entities=(), sources=None)¶
An immutable entity registry with source-local, many-to-one bindings.
selected(source, local_ids)-- Translate a source selection to canonical entity IDs.targets(entities)-- Translate canonical selection to every mapped content source.selection_for(source, table, entities)-- Bind selection to an existing table with source-local keys.validate_source(source, local_ids)-- Require exact coverage, including IDs which are currently unselected.view(source, table, view)-- Map a source-native drawing/image/field view into the linked runtime.joined_table(name, tables)-- Join keyed tables by explicit entities for the existing linked runtime.changes(revised)-- Report removed entities and every removed or reassigned local binding.to_dict()from_dict(value)
class ExportDriftWarning¶
A reopened project's SVG differs from the export recorded when it was saved.
class FigureProject(name, recipe, *, assets=None, identities=None, selected=(), width=None, height=None, preset=None)¶
Connect a Composition editor, an asset inventory and entity selection.
select(source, local_ids)-- Select through any registered content source; return all linked targets.state_for(figure)-- Apply canonical selection to a BrowserFigure built from joined_table().select_state(figure, state)-- Transfer a validated linked-view selection back into the project.save(directory, *, asset_root)-- Stage a new portable directory with verified assets and SVG/PDF exports.open(directory, factory, *, verify_export=True)-- Verify the bundle, then call trusted factory(root) to rebuild its recipe.revise(recipe, *, assets=None, identities=None, missing='error')-- Return a new project, preserving valid choices and reporting conflicts.
inklet.editor¶
Local browser editing of composition layouts, labels, styles and cameras through Python.
class LayoutEditor(recipe, *, width=None, height=None, preset=None)¶
Edit a live Composition layout, labels, styles and cameras with matching Python exports.
overrides()-- Return independently owned JSON-compatible saved layout choices.snapshot()-- Return current controls, revision and preview without rebuilding.command(action, value=None, *, revision=None, missing='error')-- Compile a command atomically; a stale revision or failed build changes nothing.start(*, port=0)-- Start a loopback-only editor server; port=0 chooses a free local port.close()-- Stop the local server; compiled output and saved choices remain accessible.
Diagnostic codes¶
Diagnostic codes returned by fig.lint() and formatted by fig.report().
Review each finding in the context of the finished figure; passing diagnostics
does not replace visual or scientific review.
fig.lint() takes the thresholds as keywords: min_font_pt, min_clearance_mm,
max_stroke_widths, min_contrast, min_dpi. fig.report() takes the same
ones and formats the result.
AXIS_TITLE_OVERHANG¶
A plot's y-axis title longer than the plot, and what it runs into.
BAR_WIDTH_OUT_OF_SCALE¶
Bars whose width in data units is wider than the axis they stand on.
BOLD_TEXT¶
Bold anywhere but a panel letter.
BREAK_DISTORTS¶
Report marks compared across a broken axis and the scale distortion.
COINCIDENT_SHAFT¶
Two links drawn along the same line, one hidden under the other.
CROWDING¶
Neighbours that clear each other but only just.
DATA_CLIPPED¶
Named series whose points clip=True hid from the axes, counted.
DATA_OUTSIDE¶
Data drawn past the axes of its panel: a range narrower than the data.
DEPTH_ORDER¶
Report a scene part drawn over another part that is geometrically in front of it.
DUPLICATE_KEY¶
Two colour bars, or two legends, in one panel for the same series.
EMPTY_DIAGRAM¶
Nodes that draw nothing, and figures that draw nothing at all.
FONT_SUBSTITUTED¶
Report text shaped with a font different from the requested font.
HAIRLINE¶
Strokes that vanish on press. 0.088mm is the usual 0.25pt floor.
INCONSISTENT_STROKE¶
Report more distinct line weights than the configured limit.
KEY_COVERS_DATA¶
A key inside the plot area painted over the panel's own data.
KEY_IN_PANEL¶
A key drawn as part of a plot panel rather than outside every panel.
KEY_MISMATCH¶
Report a color key that does not match the adjacent marks.
LABEL_COVERS_SHAFT¶
A link's own label plate drawn over its own elbow.
LABEL_OFF_LINK¶
A link label that found no room beside its link and was moved away.
LABEL_UNPLACED¶
Labels a placer reported it could not place without a collision.
LARGE_TEXT¶
Text above an optional publication maximum after enclosing transforms.
LINK_COLLAPSED¶
An arrow the author asked for that is not on the page.
LINK_CROSSES¶
A connector running straight through a shape it was not routed to.
LINK_CROSSES_LINK¶
Two connectors that cross each other.
LINK_UNCLIPPED¶
Report an arrow whose endpoint does not meet the target boundary.
LOW_CONTRAST¶
Text that does not separate from what is behind it.
LOW_DPI¶
Rasters placed larger than their pixels support.
MARKER_CUT¶
Markers the axes edge cuts through, which clip=True leaves half drawn.
MARKER_OUTLINE¶
A filled marker with an outline in another colour.
MISSING_GLYPHS¶
Text no installed font can draw, which prints as a row of empty boxes.
MUTED_TEXT¶
Text in a grey lighter than ink, or in a colour the house calls muted.
OFF_CANVAS¶
Anything drawable that leaves the page.
OFF_PANEL¶
Text that leaves the plot box of the panel it was placed in.
ORPHAN_LEADER¶
Leaders drawn to a label with no text in it.
OVERLAP¶
Colliding elements, filtered hard against false positives.
PAGE_TOO_TALL¶
Page height above an optional publication limit, in physical millimetres.
PATH_CROSSES¶
A stroke that is not a routed link running through a drawing.
PLOT_WIDTH_OVERRIDDEN¶
A plot drawn much narrower than the width its author set.
ROUTE_BLOCKED¶
A link that asked to go around the obstacles and could not.
ROWS_COMBINED¶
Bars that summed repeated rows, and lines that zigzag through them.
SERIES_FLATTENED¶
A named series squashed flat by a much taller one on the same axis.
STROKE_TIER¶
An author's stroke in a plot panel at a width the house does not use.
TEXT_FILL_IGNORED¶
fill= on a text node, where the glyph colour is text_fill=.
TEXT_OVERFLOW¶
A label wider or taller than the box it was put inside.
TEX_MATH¶
LaTeX written into a label, which inklet prints literally.
TICKS_DROPPED¶
Explicitly supplied ticks an axis left out for lack of room.
TINY_TEXT¶
Type below the legibility floor once every enclosing scale is applied.