Rust workspace for scientific and sci-fi color palettes from ggsci.
The ggsci crate provides a core registry of the discrete palettes,
continuous palettes, fixed discrete iTerm palettes, and Gephi generative
discrete palettes.
The ggsci-ratatui crate converts that output to ratatui colors and styles
in truecolor or ANSI-256 mode.
The ggsci-ggsql crate converts palettes to typed ggsql output ranges or
explicit-array SQL scale clauses.
The core registry contains the stored discrete palettes and the continuous palettes represented by canonical interpolation anchors.
Use take() for discrete category colors:
use ggsci::palette_by_spec;
fn main() -> Result<(), ggsci::Error> {
let palette = palette_by_spec("observable:observable10")?;
let colors = palette.take_hex(3)?;
assert_eq!(colors, ["#4269D0", "#EFB118", "#FF725C"]);
Ok(())
}Use interpolate() for continuous gradient samples:
use ggsci::{palette_by_spec, ContinuousOptions};
fn main() -> Result<(), ggsci::Error> {
let palette = palette_by_spec("material:blue-grey")?;
let colors = palette.interpolate(256)?;
let reversed = palette.interpolate_with(
256,
ContinuousOptions::new().with_reverse(true),
)?;
assert_eq!(reversed, colors.into_iter().rev().collect::<Vec<_>>());
Ok(())
}Use sample() for kind-aware dispatch when accepting either palette kind.
PaletteKind::{Discrete, Continuous} describes scale semantics. Whether data
is stored or generated is an orthogonal implementation detail. Accordingly,
Palette::colors() contains category colors for discrete palettes and the
canonical interpolation anchors for continuous palettes.
iTerm themes use their own API because each theme has normal and bright variants plus the fixed terminal-channel order Blue, Yellow, Red, Cyan, Green, Magenta:
use ggsci::{iterm_palette, ItermVariant};
fn main() -> Result<(), ggsci::Error> {
let rose_pine = iterm_palette("Rose Pine")?;
let colors = rose_pine.take_hex(ItermVariant::Normal, 6)?;
assert_eq!(colors.len(), 6);
Ok(())
}Theme lookup is case-insensitive and treats _, -, and whitespace as
interchangeable separators while preserving other punctuation. Variant parsing
is also case-insensitive. Every ItermPalette reports
PaletteKind::Discrete; normal/bright is an ItermVariant, not a palette
kind. The iTerm records are not flattened into palettes() or
palettes_by_kind() because the core Palette model cannot preserve their two
variants and terminal-channel ordering. The complete iTerm data is included in
the normal crate package without feature flags.
Gephi palettes generate visually distinct category colors for a discrete
scale. Every GephiPalette reports PaletteKind::Discrete; generation is its
mechanism, not a third palette kind.
use ggsci::gephi_palette;
fn main() -> Result<(), ggsci::Error> {
let gephi = gephi_palette("fancy-light")?;
let colors = gephi.generate_with_seed(20, 42)?;
assert_eq!(colors.len(), 20);
Ok(())
}Available canonical names are default, fancy_light, fancy_dark,
shades, tarnish, pastel, pimp, intense, fluo, red_roses,
ochre_sand, yellow_lime, green_mint, ice_cube, blue_ocean,
indigo_night, and purple_wine. Lookup is case-insensitive and treats _,
-, and whitespace as interchangeable separators.
Use generate_with_seed() for reproducible output. It uses ChaCha8Rng with
an explicitly defined SplitMix64 u64-to-32-byte seed expansion and a stable
53-bit floating-point sampling rule. Golden tests lock this crate's seeded
output, but seeds are not cross-language compatible with R or NumPy. Use
generate() for fresh nondeterministic output from an independent RNG seeded
from the operating system; it does not mutate an application RNG. The RGBA
methods accept finite alpha in (0.0, 1.0] and apply it after RGB generation.
Generation performs rejection sampling followed by filtered k-means and farthest-first ordering. Its cost grows with the requested color count; as in R, quality drops from 50 iterations at up to 50 colors to 25, 10, 5, and 2 at the 50/100/200/300 boundaries. The deterministic 9,261-point candidate grid is filtered once into a thread-safe indexed cache for all 17 generated filters; generated palettes themselves are never cached.
Gephi has a dedicated generator registry because each result requires an
algorithm and random state. Its definitions are not duplicated in the stored
core palettes() or palettes_by_kind() registry even though both Gephi and
stored categorical palettes have discrete scale semantics.
The workspace has three publishable crates, all released at the same version:
ggscicontains palette data, interpolation, and generation.ggsci-ratatuidepends onratatui-coreand provides color conversion, alpha compositing, palette adapters, and foreground/background style helpers.ggsci-ggsqldepends on ggsql without its default features and provides typedOutputRangeconversion plus validated textual scale clauses.
The ggsci crate requires Rust 1.85, the first stable release whose Cargo can
load the workspace's Rust 2024 manifests.
ggsci-ratatui requires Rust 1.88 to match ratatui-core 0.1.2.
ggsci-ggsql requires Rust 1.86 to match ggsql 0.4.1.
CI checks each public crate at its own MSRV in addition to checking the
workspace on stable, beta, and nightly.
For example:
use ggsci_ratatui::{colors, foreground_styles, ColorMode};
fn main() -> Result<(), ggsci::Error> {
let colors = colors("observable:observable10", 5, ColorMode::TrueColor)?;
let styles = foreground_styles(&colors);
assert_eq!(colors.len(), 5);
assert_eq!(styles.len(), 5);
Ok(())
}See the ggsci-ratatui README for ANSI-256, continuous, iTerm, Gephi, and RGBA conversion details.
ggsql does not currently expose a third-party palette registry, so
ggsci-ggsql emits explicit color arrays instead of globally registering
ggsci names. It preserves source PaletteKind separately from its ggsql
ScaleKind, supports typed OutputRange::Array conversion, and provides
discrete, continuous, fixed iTerm, and seeded Gephi SQL helpers. See the
ggsci-ggsql README for examples and the ggsql
parser build note.
Run the complete interactive Ratatui gallery from the workspace root:
cargo run -p ggsci-ratatui --example palette-galleryThe responsive gallery browses every core, iTerm, and Gephi definition in TrueColor or ANSI-256 mode. It shows a realistic terminal application with tabs, palette cards, scrolling, resize handling, and keyboard controls.
Core, iTerm, and Gephi metadata plus R-generated continuous golden fixtures are checked in. To refresh all of them from the vendored upstream source during development:
cargo xtask update-palettesThe command regenerates the core registry, continuous fixtures, dedicated iTerm registry, and Gephi filter registry, then formats the workspace. It requires R. Building, testing, documenting, and using the published crate do not require R, Python, NumPy, or the vendor sources.
ggsci is also available in other programming languages:
