Skip to content

jolars/qualpal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qualpal

Build Status codecov Docs DOI CRAN_Status_Badge App DOI

A C++ library for generating qualitative color palettes with maximum perceptual distinctiveness, especially for data visualization. The API uses a builder-style interface for flexible palette configuration, supporting multiple input formats, color vision deficiency simulation, and perceptual color difference metrics.

Full documentation is available at https://jolars.github.io/qualpal/.

This library is also available as an R package called qualpalr, and as a web application at qualpal.cc.

Features

  • Automatic selection of color palettes using perceptual color difference metrics
  • Color vision deficiency simulation for accessible palette design
  • Multiple input formats: RGB values, hex strings, HSL ranges, built-in palettes
  • Fast algorithms for large color spaces
  • Builder-style C++ API for flexible palette configuration
  • Web-Based Interface for simple and interactive color palette generation

Table of Contents

Motivation

When visualizing categorical data, it is often necessary to select a set of distinct colors that are easily distinguishable from each other. This is especially important for accessibility, as many people have color vision deficiencies (CVD) that make it difficult to distinguish certain colors. qualpal aims to provide a simple and effective way to generate such color palettes, ensuring that the selected colors are not only distinct from each other, but also accessible to people with CVD.

The problem with almost all standard color palettes is that they are optimized for a specific number of colors. This is of course a problem by design, since a good 10-color palette has to be designed with the assumption that it will be used as a whole, not that it will be used in parts. But it means that if you want to select a subset of colors from a palette, you will not get the best possible result.

They are also often created by a human designer, which means that they may not be optimized for perceptual distinctiveness. qualpal, on the other hand, uses state-of-the art color difference metrics and a farthest-point sampling algorithm to select colors that are (approximately) maximally distinct from each other, while also considering color vision deficiencies.

R Package

The qualpal library is also available as an R package called qualpalr. This package is continuously updated to match the latest features of the C++ library, but may sometimes lag behind slightly. It provides a similar API for generating colors from R, making it easy to integrate qualpal into R workflows,

Web App

Qualpal is also available as a web application at qualpal.cc. The web app has slightly limited functionality compared to the library and R package, but it allows users to quickly generate color palettes directly in their browser.

JOSS Paper

Qualpal has been published in JOSS. You can read more about the motivation and design of qualpal in the paper. If you find qualpal useful in your research, please consider citing it (either using the DOI badge, the GitHub citation tool, or by referring directly to <CITATION.cff>.

Quick Start

Library Usage

Generate 5 colors from a HSL colorspace:

#include <qualpal.h>

using namespace qualpal;

Qualpal qp;
qp.setInputColorspace({ -170, 60 }, { 0, 0.7 }, { 0.2, 0.8 });
auto colorspace_pal = qp.generate(5);

Five colors from the HSL color space

Select 2 colors from given RGB values:

qp.setInputRGB({ colors::RGB("#ff0000"),
                 colors::RGB("#00ff00"),
                 colors::RGB("#0000ff") });
auto rgb_pal = qp.generate(2);

Two colors from hex RGB input

Consider color vision deficiency (CVD) when generating colors

qp.setInputPalette("ColorBrewer:Set2").setCvd({ { "deutan", 0.7 } });
auto cvd_pal = qp.generate(4);

Four colors from ColorBrewer Set2 palette with deuteranomaly simulation

Command Line Interface (CLI)

qualpal includes a powerful command line interface for palette generation and analysis. For a full list of options and usage examples, run:

qualpal --help

There are also man pages available for the CLI:

man qualpal

You can also view the Doxygen-generated documentation for detailed CLI and API usage.

Examples

Generate 5 colors from the HSL color space, with full hue range, medium-high saturation (0.4-0.8), and medium lightness (0.3-0.7):

qualpal -n 5 -i colorspace "0:360" "0.4:0.8" "0.3:0.7"

Five colors from the HSL color space

Select from hex colors:

qualpal -n 3 "#ff0000" "#00ff00" "#0000ff" "#ffff00"

Three colors from hex RGB input

Extend existing palette (keep fixed colors provided after --extend):

qualpal -n 3 -i colorspace "0:180" "0.3:0.6" "0.7:0.9" --extend "#ff0000" "#00ff00"

A fixed palette of red and green extended with one color from the HSL space

Analyze palette with hex input:

qualpal analyze --input hex "#ffe402" "#ff5733" "#33ff57" "#3357ff"
Color Difference Matrix (ciede2000 metric):
Colors analyzed: 4
Colors:
  Idx      Hex  MinDist
    0  #ffe402    29.52
    1  #ff5733    49.57
    2  #33ff57    29.52
    3  #3357ff    50.07

Color Difference Matrix:
          0       1       2       3
  0     0.00   49.57   29.52   83.87
  1    49.57    0.00   78.05   50.07
  2    29.52   78.05    0.00   71.78
  3    83.87   50.07   71.78    0.00

Installation

Binary Packages (Recommended)

Pre-built packages are available for major Linux distributions from GitHub Releases.

Quick Install Script

# Automatic installation (detects your system)
curl -sSL https://raw.githubusercontent.com/jolars/qualpal/main/scripts/install.sh | bash

Manual Installation

Debian/Ubuntu:

# Download packages (replace with your architecture)
# For x86_64/amd64:
wget https://github.com/jolars/qualpal/releases/latest/download/libqualpal1_3.3.0_amd64.deb
wget https://github.com/jolars/qualpal/releases/latest/download/qualpal_3.3.0_amd64.deb

# For ARM64/aarch64:
wget https://github.com/jolars/qualpal/releases/latest/download/libqualpal1_3.3.0_arm64.deb
wget https://github.com/jolars/qualpal/releases/latest/download/qualpal_3.3.0_arm64.deb

# Install
sudo dpkg -i libqualpal1_*.deb qualpal_*.deb

Red Hat/Fedora/SUSE:

# Download packages (replace with your architecture)
# For x86_64:
wget https://github.com/jolars/qualpal/releases/latest/download/libqualpal1-3.3.0.x86_64.rpm
wget https://github.com/jolars/qualpal/releases/latest/download/qualpal-3.3.0.x86_64.rpm

# For ARM64/aarch64:
wget https://github.com/jolars/qualpal/releases/latest/download/libqualpal1-3.3.0.aarch64.rpm
wget https://github.com/jolars/qualpal/releases/latest/download/qualpal-3.3.0.aarch64.rpm

# Install
sudo rpm -i libqualpal1-*.rpm qualpal-*.rpm

Development Files: If you plan to develop with qualpal, also install the development package:

  • Debian/Ubuntu: libqualpal-dev_3.3.0_{amd64,arm64}.deb
  • Red Hat/Fedora/SUSE: libqualpal-devel-3.3.0.{x86_64,aarch64}.rpm

Requirements

  • CMake >= 3.15
  • C++17 compatible compiler (e.g., GCC, Clang, MSVC)
  • [Optional] OpenMP for parallelization
  • [Optional] help2man for CLI man page generation
  • [Optional] Catch2 for testing

From Source

To build and install qualpal from source, you need to have CMake and a C++17 compatible C++ compiler installed. If you want the algorithm to be parallelized, you also need to have support for OpenMP.

To build, clone the repository and run the following commands:

git clone https://github.com/jolars/qualpal.git
cd qualpal
cmake -B build -S .
cmake --build build --config Release

If you want to include the CLI interface, make sure to pass the -DBUILD_CLI=ON option to CMake:

cmake -B build -S . -DBUILD_CLI=ON

Then, to install the library (and CLI, if built), use the following command:

sudo cmake --install build

If you prefer to install the library in a custom location, such as your home directory, you can specify the --prefix option:

cmake --install build --prefix "$HOME/.local"

Optionally, you can also run the CLI app directly from the build directory without installing it:

./build/qualpal --help

What Gets Installed

Under your chosen prefix (e.g., $HOME/.local or /usr/local):

  • bin/qualpal - Command-line interface (when BUILD_CLI=ON)
  • include/qualpal/ - C++ header files
  • lib/libqualpal.* (or lib64/libqualpal.*) - Library files
  • lib/cmake/qualpal/ - CMake package configuration
  • share/doc/qualpal/LICENSE - License file
  • share/man/man1/qualpal.1 - Manual page

Package Types

The binary packages are split into separate components:

  • Runtime packages (libqualpal1): Contains the shared library needed to run applications that use qualpal
  • CLI packages (qualpal): Contains the command-line interface - depends on the runtime package
  • Development packages (libqualpal-dev/libqualpal-devel): Contains headers, static library, and CMake files for building applications with qualpal

This separation allows you to install only what you need:

  • Just want the CLI? Install runtime + CLI packages
  • Developing with qualpal? Install all three packages
  • Deploying an application? Install just the runtime package

Uninstall

To uninstall qualpal, we provide a CMake uninstall target. Run the following command:

cmake --build build --target uninstall

Unix users can also delete the files directly by calling

xargs rm < build/install_manifest.txt

WebAssembly

To build the WebAssembly package for web applications, you need to first install Emscripten.

Then, you can build the package with the following commands:

emcmake cmake -B build/wasm -S . -DBUILD_WASM=ON -DCMAKE_BUILD_TYPE=Release
emmake make -C build/wasm qualpal_wasm

CMake Integration

qualpal can be easily integrated into your CMake projects. After building and installing the library, you can find it using CMake's find_package command.

find_package(qualpal REQUIRED)
target_link_libraries(your_target qualpal::qualpal)

If you installed qualpal in a custom location, make sure to set the CMAKE_PREFIX_PATH variable first to include the installation prefix, e.g.:

set(CMAKE_PREFIX_PATH "$ENV{HOME}/.local") # Or your custom prefix

Usage Examples

Basic Color Selection

#include <iostream>
#include <qualpal.h>

using namespace qualpal;

int
main()
{
  // Start with some input colors
  Qualpal qp;
  qp.setInputRGB({
    colors::RGB("#e41a1c"), // Red
    colors::RGB("#377eb8"), // Blue
    colors::RGB("#4daf4a"), // Green
    colors::RGB("#984ea3"), // Purple
    colors::RGB("#ff7f00"), // Orange
  });

  // Select 3 most distinct colors
  auto palette = qp.generate(3);

  for (const auto& color : palette) {
    std::cout << color.hex() << std::endl;
  }

  return 0;
}

Three colors from given RGB input

Color Vision Deficiency Consideration

Adapt to deuteranomaly (red-green colorblindness) of severity 0.8:

Qualpal qp;
qp.setInputRGB(colors).setCvd({ { "deutan", 0.8 } });
auto accessible_palette = qp.generate(2);

Two colors from given RGB input with deuteranomaly adaptation

HSL Color Space

A soothing pastel palette, generated from a HSL color space:

Qualpal qp;
qp.setInputColorspace({ 20, 300 }, { 0.3, 0.7 }, { 0.7, 0.9 });
auto pastel_palette = qp.generate(5);

A palette of pastels

Adaptation to Background Color

When visualizing categorical data, consider a background color to ensure contrast:

auto pal = Qualpal{}
             .setInputRGB({
               colors::RGB("#f0f0f0"), // Light color (which we want to avoid)
               colors::RGB("#e41a1c"), // Red
               colors::RGB("#377eb8"), // Blue
               colors::RGB("#4daf4a"), // Green
             })
             .setBackground(colors::RGB("#ffffff"))
             .generate(3);

Three colors from given RGB input avoiding light colors on white background

Improving Existing Palettes

Qualpal can take an existing color palette and improve it by selecting a subset of the most distinct colors from it, as well as ordering the result.

Here we design a CVD-friendly version of the "ColorBrewer:Set2" palette for a black background, selecting 3 colors.

auto pal = Qualpal{}
             .setInputPalette("ColorBrewer:Set2")
             .setBackground(colors::RGB("#000000"))
             .setCvd({ { "tritan", 0.2 }, { "deutan", 0.5 } })
             .generate(3);

Three colors from ColorBrewer Set2 palette with tritanomaly and deuteranomaly simulation on black background

Palette Extension Example

Extend an existing palette by adding more distinct colors to it:

std::vector<colors::RGB> fixed = {
  colors::RGB("#e41a1c"), // Red
  colors::RGB("#377eb8"), // Blue
};

std::vector<colors::RGB> input = {
  colors::RGB("#4daf4a"), // Green
  colors::RGB("#984ea3"), // Purple
  colors::RGB("#ff7f00"), // Orange
  colors::RGB("#ffff33"), // Yellow
};

// Extend to 6 colors, keeping the first two fixed
auto ext_pal = Qualpal{}.setInputRGB(input).extend(fixed, 4);

A fixed palette of red and blue extended with four colors from given RGB input

Contributing

Contributions are welcome! Please see the CONTRIBUTING file for more information.

Versioning

This project follows Semantic Versioning. Expect breaking changes in major releases, new features in minor releases, and bug fixes in patch releases.

License

MIT License - see LICENSE file.

About

Generate qualitative color palettes optimized for dinstictiveness

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Contributors 6