Closed proppy closed 1 year ago
+1 - I'm having this issue as well. Will look to see if I can fix it myself and if so I'll post the results back here (and maybe submit a PR)
tl;dr - I wasn't able to get a quick fix. Full steps to repro as well as the error message are below.
I also included a list of installed conda packages. It looks like gdstk is getting installed (version 0.7.0) but for some reason python isn't recognizing it.
Based on a suggestion by @proppy I tried updating these lines in the first code block to 3.8. I got a dependency error after doing that.
site_package_path = conda_prefix_path / 'lib/python3.8/site-packages' !echo 'python ==3.8*' >> {CONDA_PREFIX}/conda-meta/pinned
Minimum steps to reproduce the initial bug:
ModuleNotFoundError Traceback (most recent call last)
ModuleNotFoundError: No module named 'gdstk'
NOTE: If your import is failing due to a missing package, you can manually install dependencies using either !pip or !apt.
Here is the output of '!CI=0 bin/micromamba list' when run from the notebook.
List of packages in environment: "/content/conda-env"
Name Version Build Channel
────────────────────────────────────────────────────────────────────────────────
_libgcc_mutex 0.1 main main
_openmp_mutex 5.1 1_gnu main
bzip2 1.0.8 h7b6447c_0 main
ca-certificates 2022.10.11 h06a4308_0 main
cairo 1.16.0 h19f5f5c_2 main
certifi 2022.9.24 py37h06a4308_0 main
click 8.0.4 py37h06a4308_0 main
flit-core 3.6.0 pyhd3eb1b0_0 main
fontconfig 2.14.1 hef1e5e3_0 main
freetype 2.12.1 h4a9f257_0 main
gdstk 0.7.0 py37h60116be_0 conda-forge
glib 2.69.1 h4ff587b_1 main
icu 58.2 he6710b0_3 main
importlib-metadata 4.11.3 py37h06a4308_0 main
ld_impl_linux-64 2.38 h1181459_1 main
libblas 3.9.0 15_linux64_openblas conda-forge
libboost 1.73.0 h28710b8_12 main
libcblas 3.9.0 15_linux64_openblas conda-forge
libffi 3.3 he6710b0_2 main
libgcc-ng 11.2.0 h1234567_1 main
libgfortran-ng 12.2.0 h69a702a_19 conda-forge
libgfortran5 12.2.0 h337968e_19 conda-forge
libgomp 11.2.0 h1234567_1 main
liblapack 3.9.0 15_linux64_openblas conda-forge
libopenblas 0.3.20 pthreads_h78a6416_0 conda-forge
libpng 1.6.37 hbc83047_0 main
libstdcxx-ng 11.2.0 h1234567_1 main
libxcb 1.15 h7f8727e_0 main
libxml2 2.9.14 h74e7548_0 main
lz4-c 1.9.3 h295c915_1 main
magic 8.3.349_0_g02bbb10 20221206_125647 litex-hub
ncurses 6.3 h5eee18b_3 main
netgen 1.5.242_0_g4edaf08 20221206_125647 litex-hub
numpy 1.21.6 py37h976b520_0 conda-forge
open_pdks.sky130a 1.0.369_2_gffb8b61 20221206_125647 litex-hub
openlane 2022.11.12_3_g1298859 20221104_084554 litex-hub
openroad 2.0_5614_g71fa4b775 20221104_084554 litex-hub
openssl 1.1.1s h7f8727e_0 main
pcre 8.45 h295c915_0 main
pip 22.2.2 py37h06a4308_0 main
pixman 0.40.0 h7f8727e_1 main
python 3.7.15 haa1d7c7_0 main
python_abi 3.7 2_cp37m conda-forge
pyyaml 6.0 py37h7f8727e_1 main
readline 8.2 h5eee18b_0 main
setuptools 65.5.0 py37h06a4308_0 main
sqlite 3.40.0 h5082296_0 main
tcllib 1.20 0 litex-hub
tk 8.6.12 h1ccaba5_0 main
typing_extensions 4.4.0 py37h06a4308_0 main
wheel 0.37.1 pyhd3eb1b0_0 main
xz 5.2.8 h5eee18b_0 main
yaml 0.2.5 h7b6447c_0 main
yosys 0.23_6_g853f4bb3c 20221104_084554_py37 litex-hub
zipp 3.8.0 py37h06a4308_0 main
zlib 1.2.13 h5eee18b_0 main
zstd 1.5.2 ha4553b6_0 main
Installing from pypi https://pypi.org/project/gdstk/ triggers the following issue:
RuntimeError: module compiled against API version 0x10 but this version of numpy is 0xe
Rebuilding the wheel against the version of numpy pre-installed in colab like this:
!python -m pip install --no-binary gdstk gdstk
Seems to workaround the issue:
Alternatively we could rely on the klayout 0.28 wheel to display the gds (see https://github.com/KLayout/klayout/issues/1082#issuecomment-1345709883), that would have the advantage to scale to bigger design (gdstk
generated svg will start crashing chrome once it crosses a few hundreds megabyte).
would be great to make it interactive as well, as was done here: https://github.com/klayoutmatthias/canvas2canvas
since jupyter notebooks inherently already have a python server running, i don't think it should be too hard to adapt to run within a notebook
@tvt173 I think there might be ways to leverage https://holoviews.org/ to call the appropriate method to refresh the klayout LayoutView
on holoview navigation event (zoom, pan, click) without the need of running a server?
interesting idea... at that point, you might as well just be using bokeh directly though, right? https://docs.bokeh.org/en/latest/docs/gallery/image.html
to my understanding, holoviews is just a layer on top of bokeh used for efficient rendering of large datasets. but in this case, we would be using klayout to render the data into images anyways (usually the job of holoviews).
have you seen my schematic capture notebook demo in gdsfactory yet? https://github.com/gdsfactory/gdsfactory/blob/main/docs/notebooks/20_schematic_driven_layout.ipynb
it's still a bit rough around the edges, but in principle, you could do what i'm doing there to create a layout viewer in bokeh as well, if you're interested in going in that direction. if you make the datasources based on cells, you can leverage the same advantages with hierarchy... only have one datasource per cell, rather than a flat one for the entire layout. not sure what the rendering time would be like, but in that case, it could be completely browser based without need for python callbacks
this may actually be an interesting avenue to explore also...
though I think the above will start to get dicey when you have multiple levels of hierarchy, if you try to maintain the polygons as polygon data. it may work well to have each cell under the top level as its own image though (and display each instance as an image, with its own hit-testing capabilities etc.)
@tvt173 There seems to be some colab support for being in the work for holoview: https://github.com/bokeh/bokeh/issues/9302 did you already give it a try?
hi @proppy , sorry what's the issue? you can't get the notebook to work in colab?
@tvt173 yep, I have trouble running most of the push_notebook
based bokeh demos in colab, so I'd suspect that the schematic capture notebook wouldn't work either.
this doesn't actually use push_notebook
since it is a live server application and not a static bokeh visualization. give it a try maybe?
@tvt173 got an error because of the version of numpy linked against gdsfactory is different from the colab environment:
RuntimeError: module compiled against API version 0x10 but this version of numpy is 0xe
My understanding is that service running within the colab environment aren't directly accessible from the JS context (and that colab comms mecanism have to used, hence: https://github.com/bokeh/bokeh/issues/9302).
I managed to get something interactive working with ipywidgets
see:
https://colab.research.google.com/gist/proppy/b71d4678bd47bf6f6e94d86bf32d83f2/klayout-widgets-playground.ipynb
which lead me to believe something similar using bokeh is possible.
by the way @proppy , you had initially recommended holoviews... are you able to get that to run in colab? if so, are you using the bokeh backend? if so, that's a bit peculiar, right?
We tried !python -m pip install --force-reinstall --no-binary gdstk gdstk
but it doesn't seem to be working?
@mithro can you save your "not working" notebook as a gist (File > Save a copy as a GitHub Gist
) and link it here?
are you able to get that to run in colab?
It does run in colab but as you said, since it depends on bokeh for its backend, we would likely run into the same issue with regard to colab comms.
yeah, I was able to take the widget concept a bit further, and have it listen to mouse and wheel events, but it's still not working very well. it listens to mouse and wheel events, and I can respond with layout_view.zoom_in()
and layout_view.zoom_out()
just fine, but when I try layout_view.send_wheel_event(delta, False, db.Point(x, y), buttons)
as matthias did in his demo, I am not able to get the desired reaction. not yet sure what i am doing wrong. also it seems that drag actions get intercepted by other events inherent to Image
, so we may need to make a canvas from scratch, pop the existing callbacks off, or something like that. i'll push what I have for now to a branch on gdsfactory later
it also just struck me that matplotlib may be another viable option: https://matplotlib.org/stable/users/explain/event_handling.html
Maybe with https://matplotlib.org/ipympl/ (since the event handling wouldn't work with the inline
backend).
It also look there is some support for the notebook
backend with https://github.com/googlecolab/colabtools/issues/706#issuecomment-921266837
for reference, this is what I had so far
from ipywidgets import Label, HTML, HBox, Image, VBox, Box, HBox
from ipyevents import Event
from typing import Optional
import klayout.db as db
import klayout.lay as lay
from loguru import logger
class LayoutViewer:
def __init__(self, filepath: str, layer_properties: Optional[str]):
self.filepath = filepath
self.layer_properties = layer_properties
self.layout_view = lay.LayoutView()
self.load_layout(filepath, layer_properties)
pixel_buffer = self.layout_view.get_pixels_with_options(800, 600)
png_data = pixel_buffer.to_png_data()
self.image = Image(value=png_data, format='png')
scroll_event = Event(source=self.image, watched_events=['wheel'])
scroll_event.on_dom_event(self.on_scroll)
self.wheel_info = HTML("Waiting for a scroll...")
self.mouse_info = HTML("Waiting for a mouse event...")
# self.layout_view.on_image_updated_event = lambda: self.refresh
mouse_event = Event(source=self.image, watched_events=['mousedown', 'mouseup', 'mousemove'])
mouse_event.on_dom_event(self.on_mouse_down)
def load_layout(self, filepath: str, layer_properties: Optional[str]):
self.layout_view.load_layout(filepath)
self.layout_view.max_hier()
if layer_properties:
self.layout_view.load_layer_props(layer_properties)
def refresh(self):
pixel_buffer = self.layout_view.get_pixels_with_options(800, 600)
png_data = pixel_buffer.to_png_data()
self.image.value = png_data
def _get_modifier_buttons(self, event):
shift = event['shiftKey']
alt = event['altKey']
ctrl = event['ctrlKey']
meta = event['metaKey']
mouse_buttons = event['buttons']
buttons = 0
if shift:
buttons |= lay.ButtonState.ShiftKey
if alt:
buttons |= lay.ButtonState.AltKey
if ctrl:
buttons |= lay.ButtonState.ControlKey
if mouse_buttons == 1:
buttons |= lay.ButtonState.LeftButton
if mouse_buttons == 2:
buttons |= lay.ButtonState.RightButton
if mouse_buttons == 4:
buttons |= lay.ButtonState.MidButton
return buttons
def on_scroll(self, event):
delta = event['deltaY']
x = event['offsetX']
y = event['offsetY']
self.wheel_info.value = f'scroll event: {event}'
buttons = self._get_modifier_buttons(event)
# TODO: this is what I *want* to respond with, but it doesn't work, so I am using zoom_in/zoom_out instead
# self.layout_view.send_wheel_event(delta, False, db.Point(x, y), buttons)
if delta < 0:
self.layout_view.zoom_in()
else:
self.layout_view.zoom_out()
self.refresh()
def on_mouse_down(self, event):
x = event['offsetX']
y = event['offsetY']
moved_x = event['movementX']
moved_y = event['movementY']
buttons = self._get_modifier_buttons(event)
# TODO: this part is also not working. why?
if event == 'mousedown':
self.layout_view.send_mouse_press_event(db.Point(x, y), buttons)
elif event == 'mouseup':
self.layout_view.send_mouse_release_event(db.Point(x, y), buttons)
elif event == 'mousemove':
self.layout_view.send_mouse_move_event(db.Point(moved_x, moved_y), buttons)
self.refresh()
self.mouse_info.value = f'mouse event: {event}'
in the notebook you can instantiate like
layout_viewer = LayoutViewer(gds_filepath, lyp_filepath)
layout_viewer.image
additionally you can return layout_viewer.mouse_info
or layout_viewer.wheel_info
to see that indeed the events are properly registering, but you will see the issues i describe both on the klayout side and with Image
reacting in unpleasant ways to drag events
@mithro can you try #44?
all notebooks currently fails with the following error:
This is likely due to a recently update from colab to python 3.8. https://medium.com/google-colab/colab-updated-to-python-3-8-4922f9970a72