From 68122fc3b1d8ed51aed0590e8e8dde287ed527f4 Mon Sep 17 00:00:00 2001 From: "Christopher M. Pierce" Date: Wed, 8 Jul 2026 00:31:18 -0700 Subject: [PATCH 1/7] starting to setup mkdocs site --- .github/workflows/docs.yml | 45 ++ .gitignore | 1 + .pre-commit-config.yaml | 6 +- README.md | 6 +- .../examples}/container_objects.ipynb | 77 +-- .../examples}/data/CPSMOEA.h5 | Bin .../examples}/data/NSGAII.h5 | Bin .../examples}/data/ParEGO.h5 | Bin docs/examples/data/for_plotting.h5 | Bin 0 -> 1377904 bytes .../examples}/duplicate_detection.ipynb | 28 +- ...erted_generational_distance_analysis.ipynb | 103 ++++ docs/examples/plotting_histories.ipynb | 152 ++++++ docs/examples/plotting_metrics.ipynb | 91 ++++ docs/examples/plotting_populations.ipynb | 206 +++++++ docs/examples/problems.ipynb | 198 +++++++ docs/index.md | 1 + ...erted_generational_distance_analysis.ipynb | 514 ------------------ example_notebooks/plotting_histories.ipynb | 278 ---------- example_notebooks/plotting_metrics.ipynb | 156 ------ example_notebooks/plotting_populations.ipynb | 468 ---------------- example_notebooks/problems.ipynb | 317 ----------- mkdocs.yml | 24 + pyproject.toml | 5 + 23 files changed, 850 insertions(+), 1826 deletions(-) create mode 100644 .github/workflows/docs.yml rename {example_notebooks => docs/examples}/container_objects.ipynb (82%) rename {example_notebooks => docs/examples}/data/CPSMOEA.h5 (100%) rename {example_notebooks => docs/examples}/data/NSGAII.h5 (100%) rename {example_notebooks => docs/examples}/data/ParEGO.h5 (100%) create mode 100644 docs/examples/data/for_plotting.h5 rename {example_notebooks => docs/examples}/duplicate_detection.ipynb (82%) create mode 100644 docs/examples/inverted_generational_distance_analysis.ipynb create mode 100644 docs/examples/plotting_histories.ipynb create mode 100644 docs/examples/plotting_metrics.ipynb create mode 100644 docs/examples/plotting_populations.ipynb create mode 100644 docs/examples/problems.ipynb create mode 100644 docs/index.md delete mode 100644 example_notebooks/inverted_generational_distance_analysis.ipynb delete mode 100644 example_notebooks/plotting_histories.ipynb delete mode 100644 example_notebooks/plotting_metrics.ipynb delete mode 100644 example_notebooks/plotting_populations.ipynb delete mode 100644 example_notebooks/problems.ipynb create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..b2b8e65e --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,45 @@ +name: Build and deploy documentation + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + env: + MPLBACKEND: Agg + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install ffmpeg for notebook animations + run: sudo apt-get update && sudo apt-get install -y ffmpeg + - name: Install package and docs dependencies + run: pip install ".[docs]" + - name: Build documentation + run: mkdocs build + - uses: actions/upload-pages-artifact@v3 + with: + path: site + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 41ccca4f..ae772e62 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ __pycache__ /large_files/ *.h5 +!/docs/examples/data/*.h5 venv profile* *-checkpoint.ipynb diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 43f1504d..2acf9e54 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,4 +11,8 @@ repos: rev: v4.5.0 hooks: - id: check-added-large-files - args: ['--maxkb=2000'] \ No newline at end of file + args: ['--maxkb=2000'] +- repo: https://github.com/kynan/nbstripout + rev: 0.8.1 + hooks: + - id: nbstripout \ No newline at end of file diff --git a/README.md b/README.md index e2d395cd..a7e0229e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The `Experiment` objects may be saved to a standardized HDF5-backed format for l Learn more about the containers in the following example notebook. -[container_objects.ipynb](example_notebooks/container_objects.ipynb) +[container_objects.ipynb](https://electronsandstuff.github.io/ParetoBench/examples/container_objects/) ## Plotting @@ -48,8 +48,8 @@ Tools for plotting the data from multi-objective optimization algorithms are als See more information in the following notebooks. -- [plotting_populations.ipynb](example_notebooks/plotting_populations.ipynb) -- [plotting_histories.ipynb](example_notebooks/plotting_histories.ipynb) +- [plotting_populations.ipynb](https://electronsandstuff.github.io/ParetoBench/examples/plotting_populations/) +- [plotting_histories.ipynb](https://electronsandstuff.github.io/ParetoBench/examples/plotting_histories/) diff --git a/example_notebooks/container_objects.ipynb b/docs/examples/container_objects.ipynb similarity index 82% rename from example_notebooks/container_objects.ipynb rename to docs/examples/container_objects.ipynb index 4f9baa51..f3f1ae67 100644 --- a/example_notebooks/container_objects.ipynb +++ b/docs/examples/container_objects.ipynb @@ -10,7 +10,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -30,21 +30,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Population(size=32, vars=10, objs=[--], cons=[], fevals=32)\n", - "Decision variables: (32, 10)\n", - "Objectives: (32, 2)\n", - "Constraints: (32, 0)\n", - "Function evaluations: 32\n" - ] - } - ], + "outputs": [], "source": [ "# Create an example population\n", "pop = pb.Population(\n", @@ -71,20 +59,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Population(size=32, vars=10, objs=[--], cons=[>0.0e+00], fevals=32)" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Create a population with some names\n", "pop = pb.Population(\n", @@ -107,20 +84,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Population(size=32, vars=10, objs=[+-+], cons=[>3.3e-01,<6.6e-01], fevals=32)" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# Create a population and specify the objective / constraint directions and target\n", "pop = pb.Population(\n", @@ -145,19 +111,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "History(problem='WFG1', reports=10, vars=30, objs=[--], cons=[])\n", - "Problem: WFG1\n", - "Number of reports: 10\n" - ] - } - ], + "outputs": [], "source": [ "# Create some population objects which will go into the history. We will use the random generation helper function here.\n", "n_reports = 10\n", @@ -188,20 +144,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Experiment(name='NSGA-II (default params)', created='2025-01-26', author='The author of ParetoBench', software='ParetoBench example notebook 1.0.0', runs=32)\n", - "Number of histories: 32\n", - "Name: NSGA-II (default params)\n", - "Creation time: 2025-01-26 06:36:29.299300+00:00\n" - ] - } - ], + "outputs": [], "source": [ "# Create some random history objects to store\n", "runs = []\n", diff --git a/example_notebooks/data/CPSMOEA.h5 b/docs/examples/data/CPSMOEA.h5 similarity index 100% rename from example_notebooks/data/CPSMOEA.h5 rename to docs/examples/data/CPSMOEA.h5 diff --git a/example_notebooks/data/NSGAII.h5 b/docs/examples/data/NSGAII.h5 similarity index 100% rename from example_notebooks/data/NSGAII.h5 rename to docs/examples/data/NSGAII.h5 diff --git a/example_notebooks/data/ParEGO.h5 b/docs/examples/data/ParEGO.h5 similarity index 100% rename from example_notebooks/data/ParEGO.h5 rename to docs/examples/data/ParEGO.h5 diff --git a/docs/examples/data/for_plotting.h5 b/docs/examples/data/for_plotting.h5 new file mode 100644 index 0000000000000000000000000000000000000000..1a46cc770c194a23bcaca8e2d31fe0a9307f1f7e GIT binary patch literal 1377904 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