Skip to content

Add Static/Dynamic layout viewer tabs to cells page#670

Merged
nikosavola merged 1 commit into
mainfrom
niko/add-static-dynamic-tabs
Jul 1, 2026
Merged

Add Static/Dynamic layout viewer tabs to cells page#670
nikosavola merged 1 commit into
mainfrom
niko/add-static-dynamic-tabs

Conversation

@nikosavola

@nikosavola nikosavola commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

This PR adds static PNG and dynamic kwasm-based viewers for cell layouts in the API reference cells page.

  • Each layout viewer in the API Reference docs now renders as two tabs: Static (PNG image, default) and Dynamic (interactive kwasm viewer).
  • Gallery grid cards retain .. plot:: for dynamic thumbnail rendering.

Also resolves the pre-commit Ruff lint failures in .github/write_cells.py by refactoring the GDS/PNG generation into a helper function _generate_artifacts.

This PR replaces #643, which was opened from an external fork and was permanently blocked due to the required CodeQL check not running on fork pull requests.

Summary by Sourcery

Add static PNG and dynamic kwasm-based viewer tabs to API reference cell layout docs and centralize GDS/PNG generation in a reusable helper.

Enhancements:

  • Render each cell layout in the API reference as a tabbed viewer with static PNG and dynamic kwasm-based views when pre-generated artifacts are available.
  • Fallback to existing dynamic .. plot:: rendering for cells where GDS/PNG artifacts cannot be generated.
  • Refactor cell GDS and PNG artifact generation into a shared helper used during docs build, including setup of a reusable kwasm viewer HTML scaffold.

Tests:

  • Update model data CSV fixtures for various components to align with the new or regenerated reference data.

Replace the single plot directive in the API Reference section with
sphinx-design tab-set showing a Static PNG tab and a Dynamic kwasm
viewer tab for each cell. Gallery grid cards retain plot directives
for dynamic thumbnail rendering.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds kwasm-based static/dynamic layout viewers to the cells API reference page by pre-generating GDS/PNG artifacts and wiring them into a tabbed Sphinx template, while refactoring and hardening the GDS/PNG generation logic in the write_cells script.

Flow diagram for generating GDS/PNG artifacts and tabbed cells layout

flowchart LR
    write_cells[write_cells.py main] --> setup_kwasm[_setup_kwasm_viewer]
    write_cells --> loop_cells[for each cell name]
    loop_cells --> write_gds[_write_gds]
    write_gds --> gen_artifacts[_generate_artifacts]
    gen_artifacts --> files[GDS and PNG in kwasm_gds]
    write_gds --> has_gds[has_gds flag in cells_items]
    has_gds --> template[cells.rst.j2]
    template -->|has_gds true| tabset[.. tab-set with Static PNG and Dynamic kwasm iframe]
    template -->|has_gds false| plot[.. plot:: fallback]
    tabset --> cells_page[cells API reference page]
    plot --> cells_page
Loading

File-Level Changes

Change Details Files
Pre-generate GDS and PNG artifacts for each cell and set up a reusable kwasm viewer scaffold
  • Configured Matplotlib to use the Agg backend and defined paths for kwasm output and GDS artifacts under the docs directory
  • Added _setup_kwasm_viewer() to materialize a kwasm viewer HTML template and ensure the GDS output directory exists
  • Introduced _generate_artifacts() to centralize GDS writing and PNG plotting for a given component
  • Implemented _write_gds() to derive default kwargs from a cell signature, invoke the cell factory, generate artifacts, and return a boolean success flag while logging exceptions
.github/write_cells.py
Integrate artifact generation status into cells.rst Jinja template to render Static/Dynamic tabs when possible and fall back to existing plots otherwise
  • Extended items passed from write_cells to the template with a has_gds flag based on _write_gds() and skip_plot
  • Updated cells.rst.j2 so that, for cells with GDS artifacts, it renders a tab-set with a Static PNG image and a Dynamic kwasm iframe referencing the pre-generated GDS
  • Preserved the existing .. plot:: directive as a fallback when artifacts are not available
.github/write_cells.py
docs/templates/cells.rst.j2
Adjusted test fixture CSVs for model data (exact content changes not shown)
  • Updated multiple Qucs-related CSV fixtures, likely to align with new or corrected model behavior
tests/models/data/capacitor_qucs.csv
tests/models/data/coupler_straight_qucs.csv
tests/models/data/cpw_w10_s_6_l10mm.csv
tests/models/data/inductor_qucs.csv
tests/models/data/lc_resonator_qucs.csv

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions github-actions Bot added documentation Improvements or additions to documentation python Pull requests that update python code tests Relating to testing labels Jul 1, 2026
@nikosavola nikosavola self-assigned this Jul 1, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • Consider avoiding the use of the private kwasm.embed._read_artifacts API in _setup_kwasm_viewer and instead expose or wrap a public helper so the script doesn’t rely on internal implementation details.
  • In _write_gds, printing full tracebacks on any Exception may be too noisy for normal docs generation; you might want to log a concise error message or restrict exceptions to expected failure modes instead of traceback.print_exc().
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider avoiding the use of the private kwasm.embed._read_artifacts API in _setup_kwasm_viewer and instead expose or wrap a public helper so the script doesn’t rely on internal implementation details.
- In _write_gds, printing full tracebacks on any Exception may be too noisy for normal docs generation; you might want to log a concise error message or restrict exceptions to expected failure modes instead of traceback.print_exc().

## Individual Comments

### Comment 1
<location path=".github/write_cells.py" line_range="10-18" />
<code_context>
 from pathlib import Path

+import kwasm.embed
+import matplotlib as mpl
+import matplotlib.pyplot as plt
 from gdsfactory.serialization import clean_value_json
 from jinja2 import Environment, FileSystemLoader

 import qpdk
 from qpdk.config import PATH

+mpl.use("Agg")
+
 filepath_cells = PATH.docs / "cells.rst"
</code_context>
<issue_to_address>
**issue (bug_risk):** Set the Matplotlib backend before importing pyplot to ensure it takes effect

Because the backend is fixed when `matplotlib.pyplot` is first imported, calling `mpl.use("Agg")` after `import matplotlib.pyplot as plt` is ineffective and can cause issues in headless/CI runs. Please move `mpl.use("Agg")` to immediately after `import matplotlib as mpl` and before importing `pyplot`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread .github/write_cells.py
Comment on lines +10 to +18
import matplotlib as mpl
import matplotlib.pyplot as plt
from gdsfactory.serialization import clean_value_json
from jinja2 import Environment, FileSystemLoader

import qpdk
from qpdk.config import PATH

mpl.use("Agg")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Set the Matplotlib backend before importing pyplot to ensure it takes effect

Because the backend is fixed when matplotlib.pyplot is first imported, calling mpl.use("Agg") after import matplotlib.pyplot as plt is ineffective and can cause issues in headless/CI runs. Please move mpl.use("Agg") to immediately after import matplotlib as mpl and before importing pyplot.

@nikosavola nikosavola enabled auto-merge July 1, 2026 10:12
@nikosavola nikosavola added this pull request to the merge queue Jul 1, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces automated GDS and PNG artifact generation for PDK cells, setting up an interactive kwasm HTML viewer and updating the documentation templates to display static and dynamic tabs for cell previews. Additionally, several test data CSV files have been converted from Git LFS pointers to actual data files. The review feedback highlights two key improvements: avoiding the use of the private API _read_artifacts from kwasm.embed to prevent future breakage, and wrapping the matplotlib figure generation in a try...finally block to guarantee the figure is closed and avoid memory leaks if an exception occurs.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread .github/write_cells.py
viewer_path = kwasm_dir / "viewer.html"
if viewer_path.exists():
return
template = kwasm.embed._read_artifacts()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using a private/internal API _read_artifacts from the kwasm.embed module is risky because internal functions can change or be removed in future versions without notice. If a public API is available, please use that instead.

Comment thread .github/write_cells.py
Comment on lines +55 to +62
def _generate_artifacts(c, name: str) -> None:
"""Generate GDS and PNG plot for the component."""
c.draw_ports()
c.write_gds(gds_dir / f"{name}.gds")
fig, ax = plt.subplots()
c.plot(ax=ax)
fig.savefig(gds_dir / f"{name}.png", dpi=150, bbox_inches="tight")
plt.close(fig)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In _generate_artifacts, the matplotlib figure is created using plt.subplots() and then closed with plt.close(fig). However, if an exception occurs during c.plot(ax=ax) or fig.savefig(...), plt.close(fig) will not be called, which can lead to memory leaks when generating many artifacts. It is safer to use a try...finally block to ensure the figure is always closed.

Suggested change
def _generate_artifacts(c, name: str) -> None:
"""Generate GDS and PNG plot for the component."""
c.draw_ports()
c.write_gds(gds_dir / f"{name}.gds")
fig, ax = plt.subplots()
c.plot(ax=ax)
fig.savefig(gds_dir / f"{name}.png", dpi=150, bbox_inches="tight")
plt.close(fig)
def _generate_artifacts(c, name: str) -> None:
"""Generate GDS and PNG plot for the component."""
c.draw_ports()
c.write_gds(gds_dir / f"{name}.gds")
fig, ax = plt.subplots()
try:
c.plot(ax=ax)
fig.savefig(gds_dir / f"{name}.png", dpi=150, bbox_inches="tight")
finally:
plt.close(fig)

Merged via the queue into main with commit 61682e3 Jul 1, 2026
28 of 29 checks passed
@nikosavola nikosavola deleted the niko/add-static-dynamic-tabs branch July 1, 2026 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python Pull requests that update python code tests Relating to testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants