Skip to content
Draft
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
71 changes: 66 additions & 5 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ on:
push:
branches:
- main
# Test changes to the image generation or to the plotting code (images
# and a comparison with the published site are uploaded as an artifact,
# nothing is deployed)
pull_request:
paths:
- docs/scripts/**
- src/**
- .github/workflows/deploy-docs.yml
workflow_dispatch:

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
Expand All @@ -12,17 +20,48 @@ permissions:
pages: write
id-token: write

# Allow only one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: false
env:
MTEX_VERSION: 7.1.0

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# Plot images for the docs are generated by docs/scripts/make_doc_images.m
- uses: matlab-actions/setup-matlab@v2
with:
release: R2024b
products: >
Signal_Processing_Toolbox
Image_Processing_Toolbox
Statistics_and_Machine_Learning_Toolbox
cache: true

- name: Download MTEX
run: |
curl -sSfL -o "$RUNNER_TEMP/mtex.zip" \
"https://github.com/mtex-toolbox/mtex/releases/download/mtex-${MTEX_VERSION}/mtex-${MTEX_VERSION}.zip"
unzip -q "$RUNNER_TEMP/mtex.zip" -d "$RUNNER_TEMP/mtex"
MTEX_DIR=$(dirname "$(find "$RUNNER_TEMP/mtex" -name startup_mtex.m | head -1)")
# mtexdata downloads the example datasets into this folder
mkdir -p "$MTEX_DIR/data/EBSD"
echo "MTEX_DIR=$MTEX_DIR" >> "$GITHUB_ENV"

# Some ORTools functions dock their figures, which MATLAB only allows
# with a display, so provide a virtual one
- name: Start virtual display
run: |
sudo apt-get install -y -qq xvfb > /dev/null
Xvfb :99 -screen 0 1920x1200x24 &
echo "DISPLAY=:99" >> "$GITHUB_ENV"

- name: Generate documentation images
uses: matlab-actions/run-command@v2
with:
command: addpath(getenv('MTEX_DIR')); startup_mtex; addpath('docs/scripts'); make_doc_images

- uses: actions/setup-python@v5
with:
python-version: 3.x
Expand All @@ -41,14 +80,36 @@ jobs:
run: pip install -r docs/requirements.txt

- name: Build site
run: mkdocs build
run: mkdocs build --strict

- name: Compare with the published images
if: github.event_name == 'pull_request'
run: |
pip install pillow
python docs/scripts/compare_with_site.py

- name: Upload generated images for review
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: doc-images
path: |
docs/images/
docs/snippets/
docs-review/

- name: Upload artifact
if: github.event_name != 'pull_request'
uses: actions/upload-pages-artifact@v3
with:
path: site/

deploy:
if: github.event_name != 'pull_request'
# Allow only one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: false
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand Down
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,19 @@ desktop.ini

# MkDocs build output
site/

# Documentation images and snippets generated by docs/scripts/make_doc_images.m.
# Only screenshots of GUIs and the logos are kept in the repository.
docs/images/*
!docs/images/ORTools.png
!docs/images/ORTools_white.png
!docs/images/computeGrains.png
!docs/images/grainClick.png
!docs/images/guiOR.png
!docs/images/peakFitORs.png
!docs/images/recolorPhases.png
docs/snippets/
docs-review/

# Python
__pycache__/
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ mkdocs serve

CI builds the site with `mkdocs build --strict`, so broken links fail the pull request.

The plot images in `docs/images` and the command window output in `docs/snippets` are not stored in
the repository. They are generated by `docs/scripts/make_doc_images.m` whenever the site is
deployed. To generate them locally (MATLAB with MTEX, plus the Signal Processing, Image Processing and
Statistics toolboxes):

```matlab
startup_mtex
addpath('docs/scripts')
make_doc_images
```

When documenting a new plotting function, add a call for it to `make_doc_images.m`. Screenshots of
GUIs and interactive windows cannot be generated; they are the only images kept in `docs/images`.

## Code of conduct

This project follows the [Code of Conduct](CODE_OF_CONDUCT.md).
8 changes: 5 additions & 3 deletions docs/function_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,9 +259,11 @@ The function extracts orientation relationship (OR) information contained in the
- Options
- silent - suppress command window output

<p align="center">
<img src="../images/ORinfo.png" alt="Command window output example from ORinfo" width="500"/>
</p>
Example command window output:

```text
--8<-- "ORinfo.txt"
```

## P

Expand Down
Binary file removed docs/images/ORinfo.png
Binary file not shown.
Binary file removed docs/images/computeParentTwins.png
Binary file not shown.
Binary file removed docs/images/computehabitPlane.png
Binary file not shown.
Binary file removed docs/images/plotHist_ORMisfit.png
Binary file not shown.
Binary file removed docs/images/plotHist_OR_misfit.png
Binary file not shown.
Binary file removed docs/images/plotIPDF_gB_misfit.png
Binary file not shown.
Binary file removed docs/images/plotIPDF_gB_prob.png
Binary file not shown.
Binary file removed docs/images/plotMap_IPF_p2c.png
Binary file not shown.
Binary file removed docs/images/plotMap_KSvariantPairs.png
Binary file not shown.
Binary file removed docs/images/plotMap_bain.png
Binary file not shown.
Binary file removed docs/images/plotMap_blockWidths.png
Binary file not shown.
Binary file removed docs/images/plotMap_clusters.png
Binary file not shown.
Binary file removed docs/images/plotMap_gB_c2c.png
Binary file not shown.
Binary file removed docs/images/plotMap_gB_misfit.png
Binary file not shown.
Binary file removed docs/images/plotMap_gB_p2c.png
Binary file not shown.
Binary file removed docs/images/plotMap_gB_prob.png
Binary file not shown.
Binary file removed docs/images/plotMap_packets.png
Binary file not shown.
Binary file removed docs/images/plotMap_phases.png
Binary file not shown.
Binary file removed docs/images/plotMap_variants.png
Binary file not shown.
Binary file removed docs/images/plotPDF_packets.png
Binary file not shown.
Binary file removed docs/images/plotPDF_variants.png
Binary file not shown.
Binary file removed docs/images/plotPODF_transformation.png
Binary file not shown.
Binary file removed docs/images/plotStack.png
Binary file not shown.
98 changes: 98 additions & 0 deletions docs/scripts/compare_with_site.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Compare generated documentation images with the published ones.

For every PNG in docs/images, download the image of the same name from the
published documentation site and write a side-by-side comparison (published
left, generated right) to docs-review/compare/, plus an index.html listing
them all. Images identical to the published ones are skipped. Used by the
deploy workflow on pull requests.
"""

import html
import io
import sys
import urllib.error
import urllib.request
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont

SITE = "https://ortools4mtex.github.io/ORTools/images/"
ROOT = Path(__file__).resolve().parents[2]
IMAGES = ROOT / "docs" / "images"
OUT = ROOT / "docs-review" / "compare"
HEIGHT = 700 # both images are scaled to this height
LABEL = 40


def published(name):
"""Return the bytes of the published image, or None if there is none."""
try:
with urllib.request.urlopen(SITE + name, timeout=30) as response:
return response.read()
except urllib.error.HTTPError as err:
if err.code == 404:
return None
raise


def scaled(img):
width = round(img.width * HEIGHT / img.height)
return img.resize((width, HEIGHT), Image.LANCZOS)


def placeholder(text):
img = Image.new("RGB", (HEIGHT, HEIGHT), "white")
ImageDraw.Draw(img).text((20, HEIGHT // 2), text, fill="gray", font=font(28))
return img


def font(size):
try:
return ImageFont.truetype("DejaVuSans.ttf", size)
except OSError:
return ImageFont.load_default()


def side_by_side(left, right):
panels = [("Published", left), ("Generated", right)]
width = sum(img.width for _, img in panels) + 20
out = Image.new("RGB", (width, HEIGHT + LABEL), "white")
draw = ImageDraw.Draw(out)
x = 0
for label, img in panels:
draw.text((x + 10, 5), label, fill="black", font=font(28))
out.paste(img, (x, LABEL))
x += img.width + 20
return out


def main():
OUT.mkdir(parents=True, exist_ok=True)
rows = []
for path in sorted(IMAGES.glob("*.png")):
data = published(path.name)
if data == path.read_bytes():
continue # unchanged, e.g. the logos and GUI screenshots
old = None if data is None else Image.open(io.BytesIO(data)).convert("RGB")
new = Image.open(path).convert("RGB")
status = "new image" if old is None else f"{old.width}x{old.height} -> {new.width}x{new.height}"
left = placeholder("not on the site") if old is None else scaled(old)
side_by_side(left, scaled(new)).save(OUT / path.name)
rows.append((path.name, status))
print(f"{path.name}: {status}")

items = "\n".join(
f'<h2>{html.escape(name)} <small>({html.escape(status)})</small></h2>\n'
f'<img src="{html.escape(name)}" style="max-width:100%">'
for name, status in rows
)
(OUT / "index.html").write_text(
"<!doctype html><meta charset=utf-8><title>Documentation images</title>\n"
"<body style='font-family:sans-serif'>\n"
"<h1>Published (left) vs generated (right)</h1>\n" + items + "\n",
encoding="utf-8",
)


if __name__ == "__main__":
sys.exit(main())
Loading
Loading