Skip to content

feature: scene support plot3d #2730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added KLayout plugin, with DRC functionality for running design rule checks in `plugins.klayout.drc`. Supports running DRC on GDS files as well as `Geometry`, `Structure`, and `Simulation` objects.
- Added "mil" and "in" (inch) units to `plot_length_units`.
- Objective functions that involve running `tidy3d.plugins.smatrix.ComponentModeler` can be differentiated with autograd.
- `Scene.plot_3d()` method to make 3D rendering of scene.

### Changed
- Validate mode solver object for large number of grid points on the modal plane.
Expand Down
13 changes: 13 additions & 0 deletions tidy3d/components/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
equal_aspect,
plot_params_fluid,
plot_params_structure,
plot_scene_3d,
polygon_path,
)

Expand Down Expand Up @@ -1955,3 +1956,15 @@ def _pcolormesh_shape_doping_box(
alpha=alpha,
clip_box=ax.bbox,
)

def plot_3d(self, width=800, height=800) -> None:
"""Render 3D plot of ``Scene`` (in jupyter notebook only).
Parameters
----------
width : float = 800
width of the 3d view dom's size
height : float = 800
height of the 3d view dom's size

"""
return plot_scene_3d(self, width=width, height=height)
3 changes: 2 additions & 1 deletion tidy3d/components/viz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
plot_params_structure,
plot_params_symmetry,
)
from .plot_sim_3d import plot_sim_3d
from .plot_sim_3d import plot_scene_3d, plot_sim_3d
from .styles import (
ARROW_ALPHA,
ARROW_COLOR_MONITOR,
Expand Down Expand Up @@ -75,6 +75,7 @@
"plot_params_source",
"plot_params_structure",
"plot_params_symmetry",
"plot_scene_3d",
"plot_sim_3d",
"polygon_patch",
"polygon_path",
Expand Down
71 changes: 65 additions & 6 deletions tidy3d/components/viz/plot_sim_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,63 @@
from tidy3d.exceptions import SetupError


def plot_sim_3d(sim, width=800, height=800) -> None:
"""Make 3D display of simulation in ipyython notebook."""
def plot_scene_3d(scene, width=800, height=800) -> None:
import gzip
import json
from base64 import b64encode
from io import BytesIO

import h5py

# Serialize scene to HDF5 in-memory
buffer = BytesIO()
scene.to_hdf5(buffer)
buffer.seek(0)

# Open source HDF5 for reading and prepare modified copy
with h5py.File(buffer, "r") as src:
buffer2 = BytesIO()
with h5py.File(buffer2, "w") as dst:

def copy_item(name, obj):
if isinstance(obj, h5py.Group):
dst.create_group(name)
for k, v in obj.attrs.items():
dst[name].attrs[k] = v
elif isinstance(obj, h5py.Dataset):
data = obj[()]
if name == "JSON_STRING":
# Parse and update JSON string
json_str = (
data.decode("utf-8") if isinstance(data, (bytes, bytearray)) else data
)
json_data = json.loads(json_str)
json_data["size"] = list(scene.size)
json_data["center"] = list(scene.center)
json_data["grid_spec"] = {}
new_str = json.dumps(json_data)
dst.create_dataset(name, data=new_str.encode("utf-8"))
else:
dst.create_dataset(name, data=data)
for k, v in obj.attrs.items():
dst[name].attrs[k] = v

src.visititems(copy_item)
buffer2.seek(0)

# Gzip the modified HDF5
gz_buffer = BytesIO()
with gzip.GzipFile(fileobj=gz_buffer, mode="wb") as gz:
gz.write(buffer2.read())
gz_buffer.seek(0)

# Base64 encode and display with gzipped flag
sim_base64 = b64encode(gz_buffer.read()).decode("utf-8")
plot_sim_3d(sim_base64, width=width, height=height, is_gz_base64=True)


def plot_sim_3d(sim, width=800, height=800, is_gz_base64=False) -> None:
"""Make 3D display of simulation in ipython notebook."""

try:
from IPython.display import HTML, display
Expand All @@ -19,10 +74,14 @@ def plot_sim_3d(sim, width=800, height=800) -> None:
from base64 import b64encode
from io import BytesIO

buffer = BytesIO()
sim.to_hdf5_gz(buffer)
buffer.seek(0)
base64 = b64encode(buffer.read()).decode("utf-8")
if not is_gz_base64:
buffer = BytesIO()
sim.to_hdf5_gz(buffer)
buffer.seek(0)
base64 = b64encode(buffer.read()).decode("utf-8")
else:
base64 = sim

js_code = """
/**
* Simulation Viewer Injector
Expand Down