How to archive real time communication between Python and JS ?
- 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
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