# Scientific Documentation

> Set up and maintain documentation for scientific Python packages. Covers Sphinx, MkDocs, NumPy-style docstrings, Diataxis framework, accessibility standards, and documentation hosting with Read the Docs.

- Skill: `uw-ssec/scientific-documentation` (Agent Skill, multi-file: 13 files)
- Install (CLI): `npx skillmds@latest add uw-ssec/scientific-documentation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/uw-ssec/scientific-documentation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: uw-ssec (https://skillmd.com/u/uw-ssec)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/uw-ssec/scientific-documentation

---


# Scientific Python Documentation

A comprehensive guide to creating documentation for scientific Python packages following community best practices from the [Scientific Python Development Guide](https://learn.scientific-python.org/development/guides/docs/).

## Resources in This Skill

This skill includes extensive supporting materials for documentation tasks:

**References** (detailed guides):
- `references/diataxis-framework.md` - Complete Diátaxis framework guide with examples for all four documentation types
- `references/sphinx-extensions.md` - Detailed Sphinx extension configuration and usage
- `references/docstring-examples.md` - Comprehensive NumPy-style docstring examples for functions, classes, and modules
- `references/notebook-integration.md` - Jupyter notebook integration guide for Sphinx and MkDocs
- `references/common-issues.md` - Troubleshooting documentation build issues
- `references/accessible-documentation.md` - Accessibility guidelines for scientific documentation including images, color contrast, and alt text

**Assets** (ready-to-use templates):
- `assets/sphinx-conf-scientific.py` - Complete Sphinx `conf.py` template for scientific Python
- `assets/readthedocs.yaml` - Read the Docs configuration template
- `assets/mkdocs-scientific.yml` - MkDocs configuration template with Material theme
- `assets/noxfile-docs.py` - Nox automation sessions for documentation builds
- `assets/index-template.md` - Documentation landing page template

**Scripts**:
- `scripts/generate-api-docs.py` - Script to generate API documentation stubs

## Quick Decision Trees

### Documentation Framework Selection

Choose your documentation framework based on project needs:

**Sphinx** - Best for:
- LaTeX/math-heavy documentation
- Established scientific Python ecosystem integration
- Projects similar to NumPy, SciPy, Astropy
- Need for PDF output
- Extensive API documentation with autodoc

**MkDocs** - Best for:
- Markdown-native documentation
- Simpler setup with fewer plugins
- Projects similar to FastAPI, Typer
- Modern, clean aesthetics
- Rapid prototyping

**Jupyter Book** - Best for:
- Notebook-centric documentation
- Computational narratives and tutorials
- Interactive examples and visualizations
- Educational content
- Data science workflows

### Theme Selection

**For Sphinx:**

| Theme | Best For | Pros | Cons |
|-------|----------|------|------|
| `pydata-sphinx-theme` | Scientific Python standard | Dark mode, excellent navigation, ecosystem alignment | Requires configuration |
| `furo` | Modern projects | Clean design, excellent search, fast | Less customization |
| `sphinx_rtd_theme` | Traditional docs | Widely recognized, simple setup | Older design |
| `sphinx-book-theme` | Book-like docs | Beautiful, narrative-focused | Less suitable for API-heavy |

**For MkDocs:**

| Theme | Best For | Pros | Cons |
|-------|----------|------|------|
| `material` | Modern projects | Feature-rich, beautiful, customizable | Can be overwhelming |
| `readthedocs` | Simple needs | Familiar, straightforward | Basic features |

### Hosting Selection

| Platform | Best For | Pros | Cons |
|----------|----------|------|------|
| **Read the Docs** | Open source projects | Free, automatic builds, versioning | Limited customization |
| **GitHub Pages** | Simple static sites | Simple, integrated with GitHub | Manual build process |
| **Netlify** | Advanced needs | Preview deployments, control | Requires setup |

## Diátaxis Framework

The [Diátaxis framework](https://diataxis.fr/) organizes documentation into four categories based on user needs:

| Type | Purpose | Characteristics |
|------|---------|-----------------|
| **Tutorials** | Help newcomers learn by doing | Progressive difficulty, complete examples, encouraging tone |
| **How-to Guides** | Help users accomplish specific goals | Problem-focused, practical recipes, real-world scenarios |
| **Reference** | Provide technical specifications | Comprehensive, consistent, auto-generated from docstrings |
| **Explanation** | Help users understand concepts | Discursive, contextual, theory and design decisions |

**Key principle:** Don't mix documentation types. Keep tutorials separate from reference docs.

> For complete Diátaxis guidance with detailed examples and templates for each documentation type, see `references/diataxis-framework.md`.

## Sphinx Configuration for Scientific Python

### Essential Extensions

Create `docs/conf.py` with these core extensions:

```python
extensions = [
    # Core Sphinx extensions
    "sphinx.ext.autodoc",        # Auto-generate docs from docstrings
    "sphinx.ext.autosummary",    # Generate summary tables
    "sphinx.ext.viewcode",       # Add source code links
    "sphinx.ext.intersphinx",    # Link to other projects

    # Scientific Python extensions
    "sphinx.ext.napoleon",       # NumPy/Google docstrings
    "sphinx.ext.mathjax",        # Math rendering
    "numpydoc",                  # NumPy documentation style
    "sphinx_autodoc_typehints",  # Type hint integration

    # Markdown support
    "myst_parser",               # MyST Markdown parser

    # Notebook integration
    "nbsphinx",                  # Jupyter notebook rendering
]
```

### Extension Purposes

**autodoc** - Automatically generate documentation from docstrings:
```python
.. automodule:: mypackage.analysis
   :members:
   :undoc-members:
   :show-inheritance:
```

**autosummary** - Create summary tables:
```rst
.. autosummary::
   :toctree: generated/

   mypackage.function1
   mypackage.function2
```

**napoleon** - Parse NumPy-style docstrings (configure in `conf.py`):
```python
napoleon_google_docstring = False
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = True
napoleon_use_param = True
napoleon_use_rtype = True
```

**intersphinx** - Link to external documentation:
```python
intersphinx_mapping = {
    "python": ("https://docs.python.org/3", None),
    "numpy": ("https://numpy.org/doc/stable/", None),
    "scipy": ("https://docs.scipy.org/doc/scipy/", None),
    "pandas": ("https://pandas.pydata.org/docs/", None),
    "matplotlib": ("https://matplotlib.org/stable/", None),
    "xarray": ("https://docs.xarray.dev/en/stable/", None),
    "sklearn": ("https://scikit-learn.org/stable/", None),
}
```

**myst_parser** - Use Markdown in Sphinx:
```python
myst_enable_extensions = [
    "colon_fence",    # ::: fences
    "deflist",        # Definition lists
    "dollarmath",     # $...$ and $$...$$ for math
    "fieldlist",      # Field lists
    "substitution",   # Variable substitution
    "tasklist",       # Task lists
]
```

### Theme Configuration

**PyData Sphinx Theme** (recommended for scientific Python):
```python
html_theme = "pydata_sphinx_theme"

html_theme_options = {
    "github_url": "https://github.com/org/package",
    "use_edit_page_button": True,
    "show_toc_level": 2,
    "navigation_with_keys": True,
    "icon_links": [
        {
            "name": "PyPI",
            "url": "https://pypi.org/project/your-package",
            "icon": "fas fa-box",
        },
    ],
}

html_context = {
    "github_user": "org",
    "github_repo": "package",
    "github_version": "main",
    "doc_path": "docs",
}
```

> For complete Sphinx extension configuration including advanced options, autodoc directives, and troubleshooting, see `references/sphinx-extensions.md`. For a complete ready-to-use `conf.py`, see `assets/sphinx-conf-scientific.py`.

## NumPy-style Docstrings

NumPy-style docstrings are the standard for scientific Python projects. Key sections include:

- **Short summary** - One-line description
- **Extended summary** - More detailed explanation
- **Parameters** - Input arguments with types and descriptions
- **Returns** - Return values with types
- **Raises** - Exceptions that may be raised
- **See Also** - Related functions/classes
- **Notes** - Additional information, math formulas
- **Examples** - Runnable code examples

### Concise Function Example

```python
def compute_statistic(data, method="mean", axis=0, weights=None):
    """
    Compute a statistical measure along the specified axis.

    Parameters
    ----------
    data : array_like
        Input data array. Can be any shape.
    method : {'mean', 'median', 'std'}, optional
        Statistical method to compute. Default is 'mean'.
    axis : int or None, optional
        Axis along which to compute. Default is 0.
    weights : array_like, optional
        Weights for each value. If None, equal weights.

    Returns
    -------
    ndarray
        Computed statistic.

    Raises
    ------
    ValueError
        If `method` is not supported.

    Examples
    --------
    >>> import numpy as np
    >>> data = np.array([1, 2, 3, 4, 5])
    >>> compute_statistic(data, method='mean')
    3.0
    """
    pass
```

> For comprehensive NumPy-style docstring examples including classes, modules, generators, and all supported sections, see `references/docstring-examples.md`.

## Read the Docs Integration

### Configuration File: `.readthedocs.yaml`

Place in repository root:

```yaml
version: 2

build:
  os: ubuntu-24.04
  tools:
    python: "3.12"
  jobs:
    post_install:
      # Install package with docs dependencies
      - pip install .[docs]

sphinx:
  configuration: docs/conf.py
  fail_on_warning: true

formats:
  - pdf
  - epub
```

### Dependencies

In `pyproject.toml`, add docs extra:

```toml
[project.optional-dependencies]
docs = [
    "sphinx>=7.0",
    "pydata-sphinx-theme>=0.15",
    "sphinx-autodoc-typehints>=2.0",
    "numpydoc>=1.6",
    "myst-parser>=2.0",
    "nbsphinx>=0.9",
]
```

Or in `setup.py`:

```python
extras_require = {
    "docs": [
        "sphinx>=7.0",
        "pydata-sphinx-theme>=0.15",
        "sphinx-autodoc-typehints>=2.0",
        "numpydoc>=1.6",
        "myst-parser>=2.0",
        "nbsphinx>=0.9",
    ],
}
```

### Setting up RTD

1. Go to https://readthedocs.org/
2. Import your repository
3. Trigger a build
4. Configure advanced settings:
   - Default version
   - Privacy level
   - Build notifications

## MkDocs Configuration for Scientific Python

### `mkdocs.yml`

```yaml
site_name: My Scientific Package
site_description: Description of your scientific package
site_url: https://org.github.io/package
repo_url: https://github.com/org/package
repo_name: org/package

theme:
  name: material
  features:
    - navigation.tabs
    - navigation.sections
    - navigation.expand
    - navigation.top
    - search.suggest
    - search.highlight
    - content.code.copy
    - content.tabs.link
  palette:
    - scheme: default
      primary: indigo
      accent: indigo
      toggle:
        icon: material/brightness-7
        name: Switch to dark mode
    - scheme: slate
      primary: indigo
      accent: indigo
      toggle:
        icon: material/brightness-4
        name: Switch to light mode

plugins:
  - search
  - mkdocstrings:
      handlers:
        python:
          options:
            docstring_style: numpy
            show_source: true
            show_root_heading: true
            separate_signature: true
            merge_init_into_class: true
  - mkdocs-jupyter:
      include_source: true
      execute: false

markdown_extensions:
  - pymdownx.arithmatex:
      generic: true
  - pymdownx.highlight:
      anchor_linenums: true
      line_spans: __span
      pygments_lang_class: true
  - pymdownx.inlinehilite
  - pymdownx.snippets
  - pymdownx.superfences
  - pymdownx.tabbed:
      alternate_style: true
  - admonition
  - pymdownx.details
  - tables
  - attr_list
  - md_in_html
  - def_list

extra_javascript:
  - javascripts/mathjax.js
  - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js

nav:
  - Home: index.md
  - Getting Started:
      - Installation: getting-started/installation.md
      - Quick Start: getting-started/quickstart.md
  - Tutorials:
      - tutorials/index.md
      - First Analysis: tutorials/first-analysis.md
  - How-to Guides:
      - guides/index.md
      - Handle Large Data: guides/large-data.md
  - Reference:
      - API: reference/api.md
      - Configuration: reference/configuration.md
  - Explanation:
      - explanation/index.md
      - Architecture: explanation/architecture.md
```

### MathJax Configuration

Create `docs/javascripts/mathjax.js`:

```javascript
window.MathJax = {
  tex: {
    inlineMath: [["\\(", "\\)"]],
    displayMath: [["\\[", "\\]"]],
    processEscapes: true,
    processEnvironments: true
  },
  options: {
    ignoreHtmlClass: ".*|",
    processHtmlClass: "arithmatex"
  }
};

document$.subscribe(() => {
  MathJax.typesetPromise()
})
```

## Notebook Integration

### With Sphinx (nbsphinx)

**Configuration in `conf.py`:**
```python
extensions = [
    # ... other extensions
    "nbsphinx",
]

# nbsphinx configuration
nbsphinx_execute = "auto"  # or "always", "never"
nbsphinx_allow_errors = False
nbsphinx_timeout = 60  # seconds

# Exclude patterns
exclude_patterns = [
    "_build",
    "**.ipynb_checkpoints",
]
```

**Include notebooks in documentation:**
```rst
.. toctree::
   :maxdepth: 2

   notebooks/tutorial
   notebooks/advanced_usage
```

### With MkDocs (mkdocs-jupyter)

**Configuration in `mkdocs.yml`:**
```yaml
plugins:
  - mkdocs-jupyter:
      include_source: true
      execute: false
      allow_errors: false
      kernel_name: python3
```

**Reference in navigation:**
```yaml
nav:
  - Tutorials:
      - Getting Started: notebooks/tutorial.ipynb
      - Advanced: notebooks/advanced.ipynb
```

> For advanced notebook integration including execution options, cell tags, and troubleshooting, see `references/notebook-integration.md`.

## Build Automation with Nox

### `noxfile.py`

```python
"""Nox sessions for documentation."""
import nox

@nox.session(python="3.12")
def docs(session):
    """Build the documentation."""
    session.install(".[docs]")
    session.run(
        "sphinx-build",
        "-W",  # Treat warnings as errors
        "-b", "html",
        "docs",
        "docs/_build/html",
    )

@nox.session(python="3.12")
def docs_live(session):
    """Build and serve documentation with live reload."""
    session.install(".[docs]", "sphinx-autobuild")
    session.run(
        "sphinx-autobuild",
        "-W",
        "--open-browser",
        "docs",
        "docs/_build/html",
    )

@nox.session(python="3.12")
def docs_linkcheck(session):
    """Check documentation links."""
    session.install(".[docs]")
    session.run(
        "sphinx-build",
        "-b", "linkcheck",
        "docs",
        "docs/_build/linkcheck",
    )
```

**Usage:**
```bash
nox -s docs        # Build docs
nox -s docs_live   # Live preview
nox -s docs_linkcheck  # Check links
```

> For a complete noxfile with additional sessions (spelling, coverage, doctest, PDF builds), see `assets/noxfile-docs.py`.

## Documentation Structure

### Recommended Directory Layout

```
docs/
├── conf.py                    # Sphinx configuration
├── index.md                   # Landing page
├── getting-started/
│   ├── installation.md
│   └── quickstart.md
├── tutorials/
│   ├── index.md
│   ├── first-analysis.md
│   └── advanced-usage.md
├── guides/
│   ├── index.md
│   ├── large-datasets.md
│   ├── performance.md
│   └── extending.md
├── reference/
│   ├── api.rst
│   ├── cli.md
│   └── configuration.md
├── explanation/
│   ├── index.md
│   ├── architecture.md
│   ├── algorithms.md
│   └── design-decisions.md
├── notebooks/
│   └── *.ipynb
└── _static/
    └── custom.css
```

## Best Practices

### Writing Tips

1. **Start with the user's goal** - What are they trying to accomplish?
2. **Use active voice** - "The function returns..." not "The return value is..."
3. **Include runnable examples** - Every example should work
4. **Cross-reference liberally** - Use `:func:`, `:class:`, `:ref:`
5. **Update docs with code** - Documentation is code

### Common Pitfalls

1. **Mixing documentation types** - Don't put tutorials in reference docs
2. **Outdated examples** - Test your examples in CI
3. **Missing dependencies** - Document all requirements clearly
4. **Broken links** - Use `linkcheck` builder
5. **No search keywords** - Use descriptive titles and headers

> For detailed troubleshooting of common documentation build issues, see `references/common-issues.md`.

## Accessibility Guidelines

Accessible documentation ensures all users can effectively use your documentation regardless of ability. Follow these core principles based on the [Scientific Python Accessible Documentation Guide](https://learn.scientific-python.org/documentation/accessible-documentation/).

### Core Principles

1. **Write it out** - Text is highly adaptable across screen readers, search engines, and different devices
2. **Provide multiple options** - Offer both text explanations and images for concepts
3. **Use semantic structures** - Use HTML/Markdown elements as intended (headings for hierarchy, lists for related items)

### Documentation Structure

- Use headings in hierarchical order without skipping levels (H1 to H2 to H3, not H1 to H3)
- Create descriptive page titles that match navigation labels
- Include table of contents with jump links for long pages
- Provide site search functionality

### Text Accessibility

- Write complete sentences with proper grammar and punctuation
- Use plain language; avoid unnecessary jargon
- Define field-specific terms and expand acronyms on first use
- Write descriptive link text (not "click here")

### Image Accessibility

**Design requirements:**
- Images must remain comprehensible in grayscale
- Avoid red-green color combinations that overlap
- Maintain minimum 4.5:1 color contrast for text
- Ensure annotations are readable (similar size to body text)
- Prevent animated flashing (no more than 3 times per second)

**Context requirements:**
- Provide alt text capturing the information conveyed
- Include detailed image descriptions for complex figures
- All text in images must appear as actual text elsewhere
- Link to source data or notebooks when applicable

### Video Accessibility

- Introduce videos contextually before they appear
- Require explicit play/pause controls (no autoplay)
- Include closed captions and provide linked transcripts
- Ensure video content is duplicated in text elsewhere

### Quick Accessibility Checklist

- [ ] Page titles match navigation labels
- [ ] Headings in proper order (no skipping levels)
- [ ] Color contrast at least 4.5:1
- [ ] Images work in grayscale
- [ ] All images have meaningful alt text
- [ ] Link text describes destination
- [ ] Videos have controls (no autoplay)
- [ ] Text alternatives for all non-text content

> For comprehensive accessibility guidelines including code examples, testing tools, and detailed checklists, see `references/accessible-documentation.md`.

### Version Documentation

For multiple versions:

```python
# conf.py
version = "0.1"  # Short version
release = "0.1.0"  # Full version

# Add version switcher (pydata theme)
html_theme_options = {
    "navbar_end": ["version-switcher", "navbar-icon-links"],
}
```

## Scientific-Specific Sections

### Citation Information

Create `CITATION.cff`:
```yaml
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
  - family-names: "Doe"
    given-names: "Jane"
    orcid: "https://orcid.org/0000-0000-0000-0000"
title: "My Scientific Package"
version: 0.1.0
doi: 10.5281/zenodo.1234567
date-released: 2024-01-01
url: "https://github.com/org/package"
```

Document in `docs/citation.md`:
```markdown
# Citing This Software

If you use this software in your research, please cite:

## BibTeX
\`\`\`bibtex
@software{doe2024package,
  author = {Doe, Jane},
  title = {My Scientific Package},
  year = {2024},
  version = {0.1.0},
  doi = {10.5281/zenodo.1234567},
  url = {https://github.com/org/package}
}
\`\`\`

## APA
Doe, J. (2024). My Scientific Package (Version 0.1.0) [Computer software]. https://doi.org/10.5281/zenodo.1234567
```

### Reproducibility Guide

```markdown
# Reproducibility

## Environment Setup

Install exact versions:
\`\`\`bash
pip install <package-name>==0.1.0
\`\`\`

Or from `requirements.txt`:
\`\`\`bash
pip install -r requirements.txt
\`\`\`

## Random Seeds

For reproducible results:
\`\`\`python
import numpy as np
import random

random.seed(42)
np.random.seed(42)
\`\`\`

## Data Requirements

Sample data available at: [URL]

Expected data format:
- CSV with columns: [...]
- Missing values encoded as NaN
- Date format: ISO 8601

## System Requirements

- Python 3.9+
- 8GB RAM minimum
- 16GB RAM recommended for large datasets
```

## Resources

### Primary References
- [Scientific Python Documentation Guide](https://learn.scientific-python.org/development/guides/docs/)
- [Diátaxis Framework](https://diataxis.fr/)
- [NumPy Documentation Style Guide](https://numpydoc.readthedocs.io/en/latest/format.html)

### Tooling Documentation
- [Sphinx](https://www.sphinx-doc.org/)
- [MyST Parser](https://myst-parser.readthedocs.io/)
- [MkDocs Material](https://squidfunk.github.io/mkdocs-material/)
- [Read the Docs](https://docs.readthedocs.io/)

### Example Projects
- [NumPy](https://numpy.org/doc/stable/)
- [SciPy](https://docs.scipy.org/doc/scipy/)
- [Xarray](https://docs.xarray.dev/)
- [scikit-learn](https://scikit-learn.org/stable/)

