git:20260611.1b8fae3 to v1.1

203 added, 688 removed. Audit A to A.

---
name: scientific-visualization
- description: Meta-skill for publication-ready figures. Use when creating journal submission figures requiring multi-panel layouts, significance annotations, error bars, colorblind-safe palettes, and specific journal formatting (Nature, Science, Cell). Orchestrates matplotlib/seaborn/plotly with publication styles. For quick exploration use seaborn or plotly directly.
- license: MIT license
- metadata: {"version": "1.0", "skill-author": "K-Dense Inc."}
+ description: Create and audit truthful, accessible, publication-ready scientific figures with Matplotlib, Seaborn, or Plotly. Use for figure design, multi-panel layouts, uncertainty and missing-data displays, color/contrast review, image metadata validation, and journal export planning.
+ license: MIT
+ compatibility: Requires Python 3.11+ and uv for pinned examples. Bundled CLIs are network-free and load Matplotlib, Pillow, or pypdf only when needed. Plotly static export with Kaleido v1 requires a compatible Chrome/Chromium installation.
+ allowed-tools:
+ - Read
+ - Write
+ - Edit
+ - Bash
+ - Glob
+ - Grep
+ metadata:
+ version: "1.1"
+ skill-author: K-Dense Inc.
---
# Scientific Visualization
- ## Overview
-
- Scientific visualization transforms data into clear, accurate figures for publication. Create journal-ready plots with multi-panel layouts, error bars, significance markers, and colorblind-safe palettes. Export as PDF/EPS/TIFF using matplotlib, seaborn, and plotly for manuscripts.
-
- ## When to Use This Skill
-
- This skill should be used when:
- - Creating plots or visualizations for scientific manuscripts
- - Preparing figures for journal submission (Nature, Science, Cell, PLOS, etc.)
- - Ensuring figures are colorblind-friendly and accessible
- - Making multi-panel figures with consistent styling
- - Exporting figures at correct resolution and format
- - Following specific publication guidelines
- - Improving existing figures to meet publication standards
- - Creating figures that need to work in both color and grayscale
-
- ## Quick Start Guide
+ Build figures that preserve scientific meaning before optimizing appearance. Separate universal principles from dated publisher rules, preserve raw data and transformations, use color redundantly, and inspect delivered files rather than trusting plotting defaults.
- ### Basic Publication-Quality Figure
+ ## Non-negotiable guardrails
- ```python
- import matplotlib.pyplot as plt
- import numpy as np
+ - Never alter, hide, invent, or selectively enhance data to improve a figure.
+ - Preserve raw tables/images, exclusions, missing-value codes, analysis code, normalization, binning, image adjustments, and random seeds.
+ - Do not infer journal requirements. Identify the exact journal, article type, figure type, and submission phase; verify its live official guidance.
+ - Do not claim that a palette, DPI value, format, or automated report makes a figure accessible or journal-compliant.
+ - Do not silently connect missing observations, suppress inconvenient points, upsample images as if detail increased, or tune axes/dual axes to exaggerate a conclusion.
+ - Keep interactive and static outputs as distinct deliverables. Interactive hover is not a substitute for labels, alt text, keyboard access, an accessible data table, or a static fallback.
- # Apply publication style (from scripts/style_presets.py)
- from style_presets import apply_publication_style
- apply_publication_style('default')
+ Read `references/publication_guidelines.md` for deceptive-encoding and integrity checks. Read `references/journal_requirements.md` only after the target and phase are known.
- # Create figure with appropriate size (single column = 3.5 inches)
- fig, ax = plt.subplots(figsize=(3.5, 2.5))
+ ## Workflow
- # Plot data
- x = np.linspace(0, 10, 100)
- ax.plot(x, np.sin(x), label='sin(x)')
- ax.plot(x, np.cos(x), label='cos(x)')
+ ### 1. Define the evidence and destination
- # Proper labeling with units
- ax.set_xlabel('Time (seconds)')
- ax.set_ylabel('Amplitude (mV)')
- ax.legend(frameon=False)
+ Record:
- # Remove unnecessary spines
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
+ - audience and medium: manuscript, web, slide, poster, supplement;
+ - exact publisher/journal, article type, submission phase, and intended final width;
+ - variable semantics, units, sample/replicate structure, missing/censored values;
+ - estimator and uncertainty definition;
+ - transformations: filtering, aggregation, normalization, smoothing, bins, image processing;
+ - source-data paths/identifiers and output provenance.
- # Save in publication formats (from scripts/figure_export.py)
- from figure_export import save_publication_figure
- save_publication_figure(fig, 'figure1', formats=['pdf', 'png'], dpi=300)
- ```
+ If requirements are not known, create a provisional general figure and label all publisher choices as pending verification.
- ### Using Pre-configured Styles
+ ### 2. Choose an honest encoding
- Apply journal-specific styles using the matplotlib style files in `assets/`:
+ Prefer position on a common scale. Before coding, check:
- ```python
- import matplotlib.pyplot as plt
+ - **Bars/areas:** normally include zero because length/area is measured from a baseline.
+ - **Points/lines:** nonzero limits can be valid; show context and disclose breaks.
+ - **Uncertainty:** name SD, SE, CI, percentile, posterior, or another interval; state `n` and the unit of replication.
+ - **Raw observations:** show them when feasible; do not let jitter obscure categories/values.
+ - **Missing data:** distinguish missing, zero, censored, and excluded; use gaps or explicit model/interpolation styling.
+ - **Area/volume:** scale area/volume, not radius/diameter; avoid decorative 3D.
+ - **Log axes:** label the base/transform and declare how zero/negative values are handled.
+ - **Binning/smoothing:** record edges, bandwidth/window, method, and sensitivity.
+ - **Normalization:** state formula/reference and keep limits consistent across compared panels.
+ - **Dual axes:** prefer aligned panels; if unavoidable, justify units and do not engineer apparent correlation.
+ - **Images:** preserve originals, disclose whole-image adjustments, show scale bars, and avoid clipped/erased background.
- # Option 1: Use style file directly
- plt.style.use('assets/nature.mplstyle')
+ ### 3. Design accessibility in, not after
- # Option 2: Use style_presets.py helper
- from style_presets import configure_for_journal
- configure_for_journal('nature', figure_width='single')
+ - Use color plus marker, line style, hatching, direct label, or panel separation.
+ - Choose qualitative, sequential, diverging, or cyclic color according to data semantics.
+ - Audit foreground/background contrast at the rendered size.
+ - Make missing and out-of-range values explicit.
+ - Provide alt text, a longer description for complex figures, and underlying data for web delivery.
+ - Treat WCAG 2.2 as web guidance: 4.5:1 normal text, 3:1 large text, and 3:1 for graphical objects required for understanding; color cannot be the only cue. Applicability and exceptions matter.
- # Now create figures - they'll automatically match Nature specifications
- fig, ax = plt.subplots()
- # ... your plotting code ...
- ```
+ See `references/color_palettes.md`. A grayscale screen is useful but is not a complete color-vision or accessibility test.
- ### Quick Start with Seaborn
+ ### 4. Implement with scoped styles
- For statistical plots, use seaborn with publication styling:
+ Use Matplotlib's object-oriented API and temporary style contexts:
```python
- import seaborn as sns
import matplotlib.pyplot as plt
- from style_presets import apply_publication_style
- # Apply publication style
- apply_publication_style('default')
- sns.set_theme(style='ticks', context='paper', font_scale=1.1)
- sns.set_palette('colorblind')
-
- # Create statistical comparison figure
- fig, ax = plt.subplots(figsize=(3.5, 3))
- sns.boxplot(data=df, x='treatment', y='response',
- order=['Control', 'Low', 'High'], palette='Set2', ax=ax)
- sns.stripplot(data=df, x='treatment', y='response',
- order=['Control', 'Low', 'High'],
- color='black', alpha=0.3, size=3, ax=ax)
- ax.set_ylabel('Response (μM)')
- sns.despine()
-
- # Save figure
- from figure_export import save_publication_figure
- save_publication_figure(fig, 'treatment_comparison', formats=['pdf', 'png'], dpi=300)
- ```
-
- ## Core Principles and Best Practices
-
- ### 1. Resolution and File Format
-
- **Critical requirements** (detailed in `references/publication_guidelines.md`):
- - **Raster images** (photos, microscopy): 300-600 DPI
- - **Line art** (graphs, plots): 600-1200 DPI or vector format
- - **Vector formats** (preferred): PDF, EPS, SVG
- - **Raster formats**: TIFF, PNG (never JPEG for scientific data)
-
- **Implementation:**
- ```python
- # Use the figure_export.py script for correct settings
- from figure_export import save_publication_figure
-
- # Saves in multiple formats with proper DPI
- save_publication_figure(fig, 'myfigure', formats=['pdf', 'png'], dpi=300)
-
- # Or save for specific journal requirements
- from figure_export import save_for_journal
- save_for_journal(fig, 'figure1', journal='nature', figure_type='combination')
- ```
-
- ### 2. Color Selection - Colorblind Accessibility
-
- **Always use colorblind-friendly palettes** (detailed in `references/color_palettes.md`):
-
- **Recommended: Okabe-Ito palette** (distinguishable by all types of color blindness):
- ```python
- # Option 1: Use assets/color_palettes.py
- from color_palettes import OKABE_ITO_LIST, apply_palette
- apply_palette('okabe_ito')
+ from style_presets import style_context
- # Option 2: Manual specification
- okabe_ito = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
- '#0072B2', '#D55E00', '#CC79A7', '#000000']
- plt.rcParams['axes.prop_cycle'] = plt.cycler(color=okabe_ito)
+ with style_context("default", palette_name="okabe_ito_on_white"):
+ fig, ax = plt.subplots(
+ figsize=(89 / 25.4, 60 / 25.4),
+ layout="constrained",
+ )
+ ax.plot(x, y, marker="o", label="Observed")
+ ax.set(xlabel="Time (hours)", ylabel="Response (unit)")
+ ax.legend()
```
- **For heatmaps/continuous data:**
- - Use perceptually uniform colormaps: `viridis`, `plasma`, `cividis`
- - Avoid red-green diverging maps (use `PuOr`, `RdBu`, `BrBG` instead)
- - Never use `jet` or `rainbow` colormaps
-
- **Always test figures in grayscale** to ensure interpretability.
+ `layout="constrained"` supports colorbars, nested GridSpec, subfigures, and `subplot_mosaic`. Do not call `tight_layout()` afterward; it disables constrained layout.
- ### 3. Typography and Text
+ For exact physical dimensions, do not use `bbox_inches="tight"` unless the changed page size is intentional.
- **Font guidelines** (detailed in `references/publication_guidelines.md`):
- - Sans-serif fonts: Arial, Helvetica, Calibri
- - Minimum sizes at **final print size**:
- - Axis labels: 7-9 pt
- - Tick labels: 6-8 pt
- - Panel labels: 8-12 pt (bold)
- - Sentence case for labels: "Time (hours)" not "TIME (HOURS)"
- - Always include units in parentheses
+ #### Color normalization
- **Implementation:**
```python
- # Set fonts globally
import matplotlib as mpl
- mpl.rcParams['font.family'] = 'sans-serif'
- mpl.rcParams['font.sans-serif'] = ['Arial', 'Helvetica']
- mpl.rcParams['font.size'] = 8
- mpl.rcParams['axes.labelsize'] = 9
- mpl.rcParams['xtick.labelsize'] = 7
- mpl.rcParams['ytick.labelsize'] = 7
- ```
- ### 4. Figure Dimensions
-
- **Journal-specific widths** (detailed in `references/journal_requirements.md`):
- - **Nature**: Single 89 mm, Double 183 mm
- - **Science**: Single 55 mm, Double 175 mm
- - **Cell**: Single 85 mm, Double 178 mm
-
- **Check figure size compliance:**
- ```python
- from figure_export import check_figure_size
-
- fig = plt.figure(figsize=(3.5, 3)) # 89 mm for Nature
- check_figure_size(fig, journal='nature')
- ```
-
- ### 5. Multi-Panel Figures
-
- **Best practices:**
- - Label panels with bold letters: **A**, **B**, **C** (uppercase for most journals, lowercase for Nature)
- - Maintain consistent styling across all panels
- - Align panels along edges where possible
- - Use adequate white space between panels
-
- **Example implementation** (see `references/matplotlib_examples.md` for complete code):
- ```python
- from string import ascii_uppercase
-
- fig = plt.figure(figsize=(7, 4))
- gs = fig.add_gridspec(2, 2, hspace=0.4, wspace=0.4)
-
- ax1 = fig.add_subplot(gs[0, 0])
- ax2 = fig.add_subplot(gs[0, 1])
- # ... create other panels ...
-
- # Add panel labels
- for i, ax in enumerate([ax1, ax2, ...]):
- ax.text(-0.15, 1.05, ascii_uppercase[i], transform=ax.transAxes,
- fontsize=10, fontweight='bold', va='top')
- ```
-
- ## Common Tasks
-
- ### Task 1: Create a Publication-Ready Line Plot
-
- See `references/matplotlib_examples.md` Example 1 for complete code.
-
- **Key steps:**
- 1. Apply publication style
- 2. Set appropriate figure size for target journal
- 3. Use colorblind-friendly colors
- 4. Add error bars with correct representation (SEM, SD, or CI)
- 5. Label axes with units
- 6. Remove unnecessary spines
- 7. Save in vector format
-
- **Using seaborn for automatic confidence intervals:**
- ```python
- import seaborn as sns
- fig, ax = plt.subplots(figsize=(5, 3))
- sns.lineplot(data=timeseries, x='time', y='measurement',
- hue='treatment', errorbar=('ci', 95),
- markers=True, ax=ax)
- ax.set_xlabel('Time (hours)')
- ax.set_ylabel('Measurement (AU)')
- sns.despine()
- ```
-
- ### Task 2: Create a Multi-Panel Figure
-
- See `references/matplotlib_examples.md` Example 2 for complete code.
-
- **Key steps:**
- 1. Use `GridSpec` for flexible layout
- 2. Ensure consistent styling across panels
- 3. Add bold panel labels (A, B, C, etc.)
- 4. Align related panels
- 5. Verify all text is readable at final size
-
- ### Task 3: Create a Heatmap with Proper Colormap
-
- See `references/matplotlib_examples.md` Example 4 for complete code.
-
- **Key steps:**
- 1. Use perceptually uniform colormap (`viridis`, `plasma`, `cividis`)
- 2. Include labeled colorbar
- 3. For diverging data, use colorblind-safe diverging map (`RdBu_r`, `PuOr`)
- 4. Set appropriate center value for diverging maps
- 5. Test appearance in grayscale
-
- **Using seaborn for correlation matrices:**
- ```python
- import seaborn as sns
- fig, ax = plt.subplots(figsize=(5, 4))
- corr = df.corr()
- mask = np.triu(np.ones_like(corr, dtype=bool))
- sns.heatmap(corr, mask=mask, annot=True, fmt='.2f',
- cmap='RdBu_r', center=0, square=True,
- linewidths=1, cbar_kws={'shrink': 0.8}, ax=ax)
- ```
-
- ### Task 4: Prepare Figure for Specific Journal
-
- **Workflow:**
- 1. Check journal requirements: `references/journal_requirements.md`
- 2. Configure matplotlib for journal:
- ```python
- from style_presets import configure_for_journal
- configure_for_journal('nature', figure_width='single')
- ```
- 3. Create figure (will auto-size correctly)
- 4. Export with journal specifications:
- ```python
- from figure_export import save_for_journal
- save_for_journal(fig, 'figure1', journal='nature', figure_type='line_art')
- ```
-
- ### Task 5: Fix an Existing Figure to Meet Publication Standards
-
- **Checklist approach** (full checklist in `references/publication_guidelines.md`):
-
- 1. **Check resolution**: Verify DPI meets journal requirements
- 2. **Check file format**: Use vector for plots, TIFF/PNG for images
- 3. **Check colors**: Ensure colorblind-friendly
- 4. **Check fonts**: Minimum 6-7 pt at final size, sans-serif
- 5. **Check labels**: All axes labeled with units
- 6. **Check size**: Matches journal column width
- 7. **Test grayscale**: Figure interpretable without color
- 8. **Remove chart junk**: No unnecessary grids, 3D effects, shadows
-
- ### Task 6: Create Colorblind-Friendly Visualizations
-
- **Strategy:**
- 1. Use approved palettes from `assets/color_palettes.py`
- 2. Add redundant encoding (line styles, markers, patterns)
- 3. Test with colorblind simulator
- 4. Ensure grayscale compatibility
-
- **Example:**
- ```python
- from color_palettes import apply_palette
- import matplotlib.pyplot as plt
-
- apply_palette('okabe_ito')
-
- # Add redundant encoding beyond color
- line_styles = ['-', '--', '-.', ':']
- markers = ['o', 's', '^', 'v']
-
- for i, (data, label) in enumerate(datasets):
- plt.plot(x, data, linestyle=line_styles[i % 4],
- marker=markers[i % 4], label=label)
- ```
-
- ## Statistical Rigor
-
- **Always include:**
- - Error bars (SD, SEM, or CI - specify which in caption)
- - Sample size (n) in figure or caption
- - Statistical significance markers (*, **, ***)
- - Individual data points when possible (not just summary statistics)
-
- **Example with statistics:**
- ```python
- # Show individual points with summary statistics
- ax.scatter(x_jittered, individual_points, alpha=0.4, s=8)
- ax.errorbar(x, means, yerr=sems, fmt='o', capsize=3)
-
- # Mark significance
- ax.text(1.5, max_y * 1.1, '***', ha='center', fontsize=8)
+ norm = mpl.colors.TwoSlopeNorm(vmin=-2, vcenter=0, vmax=5)
+ cmap = mpl.colormaps["RdBu_r"].with_extremes(bad="#777777")
+ image = ax.imshow(values, norm=norm, cmap=cmap, interpolation="nearest")
+ fig.colorbar(image, ax=ax, label="Change (unit)")
```
- ## Working with Different Plotting Libraries
-
- ### Matplotlib
- - Most control over publication details
- - Best for complex multi-panel figures
- - Use provided style files for consistent formatting
- - See `references/matplotlib_examples.md` for extensive examples
-
- ### Seaborn
-
- Seaborn provides a high-level, dataset-oriented interface for statistical graphics, built on matplotlib. It excels at creating publication-quality statistical visualizations with minimal code while maintaining full compatibility with matplotlib customization.
-
- **Key advantages for scientific visualization:**
- - Automatic statistical estimation and confidence intervals
- - Built-in support for multi-panel figures (faceting)
- - Colorblind-friendly palettes by default
- - Dataset-oriented API using pandas DataFrames
- - Semantic mapping of variables to visual properties
-
- #### Quick Start with Publication Style
-
- Always apply matplotlib publication styles first, then configure seaborn:
-
- ```python
- import seaborn as sns
- import matplotlib.pyplot as plt
- from style_presets import apply_publication_style
-
- # Apply publication style
- apply_publication_style('default')
-
- # Configure seaborn for publication
- sns.set_theme(style='ticks', context='paper', font_scale=1.1)
- sns.set_palette('colorblind') # Use colorblind-safe palette
+ Use `LogNorm`, `CenteredNorm`, `SymLogNorm`, `BoundaryNorm`, or `TwoSlopeNorm` only when its mapping matches the scientific meaning.
- # Create figure
- fig, ax = plt.subplots(figsize=(3.5, 2.5))
- sns.scatterplot(data=df, x='time', y='response',
- hue='treatment', style='condition', ax=ax)
- sns.despine() # Remove top and right spines
- ```
+ #### Seaborn
- #### Common Plot Types for Publications
+ Seaborn 0.13.2 uses the current `errorbar` API:
- **Statistical comparisons:**
```python
- # Box plot with individual points for transparency
- fig, ax = plt.subplots(figsize=(3.5, 3))
- sns.boxplot(data=df, x='treatment', y='response',
- order=['Control', 'Low', 'High'], palette='Set2', ax=ax)
- sns.stripplot(data=df, x='treatment', y='response',
- order=['Control', 'Low', 'High'],
- color='black', alpha=0.3, size=3, ax=ax)
- ax.set_ylabel('Response (μM)')
- sns.despine()
+ sns.lineplot(
+ data=frame,
+ x="time",
+ y="response",
+ hue="treatment",
+ style="treatment",
+ markers=True,
+ errorbar=("ci", 95),
+ n_boot=5000,
+ seed=20260723,
+ ax=ax,
+ )
```
- **Distribution analysis:**
- ```python
- # Violin plot with split comparison
- fig, ax = plt.subplots(figsize=(4, 3))
- sns.violinplot(data=df, x='timepoint', y='expression',
- hue='treatment', split=True, inner='quartile', ax=ax)
- ax.set_ylabel('Gene Expression (AU)')
- sns.despine()
- ```
+ Axes-level functions fit custom Matplotlib layouts; figure-level functions create their own figures/facets. Do not customize Seaborn's internal artist lists as if they were stable API.
- **Correlation matrices:**
- ```python
- # Heatmap with proper colormap and annotations
- fig, ax = plt.subplots(figsize=(5, 4))
- corr = df.corr()
- mask = np.triu(np.ones_like(corr, dtype=bool)) # Show only lower triangle
- sns.heatmap(corr, mask=mask, annot=True, fmt='.2f',
- cmap='RdBu_r', center=0, square=True,
- linewidths=1, cbar_kws={'shrink': 0.8}, ax=ax)
- plt.tight_layout()
- ```
+ #### Plotly
- **Time series with confidence bands:**
- ```python
- # Line plot with automatic CI calculation
- fig, ax = plt.subplots(figsize=(5, 3))
- sns.lineplot(data=timeseries, x='time', y='measurement',
- hue='treatment', style='replicate',
- errorbar=('ci', 95), markers=True, dashes=False, ax=ax)
- ax.set_xlabel('Time (hours)')
- ax.set_ylabel('Measurement (AU)')
- sns.despine()
- ```
+ - Use `write_html()` for interaction and `write_image()`/`plotly.io.write_images()` for static output.
+ - Kaleido 1.3.0 requires Chrome/Chromium; it no longer bundles Chrome.
+ - Current static formats: PNG, JPEG, WebP, SVG, PDF. EPS is Kaleido v0-only.
+ - Do not pass deprecated `engine=` or use Orca/`plotly.io.kaleido.scope`.
+ - `width`, `height`, and `scale` control pixels; `scale=3` is not inherently “300 DPI.”
+ - WebGL traces embed raster content in PDF/SVG.
+ - Fully offline exports need local external assets when a figure references MathJax/topojson/tiles.
- #### Multi-Panel Figures with Seaborn
+ ### 5. Export explicitly and record provenance
- **Using FacetGrid for automatic faceting:**
```python
- # Create faceted plot
- g = sns.relplot(data=df, x='dose', y='response',
- hue='treatment', col='cell_line', row='timepoint',
- kind='line', height=2.5, aspect=1.2,
- errorbar=('ci', 95), markers=True)
- g.set_axis_labels('Dose (μM)', 'Response (AU)')
- g.set_titles('{row_name} | {col_name}')
- sns.despine()
+ from figure_export import export_figure
- # Save with correct DPI
- from figure_export import save_publication_figure
- save_publication_figure(g.figure, 'figure_facets',
- formats=['pdf', 'png'], dpi=300)
+ report = export_figure(
+ fig,
+ "outputs/figure1",
+ formats=["pdf", "png"],
+ dpi=600,
+ bbox_inches=None, # preserve figure page dimensions
+ provenance={
+ "raw_data": "data/source.csv",
+ "transformations": ["predeclared QC filter", "group mean"],
+ "uncertainty": "95% bootstrap CI; seed 20260723",
+ "missing_data": "retained as gaps",
+ },
+ write_manifest=True,
+ )
```
- **Combining seaborn with matplotlib subplots:**
- ```python
- # Create custom multi-panel layout
- fig, axes = plt.subplots(2, 2, figsize=(7, 6))
-
- # Panel A: Scatter with regression
- sns.regplot(data=df, x='predictor', y='response', ax=axes[0, 0])
- axes[0, 0].text(-0.15, 1.05, 'A', transform=axes[0, 0].transAxes,
- fontsize=10, fontweight='bold')
-
- # Panel B: Distribution comparison
- sns.violinplot(data=df, x='group', y='value', ax=axes[0, 1])
- axes[0, 1].text(-0.15, 1.05, 'B', transform=axes[0, 1].transAxes,
- fontsize=10, fontweight='bold')
+ The exporter refuses implicit overwrite, writes atomically, keeps vector DPI for embedded rasters, uses TIFF LZW, and can use PDF/PS Type 42 fonts. It does not validate scientific content or publisher acceptance.
- # Panel C: Heatmap
- sns.heatmap(correlation_data, cmap='viridis', ax=axes[1, 0])
- axes[1, 0].text(-0.15, 1.05, 'C', transform=axes[1, 0].transAxes,
- fontsize=10, fontweight='bold')
+ For editable fonts:
- # Panel D: Time series
- sns.lineplot(data=timeseries, x='time', y='signal',
- hue='condition', ax=axes[1, 1])
- axes[1, 1].text(-0.15, 1.05, 'D', transform=axes[1, 1].transAxes,
- fontsize=10, fontweight='bold')
+ - PDF/PS Type 42 embeds TrueType fonts.
+ - `svg.fonttype="none"` keeps text editable/searchable but does not embed fonts; appearance depends on installed fonts.
+ - `svg.fonttype="path"` preserves glyph appearance as paths but loses editable/searchable text.
- plt.tight_layout()
- sns.despine()
- ```
+ Use an opaque explicit background unless transparency is required; blending against another background changes apparent contrast.
- #### Color Palettes for Publications
+ ### 6. Inspect, compare, and review
- Seaborn includes several colorblind-safe palettes:
+ 1. Inspect file metadata.
+ 2. Audit palette contrast/grayscale separation.
+ 3. Compare against a dated publisher snapshot.
+ 4. View at final size in the manuscript/web context.
+ 5. Manually review fonts, embedded rasters, clipping, legends, scale bars, image integrity, caption, alt text, and source data.
+ 6. Re-check the live target-journal page immediately before upload.
- ```python
- # Use built-in colorblind palette (recommended)
- sns.set_palette('colorblind')
+ ## Pinned snapshot
- # Or specify custom colorblind-safe colors (Okabe-Ito)
- okabe_ito = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
- '#0072B2', '#D55E00', '#CC79A7', '#000000']
- sns.set_palette(okabe_ito)
+ The examples and smoke tests use direct package pins current on 2026-07-23:
- # For heatmaps and continuous data
- sns.heatmap(data, cmap='viridis') # Perceptually uniform
- sns.heatmap(corr, cmap='RdBu_r', center=0) # Diverging, centered
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ --with "matplotlib==3.11.1" \
+ --with "seaborn==0.13.2" \
+ --with "plotly==6.9.0" \
+ --with "kaleido==1.3.0" \
+ --with "pillow==12.3.0" \
+ --with "pypdf==6.14.2" \
+ python your_figure.py
```
- #### Choosing Between Axes-Level and Figure-Level Functions
+ This is a dated direct-dependency snapshot, not a transitive lock. Use the project's uv lock for exact replay; this skill intentionally ships no dependency lock.
- **Axes-level functions** (e.g., `scatterplot`, `boxplot`, `heatmap`):
- - Use when building custom multi-panel layouts
- - Accept `ax=` parameter for precise placement
- - Better integration with matplotlib subplots
- - More control over figure composition
+ ## Bundled CLIs
- ```python
- fig, ax = plt.subplots(figsize=(3.5, 2.5))
- sns.scatterplot(data=df, x='x', y='y', hue='group', ax=ax)
- ```
+ All helpers are deterministic, network-free, bounded, reject symlink inputs/destinations where relevant, and refuse overwrite unless `--force` is explicit.
- **Figure-level functions** (e.g., `relplot`, `catplot`, `displot`):
- - Use for automatic faceting by categorical variables
- - Create complete figures with consistent styling
- - Great for exploratory analysis
- - Use `height` and `aspect` for sizing
+ ### Inspect raster/vector metadata
- ```python
- g = sns.relplot(data=df, x='x', y='y', col='category', kind='scatter')
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ --with "pillow==12.3.0" \
+ python scripts/image_metadata.py figure.tiff \
+ --format tiff --mode RGB --min-dpi 300 --target-width-mm 85 \
+ --alpha-policy forbid
```
- #### Statistical Rigor with Seaborn
-
- Seaborn automatically computes and displays uncertainty:
-
- ```python
- # Line plot: shows mean ± 95% CI by default
- sns.lineplot(data=df, x='time', y='value', hue='treatment',
- errorbar=('ci', 95)) # Can change to 'sd', 'se', etc.
+ Supports raster images (Pillow), SVG, PDF (pypdf), and EPS/PS. Reports dimensions, DPI/effective DPI, mode, alpha, ICC presence, compression, page size, and conservative first-page PDF font resources. It does not inspect every embedded raster in a vector container.
- # Bar plot: shows mean with bootstrapped CI
- sns.barplot(data=df, x='treatment', y='response',
- errorbar=('ci', 95), capsize=0.1)
+ ### Audit palette contrast and grayscale
- # Always specify error type in figure caption:
- # "Error bars represent 95% confidence intervals"
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ python scripts/palette_audit.py \
+ --palette okabe_ito_on_white \
+ --background FFFFFF \
+ --role graphical
```
- #### Best Practices for Publication-Ready Seaborn Figures
-
- 1. **Always set publication theme first:**
- ```python
- sns.set_theme(style='ticks', context='paper', font_scale=1.1)
- ```
-
- 2. **Use colorblind-safe palettes:**
- ```python
- sns.set_palette('colorblind')
- ```
-
- 3. **Remove unnecessary elements:**
- ```python
- sns.despine() # Remove top and right spines
- ```
-
- 4. **Control figure size appropriately:**
- ```python
- # Axes-level: use matplotlib figsize
- fig, ax = plt.subplots(figsize=(3.5, 2.5))
-
- # Figure-level: use height and aspect
- g = sns.relplot(..., height=3, aspect=1.2)
- ```
-
- 5. **Show individual data points when possible:**
- ```python
- sns.boxplot(...) # Summary statistics
- sns.stripplot(..., alpha=0.3) # Individual points
- ```
-
- 6. **Include proper labels with units:**
- ```python
- ax.set_xlabel('Time (hours)')
- ax.set_ylabel('Expression (AU)')
- ```
-
- 7. **Export at correct resolution:**
- ```python
- from figure_export import save_publication_figure
- save_publication_figure(fig, 'figure_name',
- formats=['pdf', 'png'], dpi=300)
- ```
-
- #### Advanced Seaborn Techniques
-
- **Pairwise relationships for exploratory analysis:**
- ```python
- # Quick overview of all relationships
- g = sns.pairplot(data=df, hue='condition',
- vars=['gene1', 'gene2', 'gene3'],
- corner=True, diag_kind='kde', height=2)
- ```
+ Reports exact WCAG sRGB contrast plus pairwise CIE L* grayscale screening. The grayscale threshold is a heuristic, not a standard.
- **Hierarchical clustering heatmap:**
- ```python
- # Cluster samples and features
- g = sns.clustermap(expression_data, method='ward',
- metric='euclidean', z_score=0,
- cmap='RdBu_r', center=0,
- figsize=(10, 8),
- row_colors=condition_colors,
- cbar_kws={'label': 'Z-score'})
- ```
+ ### Plan/screen publisher export
- **Joint distributions with marginals:**
- ```python
- # Bivariate distribution with context
- g = sns.jointplot(data=df, x='gene1', y='gene2',
- hue='treatment', kind='scatter',
- height=6, ratio=4, marginal_kws={'kde': True})
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ python scripts/export_plan.py \
+ --publisher nature \
+ --figure-type combination \
+ --width single \
+ --phase final
```
- #### Common Seaborn Issues and Solutions
-
- **Issue: Legend outside plot area**
- ```python
- g = sns.relplot(...)
- g._legend.set_bbox_to_anchor((0.9, 0.5))
- ```
+ Add `--input figure.pdf` to screen machine-readable properties. Profiles are official-source snapshots accessed 2026-07-23, not automatic compliance rules.
- **Issue: Overlapping labels**
- ```python
- plt.xticks(rotation=45, ha='right')
- plt.tight_layout()
- ```
+ ### Preview styles
- **Issue: Text too small at final size**
- ```python
- sns.set_context('paper', font_scale=1.2) # Increase if needed
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ --with "matplotlib==3.11.1" \
+ python scripts/style_preview.py \
+ --output outputs/style-preview \
+ --style default \
+ --palette okabe_ito_on_white \
+ --formats png,svg
```
- #### Additional Resources
-
- For more detailed seaborn information, see:
- - `skills/seaborn/SKILL.md` - Comprehensive seaborn documentation
- - `skills/seaborn/references/examples.md` - Practical use cases
- - `skills/seaborn/references/function_reference.md` - Complete API reference
- - `skills/seaborn/references/objects_interface.md` - Modern declarative API
+ ### Inspect/write styles and smoke-test export
- ### Plotly
- - Interactive figures for exploration
- - Export static images for publication
- - Configure for publication quality:
- ```python
- fig.update_layout(
- font=dict(family='Arial, sans-serif', size=10),
- plot_bgcolor='white',
- # ... see matplotlib_examples.md Example 8
- )
- fig.write_image('figure.png', scale=3) # scale=3 gives ~300 DPI
+ ```bash
+ uv run --isolated --no-project --python 3.13 \
+ python scripts/style_presets.py --list
+ uv run --isolated --no-project --python 3.13 \
+ python scripts/style_presets.py --show nature
+ uv run --isolated --no-project --python 3.13 \
+ --with "matplotlib==3.11.1" \
+ python scripts/figure_export.py --demo outputs/export-smoke --manifest
```
- ## Resources
-
- ### References Directory
-
- **Load these as needed for detailed information:**
-
- - **`publication_guidelines.md`**: Comprehensive best practices
- - Resolution and file format requirements
- - Typography guidelines
- - Layout and composition rules
- - Statistical rigor requirements
- - Complete publication checklist
-
- - **`color_palettes.md`**: Color usage guide
- - Colorblind-friendly palette specifications with RGB values
- - Sequential and diverging colormap recommendations
- - Testing procedures for accessibility
- - Domain-specific palettes (genomics, microscopy)
-
- - **`journal_requirements.md`**: Journal-specific specifications
- - Technical requirements by publisher
- - File format and DPI specifications
- - Figure dimension requirements
- - Quick reference table
-
- - **`matplotlib_examples.md`**: Practical code examples
- - 10 complete working examples
- - Line plots, bar plots, heatmaps, multi-panel figures
- - Journal-specific figure examples
- - Tips for each library (matplotlib, seaborn, plotly)
-
- ### Scripts Directory
-
- **Use these helper scripts for automation:**
-
- - **`figure_export.py`**: Export utilities
- - `save_publication_figure()`: Save in multiple formats with correct DPI
- - `save_for_journal()`: Use journal-specific requirements automatically
- - `check_figure_size()`: Verify dimensions meet journal specs
- - Run directly: `python scripts/figure_export.py` for examples
-
- - **`style_presets.py`**: Pre-configured styles
- - `apply_publication_style()`: Apply preset styles (default, nature, science, cell)
- - `set_color_palette()`: Quick palette switching
- - `configure_for_journal()`: One-command journal configuration
- - Run directly: `python scripts/style_presets.py` to see examples
-
- ### Assets Directory
-
- **Use these files in figures:**
-
- - **`color_palettes.py`**: Importable color definitions
- - All recommended palettes as Python constants
- - `apply_palette()` helper function
- - Can be imported directly into notebooks/scripts
-
- - **Matplotlib style files**: Use with `plt.style.use()`
- - `publication.mplstyle`: General publication quality
- - `nature.mplstyle`: Nature journal specifications
- - `presentation.mplstyle`: Larger fonts for posters/slides
-
- ## Workflow Summary
-
- **Recommended workflow for creating publication figures:**
-
- 1. **Plan**: Determine target journal, figure type, and content
- 2. **Configure**: Apply appropriate style for journal
- ```python
- from style_presets import configure_for_journal
- configure_for_journal('nature', 'single')
- ```
- 3. **Create**: Build figure with proper labels, colors, statistics
- 4. **Verify**: Check size, fonts, colors, accessibility
- ```python
- from figure_export import check_figure_size
- check_figure_size(fig, journal='nature')
- ```
- 5. **Export**: Save in required formats
- ```python
- from figure_export import save_for_journal
- save_for_journal(fig, 'figure1', 'nature', 'combination')
- ```
- 6. **Review**: View at final size in manuscript context
-
- ## Common Pitfalls to Avoid
+ ## Assets
- 1. **Font too small**: Text unreadable when printed at final size
- 2. **JPEG format**: Never use JPEG for graphs/plots (creates artifacts)
- 3. **Red-green colors**: ~8% of males cannot distinguish
- 4. **Low resolution**: Pixelated figures in publication
- 5. **Missing units**: Always label axes with units
- 6. **3D effects**: Distorts perception, avoid completely
- 7. **Chart junk**: Remove unnecessary gridlines, decorations
- 8. **Truncated axes**: Start bar charts at zero unless scientifically justified
- 9. **Inconsistent styling**: Different fonts/colors across figures in same manuscript
- 10. **No error bars**: Always show uncertainty
+ - `assets/publication.mplstyle`: general print starting point.
+ - `assets/nature.mplstyle`: dated flagship Nature visual starting point, not a compliance preset.
+ - `assets/presentation.mplstyle`: larger projected-display style.
+ - `assets/color_palettes.py`: importable Okabe-Ito and Paul Tol values with metadata.
+ - `assets/publisher_profiles.json`: dated, machine-readable planning snapshots.
- ## Final Checklist
+ Matplotlib style files omit `#` in hex colors because `#` begins comments in `.mplstyle` parsing.
- Before submitting figures, verify:
+ ## References
- - [ ] Resolution meets journal requirements (300+ DPI)
- - [ ] File format is correct (vector for plots, TIFF for images)
- - [ ] Figure size matches journal specifications
- - [ ] All text readable at final size (≥6 pt)
- - [ ] Colors are colorblind-friendly
- - [ ] Figure works in grayscale
- - [ ] All axes labeled with units
- - [ ] Error bars present with definition in caption
- - [ ] Panel labels present and consistent
- - [ ] No chart junk or 3D effects
- - [ ] Fonts consistent across all figures
- - [ ] Statistical significance clearly marked
- - [ ] Legend is clear and complete
+ - `references/publication_guidelines.md`: integrity, deceptive encodings, accessibility, static/interactive output.
+ - `references/color_palettes.md`: palette semantics, exact values, WCAG contrast, grayscale caveats, color management.
+ - `references/journal_requirements.md`: phase-specific official publisher snapshots.
+ - `references/matplotlib_examples.md`: current, runnable Matplotlib/Seaborn/Plotly patterns.
+ - `references/sources.md`: official URLs, dates, versions, and research basis.
- Use this skill to ensure scientific figures meet the highest publication standards while remaining accessible to all readers.
+ ## Final review checklist
+ - [ ] Raw data/images and transformation code are preserved.
+ - [ ] Missing values, exclusions, bins, normalization, and uncertainty are explicit.
+ - [ ] Baselines, scales, limits, and area/volume encodings are honest.
+ - [ ] Color is redundant and rendered contrast was reviewed.
+ - [ ] Figure has an accessible description/data alternative where applicable.
+ - [ ] Physical dimensions, DPI, format, fonts, transparency, and file size were inspected after export.
+ - [ ] Publisher rules were verified for the exact journal and phase.
+ - [ ] No automated report is presented as a scientific, accessibility, or compliance certification.