Skip to content
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

WGLMakie does not work within mybinder.org - no plot appears #2405

Open
schlichtanders opened this issue Nov 6, 2022 · 11 comments
Open

WGLMakie does not work within mybinder.org - no plot appears #2405

schlichtanders opened this issue Nov 6, 2022 · 11 comments

Comments

@schlichtanders
Copy link

schlichtanders commented Nov 6, 2022

Hi there,
I just tried using Makie.jl, especially WGLMakie.jl and while it works locally within VSCode, which is awesome, it fails on mybinder.org.

There is no error message, the plot just won't appear. On Chrome nothing appears, on Firefox I get a Not Found
image

This is a link to my example notebook which I wanted to work https://mybinder.org/v2/gh/galleon/scikit-decide/julia-jolin?filepath=notebooks-jupyter/01-introduction-maze.ipynb

It is defined within the notebooks-juypter directory of this branch https://github.com/galleon/scikit-decide/tree/julia-jolin

Any help about is highly appreciated

@SimonDanisch
Copy link
Member

You can use Page(offline=true, exportable=true), but that way plots are not connected to the Julia session.
To get that connection working you need to figure out how you can proxy the connection through binder.
No idea how binder allows that, but if you figure that out, you can set those with JSServe.configure_server!.
https://mybinder.org/v2/gh/SimonDanisch/binder/f170c3dabc05515e589a9580fb4d436282eece1d?urlpath=lab%2Ftree%2FUntitled.ipynb

@schlichtanders
Copy link
Author

schlichtanders commented Nov 7, 2022

That sounds more difficult than expected. I was thinking that some dependencies might be missing. I have no clue about the binder internals unfortunately.

I indeed want to update the plots via Observables, so I guess that the offline=true variant does not work for me here.

https://mybinder.org/v2/gh/SimonDanisch/binder/f170c3dabc05515e589a9580fb4d436282eece1d?urlpath=lab%2Ftree%2FUntitled.ipynb

image
this does not have a notebook it seems. @SimonDanisch What is the intended purpose of this mybinder link?

EDIT: @SimonDanisch is there more documentation on how to configure JSServe for WGLMakie?

@frankier
Copy link

frankier commented Nov 8, 2022

I thought it might already be possible with https://jupyter-server-proxy.readthedocs.io/

Looking here https://jupyter-server-proxy.readthedocs.io/en/latest/arbitrary-ports-hosts.html I made a hacky and failing first attempt was to do like so. I'm documenting it just in case it helps:

https://github.com/frankier/wglmakie_binder

$ julia --project=.
pkg> instanciate
$ pipx install --include-deps jupyter
$ pipx inject jupyter jupyter_server_proxy
$ ~/.local/bin/jupyter-notebook .

Executing the notebook I get the following in the Javascript debug console

load_extensions Arguments(1)
bidi.js:19 Loaded moment locale en
session.js:55 Session: kernel_created (babb360d-f797-40fc-a876-2b6a7aa01c1c)
kernel.js:464 Starting WebSockets: ws://localhost:8888/api/kernels/5859325e-f9b6-4c09-81f9-99531c14f55e
kernel.js:107 Kernel: kernel_connected (5859325e-f9b6-4c09-81f9-99531c14f55e)
utils.js:37 Loading extension: jupyter-js-widgets/extension
kernel.js:107 Kernel: kernel_ready (5859325e-f9b6-4c09-81f9-99531c14f55e)
manager-base.js:291 Failed to fetch ipywidgets through the "jupyter.widget.control" comm channel, fallback to fetching individual model state. Reason: Control comm did not respond in time
_loadFromKernel @ manager-base.js:291
VM270:307 Websocket not in readystate!
VM270:447 CONNECTED!!:  ws://localhost:8888/proxy/9284/a6fb8c5b-1c08-41a0-be83-f24d9aed95b3/ca79/
VM270:205 Error during running onjs callback
Callback:
function setup(scenes){
    const canvas = __eval_context__[0]

    const scene_id = 11762501587609217900
    const renderer = WGLMakie.threejs_module(canvas, '13204021911775567447', 800, 600)
    if ( renderer ) {
        const three_scenes = scenes.map(x=> WGLMakie.deserialize_scene(x, canvas))
        const cam = new THREE.PerspectiveCamera(45, 1, 0, 100)
        WGLMakie.start_renderloop(renderer, three_scenes, cam, 30.0)
        JSServe.on_update('17617689498015946460', w_h => {
            // `renderer.setSize` correctly updates `canvas` dimensions
            const pixelRatio = renderer.getPixelRatio();
            renderer.setSize(w_h[0] / pixelRatio, w_h[1] / pixelRatio);
        })
    } else {
        const warning = WEBGL.getWebGLErrorMessage();
        __eval_context__[1].removeChild(canvas)
        __eval_context__[2].appendChild(warning)
    }
}
send_error @ VM270:205
VM270:206 ReferenceError: THREE is not defined
    at Object.threejs_module (<anonymous>:662:26)
    at Array.setup (eval at deserialize_js (demo.ipynb:162:39), <anonymous>:7:31)
    at run_js_callbacks (<anonymous>:248:48)
    at process_message (<anonymous>:349:21)
    at Array.forEach (<anonymous>)
    at process_message (<anonymous>:369:30)
    at process_message (<anonymous>:340:21)
    at websocket.onmessage (<anonymous>:451:21)
send_error @ VM270:206

At least part of the problem is that THREE is not successfully injected into the page.

This solution is likely to be janky since there can only be a single listener on a single socket, and this listener is controlled by code running in a single notebook, however the notebook server can serve multiple notebooks. I guess a better solution would be to hook into Jupyter notebook directly without trying to open a socket. Perhaps either WGLMakie or JSServe could have an option inject Javascript via WebIO.jl or similar when available?

@SimonDanisch
Copy link
Member

I guess that means, that the websocket connection works, but not the file serving.
Try Page(exportable=true), that should inline all JS dependencies.

@frankier
Copy link

frankier commented Nov 9, 2022

In that case I get a different problem which is things never finish loading. Since everything is getting injected directly into the Jupyter notebook it looks like a lot of things go wrong. Eventually I get this for the last cell:

┌ Warning: Waiting for page sessions to load.
│                 This can happen for the first cells to run, or is indicative of faulty state
└ @ JSServe /home/frankier/.julia/packages/JSServe/kIK9q/src/display.jl:162

The problem seems to stem from an error in some code which is executed and cannot see JSServe. Here is the code:

    const proxy_url = 'http://localhost:8888/proxy/9291'
    const session_id = '18a33751-0b77-47d4-973c-d578d55c7178'
    // track if our child session doms get removed from the document (dom)
    JSServe.track_deleted_sessions('12140126602376898139')
    JSServe.setup_connection({proxy_url, session_id})
    JSServe.sent_done_loading()

The definition of JSServe is however loaded and available on window.JSServe from the js console. So this is either an execution order problem or a different global context is being used for this snippet.

I have managed to get things working in iframe mode rather than Page() mode however. Details forthcoming.

@frankier
Copy link

frankier commented Nov 9, 2022

Okay take a look at these:

https://mybinder.org/v2/gh/frankier/wglmakie_binder/HEAD?labpath=demo.ipynb

https://mybinder.org/v2/gh/frankier/wglmakie_binder/HEAD?labpath=app_demo.ipynb

What works:

  • YES: jupyter-server-proxy + local jupyter notebook + bare widget
  • YES: jupyter-server-proxy + local jupyter notebook + widget in app
  • Unsure: jupyter-server-proxy + mybinder.org + bare widget
  • YES: jupyter-server-proxy + mybinder.org + widget in app

What needs to be done to stabilise this approach?

  • Better way of getting the proxy URL
    • Is it possible without Javascript?
    • Can we get Jupyter/mybinder.org to give the base address without having to infer it?
    • Can we message back from Javascript land so we can set the whole thing up automatically?
  • Port hopping
    • When initializing the server it can bind to any port and then report back what works

Another possibility which might make this more robust than using ports is if JSServe could use a unix domain socket e.g. in a temp directory, and we can extend jupyter-server-proxy to allow us to address these the same way as ports. See this issue in jupyter-server-proxy jupyterhub/jupyter-server-proxy#321

@frankier
Copy link

frankier commented Nov 9, 2022

I guess the Page(...) support was attempted here SimonDanisch/Bonito.jl#111 . Is there anything from that PR that can be reused?

@frankier
Copy link

This JSServe.jl PR SimonDanisch/Bonito.jl#118 should move things forward a bit, and then we can see if it's possible to improve upon the jupyter-server-proxy approach

@SimonDanisch
Copy link
Member

This should be possible now, but @frankier possibly knows better what exactly is needed to make it work.

@frankier
Copy link

frankier commented May 9, 2023

I've been trying to test the new version, but tbh mybinder.org is so flaky for me that it's pretty much impossible to test

@SimonDanisch
Copy link
Member

Ah yeah, true... I've been trying to start a julia session for a few weeks and gave up as well....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

3 participants