Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ dist/
docs/build/
docs/jupyter_execute/
docs/source/api/generated/
docs/source/_static/thumbnails/
# Note: thumbnails are generated during build (see .readthedocs.yaml)
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,24 @@
- **Build**: Use `make html` to build documentation
- **Doctest**: Use `make doctest` to test that Python examples in doctests work

### Adding new notebooks to the gallery

When creating a new example notebook:

1. **Place it** in `docs/source/notebooks/` with naming pattern `{method}_{model}.ipynb`
2. **Include at least one plot** in the notebook outputs (the first PNG image will be used as the thumbnail)
3. **Manually add it to `docs/source/notebooks/index.md`**:
- Find the appropriate category section or create a new one
- Add a `grid-item-card` entry with:
- `:img-top: ../_static/thumbnails/{notebook_name}.png` (thumbnail path)
- `:link: {notebook_name_without_extension}` (notebook name without `.ipynb`)
- `:link-type: doc`
- Cards are arranged in 3-column grids using `sphinx-design`
4. **Thumbnails are generated automatically** during the build process by `scripts/generate_gallery.py` (runs via `conf.py` during Sphinx setup)
5. **Test locally** with `make html` and check `docs/_build/html/notebooks/index.html`

**Important**: The `index.md` file is manually maintained. The `generate_gallery.py` script only generates thumbnails; it does not modify `index.md`. Thumbnails are gitignored (`docs/source/_static/thumbnails/`) and generated on-demand during builds.

## Code structure and style

- **Experiment classes**: All experiment classes inherit from `BaseExperiment` in `causalpy/experiments/`. Must declare `supports_ols` and `supports_bayes` class attributes. Only implement abstract methods for supported model types (e.g., if only Bayesian is supported, implement `_bayesian_plot()` and `get_plot_data_bayesian()`; if only OLS is supported, implement `_ols_plot()` and `get_plot_data_ols()`)
Expand Down
37 changes: 37 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,43 @@ We recommend that your contribution complies with the following guidelines befor

- When adding additional functionality, either edit an existing example, or create a new example (typically in the form of a Jupyter Notebook). Have a look at other examples for reference. Examples should demonstrate why the new functionality is useful in practice.

### Adding a new example notebook

When adding a new example notebook to the documentation gallery:

1. **Place the notebook** in `docs/source/notebooks/` following the naming convention `{method}_{model}.ipynb` (e.g., `did_pymc.ipynb`, `rd_skl.ipynb`).

2. **Ensure the notebook has at least one plot/figure** in its outputs. The gallery generation script (`scripts/generate_gallery.py`) will automatically extract the first PNG image from the notebook outputs to create a thumbnail. If the notebook has no outputs, the script will attempt to execute it to generate the thumbnail.

3. **Add the notebook to the gallery** by manually editing `docs/source/notebooks/index.md`:
- Find the appropriate category section (e.g., "Difference in Differences", "Regression Discontinuity") or create a new one if needed
- Add a new `grid-item-card` entry within the category's grid, following this format:
```markdown
:::{grid-item-card} Your Notebook Title
:class-card: sd-card-h-100
:img-top: ../_static/thumbnails/{notebook_name}.png
:link: {notebook_name_without_extension}
:link-type: doc
:::
```
- The `:img-top:` path should reference `../_static/thumbnails/{notebook_name}.png` (the thumbnail will be generated automatically)
- The `:link:` should be the notebook name without the `.ipynb` extension
- Cards are arranged in a 3-column grid layout

4. **Generate thumbnails locally** (optional, for testing):
```bash
python scripts/generate_gallery.py
```
Thumbnails are automatically generated during the documentation build process, so you don't need to commit them (the `docs/source/_static/thumbnails/` directory is gitignored).

5. **Build and test the documentation** to verify the notebook appears correctly in the gallery:
```bash
make html
```
Then open `docs/_build/html/notebooks/index.html` in your browser to see the gallery.

**Note**: The gallery generation script (`scripts/generate_gallery.py`) runs automatically during the Sphinx build process (configured in `docs/source/conf.py`), so thumbnails will be generated on Read the Docs builds without needing to commit them.

- Documentation and high-coverage tests are necessary for enhancements to be accepted.

- Documentation follows [NumPy style guide](https://numpydoc.readthedocs.io/en/latest/format.html)
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PACKAGE_DIR = causalpy
# COMMANDS #
#################################################################################

.PHONY: init lint check_lint test uml html cleandocs doctest help
.PHONY: init lint check_lint test uml gallery html cleandocs doctest help

init: ## Install the package in editable mode
python -m pip install -e . --no-deps
Expand All @@ -31,7 +31,10 @@ test: ## Run all tests with pytest
uml: ## Generate UML diagrams from code
pyreverse -o png causalpy --output-directory docs/source/_static --ignore tests

html: ## Build HTML documentation with Sphinx
gallery: ## Generate example gallery from notebooks
python scripts/generate_gallery.py

html: gallery ## Build HTML documentation with Sphinx
sphinx-build -b html docs/source docs/_build

cleandocs: ## Clean the documentation build directories
Expand Down
42 changes: 42 additions & 0 deletions docs/source/_static/gallery.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* Custom CSS for uniform gallery card sizes - square-like cards */
.sd-card {
height: 100%;
display: flex;
flex-direction: column;
}

.sd-card-body {
flex-grow: 1;
display: flex;
flex-direction: column;
padding: 0.5rem;
}

.sd-card-img-top {
width: 100%;
height: 250px;
object-fit: contain;
background-color: #f8f9fa;
padding: 8px;
}

.sd-card-header {
padding: 0.75rem 0.5rem;
line-height: 1.3;
min-height: auto;
}

.sd-grid-item {
display: flex;
}

/* Ensure grid items stretch to same height */
.sd-grid {
align-items: stretch;
}

/* Hide right sidebar - move "On this page" to left sidebar via html_sidebars config */
.bd-sidebar-secondary,
.sidebar-secondary {
display: none !important;
}
6 changes: 3 additions & 3 deletions docs/source/_static/interrogate_badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,40 @@

import os
import sys
from pathlib import Path

from causalpy.version import __version__

sys.path.insert(0, os.path.abspath("../"))


# Generate gallery before building docs
# This runs after dependencies are installed but before Sphinx processes files
def generate_gallery():
"""Generate example gallery from notebooks."""
try:
# Import here to avoid errors if dependencies aren't available
import subprocess

repo_root = Path(__file__).parent.parent.parent
script_path = repo_root / "scripts" / "generate_gallery.py"

if script_path.exists():
result = subprocess.run(
[sys.executable, str(script_path)],
cwd=str(repo_root),
capture_output=True,
text=True,
)
if result.returncode != 0:
print(f"Warning: Gallery generation failed: {result.stderr}")
except Exception as e:
print(f"Warning: Could not generate gallery: {e}")


# Generate gallery during Sphinx setup
generate_gallery()

# autodoc_mock_imports
# This avoids autodoc breaking when it can't find packages imported in the code.
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#confval-autodoc_mock_imports # noqa: E501
Expand Down Expand Up @@ -81,6 +110,13 @@
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
master_doc = "index"

# Suppress warnings for notebooks linked from gallery (not in toctree)
suppress_warnings = [
"toc.not_included", # Notebooks are linked from gallery, not toctree
"bibtex.duplicate_label", # BibTeX duplicate labels (less critical)
"bibtex.duplicate_citation", # BibTeX duplicate citations (less critical)
]

# bibtex config
bibtex_bibfiles = ["references.bib"]
bibtex_default_style = "unsrt"
Expand Down Expand Up @@ -138,6 +174,7 @@
html_theme = "labs_sphinx_theme"
html_static_path = ["_static"]
html_favicon = "_static/favicon_logo.png"
html_css_files = ["gallery.css"]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
Expand All @@ -148,6 +185,13 @@
},
"analytics": {"google_analytics_id": "G-3MCDG3M7X6"},
}

# Configure sidebars: show local TOC ("On this page") in left sidebar
# This moves "On this page" navigation from right sidebar to left sidebar
html_sidebars = {
"**": ["localtoc.html"], # Show "On this page" navigation in left sidebar
}

html_context = {
"github_user": "pymc-labs",
"github_repo": "CausalPy",
Expand Down
Loading