All notable changes to this project will be documented in this file. This change log follows the conventions of keepachangelog.com.
Ticks and their labels are most of this release. A number axis, a date axis, a size or alpha legend and a gradient bar are each ticked at round values, and a column drawn on an axis and in a legend at once is labelled the same way in both.
A legend and the marks it explains are drawn from one decision, so a reader can match one against the other.
:include names a value an axis has to reach. (pj/scale pose :y {:include 0}) puts zero on the axis, so a length drawn along it is proportional to the value it stands for.
The retired name reports the one to write.
| Gone | Write instead |
|---|---|
layer-type/channel-magnitude-fn | layer-type/aesthetic-magnitude-fn |
Every published docstring and arglist says aesthetic where it said channel -- pj/scale takes [pose aesthetic scale-type] -- and the errors layer-type/register! throws about :varies carry :aesthetic in their data.
:domain written with a fraction, and a :position :fill that draws proportions are ticked as before.2002, 2004, 2006, and a year of month starts is ticked Jan 2020, Mar 2020, May 2020. An axis of a few months carries the month alone; one covering about a year carries the year too. ggplot2 labels both spans the same way.Jan-02, Jan-05, Jan-08. An axis whose days run across two years names the year in their place, and one whose ticks step by hours is unchanged. ggplot2 labels the same days with a month too.:position :fill stacks the same way round. ggplot2's position_stack stacks this way too.pj/lay-step reads :position, so a step drawn with one is stacked or dodged like any other mark.:domain on a categorical :color. The order it gives reaches the marks as well as the legend, so the segments of a stacked bar and the members of a dodged group follow the rows of the legend beside them -- bars, boxplots and violins alike.:midpoint. The gradient is centred on the midpoint and widened until it reaches whichever end of the domain is further from it -- ggplot2's rescale_mid -- so a departure of the same size in either direction is drawn at the same saturation, and the nearer end stops short of the extreme.:midpoint at an end of its domain. The value there is drawn at the middle of the gradient, so {:midpoint 0} on a column of zero and up draws zero at the middle colour.:size, :alpha or numeric :color column, and every plot with two such layers. The aesthetic is read against every value the plot holds rather than against one panel's or one layer's, so a value means one size, one opacity and one colour wherever it is drawn, and the legend explains all of them. ggplot2 keeps one scale across facets and layers as well.:include on an :x or :y scale names a value the axis has to reach, as ggplot2's expand_limits(y = 0) does. The value lands exactly at the edge of the panel, where pj/lay-bar already draws its baseline -- ggplot2 pads past it instead. A collection names more than one: {:include [0 100]} gives an axis room the data does not fill. On a temporal axis it is written as a date, as :domain and :breaks are, and the axis is ticked across the domain it widened.:domain and an :include on one aesthetic are reported, as is an :include on a log axis, which has no reading for zero, or on a categorical one, which has no extent between its categories.pj/valid-pose? and pj/explain-pose check a pose against its schema, as the pair pj/valid-plan? and pj/valid-membrane? already did for the two later stages. The schema is structural: it says what shape a pose has, not whether the columns it names are in the data. A pose the API built conforms by construction, so the pair is for one that has been reached into and changed.:domain is checked against the column it is read for. Against a continuous column it is two finite numbers, and against a categorical one it is the list of categories that orders them.:x-type, :y-type and :color-type report a type the column cannot be read as. Only :categorical can be asked of a column holding something else; :numerical and :temporal are accepted where they name the column's own type. The message names the option, the column and what the column holds.Removed 1 rows with a missing category in :species. A column holding no values at all reports a missing value rather than a category. Marks that keep such rows rather than dropping them stay silent.:local-date and a timestamp written 2015-03-21T10:00:00Z is offered :instant. pj/lay-histogram, pj/lay-density, pj/lay-smooth, pj/lay-tile and pj/lay-contour all report it.nil that it has no values, rather than calling either numerical.:text given a value that names no column says which value it was.:color column, which it cannot read as a gradient -- bars, boxplots, violins, lollipops, lines, steps, areas, histograms, densities, smooths, rugs, text and labels among them. :point is the mark that carries a colour per row, and a contour reads the :color scale its levels are built from. The message names :color-type :categorical.pj/to-drawing and pj/to-data report a pose, a plan or the whole frames map written in the panel's place. A panel entry is one element of (:panels (pj/frames plot)), and each message names which of the three it was given and the call that reaches a panel entry from there.pj/lay-area and pj/lay-lollipop rest on a log value axis: an area fills to the bottom of the panel and a lollipop keeps its stems. The baseline is the panel's own smallest value, which is where pj/lay-bar already put it. Both closed to zero instead, which a log scale has no reading for, so an area drew a bowtie and a lollipop lost every stem.Value out of range for float: Infinity. ggplot2 drops the same bars.ZonedDateTime and an OffsetDateTime column is read as a date. Each carries its own offset, so each names an instant, and both are read at UTC as the other temporal types are. A ZonedDateTime was refused by the tick generator, and an OffsetDateTime was drawn as one tick per value without a word.YearMonth, a Year, a MonthDay. The message names what the column holds and the line that maps it to the day it starts. Which instant a month stands for is left to the writer.:domain written as dates, as its :breaks do, and is ticked across it. A domain wider than the data reaches both ends of the axis.:breaks written as dates: (pj/scale :x {:breaks [(jt/local-date 1940 1 1) ...]}) places a tick at each of them, and :tick-labels relabels them. A LocalDate, a LocalDateTime and a java.util.Date are all accepted.(pj/lay-point [[1 2] [3 4]]) draws two points, with columns 0 and 1 inferred as the :x and :y aesthetics. pj/pose accepted the same shape throughout.:midpoint moves the bar with them. The bar spans the stretch of gradient the data reaches and no more, and the colour at the end labelled with the domain's low value is the colour the lowest mark carries.:fill legend is drawn through the same scale its marks are. A :domain set on :fill moves the bar together with the tiles, and a setting written in a scale spec wins over the matching plot option -- :range and :midpoint alike. A tile reads :color as a synonym for :fill key by key, so a :fill spec naming only a gradient leaves the domain to :color.:fill legend spans the values the tiles carry. Where the domain was read from the stat's zero floor, the bar carried a label for every decade from 1e-300, printed over each other. A fill that reaches zero even so -- a :domain written from it, or a density that underflows -- is reported.:color scale its levels are built from. :fill paints the interior of a tile and a contour draws lines, so a :fill scale set on one changes neither the lines nor the bar beside them.A mapping may now be written out in full, saying which column or value it takes and whether to read it through a scale -- {:size {:column :weight :scale :log}}. A scale is written in the mapping it belongs to, and a scale set higher up carries down to the layers below it.
Three chapters are new to the book: Specifying Aesthetics, Column Types and Scales.
The names below no longer work, and every place one can be written reports it: pj/options, pj/scale, pj/with-config, pj/set-config!, plotje.edn and the :config option.
| Gone | Write instead |
|---|---|
:palette | :color-values, or :values in a :color scale |
:color-scale | :color-range, or :range in a :color or :fill scale |
:tick-spacing-x, :tick-spacing-y | :x-tick-spacing, :y-tick-spacing, or :tick-spacing in an axis scale |
:labels in a scale | :tick-labels |
:x-scale, :y-scale, :size-scale and the rest in a pose's :opts | pj/scale, which now writes the mapping |
pj/scale on :group | scale :color or :shape instead |
:size column. A value's place in its domain is square-rooted before it becomes a radius, matching ggplot2's scale_size. {:by :linear} gives the previous behaviour, ggplot2's scale_radius.:alpha column. The default range is 0.1 to 1.0, matching ggplot2. {:range [0.2 1.0]} restores the previous one.:color column with pj/scale. A scale spec changes only what it names and leaves the gradient alone. The gradient is set with :range.:size or :alpha column whose values are all equal. Every mark is drawn at the middle of the domain, read through the scale: radius 6.243 by default.:from-zero on a column holding zero or negative values. Distance from zero is what counts, so -5 and 5 draw the same size.:color given a :domain. The list sets the order of the categories, and the legend and the colours follow it.:label and the matching :x-label or :y-label. The :label in the scale wins.{:color {:column :variety :scale true}}, {:color {:column :hex :scale false}}, {:color {:value "blue" :scale false}}, {:color {:value "Model A" :scale true}}.{:size {:column :r :scale false}} uses the column's numbers as radii and {:color {:column :hex :scale false}} uses its strings as colours -- ggplot2's scale_size_identity() and scale_colour_identity(). Neither gets a legend.:x and :y take the full form too: {:x {:column 0}} reads column 0, and {:x {:value 0}} places every mark at zero. :scale false on an axis places marks by drawing units from the top left of the panel background instead of by data value.{:color :red} reads a :red column if the data has one, and otherwise draws red.pj/scale and a mapping's :scale take the same forms: true, false, a scale type, or a whole spec map. A scale set higher up carries down, key by key, and the setting closest to the layer wins -- so a pose that sets a range and a layer that sets a type give a plot with both.pj/scale :size takes :range, :by and :from-zero; :alpha takes :range and :from-zero. :range is what the aesthetic spans: on :size that is a radius in drawing units, [2 8] by default.:domain now works on :size, :alpha and :color (issue #39). A value outside a numeric domain is drawn at the nearer end instead of being dropped. The column's type decides how the domain is read, on every aesthetic that takes one. On :fill a :domain moves the marks and not the legend, so the two disagree -- issue #43.pj/arrange, where each cell has its own scales and legend.pj/scale and in a mapping, and so is giving one a value it cannot carry out -- a marker symbol that does not exist, :tick-labels without :breaks. :x-end, :x-min, :x-max, :y-min, :y-max and :text take no scale at all, like :group.pj/aesthetic-scales lists what each aesthetic's scale accepts, alongside pj/config-key-docs, pj/plot-option-docs and pj/layer-option-docs.Many scale settings can be written in two places: in the scale itself, or as a plot option that applies to the whole plot. The plot option is named after the aesthetic and the setting, joined by a hyphen -- :label on :x is :x-label, :values on :color is :color-values -- and the setting written closest to the layer wins. Not every setting has a plot option, but where one exists this is its name.
:tick-labels, paired with :breaks; :label sets the axis title. Using one where the other belongs is now an error.:n-ticks and :tick-spacing both control how many ticks a numeric axis draws, and it uses whichever you set. A categorical axis draws a tick per category, and :n-ticks thins them.:color takes its colours from its own scale: :values is the palette for a categorical column, :range the gradient for a numeric one, and :midpoint the value drawn at the middle of that gradient. :fill draws a magnitude, so it needs a numeric column and takes :range and :midpoint alone. Each of those has a plot option of the same name.:label sets the title of whatever explains a scale -- the axis for :x and :y, the legend for the rest -- and every aesthetic with a scale takes it.(layer-type/register! :bubble {:mark :bubble :varies {:size :radius} ...}). Of the built-in layer types only :point varies an aesthetic, so this mainly matters when writing an extension.layer-type/channel-magnitude-fn gives a mark's renderer the function its legend is built from, and layer-type/quantities lists what a mark can draw an aesthetic as.:size or :alpha column gets no legend when no mark on the plot varies it, and Plotje says so.pj/scale writes the mapping rather than the pose's options. pj/coord and pj/facet still write :opts.:magnitude rather than :radius, and the legend carries :quantity and :swatch.nil, or neither -- are reported at the pj/pose or lay-* call instead of later.:scale false and then setting an option for that scale is an error, since nothing would read it. :scale false on an axis is also an error on marks that cannot use it.:size, :alpha or :fill a categorical column reports which aesthetic and which column. :fill and :group report a value that names no column, and a hex colour missing its # is reported on annotations as well as layers.plotje.edn, pj/set-config!, pj/with-config and the :config option. :strict turns the report into an error, as it does for options.(pj/options {:color-range :viridis}) beside (pj/scale pose :color :log).:size-label fit the canvas at any range.[0 1] domain the y axis has always used.(pj/lay-rule-h pose {:y-intercept 2 :color :red}) draws red.:domain-padding is read through the configuration chain, so (pj/options {:domain-padding 0.0}) and pj/with-config both reach it.run_tests.sh, release.sh and snapshot.sh find bash through #!/usr/bin/env bash, so they run on distributions that do not keep it at /bin/bash, such as NixOS. (PR #35) - thanks, @otfromLocale/ROOT, so a plot draws the same numbers whatever machine renders it.:decimal-separator draws the decimal point as whatever string you name: (pj/options {:thousands-separator "." :decimal-separator ","}) writes 1.234,5. Off by default.123456, 0.1, 2.5.0.001, 0.01, 0.1.pj/save honors every plot option pj/plot honors, in SVG and PNG -- :title-font-size, :label-font-size, :thousands-separator, :grid-stroke-width and :annotation-stroke among them.:tooltip.:title-font-size, and its shared legend honors the configuration its cells honor, :thousands-separator among it.:strip-font-size wherever they are drawn, in a facet and in a grid composite alike. The default is 11.pj/to-data reads a categorical axis, answering with the category whose band holds the position, and nil outside every band.pj/to-drawing refuses a value a categorical axis has no position for -- a category it does not carry, or a fractional place such as 2.5 -- naming the value and the categories it could have been.:coord :flip, pj/to-data's dataset arity reads a categorical x back as its categories. Both functions take and answer in data order under a flip.(pj/lay-point data {:x :height :y :weight}) reads the mapping from its options map on a dataset of four or more columns. A mapping given only partly there, such as {:y :weight}, still takes its other axis from the inferred one.This release mostly follows the label-positioning topic thread. Many thanks to @behrica, @timothypratley, @phronmophobic, and @generateme for the fruitful work over that thread. See the new Placing Marks documentation chapter for the main fruits of this release.
pj/frames reports where a plot's panels sit on the canvas: per panel, the :panel-box and :drawing-area rectangles in drawing units, plus the :canvas once for the plot. A composite reports every cell in canvas coordinates. Plain data throughout. - thanks, @timothypratleypj/to-drawing and pj/to-data map between data space and drawing space for one panel of pj/frames. Both take a single x and y, or a dataset with :x and :y columns, and answer in kind. pj/to-data throws under :polar, which has no inverse; a panel's :invertible? says which case it is.:offset-x and :offset-y shift a layer by a number of drawing units, after the scales run -- the distance a label needs to clear its point. A nudge cannot: it shifts by a data amount, and throws on a categorical axis. Every layer type takes them, and a numeric domain widens to keep an offset label whole. - thanks, @behrica:x and :y may be given as a value, not only as a column. Both as values draws one mark: (pj/lay-text pose {:x 6.5 :y 3.5 :text "mean"}). One value beside a column repeats for every row, so {:x 33 :y :revenue} labels each row at one fixed x. The value counts toward the axis domains, as ggplot2's annotate() does. - thanks, @behrica:in names the space a layer's :x and :y are in: :data (default) or :drawing-area, which measures drawing units from the top left of the panel background. (pj/lay-text pose {:in :drawing-area :x 12 :y 12 :text "n = 150"}) puts a note in the corner without touching the domains.pj/lay-rule-* and pj/lay-band-* warn that they do not accept :in, instead of taking it and doing nothing. They are placed from data values only.:group no longer discards a fixed :color. (pj/lay-line data :x :y {:group :country :color "#d0d0d0"}) draws one line per country, all in that grey; before, each line took a different palette color.{:tooltip true} and {:brush true} work in the browser again. Since 0.7.0 the Scittle scripts reached the page with " where they wrote ", and a script element's content is raw text in HTML, so nothing decoded them back and neither interaction ran.:width and :height, which is a screen pixel only at the plot's natural size on a standard-resolution display.4-beta23 -> 4-beta25, brought in by Plotje: pj/plot asks for :kind/hiccup2, which 4-beta23 does not define.(pj/options {:legend-position :top}) draws its legend inside the image, instead of above the top edge where nothing is visible.:not-applicable labels a tick, legend entry or facet strip as not applicable. String categories are untouched. - thanks, @timothypratleyCost-Benefit Ratio, not Cost Benefit Ratio. Keyword and symbol names are unchanged. - thanks, @timothypratleypj/lay-* arity rejects a non-column position, as pj/pose already did. Breaking: (pj/lay-point data 0 1 {}) no longer plots integer column names -- rename them first with (tc/rename-columns ds [:x :y]).pj/scale is never widened. (Closes #18) - thanks, @behrica:fit-text-domain (default true) turns that widening off.:shape produces a legend. One column driving both :color and :shape gives one merged legend, as in ggplot2; two different columns give two legends. (Closes #4) - thanks, @timothypratleypj/shape-symbols, the marker symbols a categorical :shape mapping draws with, in assignment order.:circle, :square, :triangle, :diamond, :triangle-down, :plus, :cross. More categories than symbols repeats one, which now warns.pj/scale reads :shape: :domain sets the category and legend order, and new :values supplies the symbols -- (pj/scale pose :shape {:domain ["gold" "silver"] :values [:diamond :cross]}). An undrawable symbol is rejected, as is :values on any other channel.:shape-label, titling the shape legend as :color-label and :size-label do for theirs. Naming one half of a merged legend splits it in two.pj/svg-summary no longer counts legend symbols as plot data.{:position :dodge}. (Closes #13) - thanks, @behricapj/lay-text and pj/lay-label accept {:stat :count}, labelling each bar of a counting pj/lay-bar: (-> data (pj/lay-bar :species) (pj/lay-label {:stat :count})). pj/lay-point and pj/lay-line plot those counts too. (Closes #14) - thanks, @behrica:x-tick-angle rotates the tick labels in PNG output, not only in SVG.:y-label renders in full in PNG output, where it was cut off after about six characters -- the missing rotation above, not the upstream Membrane bug it was listed as.:label mark is gone; :text and :label are two layer types drawn by the same :text mark, so a label layer reports :mark :text in a plan. pj/lay-label and (pj/lay :label ...) are unchanged. Marks drop from 22 to 21; the 25 layer types are unchanged.:defaults map on the registry entry, which the call site overrides: :label is :text with {:box true}.:box true gives a white rounded panel with a thin border, and a map sets its properties -- {:box {:corner-radius 8}}, or 0 for square corners. (Closes #19, with :thousands-separator below; the arrows and out-of-panel text in that issue's image are #17 and #18) - thanks, @behricageom_label), where it was square.pj/svg-summary reports label background boxes as :label-boxes, one per label, instead of counting them as :tiles.pj/lay-text and pj/lay-label accept :font-weight (:normal or :bold) and :font-style (:normal or :italic), independent and combining, in SVG and PNG. A numeric CSS weight such as 700, or CSS :oblique, is rejected -- Java2D draws neither. (Closes #21) - thanks, @behricapj/svg-summary reports :bold-texts and :italic-texts.clipPath ids are derived from the clip region's geometry instead of a counter shared across the whole JVM, so rendering the same plot twice produces the same bytes.:thousands-separator too, and a whole-valued legend number drops its trailing .0 -- a size legend for a count reads 100,000, not 100,000.0.pj/layer-option-docs describes every layer option. Fourteen were missing, among them :x, :y, :data, :mark and :stat.pj/scale :values on a channel other than :shape now names :palette as the way to choose the colors a categorical :color mapping draws with.:thousands-separator groups the digits of large numbers in numeric tick labels and in text taken from a column, so (pj/options {:thousands-separator ","}) draws 462,389. Any string works. Off by default, and never applied to category names, legend entries or facet strips. Part of #19 - thanks, @behrica(pj/lay-bar :x :y {:x-label "sales"}) adds Plot options belong in pj/options: [:x-label]. The pointer works in every direction, and under :strict the same text appears in the thrown exception. - thanks, @timothypratleypj/lay-point docstring called its trailing map "aesthetic opts"; it holds layer options generally.R&D, or a title "Q1 <profit> & loss", was read as markup. pj/plot now asks for :kind/hiccup2. A saved SVG was never affected. (PR #33) - thanks, @timothypratleypj/lay-density on a column spanning 4.3 to 7.9 drew an axis from 2.1 to 10.1 and a pj/lay-rug beside it covered only the middle of the plot. The curve now starts and ends with the rug, and the axis matches what ggplot2's geom_density() produces for the same data. (Closes #23) - thanks, @behricapj/lay-violin and pj/lay-ridgeline estimate through the same kernel density, so they are bounded by their category's values too -- each body now ends where that category's data ends instead of tapering into a long needle past it. This matches ggplot2, which trims violins by default (geom_violin(trim = TRUE)).pj/lay-density, pj/lay-violin and pj/lay-ridgeline accept :trim, choosing which values each group's curve is estimated over, after ggplot2's argument of the same name and with its per-geom defaults. A density is untrimmed: every group is estimated across the whole layer, so grouped curves share one interval and each falls away to nothing rather than being cut off at its own group's extremes. {:trim true} estimates each group over its own values instead. A violin or ridgeline is trimmed, so each body ends at its category's values; {:trim false} extends it by three bandwidths on each side. This changes the appearance of a grouped pj/lay-density, which previously behaved as {:trim true}.nrd0, the bandwidth rule R's density() and ggplot2 use; the previous default smoothed about 18% wider, drawing every curve slightly flatter and broader than the same data in ggplot2. Affects pj/lay-density, pj/lay-violin and pj/lay-ridgeline. Passing an explicit :bandwidth is unchanged.pj/lay-violin and pj/lay-ridgeline keep 80, where the extra points make no visible difference.pj/plot, pj/save, pj/draft, pj/plan, and pj/membrane now accept raw data directly, giving it a default mapping first exactly as pj/pose does. Previously (pj/plot some-dataset) (data not wrapped in pj/pose) rendered a blank figure; it now renders the same inferred default as (pj/plot (pj/pose some-dataset)).pj/infer-mapping: given a pose that carries data but no mapping (the bare leaf pj/->pose produces), it attaches a default position/color mapping from the first 1-3 columns; it is a no-op on any pose that already has a mapping, has layers, is composite, or has 4+ columns. This is the step the terminal shortcuts apply after pj/->pose, exposed so pipeline-minded users can build their own chains ((-> data pj/->pose pj/infer-mapping pj/pose->draft pj/draft->plan)).[1 4 1 5 6] -- is now accepted as plot data and read as a single column named :value (previously only {:column [values]} maps or sequences of row-maps were accepted). Combined with the default-mapping change, (pj/plot [1 4 1 5 6]) renders a histogram.pj/save now returns the written file as a java.io.File carrying :kind/image metadata (instead of the path string), so evaluating a pj/save call in a notebook also displays the saved chart. The file prints as its path and compares equal to a plain java.io.File on the same path, so (str (pj/save ...)) still yields the path string. (PR #29) - thanks, @timothypratleyplotje-plot as a class on svg output (PR #28) - thanks, @timothypratleypj/svg-summary counts square markers. A :square marker draws as a rounded rectangle of radius 0, which fell between the summary's point test and its tile test, so (pj/lay-point :sepal-length :sepal-width {:shape :species}) on a 150-row dataset summarized as 100 marks. Squares now count in :points alongside circles, which also brings their colors and opacities into :colors and :alphas; :sizes still reports only positive radii.pj/lay-density and pj/lay-area accept an opt-in outline on the curve: :stroke (outline color) with optional :stroke-width. The fill still comes from :color, so (pj/lay-density :x {:color "lightblue" :stroke "black"}) draws a light-blue area with a black outline. The outline strokes only the top curve, not the baseline. Without :stroke the appearance is unchanged. (Closes #11) - thanks, @behricapj/lay-line, pj/lay-step, pj/lay-smooth, the reference lines pj/lay-rule-h / pj/lay-rule-v, and a density/area outline accept :stroke-dash, either a named preset (:dashed, :dotted, :solid) or a raw [dash gap ...] pixel pattern ({:stroke-dash [6 3]}). Renders through both the SVG and PNG (Java2D) paths. (Closes #12) - thanks, @behricapj/svg-summary reports :dashed-lines (count of polylines carrying a stroke-dasharray) and :dash-patterns (the distinct stroke-dasharray strings), for asserting that a dashed line, rule, or area outline rendered dashed and with which pattern.pj/lay-value-bar is removed. pj/lay-bar now covers both cases: with x only it counts each category (as before), and with a y column it uses the y value as the bar height (the former pj/lay-value-bar). The stat is inferred from whether a y column is present and is overridable with {:stat :count} or {:stat :identity}. To migrate, replace (pj/lay-value-bar data :x :y) with (pj/lay-bar data :x :y). This also lifts the previous "stacked bars reject pre-aggregated counts" limitation -- pj/lay-bar with {:position :stack} and a y column now stacks pre-computed values. - thanks, @timothypratleypj/lay-bar value bars now accept the categorical axis on either x or y: (pj/lay-bar :value :category) with a categorical y draws horizontal bars directly, no pj/coord :flip needed (matching how pj/lay-boxplot auto-orients). Plain and dodged horizontal bars are supported; stacked/filled horizontal bars still need (pj/coord :flip).pj/lay-bar with two numeric or temporal axes now draws a bar at each x position -- a numeric-position or time-series bar chart ((pj/lay-bar :month :revenue)), which previously errored. Bar width defaults to 0.9 of the smallest gap between adjacent x values; set it with {:bar-width n}. Grouped numeric bars currently overlap rather than dodge.pj/lay-bar's categorical-x error now points to the {:x-type :categorical} override and (pj/coord :flip), matching the guidance other categorical-axis marks already give.pj/valid-membrane? and pj/explain-membrane validate a membrane against its Malli schema, mirroring the existing pj/valid-plan? / pj/explain-plan pair for plans.pj/options -- notably :theme, but also :palette -- now flow through the explicit pj/draft->membrane and pj/draft->plot steps, not only through the pj/plot / pj/membrane shortcuts. These steps default their options to the draft's own options (any options passed explicitly override per key), so a theme set before drafting is no longer dropped at the membrane stage. (Closes #20) - thanks, @behricapj/lay-line reference line drawn beyond a narrowed pj/scale domain, say -- is masked at the panel edge instead of painting across neighbouring panels in a pj/arrange or facet layout. A narrowed :domain acts as a view window (like ggplot2's coord_cartesian): the data is kept, only the view is bounded. (Closes #16) - thanks, @behricapj/options accepts :x-tick-angle to rotate x-axis tick labels (in degrees; -45 is a common diagonal), so dense or long categorical labels stay readable instead of overlapping. :x-tick-label-pad overrides the vertical space reserved below the panel for the angled labels. The rotation flows through pj/save (SVG and PNG) as well as the notebook pj/plot path. Long labels can still run past the left plot edge (see Known Limitations). (PR #6) - thanks, @tombaryspj/scale accepts :n-ticks on a categorical axis to thin a crowded axis to about that many evenly-spaced tick labels, instead of labelling every category ((pj/scale :x {:n-ticks 8})). An alternative to rotating the labels for dense categorical axes. (PR #25) - thanks, @behricapj/scale :breaks and :labels now work on a categorical axis, not just numeric ones. On a discrete axis :breaks selects which categories get a tick (each matched to a category by its displayed label) and :labels relabels them; a break naming no category is dropped with a warning (an error under :strict). Previously the categorical branch ignored both. When both :breaks and :n-ticks are given, explicit :breaks win and no thinning is applied. (Closes #22) - thanks, @behricapj/lay-* call renders on top of the previous one -- instead of being reordered by position type. A pj/lay-text or pj/lay-label added after a bar now reads on top of it rather than being hidden underneath.pj/lay-text and pj/lay-label accept :align-x (:left/:center/:right) and :align-y (:top/:center/:bottom) to set which part of the label sits on the data point -- e.g. :align-x :right places a value label inside a bar's end. Defaults :left/:center preserve the previous placement.:nudge-x/:nudge-y on a categorical axis now raise a clear error pointing to :align-x/:align-y (and :jitter/:position :dodge). Nudge is a data-space shift and applies only to numeric or temporal axes.pj/lay-* with different x/y columns from the existing pose now produces a two-panel composite instead of throwing.pj/lay-* would create a new panel using columns that don't exist in the data, the error now fires at the lay call with a clear message, instead of later during pj/plan or pj/plot.:data but the pose's x/y columns are missing from it, the error now names where the missing column came from and suggests two fixes: rename the column to match, or set a different x/y on the layer.pj/scale :y :log now works on histograms and categorical bar charts. (Closes #5) - thanks, @harold.java.util.Locale/ROOT, so plots render correctly on JVMs whose default locale uses comma as the decimal separator (Czech, German, etc.). (PR #3) - thanks, @tombaryspj/scale accepts :labels paired with :breaks -- render numeric tick positions with custom text (e.g. days of the week 1-7 labelled "Mon"-"Sun" on a tile heatmap). Length must match :breaks; :labels without :breaks throws.PlotjeMembrane record implementing the Membrane UI protocols (IOrigin, IBounds, IChildren), so Plotje plots compose with hand-built Membrane elements. Width and height read via (membrane.ui/width m)/(height m); title rides as :plotje/title. Replaces the prior metadata-tagged-vector contract.pj/membrane? predicateCan you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |