wip - move code from webgui_jupyter_widgets project to Netgen

This commit is contained in:
Matthias Hochsteger 2024-12-06 16:03:34 +01:00
parent b808d84957
commit 75372b0695
3 changed files with 138 additions and 43 deletions

View File

@ -20,7 +20,7 @@ install(FILES
__main__.py __init__.py __main__.py __init__.py
meshing.py csg.py geom2d.py stl.py gui.py NgOCC.py occ.py meshing.py csg.py geom2d.py stl.py gui.py NgOCC.py occ.py
read_gmsh.py read_meshio.py read_gmsh.py read_meshio.py
webgui.py webgui.py jupyter.py
DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX}
COMPONENT netgen COMPONENT netgen
) )

103
python/jupyter.py Normal file
View File

@ -0,0 +1,103 @@
import json
import os
import requests
from IPython.display import HTML, DisplayHandle, Javascript, display
_id = 0 # counter for unique id for each generated div element
# VSCode has a strange meaning of "vh" in jupyter notebooks, use pixels instead
_default_height = "500px" if "VSCODE_PID" in os.environ else "50vh"
_webgui_loaded = False
def load_webgui(url: str = "", embed_code: bool = False):
global _webgui_loaded
if _webgui_loaded:
return
_webgui_loaded = True
url = url or "https://cdn.jsdelivr.net/npm/webgui@0.2.38/dist/webgui.js"
if embed_code:
if url.startswith("http"):
webgui_code = requests.get(url).text
else:
with open(url, "r") as f:
webgui_code = f.read()
display(HTML(f"<script>{webgui_code}</script>"))
else:
display(HTML(f"<script src={url}> </script>"))
def render(
data, width="100%", height=_default_height, handle: DisplayHandle | None = None
):
load_webgui()
if handle is None:
global _id
_id += 1
id = _id
else:
id = handle.display_id.split("_")[-1]
el_id = f"_webgui_root_{id}"
js_code = _render_js_template.replace("{{data}}", json.dumps(data))
js_code = js_code.replace("{{id}}", str(id))
js_code = js_code.replace("{{el_id}}", el_id)
if handle:
# this is a redraw call
handle.update(Javascript(js_code))
else:
# this is a first draw call -> create the root div element for the webgui
display(
HTML(
f'<div class="webgui-widget" id={el_id} style="position: relative; width: {width}; height:{height};" />'
)
)
return display(Javascript(js_code), display_id=f"webgui_render_{id}")
_render_js_template = """
{
if(window._webgui_scenes === undefined) {
window._webgui_scenes = {};
}
const waitForWebgui = (callback, counter) => {
counter = counter || 0;
if (window.webgui) {
callback();
} else {
if (counter < 20) {
setTimeout(() => {
waitForWebgui(callback, counter + 1);
}, 200);
}
else {
console.log("Error: Webgui not loaded");
}
}
};
const draw = () => {
const data = JSON.parse(`{{data}}`);
let scene = window._webgui_scenes[{{id}}];
// console.log("have data, scene = ", scene);
if(scene === undefined) {
console.log("init scene");
const root = document.getElementById("{{el_id}}");
console.log("root element", root);
scene = new webgui.Scene();
scene.init(root, data);
window._webgui_scenes[{{id}}] = scene;
}
else {
scene.updateRenderData(data);
}
// console.log("scene", scene);
}
waitForWebgui(draw);
}
"""

View File

@ -1,17 +1,17 @@
import math import math
import numpy as np import numpy as np
from time import time
import os import os
try: try:
import webgui_jupyter_widgets __IPYTHON__
from webgui_jupyter_widgets import BaseWebGuiScene, WebGuiDocuWidget _IN_IPYTHON = True
import webgui_jupyter_widgets.widget as wg
except ImportError:
class BaseWebGuiScene:
pass
wg = None from .jupyter import render as _render
except NameError:
_IN_IPYTHON = False
def _render(*args, **kwargs):
pass
def encodeData( data, dtype=None, encoding='b64' ): def encodeData( data, dtype=None, encoding='b64' ):
import numpy as np import numpy as np
@ -25,18 +25,8 @@ def encodeData( data, dtype=None, encoding='b64' ):
else: else:
raise RuntimeError("unknown encoding" + str(encoding)) raise RuntimeError("unknown encoding" + str(encoding))
from packaging.version import parse
import netgen.meshing as ng import netgen.meshing as ng
if wg is not None and parse(webgui_jupyter_widgets.__version__) >= parse("0.2.18"):
_default_width = None
_default_height = None
else:
_default_width = "100%"
_default_height = "50vh"
_registered_draw_types = {} _registered_draw_types = {}
@ -217,7 +207,7 @@ def GetData(mesh, args, kwargs):
d[name] = pnew d[name] = pnew
return d return d
class WebGLScene(BaseWebGuiScene): class WebGLScene:
class Widget: class Widget:
def __init__(self): def __init__(self):
self.value = {} self.value = {}
@ -228,6 +218,7 @@ class WebGLScene(BaseWebGuiScene):
self.args = args self.args = args
self.kwargs = kwargs self.kwargs = kwargs
self.encoding = "b64" self.encoding = "b64"
self.handle = None
def Redraw(self, *args, **kwargs): def Redraw(self, *args, **kwargs):
if args or kwargs: if args or kwargs:
@ -238,7 +229,8 @@ class WebGLScene(BaseWebGuiScene):
self.obj = new_scene.obj self.obj = new_scene.obj
self.args = new_scene.args self.args = new_scene.args
self.kwargs = new_scene.kwargs self.kwargs = new_scene.kwargs
super().Redraw() _render(self.GetData(), handle=self.handle)
# super().Redraw()
def GetData(self, set_minmax=True): def GetData(self, set_minmax=True):
self.kwargs["encoding"] = self.encoding self.kwargs["encoding"] = self.encoding
@ -389,8 +381,6 @@ def _get_draw_default_args():
settings={}, settings={},
fullscreen=False, fullscreen=False,
scale=1.0, scale=1.0,
width=_default_width,
height=_default_height,
) )
@ -399,27 +389,29 @@ def Draw(obj, *args, show=True, **kwargs):
kwargs_with_defaults.update(kwargs) kwargs_with_defaults.update(kwargs)
scene = WebGLScene(obj, args, kwargs_with_defaults) scene = WebGLScene(obj, args, kwargs_with_defaults)
if show and wg is not None and wg._IN_IPYTHON: scene.handle = _render(scene.GetData())
if wg._IN_GOOGLE_COLAB:
from IPython.display import display, HTML
html = scene.GenerateHTML()
display(HTML(html))
return
else:
import webgui_jupyter_widgets as wjw
from packaging.version import parse
# render scene using widgets.DOMWidget
if parse(wjw.__version__) < parse("0.2.15"):
scene.Draw()
else:
scene.Draw(
kwargs_with_defaults["width"], kwargs_with_defaults["height"]
)
if "filename" in kwargs_with_defaults:
scene.GenerateHTML(filename=kwargs_with_defaults["filename"])
return scene return scene
# if show and wg is not None and wg._IN_IPYTHON:
# if wg._IN_GOOGLE_COLAB:
# from IPython.display import display, HTML
#
# html = scene.GenerateHTML()
# display(HTML(html))
# return
# else:
# import webgui_jupyter_widgets as wjw
# from packaging.version import parse
#
# # render scene using widgets.DOMWidget
# if parse(wjw.__version__) < parse("0.2.15"):
# scene.Draw()
# else:
# scene.Draw(
# kwargs_with_defaults["width"], kwargs_with_defaults["height"]
# )
# if "filename" in kwargs_with_defaults:
# scene.GenerateHTML(filename=kwargs_with_defaults["filename"])
# return scene
async def _MakeScreenshot(data, png_file, width=1200, height=600): async def _MakeScreenshot(data, png_file, width=1200, height=600):
"""Uses playwright to make a screenshot of the given html file.""" """Uses playwright to make a screenshot of the given html file."""