9.6 KiB
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:
- Use different line styles (solid, dashed, dotted)
- Use different marker shapes (circles, squares, triangles)
- Add hatching patterns to bars
- 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:
- Convert to CMYK color space
- Check color appearance in CMYK preview
- 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