Skip to content

Get started

ggsci for Python offers a collection of plotnine color palettes inspired by scientific journals, data visualization libraries, science fiction movies, and TV shows. Palettes are exposed as plotnine scales:

  • scale_color_palname() / scale_colour_palname()
  • scale_fill_palname()

This article mirrors the original R package vignette using plotnine.

import numpy as np
import pandas as pd
from plotnine import *
from plotnine.data import diamonds, mtcars

from ggsci import *

LAST = None

Discrete color palettes

We will use a scatter plot with smoothed curves and a bar plot to demonstrate discrete palettes. The examples below use the diamonds dataset and apply each palette to color and fill scales respectively.

# Base plots shared for discrete palette demos
p1 = (
    ggplot(diamonds.query("carat >= 2.2"), aes("table", "price", color="cut"))
    + geom_point(alpha=0.7)
    + geom_smooth(method="lm", alpha=0.05, size=1)
    + theme_bw()
)

p2 = (
    ggplot(diamonds, aes("color", fill="cut"))
    + geom_bar(position=position_dodge())
    + theme_bw()
)

NPG

LAST = (p1 + scale_color_npg()) | (p2 + scale_fill_npg())

plot

AAAS

LAST = (p1 + scale_color_aaas()) | (p2 + scale_fill_aaas())

plot

NEJM

LAST = (p1 + scale_color_nejm()) | (p2 + scale_fill_nejm())

plot

Lancet

LAST = (p1 + scale_color_lancet()) | (p2 + scale_fill_lancet())

plot

JAMA

LAST = (p1 + scale_color_jama()) | (p2 + scale_fill_jama())

plot

BMJ

LAST = (p1 + scale_color_bmj()) | (p2 + scale_fill_bmj())

plot

JCO

LAST = (p1 + scale_color_jco()) | (p2 + scale_fill_jco())

plot

UCSCGB

LAST = (p1 + scale_color_ucscgb()) | (p2 + scale_fill_ucscgb())

plot

D3 (category10)

LAST = (p1 + scale_color_d3("category10")) | (p2 + scale_fill_d3("category10"))

plot

Observable 10

LAST = (p1 + scale_color_observable()) | (p2 + scale_fill_observable())

plot

LocusZoom

LAST = (p1 + scale_color_locuszoom()) | (p2 + scale_fill_locuszoom())

plot

IGV (chromosomes)

LAST = (p1 + scale_color_igv()) | (p2 + scale_fill_igv())

plot

COSMIC

LAST = (p1 + scale_color_cosmic("hallmarks_light")) | (p2 + scale_fill_cosmic("hallmarks_light"))

plot

LAST = (p1 + scale_color_cosmic("hallmarks_dark")) | (p2 + scale_fill_cosmic("hallmarks_dark"))

plot

LAST = (p1 + scale_color_cosmic("signature_substitutions")) | (p2 + scale_fill_cosmic("signature_substitutions"))

plot

UChicago

LAST = (p1 + scale_color_uchicago()) | (p2 + scale_fill_uchicago())

plot

Star Trek

LAST = (p1 + scale_color_startrek()) | (p2 + scale_fill_startrek())

plot

Tron Legacy (use with dark theme)

LAST = (p1 + theme_dark() + scale_color_tron()) | (p2 + theme_dark() + scale_fill_tron())

plot

Futurama

LAST = (p1 + scale_color_futurama()) | (p2 + scale_fill_futurama())

plot

Rick and Morty

LAST = (p1 + scale_color_rickandmorty()) | (p2 + scale_fill_rickandmorty())

plot

The Simpsons

LAST = (p1 + scale_color_simpsons()) | (p2 + scale_fill_simpsons())

plot

Flat UI

LAST = (p1 + scale_color_flatui()) | (p2 + scale_fill_flatui())

plot

Frontiers

LAST = (p1 + scale_color_frontiers()) | (p2 + scale_fill_frontiers())

plot

Continuous color palettes

There are two types of continuous palettes: diverging and sequential. We demonstrate with a correlation heatmap and a small random matrix.

# Correlation matrix for diverging palettes (numeric columns only)
cor = mtcars.select_dtypes(include=[np.number]).corr()
cor_melt = (
    cor.stack()
    .reset_index()
    .rename(columns={"level_0": "Var1", "level_1": "Var2", 0: "value"})
)

p3 = (
    ggplot(cor_melt, aes("Var1", "Var2", fill="value"))
    + geom_tile(color="black", size=0.3)
    + theme_void()
)

# Random upper-triangular matrix for sequential palettes
np.random.seed(42)
k = 6
x = np.eye(k)
iu = np.triu_indices(k, 1)
x[iu] = np.random.uniform(0, 1, size=len(iu[0]))
x_melt = (
    pd.DataFrame(x)
    .stack()
    .reset_index()
    .rename(columns={"level_0": "Var1", "level_1": "Var2", 0: "value"})
)

p4 = (
    ggplot(x_melt, aes("Var1", "Var2", fill="value"))
    + geom_tile(color="black", size=0.3)
    + scale_x_continuous(expand=(0, 0))
    + scale_y_continuous(expand=(0, 0))
    + theme_bw()
    + theme(
        legend_position="none",
        plot_background=element_rect(fill="white"),
        panel_background=element_rect(fill="white"),
        axis_title_x=element_blank(),
        axis_title_y=element_blank(),
        axis_text_x=element_blank(),
        axis_text_y=element_blank(),
        axis_ticks=element_blank(),
        axis_line=element_blank(),
        panel_border=element_blank(),
        panel_grid_major=element_blank(),
        panel_grid_minor=element_blank(),
    )
)

# Placeholder panel to pad compositions to equal column counts
def blank_panel():
    # Build a grid matching p4's tile layout, but with white tiles (no fill mapping)
    try:
        df = x_melt[["Var1", "Var2"]].copy()
    except NameError:
        # Fallback to a 6x6 grid if x_melt is not yet defined
        k = 6
        df = pd.DataFrame(
            [(i, j) for i in range(k) for j in range(k)], columns=["Var1", "Var2"]
        )
    return (
        ggplot(df, aes("Var1", "Var2"))
        + geom_tile(fill="white", color="black", size=0.3)
        + scale_x_continuous(expand=(0, 0))
        + scale_y_continuous(expand=(0, 0))
        + theme_bw()
        + theme(
            legend_position="none",
            plot_background=element_rect(fill="white"),
            panel_background=element_rect(fill="white"),
            axis_title_x=element_blank(),
            axis_title_y=element_blank(),
            axis_text_x=element_blank(),
            axis_text_y=element_blank(),
            axis_ticks=element_blank(),
            axis_line=element_blank(),
            panel_border=element_blank(),
            panel_grid_major=element_blank(),
            panel_grid_minor=element_blank(),
        )
    )

GSEA (diverging)

LAST = (p3 + scale_fill_gsea()) | (p3 + scale_fill_gsea(reverse=True))

plot

Bootstrap 5 (sequential)

row1 = (
    (p4 + scale_fill_bs5("blue"))
    | (p4 + scale_fill_bs5("indigo"))
    | (p4 + scale_fill_bs5("purple"))
    | (p4 + scale_fill_bs5("pink"))
    | (p4 + scale_fill_bs5("red"))
    | (p4 + scale_fill_bs5("orange"))
    | (p4 + scale_fill_bs5("yellow"))
    | (p4 + scale_fill_bs5("green"))
)
row2 = (
    (p4 + scale_fill_bs5("teal"))
    | (p4 + scale_fill_bs5("cyan"))
    | (p4 + scale_fill_bs5("gray"))
    | blank_panel()
    | blank_panel()
    | blank_panel()
    | blank_panel()
    | blank_panel()
)
LAST = row1 / row2

plot

Material Design (sequential)

row1 = (
    (p4 + scale_fill_material("red"))
    | (p4 + scale_fill_material("pink"))
    | (p4 + scale_fill_material("purple"))
    | (p4 + scale_fill_material("deep-purple"))
    | (p4 + scale_fill_material("indigo"))
    | (p4 + scale_fill_material("blue"))
    | (p4 + scale_fill_material("light-blue"))
    | (p4 + scale_fill_material("cyan"))
)
row2 = (
    (p4 + scale_fill_material("teal"))
    | (p4 + scale_fill_material("green"))
    | (p4 + scale_fill_material("light-green"))
    | (p4 + scale_fill_material("lime"))
    | (p4 + scale_fill_material("yellow"))
    | (p4 + scale_fill_material("amber"))
    | (p4 + scale_fill_material("orange"))
    | (p4 + scale_fill_material("deep-orange"))
)
row3 = (
    (p4 + scale_fill_material("brown"))
    | (p4 + scale_fill_material("grey"))
    | (p4 + scale_fill_material("blue-grey"))
    | blank_panel()
    | blank_panel()
    | blank_panel()
    | blank_panel()
    | blank_panel()
)
LAST = row1 / row2 / row3

plot

Tailwind CSS 3 (sequential)

row1 = (
    (p4 + scale_fill_tw3("slate"))
    | (p4 + scale_fill_tw3("gray"))
    | (p4 + scale_fill_tw3("zinc"))
    | (p4 + scale_fill_tw3("neutral"))
    | (p4 + scale_fill_tw3("stone"))
    | (p4 + scale_fill_tw3("red"))
    | (p4 + scale_fill_tw3("orange"))
    | (p4 + scale_fill_tw3("amber"))
)
row2 = (
    (p4 + scale_fill_tw3("yellow"))
    | (p4 + scale_fill_tw3("lime"))
    | (p4 + scale_fill_tw3("green"))
    | (p4 + scale_fill_tw3("emerald"))
    | (p4 + scale_fill_tw3("teal"))
    | (p4 + scale_fill_tw3("cyan"))
    | (p4 + scale_fill_tw3("sky"))
    | (p4 + scale_fill_tw3("blue"))
)
row3 = (
    (p4 + scale_fill_tw3("indigo"))
    | (p4 + scale_fill_tw3("violet"))
    | (p4 + scale_fill_tw3("purple"))
    | (p4 + scale_fill_tw3("fuchsia"))
    | (p4 + scale_fill_tw3("pink"))
    | (p4 + scale_fill_tw3("rose"))
    | blank_panel()
    | blank_panel()
)
LAST = row1 / row2 / row3

plot

Use palette functions outside plotnine

You can use palette generator functions to get hex color codes directly for other plotting systems.

mypal = pal_observable("observable10", alpha=0.7)(10)
df_cols = pd.DataFrame({"x": range(len(mypal)), "fill": mypal})
LAST = (
    ggplot(df_cols, aes("x", 1, fill="fill"))
    + geom_tile(width=1, height=1)
    + scale_fill_identity(guide=None)
    + theme_void()
)

plot

Discussion

Some palettes may not be optimal for specific needs such as color-blind safety, photocopy safety, or print-friendliness. Consider alternatives like ColorBrewer or viridis when these constraints apply. Palettes in ggsci are for research and demonstration purposes only.