LiveViewer

class photonforge.live_viewer.LiveViewer(port=0, *, start=True, host=None, allowed_hosts=(), auto_refresh=True, auto_refresh_delay=0.1, verbose=True)[source]

Live viewer for PhotonForge objects and layout files.

A displayed component can be edited in the Schematic view: move, turn, flip and resize symbols, draw wires, place components added with add_to_component_library(), delete, group, undo and redo. Edits change the component passed in, in place (there is no separate copy), and component holds it. Save, in the viewer’s toolbar, writes it to a .phf file. Moving, turning or resizing a symbol changes only the drawing, never the layout.

The server listens on this machine only (127.0.0.1), and accepts edits, file opens and folder listings only from its own page. On a remote machine, reach it through a tunnel:

  • SSH: ssh -L 8765:127.0.0.1:8765 user@remote, then open http://localhost:8765. The local port can differ.

  • A proxy on the remote machine (jupyter-server-proxy, a VS Code tunnel or a Codespace) reaches the viewer on 127.0.0.1 too, but the page is opened under the proxy’s name, which the viewer must be told: allowed_hosts=["jupyter.example.com", "*.app.github.dev"].

  • In VS Code in the browser (code-server), the viewer allows the name in VSCODE_PROXY_URI by itself and gives its address under that proxy.

  • To be reached directly over the network, or from outside a container, pass host="0.0.0.0" (and allowed_hosts for the name the page is opened by). Anything that can reach the port can then try to edit the design, so prefer a tunnel.

The plugins.photonforge.live_viewer_host and plugins.photonforge.live_viewer_allowed_hosts tidy3d settings provide machine-wide defaults. Their environment overrides are named TIDY3D_PLUGINS__PHOTONFORGE__LIVE_VIEWER_<FIELD>.

Parameters:
  • port (int) – Port the viewer listens on; 0 takes any free one. If the port is not available, another one is used (see notes below).

  • start (bool) – If True, the viewer server is automatically started.

  • host (str | None) – Address the server listens on. Defaults to 127.0.0.1.

  • allowed_hosts (Sequence[str]) – Host names the viewer’s page may be opened by (see description above).

  • auto_refresh (bool) – If True, automatically refresh the most recently displayed component after successful IPython cell executions.

  • auto_refresh_delay (float) – Seconds to wait for another cell execution before rebuilding the displayed component.

  • verbose (bool) – If True, print status messages and notices: the server address, ports in use, refused edits, and where edits are kept. If False, the viewer prints nothing.

Example

>>> from photonforge.live_viewer import LiveViewer
>>> viewer = LiveViewer()
>>> component = pf.parametric.straight(port_spec="Strip", length=3)
>>> viewer(component)

Notes

If port is being used by another viewer in this Python session, that viewer is replaced. Otherwise, the port number is incremented until a free port is found. LiveViewer.port holds the used port number. A port that another program or another Python process’s viewer uses is never taken: a verbose viewer says which process uses it and how to stop that process.

Methods

add_to_component_library(source[, name, ...])

Add a component to the schematic editor's component library, to place from there.

changes([since])

What was changed in the viewer, to write into the script that builds the design.

display(item)

Display a component, reference, 2D structure or GDSII/OASIS path.

generate()

set_status(text, *[, scene_transition_done])

Show a live status line in the browser's loading overlay.

start()

Start the server.

stop()

Stop the server and free its port.

Attributes

AUTOSAVE_FOLDER

Where the edits of each session are kept as they are made, under the folder the viewer runs in (where Save writes too): PhotonForge has no cache folder of its own to use.

AUTOSAVE_KEEP

Sessions kept per design; the oldest go.

MESSAGES_FOLDER

Where the message bar's words are kept, a file per session, beside the edits.

MESSAGES_KEEP

Messages kept in memory for /api/messages; the file keeps every one.

component

The component on screen.

scene_generation

Generation of the currently published native scene.

AUTOSAVE_FOLDER = PosixPath('.photonforge/edits')

Where the edits of each session are kept as they are made, under the folder the viewer runs in (where Save writes too): PhotonForge has no cache folder of its own to use.

AUTOSAVE_KEEP = 10

Sessions kept per design; the oldest go.

MESSAGES_FOLDER = PosixPath('.photonforge/messages')

Where the message bar’s words are kept, a file per session, beside the edits.

MESSAGES_KEEP = 1000

Messages kept in memory for /api/messages; the file keeps every one.

add_to_component_library(source, name=None, category=None)[source]

Add a component to the schematic editor’s component library, to place from there.

The library is listed under the schematic toolbar’s Add button, as the GUI’s Component Library panel is, and keeps what it holds whatever is displayed. A placed component is added to the circuit and to the chip, where it goes into free space past the right edge of the layout, unrouted; on the page it lands where it was dropped.

Parameters:
  • source (Any) – A component, or a callable returning one. A callable is called again for every placement, so each drop can be its own cell.

  • name (str | None) – What the menu calls it. Defaults to the component’s name as the schematic captions it, without the parametric digest, with a number added if taken.

  • category (str | None) – The group the panel lists it under, as the GUI lists each library under its own name (“Passives”, “SiEPIC”, “My PCells”). Entries without one are listed under “Added from Python”.

Returns:

The name to pass as cell in an add_instance edit.

Return type:

str

changes(since=None)[source]

What was changed in the viewer, to write into the script that builds the design.

Edits made here change the component in place, and a script that builds it again makes it as it was. This lists the net effect of every edit to the component on screen since the first one: instances added, deleted, moved, turned or given new parameters; wires, nets and routes added or taken off, and route settings changed; the circuit’s own ports and terminals; shapes drawn on it. Each change is said in words and given as Python, with instances named as the viewer names them and identified by their cell and where the script put them, so the script’s own variable can be found. A device moved and moved back is no change; a route rebuilt because its devices moved is none.

Parameters:

since (Changes | None) – An earlier result, for only what changed after it.

Returns:

print them, iterate over them, python() for the code, as_dicts() for plain data, and edits for the edits themselves with the time each was made and the browser tab it came from.

Return type:

The changes

Example

>>> changes = viewer.changes()
>>> print(changes)            # what the person changed, in words
>>> print(changes.python())   # the same, as lines for the script
property component: Component | None

The component on screen.

A shape is shown in a component named after it ("Rectangle"), with the default technology; a Reference in "LiveViewer Support", with its cell’s technology. Returns None for a file or untouched blank canvas.

display(item)[source]

Display a component, reference, 2D structure or GDSII/OASIS path.

Parameters:

item (_T)

Return type:

_T

property scene_generation: int

Generation of the currently published native scene.

set_status(text, *, scene_transition_done=False)[source]

Show a live status line in the browser’s loading overlay.

Parameters:
  • text (str)

  • scene_transition_done (bool)

Return type:

None

start()[source]

Start the server.

Calling this again while the viewer runs does nothing. On the port asked for, a different viewer this session already runs there is replaced, and one another program holds is skipped for the next free port (see the port argument).

Return type:

LiveViewer

stop()[source]

Stop the server and free its port.

Return type:

None