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¶
AAAS¶
NEJM¶
Lancet¶
JAMA¶
BMJ¶
JCO¶
UCSCGB¶
D3 (category10)¶
Observable 10¶
LocusZoom¶
IGV (chromosomes)¶
COSMIC¶
LAST = (p1 + scale_color_cosmic("signature_substitutions")) | (p2 + scale_fill_cosmic("signature_substitutions"))
UChicago¶
Star Trek¶
Tron Legacy (use with dark theme)¶
Futurama¶
Rick and Morty¶
The Simpsons¶
Flat UI¶
Frontiers¶
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)¶
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
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
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
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()
)
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.