BruceSherwood / vpython-jupyter

This repository has been moved to https://github.com/vpython/vpython-jupyter
64 stars 33 forks source link

Inconsistent two-canvas alignment #23

Closed wigie closed 8 years ago

wigie commented 8 years ago

I'm trying to make use of the "align" parameter for side-by-side canvases in Jupyter VPython, based on your post to the VPython-users group back in May. The following program snippet works correctly in Glowscript, but not in a Jupyter notebook:

scene.width = 400
scene.align = 'left'
scene2 = canvas(width=400, align='right')

# Box on the left, sphere on the right; not side-by-side in Jupyter
scene.select()
box()
scene2.select()
sphere()

However, reversing the order of the scene selections will produce the correct behavior in both Jupyter and Glowscript:

scene.width = 400
scene.align = 'left'
scene2 = canvas(width=400, align='right')

# Box on the left, sphere on the right; Jupyter happy
scene2.select()
sphere()
scene.select()
box()

When inspecting the generated HTML in Jupyter, I notice that the first code snippet doesn't seem to be properly styled. The relevant bit seems to be the div for the default canvas: <div style="position: relative; float: none;" class="glowscript-canvas-wrapper ui-resizable ui-resizable-disabled"> In Glowscript and in the correctly-functioning version of the Jupyter code, that "float: none" style is "float: left" instead. So somehow the alignment info makes its way into the canvas setup in Glowscript, but not in Jupyter unless scene2 is selected and drawn first.

Version info:

The version of the notebook server is 4.2.3 and is running on: Python 2.7.12+ (default, Sep 1 2016, 20:27:38) [GCC 6.2.0 20160822]

wigie commented 8 years ago

Additional test: trying to align the default scene on the right, and scene2 on the left, doesn't work properly in Jupyter no matter which scene is selected/drawn first. The div element for scene2 seems to get a correct "float" property no matter what, but once again the default canvas shows up as "float: none".

Glowscript passes with flying colors, as before.

BruceSherwood commented 8 years ago

Thanks much for the report. The good news is that in the development version of Jupyter VPython all of the three cases work properly, so when we're able to release this the problem will be solved. We very recently discovered that the currently released version, and all those before it, had a flaw that could cause data to be lost or sent out of order between Python and the browser, which is the likely cause of the problem (and many other problems). Here is a note about this that I posted to the Jupyter forum:

In Jupyter VPython (see vpython.org) data is sent from a Python program to a JavaScript program and is processed by the GlowScript WebGL library to display 3D animations in the notebook. There are restrictions on sending data from a Python thread, and I even found a disastrous case where early data sent from within a Python thread arrived in the browser after later data sent from outside that thread, yet there seemed no way to avoid the necessity of a thread that would interrupt and send data about 30 times per second.

A robust solution turned out to be the following: The JavaScript program sends an event to Python, which calls a Python program that sends data (if any) to the JavaScript program and in all cases sends a message requesting that the JavaScript program set a timer to send Python another event 1/30th of a second from now. In that way there is no thread in the Python program, so data transmissions are not sent from within a Python thread.

One might think that the JavaScript program could set an interval timer to send the wakeup message regularly to Python. However, when I tried that scheme it turned out to be very difficult to rerun or kill a program, because the JavaScript program keeps running. Doing the full roundtrip handshake assures that the JavaScript program will not keep running if the Python program is killed.