Liking cljdoc? Tell your friends :D

scicloj.plotje.impl.scale


by-methodsclj

How a value spreads across the range a channel is drawn over.

Each names what is spread evenly as the value runs from the low end of the domain to the high end, and each is read in the mark's own quantity -- a circle's radius, a stroke's width:

  • :linear -- the quantity itself. A value twice another is drawn twice as wide, which on a circle is four times the ink. ggplot2 spells this scale_radius.
  • :sqrt -- the quantity against the root of the value, the root being the quantity's ink exponent. The default, and what ggplot2's scale_size does. The smallest value still draws at the low end of the range rather than vanishing, and growth is compressed the way area demands; it is exactly area-proportional when the range starts at zero.
  • :area -- the ink. Equal steps in value are equal steps in area, which is the strict reading of what a size encoding claims.

On a quantity whose ink grows linearly -- a stroke's width, an opacity -- all three are one function, because there is no area to correct for.

How a value spreads across the range a channel is drawn over.

Each names what is spread evenly as the value runs from the low end
of the domain to the high end, and each is read in the mark's own
quantity -- a circle's radius, a stroke's width:

- `:linear` -- the quantity itself. A value twice another is drawn
  twice as wide, which on a circle is four times the ink. ggplot2
  spells this `scale_radius`.
- `:sqrt` -- the quantity against the root of the value, the root
  being the quantity's ink exponent. The default, and what ggplot2's
  `scale_size` does. The smallest value still draws at the low end
  of the range rather than vanishing, and growth is compressed the
  way area demands; it is exactly area-proportional when the range
  starts at zero.
- `:area` -- the ink. Equal steps in value are equal steps in area,
  which is the strict reading of what a size encoding claims.

On a quantity whose ink grows linearly -- a stroke's width, an
opacity -- all three are one function, because there is no area to
correct for.
sourceraw docstring

categorical-domain?clj

(categorical-domain? dom)

True if domain is a sequence of non-numeric values (categorical).

True if domain is a sequence of non-numeric values (categorical).
sourceraw docstring

channel-boundsclj

What a channel's :range may span, where the quantity it is drawn as has limits of its own.

An opacity outside 0 to 1 is not a fainter or a stronger colour -- it is not a colour at all, and the PNG path throws from inside AWT where the SVG path silently emits an out-of-range attribute. A negative radius is not a smaller mark; it emits a negative width and draws nothing. Both used to pass every check.

What a channel's `:range` may span, where the quantity it is drawn
as has limits of its own.

An opacity outside 0 to 1 is not a fainter or a stronger colour --
it is not a colour at all, and the PNG path throws from inside AWT
where the SVG path silently emits an out-of-range attribute. A
negative radius is not a smaller mark; it emits a negative width and
draws nothing. Both used to pass every check.
sourceraw docstring

channel-domainclj

(channel-domain spec d-min d-max)

The [lo hi] a channel's values are read against, given its scale spec and the range the data covers.

:domain on the spec replaces the data's own range -- a way to fix what a size means across plots that would otherwise each scale to their own extremes. :from-zero anchors the low end at zero, which is what turns a spread across a range into a proportion: with the range anchored there too, twice the value is twice the ink.

Anchored at zero it is the distance from zero that decides the ink, so the domain runs to the value furthest from zero in either direction. Taking the high end alone put every value at or below zero at the bottom of the range: a column of -5, 0 and 10 drew one mark of three and said nothing, and an all-negative column drew every mark at the maximum beside a legend running the other way. ggplot2's scale_size_area reads the magnitude here too, though it divides by the maximum rather than by the widest magnitude, which on an all-negative column draws marks larger than the range's own top.

The `[lo hi]` a channel's values are read against, given its scale
spec and the range the data covers.

`:domain` on the spec replaces the data's own range -- a way to fix
what a size means across plots that would otherwise each scale to
their own extremes. `:from-zero` anchors the low end at zero, which
is what turns a spread across a range into a proportion: with the
range anchored there too, twice the value is twice the ink.

Anchored at zero it is the distance from zero that decides the ink,
so the domain runs to the value furthest from zero in either
direction. Taking the high end alone put every value at or below
zero at the bottom of the range: a column of -5, 0 and 10 drew one
mark of three and said nothing, and an all-negative column drew
every mark at the maximum beside a legend running the other way.
ggplot2's `scale_size_area` reads the magnitude here too, though it
divides by the maximum rather than by the widest magnitude, which on
an all-negative column draws marks larger than the range's own top.
sourceraw docstring

channel-mapperclj

(channel-mapper spec d-min d-max default-range ink-exponent)

A function from a data value to the quantity a mark draws it as -- a radius, a width, an opacity.

spec is the channel's scale spec: :type (:linear or :log), :domain, :range, :by and :from-zero, each optional. default-range is what the channel spans where the spec names no :range. ink-exponent comes from the mark's declared quantity -- 2 for a radius or a side, 1 for a width -- and is what lets :by mean the same thing whatever shape draws it.

Stated once because the marks and the legend have to agree: the mark drawn beside a value in the legend is the size a mark of that value is drawn at on the panel. impl.plan builds the legend from this and render.mark draws from it, and they held separate copies of the arithmetic until both were found to share a defect.

A value outside the domain is clamped to its nearer end rather than drawn outside the range. A :domain narrower than the data is a statement about what the reader should compare, not an instruction to drop rows -- and a dropped row leaves no trace on the panel.

A domain of one distinct value has no spread to map, so every value takes the middle of the range. ggplot2's scales::rescale answers a zero range the same way, and for the same reason: with nothing to compare a value against, the midpoint is the only unprejudiced answer. Collapsing to the low end instead drew {:size {:value 7 :scale true}} at radius 2.0 -- smaller than the default 3.0 -- beside a legend reading 7, and did the same to any size column whose values happen to be equal.

A function from a data value to the quantity a mark draws it as -- a
radius, a width, an opacity.

`spec` is the channel's scale spec: `:type` (`:linear` or `:log`),
`:domain`, `:range`, `:by` and `:from-zero`, each optional.
`default-range` is what the channel spans where the spec names no
`:range`. `ink-exponent` comes from the mark's declared quantity --
2 for a radius or a side, 1 for a width -- and is what lets `:by`
mean the same thing whatever shape draws it.

Stated once because the marks and the legend have to agree: the mark
drawn beside a value in the legend is the size a mark of that value
is drawn at on the panel. `impl.plan` builds the legend from this and
`render.mark` draws from it, and they held separate copies of the
arithmetic until both were found to share a defect.

A value outside the domain is clamped to its nearer end rather than
drawn outside the range. A `:domain` narrower than the data is a
statement about what the reader should compare, not an instruction
to drop rows -- and a dropped row leaves no trace on the panel.

A domain of one distinct value has no spread to map, so every value
takes the middle of the range. ggplot2's `scales::rescale` answers a
zero range the same way, and for the same reason: with nothing to
compare a value against, the midpoint is the only unprejudiced
answer. Collapsing to the low end instead drew
`{:size {:value 7 :scale true}}` at radius 2.0 -- smaller than the
default 3.0 -- beside a legend reading 7, and did the same to any
size column whose values happen to be equal.
sourceraw docstring

default-byclj

The method a channel spreads by when its scale does not say.

ggplot2's default for a point, adopted here: the perceptual correction is on, and the smallest mark stays visible.

The method a channel spreads by when its scale does not say.

ggplot2's default for a point, adopted here: the perceptual
correction is on, and the smallest mark stays visible.
sourceraw docstring

format-log-ticksclj

(format-log-ticks ticks)

Format log scale tick values. Values are always clean 1-2-3-5 multiples of powers of 10, so formatting is straightforward: integers >= 1 shown without decimals, sub-1 values use minimal decimal places.

Format log scale tick values. Values are always clean 1-2-3-5 multiples
of powers of 10, so formatting is straightforward: integers >= 1 shown
without decimals, sub-1 values use minimal decimal places.
sourceraw docstring

format-range-endpointsclj

(format-range-endpoints lo hi separators)

The two labels a continuous legend prints at the ends of its bar.

Each end is written to six significant digits in plain notation, so what a legend reads matches what its axis reads. %.4g did neither half of that: four significant digits switch to scientific notation at 10000, so a legend for a count read 1.235e+05 beside an axis reading 100,000, and two ends as far apart as 123456 and 123999 read alike. Below the switch it padded rather than truncated, so a span of 0.1 to 2.5 read 0.1000 and 2.500.

Precision follows each value's own magnitude rather than the span between them: a legend from 0.001 to 1000 has to show its low end as 0.001, which a span-derived step would have rounded to 0.

separators is the map defaults/number-separators reads off a config, as for format-ticks.

The two labels a continuous legend prints at the ends of its bar.

Each end is written to six significant digits in plain notation, so
what a legend reads matches what its axis reads. `%.4g` did neither
half of that: four significant digits switch to scientific notation
at 10000, so a legend for a count read 1.235e+05 beside an axis
reading 100,000, and two ends as far apart as 123456 and 123999 read
alike. Below the switch it padded rather than truncated, so a span of
0.1 to 2.5 read 0.1000 and 2.500.

Precision follows each value's own magnitude rather than the span
between them: a legend from 0.001 to 1000 has to show its low end as
0.001, which a span-derived step would have rounded to 0.

`separators` is the map `defaults/number-separators` reads off a
config, as for `format-ticks`.
sourceraw docstring

format-ticksclj

(format-ticks sx ticks)
(format-ticks sx ticks separators)

Format tick values: integers shown without decimals, floats rounded to the precision implied by the tick step size (avoids floating-point noise like 0.30000000000000004). Falls back to wadogo formatting only when the step cannot be determined (< 2 ticks).

Every value is formatted under Locale/ROOT, so what a tick reads does not depend on the JVM it renders on.

The 3-arity writes each formatted tick with separators, the {:thousands ... :decimal ...} map defaults/number-separators reads off a config. Layout measures label widths through this same function, so a grouped axis reserves room for the separators it will draw.

Format tick values: integers shown without decimals, floats rounded to the
precision implied by the tick step size (avoids floating-point noise like
0.30000000000000004). Falls back to wadogo formatting only when the step
cannot be determined (< 2 ticks).

Every value is formatted under `Locale/ROOT`, so what a tick reads
does not depend on the JVM it renders on.

The 3-arity writes each formatted tick with `separators`, the
`{:thousands ... :decimal ...}` map `defaults/number-separators`
reads off a config. Layout measures label widths through this same
function, so a grouped axis reserves room for the separators it will
draw.
sourceraw docstring

invertclj

(invert sc v)

Read a drawing-space position back as a data value. On a band scale this answers with the category whose band contains the position, and with nil outside every band.

The band case is computed here rather than through ws/inverse. Wadogo's bands-inverse-fn destructures :start and :end from band maps whose keys are :rstart and :rend, so both locals are nil and its ^double hint throws a NullPointerException for every input. The band data it needs is on the scale either way. Reported in dev-notes/wadogo-band-inverse-issue.md.

Read a drawing-space position back as a data value. On a band scale
this answers with the category whose band contains the position, and
with nil outside every band.

The band case is computed here rather than through `ws/inverse`.
Wadogo's `bands-inverse-fn` destructures `:start` and `:end` from
band maps whose keys are `:rstart` and `:rend`, so both locals are
nil and its `^double` hint throws a NullPointerException for every
input. The band data it needs is on the scale either way. Reported
in `dev-notes/wadogo-band-inverse-issue.md`.
sourceraw docstring

log-ticksclj

(log-ticks [lo hi] n)

Generate clean log-scale tick values for a [lo hi] domain, targeting approximately n ticks. Uses ggplot2-style 1-2-5 nice numbers instead of wadogo's linear-in-log-space approach (which produces irrational values like 3.162...). Returns a vector of tick values (doubles).

Strategy:

  • Powers of 10 only when they give >= 3 ticks (strongly preferred)
  • 1-2-5 intermediates per decade when more ticks are needed
  • 1-2-3-5 intermediates for dense sub-decade ranges
  • Bounding powers of 10 are included when they fall within a small margin (15% of log-span) of the domain edges
Generate clean log-scale tick values for a [lo hi] domain, targeting
approximately n ticks. Uses ggplot2-style 1-2-5 nice numbers instead
of wadogo's linear-in-log-space approach (which produces irrational
values like 3.162...). Returns a vector of tick values (doubles).

Strategy:
- Powers of 10 only when they give >= 3 ticks (strongly preferred)
- 1-2-5 intermediates per decade when more ticks are needed
- 1-2-3-5 intermediates for dense sub-decade ranges
- Bounding powers of 10 are included when they fall within a small
  margin (15% of log-span) of the domain edges
sourceraw docstring

make-scalecljmultimethod

Create a wadogo scale mapping domain values to a pixel range.

Create a wadogo scale mapping domain values to a pixel range.
sourceraw docstring

numeric-color-domainclj

(numeric-color-domain spec d-min d-max)

The [lo hi] a numeric colour or fill column is read against.

:domain on the spec replaces the range the data covers, so a gradient can mean the same thing across plots and across the panels of a facet. A value outside it is drawn at the nearer end of the gradient rather than dropped, which is what normalize-continuous clamps for, and matches what :size and :alpha answer.

Answers nil where the data gave no range, so a caller that had nothing to normalize against still has nothing. A categorical :domain -- a list of category names -- is not a numeric range and is ignored here; order-by-domain in impl.plan reads that one.

Stated once because four places normalize a colour and a fifth builds the legend, and each held its own min and max.

The `[lo hi]` a numeric colour or fill column is read against.

`:domain` on the spec replaces the range the data covers, so a
gradient can mean the same thing across plots and across the panels
of a facet. A value outside it is drawn at the nearer end of the
gradient rather than dropped, which is what `normalize-continuous`
clamps for, and matches what `:size` and `:alpha` answer.

Answers nil where the data gave no range, so a caller that had
nothing to normalize against still has nothing. A categorical
`:domain` -- a list of category names -- is not a numeric range and
is ignored here; `order-by-domain` in `impl.plan` reads that one.

Stated once because four places normalize a colour and a fifth
builds the legend, and each held its own min and max.
sourceraw docstring

pad-domainclj

(pad-domain domain scale-spec)
(pad-domain [lo hi] scale-spec padding)

Add padding to a numeric domain. When lo == hi (constant data), pads by ±1 or ±5% of |lo|, whichever is larger. For log scales, callers must supply positive lo and hi -- the responsibility for excluding non-positive values lives upstream (filter-log-nonpositive for raw data, the scale-aware branch of compute-global-y-domain for stat-derived ranges).

padding is the resolved :domain-padding. The 2-arity falls back to the library default, for a caller with no configuration in hand; every caller inside draft->plan passes the resolved value, which is how pj/options and pj/with-config reach this.

Add padding to a numeric domain. When lo == hi (constant data),
pads by ±1 or ±5% of |lo|, whichever is larger.
For log scales, callers must supply positive lo and hi -- the
responsibility for excluding non-positive values lives upstream
(filter-log-nonpositive for raw data, the scale-aware branch of
compute-global-y-domain for stat-derived ranges).

`padding` is the resolved `:domain-padding`. The 2-arity falls back
to the library default, for a caller with no configuration in hand;
every caller inside `draft->plan` passes the resolved value, which is
how `pj/options` and `pj/with-config` reach this.
sourceraw docstring

scale-kindclj

(scale-kind domain scale-spec)

Determine the wadogo scale type (:categorical, :log, or :linear) from domain and spec. Passes through vector dispatch values like [:linear :doc] for doc defmethods.

Determine the wadogo scale type (:categorical, :log, or :linear) from domain and spec.
Passes through vector dispatch values like [:linear :doc] for doc defmethods.
sourceraw docstring

spec-keysclj

(spec-keys aesthetic)

The keys a scale spec may carry for aesthetic. :type and :domain belong to every scale; the rest are per aesthetic, from defaults/channel-scale-options.

The keys a scale spec may carry for `aesthetic`. `:type` and
`:domain` belong to every scale; the rest are per aesthetic, from
`defaults/channel-scale-options`.
sourceraw docstring

tick-countclj

(tick-count pixel-range scale-spec spacing)

How many ticks an axis asks for across pixel-range drawing units.

:n-ticks on the spec names the count outright. Failing that, spacing names about how much room a tick should have and the count is how many fit, never fewer than two. The count is then rounded to a step a reader can read off, which is why the room each tick ends up with can come out under spacing. One answer for both column types -- each key used to be read on one of them and ignored on the other.

How many ticks an axis asks for across `pixel-range` drawing units.

`:n-ticks` on the spec names the count outright. Failing that,
`spacing` names about how much room a tick should have and the count
is how many fit, never fewer than two. The count is then rounded to
a step a reader can read off, which is why the room each tick ends
up with can come out under `spacing`. One answer for both column
types -- each key used to be read on one of them and ignored on the
other.
sourceraw docstring

validate-drawn-range-options!clj

(validate-drawn-range-options! channel spec where)

Throw when a scale spec names a drawn-range option the channel does not read, or names one Plotje cannot carry out.

Called from both places a spec can be written -- pj/scale and a mapping's :scale -- because either can name a key the channel has no use for, and a key that is read by nothing is the defect this release exists to remove. where names the caller for the message.

Only the drawn-range options are policed here. The rest of the spec is checked where it is written.

Throw when a scale spec names a drawn-range option the channel does
not read, or names one Plotje cannot carry out.

Called from both places a spec can be written -- `pj/scale` and a
mapping's `:scale` -- because either can name a key the channel has
no use for, and a key that is read by nothing is the defect this
release exists to remove. `where` names the caller for the message.

Only the drawn-range options are policed here. The rest of the spec
is checked where it is written.
sourceraw docstring

validate-spec-keys!clj

(validate-spec-keys! aesthetic spec where)

Throw when a scale spec names a key aesthetic does not read.

Called from both places a spec can be written, so pj/scale and a mapping's :scale refuse the same keys. pj/scale used to take any key and read what it understood, so a misspelled :rnge set nothing and said nothing.

Throw when a scale spec names a key `aesthetic` does not read.

Called from both places a spec can be written, so `pj/scale` and a
mapping's `:scale` refuse the same keys. `pj/scale` used to take any
key and read what it understood, so a misspelled `:rnge` set nothing
and said nothing.
sourceraw docstring

validate-spec-values!clj

(validate-spec-values! channel spec where)

Throw when a scale spec's :breaks, :tick-labels or :values holds something the channel cannot carry out.

Called from both places a spec can be written -- pj/scale and a mapping's :scale -- because a spec means the same thing wherever it is written. These four checks lived only in pj/scale, so {:shape {:column :c :scale {:values [:blob :thing :whatsit]}}} planned without a word: every mark drew the fallback symbol while the legend advertised three symbols that do not exist.

where names the caller for the message. Which channels read these keys at all is settled by validate-spec-keys!, off the published table, so this checks only what a key holds.

Throw when a scale spec's `:breaks`, `:tick-labels` or `:values`
holds something the channel cannot carry out.

Called from both places a spec can be written -- `pj/scale` and a
mapping's `:scale` -- because a spec means the same thing wherever
it is written. These four checks lived only in `pj/scale`, so
`{:shape {:column :c :scale {:values [:blob :thing :whatsit]}}}`
planned without a word: every mark drew the fallback symbol while
the legend advertised three symbols that do not exist.

`where` names the caller for the message. Which channels read these
keys at all is settled by `validate-spec-keys!`, off the published
table, so this checks only what a key holds.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close