jupyter / jupyter/notebook

How to archive real time communication between Python and JS ?

Open
#3,533 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Jupyter Notebook
Stars
13.3k
Forks
5.8k
Avg merge
6d 11h
Merged PRs (30d)
7

Description

My goal is to run JS canvas-game within a notebook and get continues data stream between itself and Python. First i have tried to execute notebook kernel from JS, 60 times per second, with an animation frame request hook. But then it hit me, this process is working on a single kernel. Here is my initial attempt:
```js
%%javascript
window.onEnterFrame = e => IPython.notebook.kernel.execute(
`sharedVariable = "${ window.getGameVar() }" `
);
```
So that resulted in non changing sharedVariable value during the cell execution
```python
import time
result_1 = sharedVariable
time.sleep( 1 )
result_2 = sharedVariable
print( result_1 == result_2 ) # output is always True
```
After which i have decided to try and use the COMM, so I made a simple one that will replay with a string value after 500ms of delay.
```js
%%javascript
Jupyter.notebook.kernel.comm_manager.register_target('my_comm_id', (comm, msg)=> {
comm.on_msg(_=> { // on msg received
setTimeout( _=> { // wait 500ms
comm.send( window.getGameVar() ); // output data
}, 500 );
});
});
```
And a matching Python COMM:
```python
my_comm = Comm( target_name='my_comm_id' )
@my_comm.on_msg
def _recv(msg):
global sharedVariable
sharedVariable = msg['content']['data']
```
But that didn't help either, as apparently the messaged were getting received only after the cell had completed it's execution
```python
my_comm.send( "" )
time.sleep( 1 )
result_1 = sharedVariable
my_comm.send( "" )
time.sleep( 1 )
result_2 = sharedVariable
print( result_1 == result_2 ) # output is always True
```
Also i have tried creating a separate async function
```python
import asyncio

async def getData2(future):
global my_comm, sharedVariable
my_comm.send( "" )
await asyncio.sleep(1)
future.set_result( sharedVariable )

def getData():
asyncio.set_event_loop(asyncio.new_event_loop()) # set new global event loop
loop = asyncio.get_event_loop()
future = asyncio.Future()
asyncio.ensure_future( getData2(future) )
loop.run_until_complete(future)
result = future.result()
loop.close()
return result
```
But the problem didn't go away
```python
result_1 = getData()
result_2 = getData()
print( result_1 == result_2 ) # output is always True
```

I had a brief overview of `ipywidgets` and was able to get one way communication to work like so:
```python
from ipywidgets import FloatSlider
from IPython.display import display
slider = FloatSlider()
display(slider)
for i in range( 11 ):
slider.value = i * 10
time.sleep( 1 )
```
But the widgets won't work if you change the slider by dragging it
```python
for i in range( 10 ):
print( slider.value ) # Will always output slider initial value
time.sleep( 1 )
```

Contributor guide

Open the contributing guide

Research direction

The examples use Jupyter kernel.execute, Comm, asyncio, and ipywidgets; start by reproducing the timing behavior in a notebook with the shown JavaScript and Python cells. Define done as a documented or implemented way to exchange changing values while a cell is executing, including the slider case.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, jupyter-notebook, python
Domain
api, full-stack
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.