Looking for simple example of __pyviz_comms__ but at the fairly low level

Hi All,

I’m the creator of trame and I would like to improve its support within the Jupyter world. Trame by nature tend to be great for creating standalone web application of any kind. And having such application work locally, remotely, on HPC, in the cloud or within Jupyter is quite powerful.

So my goal here is to provide another backend that would rely on pyviz_comms but I would love if someone could point me to some simple usage of it via Panel (or else) code base.

In the meantime, I’m going through the code, trying to extract how things get setup on the Python and JS side…

Thanks for any pointer you could provide…

Seb


Bonus: trame intro for Jupyter users

Otherwise if you want to have fun and see what it looks like within Jupyter, you can run the following in a cell assuming you did pip install trame.

The example below rely on vtk.js for the rendering and the widgets are provided by Vuetify.

from trame.app import get_server, jupyter
from trame.ui.vuetify import SinglePageLayout
from trame.widgets import vuetify, vtk as vtk_widgets

server = get_server()
state, ctrl = server.state, server.controller

with SinglePageLayout(server) as layout:
    with layout.content:
        with vuetify.VContainer(fluid=True, classes="pa-0 fill-height"):
            with vtk_widgets.VtkView() as view:
                ctrl.view_reset_camera = view.reset_camera
                with vtk_widgets.VtkGeometryRepresentation():
                    vtk_widgets.VtkAlgorithm(
                        vtk_class="vtkConeSource",
                        state=("{ resolution }",),
                    )

    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VSlider(
            v_model=("resolution", 6),
            min=3,
            max=60,
            step=1,
            hide_details=True,
            style="max-width: 300px;",
        )
        with vuetify.VBtn(icon=True, click=ctrl.view_reset_camera):
            vuetify.VIcon("mdi-crop-free")

jupyter.show(server)

And if you want to create another UI for that same server/app, you add the following in the cell below

from trame.ui.vuetify import VAppLayout
with VAppLayout(server, template_name="control"):
    vuetify.VSlider(
        v_model=("resolution", 6),
        min=3,
        max=60,
        step=1,
        hide_details=True,
        classes="my-3",
    )

jupyter.show(server, ui="control", height=60)

And if you want to react to a change with resolution by calling a function. You can do the following.

@state.change("resolution")
def on_change(resolution, **kwargs):
    print(f"cone resolution is {resolution}")

And you can also set a value yourself by doing the following

with state:
   state.resolution = 10

Enjoy!

2 Likes

@philippjfr . Any input?

1 Like

Sorry for the delay here, trying to see if I can build a quick example in a notebook to share.

3 Likes

No worries, thanks for getting back to me. Thanks for helping out!

1 Like

Hi @philippjfr , any luck to get something basic?

Thanks,

Seb

Sorry this is taking so long. I did have a go and went down a bit of rabbit hole and not super happy with what I found. The implementation is not very modular so you have to set up the components just right. If I am to recommend using pyviz_comms to anyone else I’d probably want to update a few things first.

Hope to have a basic example with bi-directional comms to share with you tomorrow.

1 Like

That would be awesome, thank you!

I finished up some exploration on the server and client side but I was about to get ready for the Jupyter Lab extension to get the comm going. So tomorrow that will be the perfect timing.

Thanks again and can’t wait to see your example.

Here’s the example:

https://anaconda.org/philippjfr/pyviz_comms_example/notebook?version=2023.06.14.1044

As you can see there’s quite a bit of setup required. If we really want to make this something you can use I’d probably suggest doing at least a few things:

  1. Update the names of the EXEC_MIME to be something more generic
  2. See if we can avoid having to load the comm_manager with the display({'application/javascript': self.manager.js_manager}, raw=True) call by shipping an extension for classic notebooks
1 Like

Thanks @philippjfr !

I tried it in Jupyter Lab but it does not seems to work.

I changed

# comm = BidirectionalComm(msg_handler=test.append)
comm = BidirectionalComm(msg_handler=received.append)

But it seems that no window.PyViz.comm_manager is defined while we do have a window.PyViz object.

I’m going to play more with it… It seems that I managed to get it to properly initialized by doing the following

from IPython.display import display, Javascript, HTML

BidirectionalComm.manager.js_manager

Javascript(BidirectionalComm.manager.js_manager)

I’ll see if I can get a better feel on how to clean it up a little and get it to work for my use case.

But thank you so much for that example! This is perfect…

2 Likes

@philippjfr What is the variable test in your notebook?
As it stands, it is undefined.

Indeed, as @jourdain correctly identified the variable should be called received.

1 Like

Sorry for getting back to that topic so many months later…

But I managed to build a jupyter extension thanks to your pointers.
I did not use the panel infrastructure, but while my extension is working, it is breaking ipywidgets as it steal the (first and only) KernelConnection on which a jupyter-comm can be created.

So I see 3 paths forward with my order of preference:

  1. Fix my extension so it does not steal the connection from ipywidgets.
  2. Use panel infrastructure to create my own jupyter-comm, so I don’t mess up with ipywidgets.
  3. Use panel communication infrastructure instead of my jupyter-comm calls. But can I send binary content or do I need to base64 it?

For 1, the core of my extension is here. Any pointer on how to better implement the logic where I can monitor any kernel available and automatically set a bunch of os.environ on it from the JS. And then create a comm on it? Or maybe I execute something in the kernel that execute some JS code that push some Python exec on the kernel. (os.environ)

For 2, do you have any pointers on how I could do the following from the Panel using its JS API?
a. To run Python code on a given kernel from some JS code execution.
b. To create a jupyter-comm to a given kernel (from id).

For 3, I think I could figure it out, but that will be the last option. :wink:

Thanks again for any help you would like to provide,

Seb