25 Known Limitations
Gaps in the current Plotje release. None produce crashes on canonical inputs; each is documented and tracked for post-alpha work.
(ns plotje-book.known-limitations
(:require
;; Kindly -- notebook rendering protocol
[scicloj.kindly.v4.kind :as kind]))Layout and Visuals
Multi-layer overlays like
(-> data (pj/lay-point ...) (pj/lay-smooth {:stat :linear-model}) (pj/lay-smooth {:stat :loess}))do not auto-generate a layer-kind legend to distinguish the two regression curves. Workaround: color each layer explicitly.Histograms, stacked bars, step plots, and other stat-derived marks do not default to a
"count"or"density"y-label.Linear continuous color legends (numeric
:colormapping with:linearscale) label only the endpoint tick marks on the gradient bar. Intermediate values are unlabeled, making it hard to map interior colors back to data values. Log-scaled continuous color and fill legends do carry intermediate ticks.SPLOMs with 6+ variables at the default 600x400 have tight panels. Increase
:width/:heightor pin:panel-width/:panel-height.Horizontal bars from
(pj/coord :flip)render the first row of data at the bottom of the chart, so a dataset sorted descending (natural “top N” order) produces the biggest bar at the bottom. The behavior matches ggplot2’scoord_flip(). Workaround: sort the dataset ascending before plotting, e.g.(tc/order-by data [:value] [:asc]). A future opt-in flag such as(pj/coord :flip {:reverse-categorical true})would spare users the sort.Rotated x-tick labels (
:x-tick-angle) reserve extra vertical space below the panel, but not extra horizontal space. A long label rotated to a diagonal extends to the left of its tick, so very long category names on the leftmost tick can run past the left edge of the plotting area. Workaround: shorten the labels, reduce the angle, or widen the plot with:width.
Marks
Aesthetic-gate versus mark-consumer asymmetry. Several aesthetics are accepted at the universal pose-mapping gate but consumed only by one or two mark extractors. Setting them on other marks has no effect and raises no error.
Aesthetic Consumed on Silently ignored on :size(column ref)lay-pointevery other lay-* :alpha(column ref)lay-pointevery other lay-* (literal :alpha Nworks on most via:fixed-alpha):shapelay-pointtext, label, lollipop, summary, … numeric (continuous) :colorlay-point,lay-interval-hevery other lay-* (a numeric column on a categorical-color path produces banded palette colors instead of a gradient) tooltip / row-indices plumbing lay-point,lay-interval-hevery other lay-* Workaround: pre-bin or convert the numeric column into a discrete color column where appropriate, or use
lay-pointfor the mark where the aesthetic must vary per row.:alphaonpj/lay-rule-h/pj/lay-rule-vis silently dropped at render time (the rendering path reads:coloronly). Bands honor:alpha. Workaround: use a lighter:colorto simulate the visual effect on rules.pj/lay-rule-hrendered under(pj/coord :flip)becomes a vertical line;pj/lay-rule-vbecomes a horizontal line. The mark name still reflects the unflipped semantics. Add a one-line note in the surrounding prose if the chart’s flipped state is non-obvious.:position :dodgeis ignored at render-time on several marks. The request fails in one of two ways: onlay-barandlay-summarythe dodge request is dropped at construction; onlay-pointandlay-linethe dodge metadata reaches the plan but no geometric offset is applied. Workaround: pre-compute dodge offsets viatc/group-by.Polar plots for bar-family marks don’t auto-emit category labels – rose charts currently render with zero text.
Stacked bars don’t split positive and negative values; all-positive data works, but mixed-sign data stacks incorrectly.
pj/lay-tile(and the underlying:bin2dstat) requires numeric x and y columns. Passing a categorical axis throws a clear “Stat :bin2d requires a numeric column” error at plan time. The recommended workaround is to render a numeric-indexed grid (1-N integers in place of the categorical column) and pair:breakswith:labelson the axis – see Customization and Troubleshooting for a worked example. For a true categorical axis (binning over labels rather than numeric intervals),pj/lay-barwith aycolumn and{:color :value}gives a categorical “heatmap” look.Horizontal value bars (
pj/lay-barwith the category on:y) support plain and dodged layouts, but not:position :stackor:position :fill– stacking accumulates along the y-axis, which is the categorical band for a horizontal bar. Workaround: put the category on:xand add(pj/coord :flip), where stacking works.Numeric/temporal-position bars (
pj/lay-barwith both axes numeric or temporal) draw one bar per row at its x position; grouped bars (via:color) overlap rather than dodge, and:position :stackis not applied. Pre-aggregate or jitter positions to separate groups.Value bars (
pj/lay-barwith a value column) cannot use a log scale on the value axis: a bar rests on a zero baseline, and a log scale has no zero. Plotje raises a clear error pointing to the alternatives – a linear scale, or a baseline-free mark (pj/lay-point,pj/lay-line,pj/lay-lollipop). Count bars and histograms do support a log axis.Stack order in
pj/lay-areaandpj/lay-bar(with:position :stack) follows the sort order of the:colorcolumn. There is no:stack-order/:color-orderoption yet, so forcing a specific bottom-to-top order requires prefixing category labels with sort-stable ordinal characters ("01: ...","02: ..."), which leaks into the legend.Annotations are silently skipped under
(pj/coord :polar). A polar rule would need to render as a circle (fixed radius) or spoke (fixed angle); those shapes are not implemented. Use Cartesian or flip coords for annotated plots.Large scatters produce large SVGs (~220 bytes/point). For >10k points, use
:format :bufimgfor raster output.Saving to PNG (
(pj/save pose "plot.png"), and the:bufimgraster path generally) truncates the rotated y-axis label after ~6 characters. The SVG path (pj/plot+ Clay GFM, orrsvg-converton the saved SVG) renders the full label. Root cause lives in Membrane’s Java2D backend (the rotated-text bounding box is clipped). Workaround: render to SVG and rasterize externally, or pad:y-labelto stay short. Needs an upstream fix in Membrane.LOESS with confidence bands is O(n^2); subsample above ~5k rows.
Options and Configuration
:panel-sizeis a legacy configuration key from the pre-total-first layout. It now emits a deprecation warning and is ignored. Use:panel-width/:panel-height(which set the panel size directly).The
:widthkey on apj/planresult preserves the user’s original request even when:panel-widthpins the real size – inspect:total-width/:total-heightfor the rendered canvas.pj/plancalled on a plan or on a hiccup value now throws a clear error. Callpj/planonly on poses.
Mixing Keyword and String Column References
- Mapping the same column with a keyword in one place and a string in another (e.g.
(pj/pose ds {:color :group})then(pj/lay-point :x :y {:color "group"})) is not normalized: the scope hierarchy treats them as different keys and the result is a silent empty plot. Workaround: pick one form (keyword or string) and use it consistently within a pose.
ggplot2 Features Not Yet Implemented
The
:fillaesthetic is currently consumed only bylay-tile(and the:bin2doutput beneathlay-density-2d). On filled marks likelay-bar,lay-area, andlay-violin,:colorpaints the interior; there is no separate stroke channel.The
:linetypeaesthetic (ggplot2’saes(linetype=...)for solid vs. dashed lines) is not implemented. Workaround: encode the same distinction via:colorinstead.No
after_stat()analog. ggplot2 idioms likegeom_bar(aes(label=after_stat(count)))andgeom_histogram(aes(y=after_stat(density)))reference computed stat values inside aesthetic mappings; Plotje requires a pre-computed column. Workaround: aggregate the data first viatc/group-by+tc/aggregate, then map the count or density column directly.Theme support is shallow versus ggplot2: today the theme map carries
:bg,:grid,:font-size, and a small handful of other keys. Named theme presets (theme_minimal,theme_bw,theme_classic), axis text rotation, panel borders, strip text styling, andlegend.positionby coordinate are not yet exposed.Per-layer
data,guides()for per-aesthetic legend control,scale_*_sqrt/reverse/date. All tracked in the backlog.