Fill and Stroke

Color values are used in two places in ggsql: When setting stroke color and fill color. Stroke color governs the color of lines, be it the outline of a rectangle (e.g. in a bar layer), or the line of a path (e.g. in a line layer). The fill color determines the color of the inside of a shape. It follows that all layers respond to the stroke aesthetic but only those containing closed shapes respond to the fill aesthetic.

The color meta-aesthetic

In addition to the fill and stroke aesthetics there is also a color meta-aesthetic. Setting this will set the fill and stroke at the same time unless they are set directly. For instance, the following will set the fill and stroke to red

DRAW bar
    SETTING color => 'red'

whereas this will set the fill to red and stroke to black

DRAW bar
    SETTING color => 'red', stroke => 'black'

The same logic applies when defining a scale. Defining a color scale creates two scales, one for fill and one for stroke, with the same settings (unless either are defined explicitly). For instance, the following

SCALE color TO viridis

defines two separate scales for fill and stroke that both use the viridis palette.

In general, it is highly advisable to be explicit and directly use the fill and stroke aesthetics. The color meta-aesthetic is a quick shortcut if you need it.

Literal values

Literal color values can be defined in any CSS compatible way 1. The gist of it is that colors can be defined in one of three different ways:

  • As a named color, e.g. 'red', or 'lemonchiffon'
  • As a hex color value, e.g. '#FF0000' or '#FFFACD88'
  • As a css color function, e.g. 'rgba(100%, 0%, 0%, 50%)' or 'oklab(98%, -0.012, 0.057)'

Literal color values are used in three places in ggsql. Either when setting an aesthetic (as opposed to mapping), e.g.

DRAW line
    SETTING stroke => '#FF0000'

when you define the output range of a fill or stroke scale manually, e.g.

SCALE fill TO ['rgb(100%, 0%, 0%)', 'lemonchiffon']

or when using an identity scale for color in which case the data values must be parsable as colors.

Note that all different types of color notation can be mixed in the same place.

Literal color values may be translucent, either by providing a fourth channel the the hex-notation, or by using a css color function that includes an alpha level (e.g. rgba()). You should avoid mixing this with the use of the opacity aesthetic to ensure the opacity is predictable.

Palettes

There are two different types of palettes for fill and stroke — those intended for continuous data and those intended for discrete data. While they both consists of multiple color values, the continuous palettes are meant for interpolation between successive values whereas the discrete palettes are not.

Palettes are used by giving them as names in the TO clause:

VISUALISE FROM ggsql:penguins
DRAW point
    MAPPING bill_dep AS x, body_mass AS y, species AS fill
    SETTING stroke => null
SCALE color TO category10

Instead of using a named palette you can create one on the fly using an array of color values:

VISUALISE FROM ggsql:penguins
DRAW point
    MAPPING bill_dep AS x, body_mass AS y, flipper_len AS fill
    SETTING stroke => null
SCALE color TO ['antiquewhite', 'firebrick']

Continuous palettes

Sequential

Sequential palettes for numeric data. navia is the default continuous color palette in ggsql.

Name Gradient Source Description
navia Crameri Default. Blue-green-cream (alias: sequential)
batlow Crameri Blue-green-yellow-red
batlowk Crameri Dark variant of batlow
batloww Crameri Light variant of batlow
hawaii Crameri Green-yellow-orange-magenta
lajolla Crameri Cream-yellow-orange-brown
tokyo Crameri White-magenta-dark blue
turku Crameri Cream-green-dark brown
acton Crameri White-purple
bamako Crameri White-brown-dark brown
bilbao Crameri White-orange-dark brown
buda Crameri White-pink-magenta
davos Crameri White-blue
devon Crameri White-blue-dark blue
glasgow Crameri Blue-cream-orange
grayc Crameri White-black grayscale
imola Crameri Blue-cream-green
lapaz Crameri White-blue-dark
lipari Crameri White-orange-dark blue
nuuk Crameri White-blue-green
oslo Crameri White-blue-black
blues ColorBrewer Light to dark blue
greens ColorBrewer Light to dark green
oranges ColorBrewer Light to dark orange
reds ColorBrewer Light to dark red
purples ColorBrewer Light to dark purple
greys ColorBrewer Light to dark grey (also grays)
ylorbr ColorBrewer Yellow-Orange-Brown
ylorrd ColorBrewer Yellow-Orange-Red
ylgn ColorBrewer Yellow-Green
ylgnbu ColorBrewer Yellow-Green-Blue
gnbu ColorBrewer Green-Blue
bugn ColorBrewer Blue-Green
bupu ColorBrewer Blue-Purple
pubu ColorBrewer Purple-Blue
pubugn ColorBrewer Purple-Blue-Green
purd ColorBrewer Purple-Red
rdpu ColorBrewer Red-Purple
orrd ColorBrewer Orange-Red
viridis Matplotlib Dark purple through blue and green to yellow
plasma Matplotlib Dark purple through pink to yellow (higher contrast)
magma Matplotlib Black through purple and pink to light yellow
inferno Matplotlib Black through red and orange to light yellow
cividis Matplotlib Dark blue through gray to yellow (colorblind-optimized)

Diverging

Diverging palettes emphasize a critical midpoint with two contrasting hues on either side. Ideal for data with a meaningful center point (e.g., zero, average).

Name Gradient Source Description
vik Crameri Blue-white-red (alias: diverging)
berlin Crameri Blue-white-red (different hues)
roma Crameri Green-cream-orange
bam Crameri Blue-white-red
broc Crameri Brown-white-green
cork Crameri Blue-white-green
lisbon Crameri Blue-white-brown
managua Crameri Blue-white-magenta
tofino Crameri Blue-cream-brown
vanimo Crameri Magenta-white-green
rdbu ColorBrewer Red-Blue
rdylbu ColorBrewer Red-Yellow-Blue
rdylgn ColorBrewer Red-Yellow-Green
spectral ColorBrewer Spectral (rainbow-like)
brbg ColorBrewer Brown-Blue-Green
prgn ColorBrewer Purple-Green
piyg ColorBrewer Pink-Yellow-Green
rdgy ColorBrewer Red-Grey
puor ColorBrewer Purple-Orange

Multi-Sequential

Multi-sequential palettes have multiple sequential segments, useful for categorical data with ordered subcategories.

Name Gradient Source Description
bukavu Crameri Multi-hue sequential
fes Crameri Multi-hue sequential
oleron Crameri Topographic (land/sea)

Cyclic

Cyclic palettes wrap around, making them suitable for periodic data like angles, phases, or time of day.

Name Gradient Source Description
romao Crameri Cyclic green-orange (alias: cyclic)
bamo Crameri Cyclic blue-red
broco Crameri Cyclic brown-green
corko Crameri Cyclic blue-green
viko Crameri Cyclic blue-red

Discrete palettes

Qualitative

Qualitative palettes for categorical data where no ordering is implied.

Name Swatches Colors Source Description
ggsql10 10 ggsql Default. Optimized for distinguishability
tableau10 10 Tableau Tableau’s default categorical palette
category10 10 D3 D3’s default categorical palette
set1 9 ColorBrewer Bold, saturated colors
set2 8 ColorBrewer Muted, softer colors
set3 12 ColorBrewer Pastel-like, lighter colors
pastel1 9 ColorBrewer Light pastel colors
pastel2 8 ColorBrewer Soft pastel colors
dark2 8 ColorBrewer Dark, saturated colors
paired 12 ColorBrewer Light-dark paired colors
accent 8 ColorBrewer Accent colors for emphasis
kelly22 20 Kelly Maximum contrast colors

References

Crameri Scientific Colour Maps

Crameri, F. (2018). Scientific colour maps. Zenodo. doi:10.5281/zenodo.1243862

Crameri, F., Shephard, G.E., & Heron, P.J. (2020). The misuse of colour in science communication. Nature Communications, 11, 5444.

ColorBrewer

Brewer, C.A. (2002). ColorBrewer: Color Advice for Cartography. colorbrewer2.org

Matplotlib

van der Walt, S. & Smith, N. (2015). A Better Default Colormap for Matplotlib. SciPy 2015.

Tableau

Tableau Software. tableau.com

D3

Bostock, M. D3.js. d3js.org

Kelly’s Colors

Kelly, K.L. (1965). Twenty-two colors of maximum contrast. Color Engineering, 3(6), 26-27.

Choosing a Palette

For general continuous data

  • navia (default) - Good all-purpose choice, perceptually uniform
  • viridis - Excellent for print, colorblind-safe, perceptually uniform
  • batlow - Wide perceptual range, good for scientific data

For data with a meaningful midpoint

Use a diverging palette:

  • vik or berlin - Clear red/blue contrast
  • roma - Warm/cool contrast without red/blue

For data representing categories with magnitude

Consider multi-sequential palettes:

  • oleron - Good for topographic data

For periodic/cyclic data

Use a cyclic palette:

  • romao - Smooth transitions that wrap around

For general categorical data

  • ggsql10 (default) - Good all-purpose choice, accessible
  • tableau10 - Familiar to many users, well-tested
  • category10 - Standard web visualization palette

For many categories (> 10)

  • kelly22 - Up to 20 distinguishable colors
  • set3 or paired - 12 colors each

For subtle/background colors

  • pastel1 or pastel2 - Light, unobtrusive
  • set2 - Muted but still distinguishable

For bold/emphasis

  • set1 - Highly saturated, attention-grabbing
  • dark2 - Rich, deep colors

For paired/related categories

  • paired - Light-dark pairs show relationships

Accessibility

  • Don’t rely on color alone: Use redundant encoding by combining color with shape, pattern, or direct labels. This ensures information is accessible when color cannot be perceived.
  • Choose colorblind-safe palettes: Approximately 8% of men and 0.5% of women have some form of color vision deficiency. Palettes like viridis, cividis, and the Crameri scientific palettes are designed to be distinguishable by colorblind viewers.
  • Avoid red-green combinations: Red-green color blindness (deuteranopia/protanopia) is the most common form. Avoid using red and green as the only distinguishing colors between categories.
  • Ensure sufficient contrast: Light colors on light backgrounds or dark colors on dark backgrounds can be difficult to perceive. Aim for a contrast ratio of at least 3:1 for graphical elements.
  • Test in grayscale: Print or display your visualization in grayscale to verify that information is still distinguishable without color. Palettes like viridis and cividis maintain luminance variation when desaturated.
  • Limit the number of colors: Most people can only reliably distinguish 6-8 colors at a glance. For more categories, consider grouping, faceting, or interactive filtering instead of adding more colors.
  • Use perceptually uniform palettes: Palettes where equal data differences produce equal perceived color differences prevent visual distortion of your data. The Crameri and matplotlib palettes (viridis, plasma, etc.) are perceptually uniform.
  • Consider cultural associations: Colors carry different meanings across cultures (e.g., red can signify danger, luck, or political affiliation). Be mindful of unintended connotations in your audience.
  • Provide alternatives: When possible, offer a data table or text description alongside color-encoded visualizations for users who cannot perceive the colors.

Footnotes

  1. For a complete overview see the documentation for the csscolorparser crate which is what we use internally.↩︎