Perceptual Analysis, Visualization and Organization of Spectral Colour Data
Overview
A cohesive framework for the spectral and spatial analysis of colour described in Maia, Eliason, Bitton, Doucet & Shawkey (2013) doi:10.1111/2041-210X.12069 and Maia, Gruson, Endler & White (2019) doi:10.1111/2041-210X.13174.
MAJOR CHANGES
sensmodel()gains atemplateargument, selecting the visual pigment template used to generate sensitivity curves. It names both the author and the chromophore, since a template's shape depends on both, and defaults to"govardovskii_a1", which is what every previous version of the function used."govardovskii_a2"adds the vitamin A2 template from the same paper, and"ssh_a1"and"ssh_a2"the two from Stavenga, Smits and Hoenders (1993). The A2 templates cover porphyropsin pigments, found in freshwater fish, amphibians, and species that switch chromophore seasonally, which pavo previously could not model at all: an A2 band is close to 20% broader than the A1 band at the same peak sensitivity, so it is not recovered by adjustingpeaksens."govardovskii_a2"is the one to reach for, since pairing it with the default compares chromophores without also changing template family. The template used is recorded as a"template"attribute on the result. Note thatbeta = FALSEis recommended with either SSH template: their beta band has a fixed peak wavelength rather than one that scales withpeaksens, so for short-wavelength pigments it pulls the maximum of the summed curve several nm away from the value asked for, andsensmodel()warns where that shift exceeds 5 nm. The alpha band on its own is unaffected, both Govardovskii beta bands scale withpeaksensand do not have this problem, and Stavenga (2010) notes the fixed beta peak to be a known shortcoming.
Show all changes in 2.10.0Hide the rest of the changes in 2.10.0
bootcoldist()gains aci.typeargument, allowing bias-corrected and accelerated (BCa) confidence limits as an alternative to the percentile limits it has always returned. Colour distances are bounded below by zero and typically right-skewed, so percentile limits tend to sit off-centre; BCa corrects for that skew and for where the empirical distance falls in the bootstrap distribution. The acceleration term comes from a jackknife leaving out one row at a time, or one cluster whereclusteris supplied. The default remains"perc".bootcoldist()gains aclusterargument for hierarchically structured data, such as several patches per individual, or repeated measurements of one individual. Bootstrap replicates then resample whole clusters rather than rows, so non-independent observations stay together and the effective sample size is the number of clusters. Thenestingargument controls whether clusters span the levels ofby("crossed", one draw shared across groups, preserving their pairing) or sit within one level ("nested", drawn independently per group), and defaults to detecting which applies. Empirical means are unaffected, and results are unchanged whenclusteris NULL.bootcoldist()gains acorrectargument, which removes the upward bias in the distance between group means that comes of those means being estimated rather than known. Distance is convex in the error of a mean, so two noisy centroids sit further apart than the true ones, and two samples of one population are separated by an apparently non-zero distance. On the squared scale the displacement is the sum over groups of the mean squared pairwise distance among a group's observations divided by twice their number, so it is worst for small, variable groups and does not fall away as the true separation approaches zero. It is therefore largest exactly where discriminability is in question.correct = TRUEsubtracts it from the empirical distance and from every bootstrap replicate, each using the observations it drew. Whereclusteris supplied the correction works on clusters rather than rows, matching what is resampled; from rows it can understate the displacement several-fold. Where the design is crossed, the two group means are correlated and the correction uses each individual's own paired difference, which carries that covariance; treating the groups as independent would subtract several times too much. Partly crossed designs are refused, as isnesting = "nested"where clusters in fact span groups. The subtraction is exactly unbiased on the squared scale. Its square root errs slightly low, so a corrected distance is a little conservative. Exactness also assumes clusters of roughly equal size; under marked imbalance the between-cluster part is under-corrected and the within-cluster part over-corrected, so the net direction depends on which dominates. The correction is unavailable under quantum noise, in the CIELAB, CIELCh and coc spaces, for achromatic contrast in a colourspace model, and withci.type = "bca". The default isFALSE, so results are unchanged unless it is asked for.procspec()gains a new"clip"option, controlled by the newclip_rangeargument to remove entire regions of the spectra and replace them by linear interpolation. Code contributed for by @rscherrer, addressing issue #271.- the
rimg2cimg()function has been removed in favour of a customas.cimg()method.
MINOR CHANGES
bootcoldist()withcorrect = TRUEnow returns the signed corrected square as the"dS.sq"attribute of the result. Flooring at zero is a presentation choice, since a negative squared distance cannot be reported as a distance, but the signed value is the quantity the correction is unbiased for and the one to carry into a further calculation.bootcoldist()now validatesachromatic, erroring where it is not a singleTRUEorFALSE.bootcoldist()now says how many bootstrap replicates failed and why, where it previously discarded the error and reported only that "Bootstrap sampling encountered errors". A run in which every replicate failed used to produce an unrelated error about a comparison of length zero, and is now reported like any other failure.bootcoldist()now fails with an informative error whenboot.nis too small for the requestedalpha. Previously the lower quantile index rounded down to zero, and the interval failed to assemble with an unrelated message about mismatched dimnames. With the defaultalphathis affected anyboot.nbelow 20.- default values for some arguments in
explorespec()andsensmodel()are now explicit in the function definition. as.rspec()now works out of the box withtibble, rather than requiring users to pass a standard data.frame.- argument checks in
colspace()internal functions (dispace(),trispace(),hexagon(), etc.) have been refactored (#263), with two minor user-facing consequences: - some messages in
tcspace()have been converted to warnings for consistency with the other internal colspace functions - some error messages are been reorder, which means that errors produced for inputs invalid for multiple reasons may appear in a different order than in previous versions.
- pavo now uses R 4.1 (released in 2021) as the minimum required R version.
BUG FIXES
coldist()withnoise = "quantum"built the photon-noise term from log-transformed quantum catches wheneverqcatch = "Qi", rather than from the catches themselves. The term is2 / (Qa + Qb)and was being computed as2 / (log Qa + log Qb), which inflates the noise, deflates the resulting distances, and leaves the quantum model short of the neural one however bright the illuminant. Results were correct forqcatch = "fi"input throughout. If you have runcoldist()orbootcoldist()withnoise = "quantum"andqcatch = "Qi"on any version from 2.4.0 onward, those distances need recalculating. Reported by Changku Kang, issue #281.- Following the above, quantum catches below one are no longer an error in
coldist(). They describe a dim, photon-limited stimulus, and give small distances rather than negative log catches. Non-positive catches remain an error, since the noise term is undefined for them. coldist()withnoise = "quantum"andachromatic = TRUEreturnedNAfor the achromatic distances to the reference stimuli that anchorjnd2xyz(). Those were then read as zeros, putting the achromatic reference on top of the data. Luminance coordinates fromjnd2xyz()change for quantum-noise models; under the defaultcenter = TRUEonly the stored reference coordinates move.sensmodel()now generates the same sensitivity curve for a givenpeaksenswhateverrangeis requested. The alpha-band expression of Govardovskii et al. (2000) contains a constant of 300 nm, which was coded asrange[1]. Since the two coincide at the defaultrange = c(300, 700), curves were correct for that range and for any range sharing its lower bound. Users who calledsensmodel()with a lower bound other than 300 nm should consider regenerating their sensitivities and rerun any downstreamvismodel()orcoldist()results. Everyone else is unaffected and results are unchanged.jndrot()and by extensionjnd2xyz()have been adjusted for trichromats to only allow rotations in the 2D plane. Until now, 3D rotations were allowed and the result was projected back in 2D but this meant that the output was no longer representing JNDs distances. Becauserotate = TRUEis the default injnd2xyz(), we recommend you re-run anyjnd2xyz()computation on trichromats. From our tests, results stay qualitatively similar but specific values may change.bootcoldist()now summarisescolspace()objects by the arithmetic mean of their coordinates, rather than a geometric mean of coordinates shifted by an arbitrary constant of 100. Distances in a colour space are measured in the coordinates themselves, so a group's centroid is their arithmetic mean. Quantum catches and luminance channels stay geometric, since those distances are linear in the logged values. Colspace distances change slightly. CIELAB, CIELCh and segment, whose coordinates can be negative, previously returned NaN and now work.bootcoldist()now summarisesqcatch = "fi"models by an arithmetic mean of the log catches rather than a geometric one, so reported distances for such models change.fivalues are alreadylog(Qi), and their geometric mean is not a centroid:"Qi"and"fi"models of the same data disagreed by around 6% on the bundledsicalisdata, and the distance depended on the factor the illuminant was scaled by, though scaling shifts every log catch equally and cannot change a chromatic distance. Calls that returned NaN because an unscaled illuminant made log catches negative now work.bootcoldist()now takesqcatchfrom avismodelorcolspaceobject's attribute, ascoldist()always has, rather than letting an argument override it. Results change only where the two disagreed, in which case the old behaviour was wrong.bootcoldist()now errors where any bootstrapped distance isNA, rather than silently taking confidence limits from the wrong order statistics. The usual cause isachromatic = TRUEon a model built without an achromatic channel.bootcoldist(raw = TRUE)now returns bootstrap distances in replicate order. Each contrast was previously sorted independently before being returned, so values sharing a row came from different resamplings, and neither different contrasts nor dS and dL could be compared with one another. The values themselves are unchanged, only their order.- the values of
avg.uvandavg.vvisual systems used insensdata()andvismodel()have been updated to match exactly the ones provided in the original source (Endler & Mielke 2005). This may result in minute changes in the values returned byvismodel()if you are using these parameters.
INTERNAL CHANGES
- dependency on the
viridisLitepackage has been removed in favour of recent base R functions
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK14 OK2026-04-10
- ERROR13 OK, 1 ERROR2026-04-09
- OK14 OK2026-03-10
Documentation
- Help pages
- 71 (25 internal)includes a package overview page
- Examples that run
- 93%54 run in a plain check (3 of them under a condition) · 4 only when donttest examples are enabled (R CMD check --as-cran)
- Exported functions with examples
- 94%
- Documented parameters
- 90%
- Return-value docs
- 80%
- Help pages citing references
- 66%
Downloads
Repository
- PRs merged (all time)
- 92%
- Median days to close, 50 most recently updated closed issues
- 43
- Median days to close, 50 most recently updated closed PRs
- 4
Stars over time
Forks over time
Releases over time
Issues over time
PRs over time
Commits over time
18 development-tooling and community-health practices detected across 8 families in the upstream repository
Checks run against github.com/rmaia/pavo on 2026-10-11.
The R CMD check workflow runs on Linux, macOS and Windows, and on R-devel
GitHub Pages site last deployed 2026-09-15 · The repository has a site deploy workflow
pkgdown site last built 2026-09-15
Show all practicesHide 4 practices
Dependencies
Installing pavo adds 33 packages (19 with compiled code, 35 MB of source tarballs). Heaviest: sf 9.3 MB, lightr 5.0 MB, magick 4.4 MB.
Code & Tests
Datasets
People & History
Previously maintained by Rafael Maia (0.1-1 to 2.4.0).
Pick two releases to compare their code metrics.
- RR 4.6.0 released · 2026-04-24
- RR 4.5.0 released · 2025-04-11
- RR 4.4.0 released · 2024-04-24
- RR 4.3.0 released · 2023-04-21
- RR 4.2.0 released · 2022-04-22
- RR 4.1.0 released · 2021-05-18
- unarchivedReturned to CRAN2020-12-18
- archivedRemoved from CRAN2020-12-09policy violation Creates 'bin/phantomjs' in home
- RR 4.0.0 released · 2020-04-24
- unarchivedReturned to CRAN2019-12-11
- archivedRemoved from CRAN2019-12-08check errors were not corrected in time From digest including attributes, hence 'random' results in checks
- RR 3.6.0 released · 2019-04-26
- RR 3.5.0 released · 2018-04-23
- RR 3.4.0 released · 2017-04-21
- RR 3.3.0 released · 2016-05-03
- RR 3.2.0 released · 2015-04-16
Show 35 earlier eventsHide 35 earlier events
- RR 3.1.0 released · 2014-04-10
- 3.0.2Latest
- RR 3.0.0 released · 2013-04-03
- 2.15.32012-12-07 · diff ↗
- 2.15.22012-10-05 · diff ↗ ·
added 24 exports
aggplot, aggspec, as.rspec, bgandilum, coldist, explorespec, getspec, is.rspec, peakshape, plotsmooth, procspec, projplot, segclass, sensmodel, spec2rgb, summary.tcs, tcs, tcsplot, tcspoints, tcsvol, ttvertex, vismodel, vissyst, voloverlap - 2.10.0
- 2.9.0
- 2.8.02022-08-16 · diff ↗
- 2.7.12021-09-21 · diff ↗
- 2.7.02021-03-23 · diff ↗
- 2.6.12020-12-18 · diff ↗
- 2.6.02020-12-09 · diff ↗
- 2.5.02020-11-12 · diff ↗
- 2.4.02020-02-08 · diff ↗
- 2.3.02019-12-11 · diff ↗
- 2.2.0
- 2.1.02019-03-06 · diff ↗ ·
removed 8 exports
bgandilum, getspecf, getspecf2, segclass, tcs, transmissiondata, ttvertex, vissystadded 2 exports
is.colspace, is.vismodel - 2.0.02018-09-22 · diff ↗ ·
added 8 exports
adjacent, as.rimg, cimg2rimg, classify, getimg, is.rimg, procimg, rimg2cimg - 1.4.0
- 1.3.1
- 1.3.0
- 1.1.0
- 1.0.12017-03-16 · diff ↗
- 1.0.02016-12-05 · diff ↗ ·
removed 1 export
summary.tcsadded 20 exports
axistetra, categorical, catplot, cie, cieplot, coc, cocplot, colspace, diplot, dispace, hexagon, hexplot, legendtetra, projpoints, tcspace, tetraplot, transmissiondata, triplot, trispace, vol - 0.5-62016-10-20 · diff ↗
- 0.5-52016-03-09 · diff ↗
- 0.5-42016-01-28 · diff ↗
- 0.5-22015-06-11 · diff ↗
- 0.5-12013-09-04 · diff ↗
- 0.52013-06-09 · diff ↗
- 0.3-1
- 0.32013-04-23 · diff ↗
- 0.1-22013-01-12 · diff ↗
- 0.1-12012-12-05
- RR 2.15.0 released · 2012-03-30
Package metadata
- First published
- 2012-10-05
- Total releases
- 32 / 14 yrs
- License
- GPL (>= 2) OSI · relicensed from BSD in 0.5-1
- Minimum R
- ≥ 4.1
- Bundled data
- 181 KB / 3 files
- Download size
- 1.5 MB
Cite
Cite this package
Run in R for the authors' entry:
citation("pavo")The package provides a citation file, so citation() returns the authors' own entry.
It points to 10.1111/2041-210x.12069, 10.1111/2041-210x.13174.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.