Scientific Color Palettes and Guidelines
Overview
Color choice in scientific visualization is critical for accessibility, clarity, and accurate data representation. This reference provides colorblind-friendly palettes and best practices for color usage.
Colorblind-Friendly Palettes
Okabe-Ito Palette (Recommended for Categories)
The Okabe-Ito palette is specifically designed to be distinguishable by people with all forms of color blindness.
# Okabe-Ito colors (RGB values)
okabe_ito = {
'orange': '#E69F00', # RGB: (230, 159, 0)
'sky_blue': '#56B4E9', # RGB: (86, 180, 233)
'bluish_green': '#009E73', # RGB: (0, 158, 115)
'yellow': '#F0E442', # RGB: (240, 228, 66)
'blue': '#0072B2', # RGB: (0, 114, 178)
'vermillion': '#D55E00', # RGB: (213, 94, 0)
'reddish_purple': '#CC79A7', # RGB: (204, 121, 167)
'black': '#000000' # RGB: (0, 0, 0)
}
Usage in Matplotlib:
import matplotlib.pyplot as plt
colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7', '#000000']
plt.rcParams['axes.prop_cycle'] = plt.cycler(color=colors)
Usage in Seaborn:
import seaborn as sns
okabe_ito_palette = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7']
sns.set_palette(okabe_ito_palette)
Usage in Plotly:
import plotly.graph_objects as go
okabe_ito_plotly = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7']
fig = go.Figure()
# Apply to discrete color scale
Wong Palette (Alternative for Categories)
Another excellent colorblind-friendly palette by Bang Wong (Nature Methods).
wong_palette = {
'black': '#000000',
'orange': '#E69F00',
'sky_blue': '#56B4E9',
'green': '#009E73',
'yellow': '#F0E442',
'blue': '#0072B2',
'vermillion': '#D55E00',
'purple': '#CC79A7'
}
Paul Tol Palettes
Paul Tol has designed multiple scientifically-optimized palettes for different use cases.
Bright Palette (up to 7 categories):
tol_bright = ['#4477AA', '#EE6677', '#228833', '#CCBB44',
'#66CCEE', '#AA3377', '#BBBBBB']
Muted Palette (up to 9 categories):
tol_muted = ['#332288', '#88CCEE', '#44AA99', '#117733',
'#999933', '#DDCC77', '#CC6677', '#882255', '#AA4499']
High Contrast (3 categories only):
tol_high_contrast = ['#004488', '#DDAA33', '#BB5566']
Sequential Colormaps (Continuous Data)
Sequential colormaps represent data from low to high values with a single hue.
Perceptually Uniform Colormaps
These colormaps have uniform perceptual change across the color scale.
Viridis (default in Matplotlib): - Colorblind-friendly - Prints well in grayscale - Perceptually uniform
plt.imshow(data, cmap='viridis')
Cividis: - Optimized for colorblind viewers - Designed specifically for deuteranopia/protanopia
plt.imshow(data, cmap='cividis')
Plasma, Inferno, Magma: - Perceptually uniform alternatives to viridis - Good for different aesthetic preferences
plt.imshow(data, cmap='plasma')
When to Use Sequential Maps
- Heatmaps showing intensity
- Geographic elevation data
- Probability distributions
- Any single-variable continuous data (low → high)
Diverging Colormaps (Negative to Positive)
Diverging colormaps have a neutral middle color with two contrasting colors at extremes.
Colorblind-Safe Diverging Maps
RdYlBu (Red-Yellow-Blue):
plt.imshow(data, cmap='RdYlBu_r') # _r reverses: blue (low) to red (high)
PuOr (Purple-Orange): - Excellent for colorblind viewers
plt.imshow(data, cmap='PuOr')
BrBG (Brown-Blue-Green): - Good colorblind accessibility
plt.imshow(data, cmap='BrBG')
Avoid These Diverging Maps
- RdGn (Red-Green): Problematic for red-green colorblindness
- RdYlGn (Red-Yellow-Green): Same issue
When to Use Diverging Maps
- Correlation matrices
- Change/difference data (positive vs. negative)
- Deviation from a central value
- Temperature anomalies
Special Purpose Palettes
For Genomics/Bioinformatics
Sequence type identification:
# DNA/RNA bases
nucleotide_colors = {
'A': '#00CC00', # Green
'C': '#0000CC', # Blue
'G': '#FFB300', # Orange
'T': '#CC0000', # Red
'U': '#CC0000' # Red (RNA)
}
Gene expression: - Use sequential colormaps (viridis, YlOrRd) for expression levels - Use diverging colormaps (RdBu) for log2 fold change
For Microscopy
Fluorescence channels:
# Traditional fluorophore colors (use with caution)
fluorophore_colors = {
'DAPI': '#0000FF', # Blue - DNA
'GFP': '#00FF00', # Green (problematic for colorblind)
'RFP': '#FF0000', # Red
'Cy5': '#FF00FF' # Magenta
}
# Colorblind-friendly alternatives
fluorophore_alt = {
'Channel1': '#0072B2', # Blue
'Channel2': '#E69F00', # Orange (instead of green)
'Channel3': '#D55E00', # Vermillion
'Channel4': '#CC79A7' # Magenta
}
Color Usage Best Practices
Categorical Data (Qualitative Color Schemes)
Do: - Use distinct, saturated colors from Okabe-Ito or Wong palette - Limit to 7-8 categories max in one plot - Use consistent colors for same categories across figures - Add patterns/markers when colors alone might be insufficient
Don't: - Use red/green combinations - Use rainbow (jet) colormap for categories - Use similar hues that are hard to distinguish
Continuous Data (Sequential/Diverging Schemes)
Do: - Use perceptually uniform colormaps (viridis, plasma, cividis) - Choose diverging maps when data has meaningful center point - Include colorbar with labeled ticks - Test appearance in grayscale
Don't: - Use rainbow (jet) colormap - not perceptually uniform - Use red-green diverging maps - Omit colorbar on heatmaps
Testing for Colorblind Accessibility
Online Simulators
- Coblis: https://www.color-blindness.com/coblis-color-blindness-simulator/
- Color Oracle: Free downloadable tool for Windows/Mac/Linux
- Sim Daltonism: Mac application
Types of Color Vision Deficiency
- Deuteranopia (~5% of males): Cannot distinguish green
- Protanopia (~2% of males): Cannot distinguish red
- Tritanopia (<1%): Cannot distinguish blue (rare)
Python Tools
# Using colorspacious to simulate colorblind vision
from colorspacious import cspace_convert
def simulate_deuteranopia(image_rgb):
from colorspacious import cspace_convert
# Convert to colorblind simulation
# (Implementation would require colorspacious library)
pass
Implementation Examples
Setting Global Matplotlib Style
import matplotlib.pyplot as plt
import matplotlib as mpl
# Set Okabe-Ito as default color cycle
okabe_ito_colors = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7']
mpl.rcParams['axes.prop_cycle'] = mpl.cycler(color=okabe_ito_colors)
# Set default colormap to viridis
mpl.rcParams['image.cmap'] = 'viridis'
Seaborn with Custom Palette
import seaborn as sns
# Set Paul Tol muted palette
tol_muted = ['#332288', '#88CCEE', '#44AA99', '#117733',
'#999933', '#DDCC77', '#CC6677', '#882255', '#AA4499']
sns.set_palette(tol_muted)
# For heatmaps
sns.heatmap(data, cmap='viridis', annot=True)
Plotly with Discrete Colors
import plotly.express as px
# Use Okabe-Ito for categorical data
okabe_ito_plotly = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7']
fig = px.scatter(df, x='x', y='y', color='category',
color_discrete_sequence=okabe_ito_plotly)
Grayscale Compatibility
All figures should remain interpretable in grayscale. Test by converting to grayscale:
# Convert figure to grayscale for testing
fig.savefig('figure_gray.png', dpi=300, colormap='gray')
Strategies for grayscale compatibility: 1. Use different line styles (solid, dashed, dotted) 2. Use different marker shapes (circles, squares, triangles) 3. Add hatching patterns to bars 4. Ensure sufficient luminance contrast between colors
Color Spaces
RGB vs CMYK
- RGB (Red, Green, Blue): For digital/screen display
- CMYK (Cyan, Magenta, Yellow, Black): For print
Important: Colors appear different in print vs. screen. When preparing for print: 1. Convert to CMYK color space 2. Check color appearance in CMYK preview 3. Ensure sufficient contrast remains
Matplotlib Color Spaces
# Save for print (CMYK)
# Note: Direct CMYK support limited; use PDF and let publisher convert
fig.savefig('figure.pdf', dpi=300)
# For RGB (digital)
fig.savefig('figure.png', dpi=300)
Common Mistakes
- Using jet/rainbow colormap: Not perceptually uniform; avoid
- Red-green combinations: ~8% of males cannot distinguish
- Too many colors: More than 7-8 becomes difficult to distinguish
- Inconsistent color meaning: Same color should mean same thing across figures
- Missing colorbar: Always include for continuous data
- Low contrast: Ensure colors differ sufficiently
- Relying solely on color: Add texture, patterns, or markers
Resources
- ColorBrewer: http://colorbrewer2.org/ - Choose palettes by colorblind-safe option
- Paul Tol's palettes: https://personal.sron.nl/~pault/
- Okabe-Ito palette origin: "Color Universal Design" (Okabe & Ito, 2008)
- Matplotlib colormaps: https://matplotlib.org/stable/tutorials/colors/colormaps.html
- Seaborn palettes: https://seaborn.pydata.org/tutorial/color_palettes.html