Skip to content

Commit

Permalink
Merge 724e1cf into 23514df
Browse files Browse the repository at this point in the history
  • Loading branch information
hainm committed Aug 8, 2019
2 parents 23514df + 724e1cf commit 0f04cab
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 125 deletions.
28 changes: 27 additions & 1 deletion js/src/widget_ngl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { FullscreenModel, FullscreenView } from "./fullscreen"
import { ColormakerRegistryModel, ColormakerRegistryView } from "./color"
import { ThemeManagerModel, ThemeManagerView} from "./theme"

NGL.nglview_debug = false

// From NGL
// http://www.broofa.com/Tools/Math.uuid.htm
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
Expand Down Expand Up @@ -152,7 +154,6 @@ class NGLView extends widgets.DOMWidgetView{
}, this);

if (this.model.comm) {
// for embeding in website
this.model.comm.on_msg(function(msg) {
var buffers = msg.buffers;
var content = msg.content.data.content;
Expand Down Expand Up @@ -999,6 +1000,28 @@ class NGLView extends widgets.DOMWidgetView{
}
}

handleMovieMaking(render_params) {
console.log('handleMovieMaking: render_params', render_params)
if (this.ngl_view_id == this.get_last_child_id()){
this.stage.makeImage(render_params).then(function(blob) {
var reader = new FileReader();
var arr_str;
reader.onload = function() {
arr_str = (reader.result as string).replace("data:image/png;base64,", "");
// this.model.set("_image_data", arr_str);
// this.touch();
this.send({
"data": arr_str,
"type": "movie_image_data",
}); // tell backend that image render is finished,
// backend will send next frame's coordinates.
this.send({'type': 'async_message', 'data': 'ok'});
}.bind(this);
reader.readAsDataURL(blob);
}.bind(this));
}
}


_handleLoadFileFinished() {
this.send({'type': 'async_message', 'data': 'ok'});
Expand Down Expand Up @@ -1171,6 +1194,9 @@ class NGLView extends widgets.DOMWidgetView{
this.updateCoordinates(coordinates, traj_index);
}
}
if (msg.movie_making){
this.handleMovieMaking(msg.render_params)
}
} else if (msg.type == 'get') {
if (msg.data == 'camera') {
this.send(JSON.stringify(this.stage.viewer.camera));
Expand Down
72 changes: 65 additions & 7 deletions nglview/contrib/movie.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from typing import List
try:
import moviepy.editor as mpy
except ImportError:
Expand All @@ -9,6 +10,7 @@
import threading
import time
from ipywidgets import Button, Output, IntProgress
from itertools import tee


class MovieMaker:
Expand Down Expand Up @@ -110,25 +112,28 @@ def __init__(self,
self.timeout = timeout
self.fps = fps
self.in_memory = in_memory
self.render_params = render_params if render_params is not None else {}
self.moviepy_params = moviepy_params if moviepy_params is not None else {}
self.render_params = render_params or dict(
factor=4,
antialias=True,
trim=False,
transparent=False)
self.moviepy_params = moviepy_params or {}
self.perframe_hook = perframe_hook
if self.render_params is not None:
assert isinstance(self.render_params, dict)
if self.moviepy_params is not None:
assert isinstance(self.moviepy_params, dict)
self.output = output
if stop < 0:
stop = self.view.max_frame + 1
self._time_range = range(start, stop, step)
self._iframe = iter(self._time_range)
self._progress = IntProgress(max=len(self._time_range)-1)
self._woutput = Output()
self._event = threading.Event()
self._thread = None
self._image_array = []

def sleep(self):
time.sleep(self.timeout)

def make(self, in_memory=False):
def make_old_impl(self, in_memory=False):
# TODO : make base class so we can reuse this with sandbox/base.py
progress = IntProgress(description='Rendering...', max=len(self._time_range)-1)
self._event = threading.Event()
Expand Down Expand Up @@ -190,6 +195,59 @@ def _make(event):
self.thread.daemon = True
self.thread.start()
return progress

def make(self, movie=True, keep_data=False):
"""
Parameters
----------
keep_data: bool
if True, save the image data in self._image_array
movie: bool
if True, make the movie
else, only do the rendering (make sure keep_data=True in this case)
"""
image_array = []
iframe = tee(self._iframe, 1)[0]
# trigger movie making communication between backend and frontend
self.view._set_coordinates(next(iframe), movie_making=True,
render_params=self.render_params)
self._progress.description = 'Rendering ...'
def on_msg(widget, msg, _):
if msg['type'] == 'movie_image_data':
image_array.append(msg.get('data'))
try:
frame = next(iframe)
self.view._set_coordinates(frame, movie_making=True,
render_params=self.render_params)
self._progress.value = frame
except StopIteration:
self._progress.description = 'Making...'
with self._woutput:
# suppress moviepy's log
self._make_from_array(image_array)
self._remove_on_msg()
self._progress.description = 'Done'
if keep_data:
self._image_array = image_array
self._on_msg = on_msg
# FIXME: if exception happens, the on_msg callback will be never removed
# from `self.view`
self.view.on_msg(on_msg)
return self._progress

def _remove_on_msg(self):
self.view.on_msg(self._on_msg, remove=True)

def _make_from_array(self, image_array: List[str]):
image_files = [self._base64_to_ndarray(a) for a in image_array]
clip = mpy.ImageSequenceClip(image_files, fps=self.fps)
with self._woutput:
if self.output.endswith('.gif'):
clip.write_gif(self.output,
fps=self.fps,
verbose=False,
**self.moviepy_params)

def interupt(self):
""" Stop making process """
Expand Down
28 changes: 26 additions & 2 deletions nglview/static/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion nglview/static/index.js.map

Large diffs are not rendered by default.

79 changes: 72 additions & 7 deletions nglview/tests/notebooks/api/test_gui_theme.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "6994e2dd3a904315a7f5f39620b8e066",
"model_id": "d3c1a1b071c7408696981bd6506b52e8",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -31,7 +31,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "d36d5d50901c437e87c77ab82dd76edd",
"model_id": "9842e1da10854f28a770ebe08b41cd06",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -58,7 +58,7 @@
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9221c5e9196444f39ba4cf9ce034faf0",
"model_id": "2e4c8d5f17fc4772b9cd3e42cbd4cd61",
"version_major": 2,
"version_minor": 0
},
Expand Down Expand Up @@ -97,13 +97,13 @@
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "0fb4af27aeff4b14bb83b1b455f1557e",
"model_id": "1234378b50ca4c81bb946ff7bde2d7a7",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -124,13 +124,13 @@
},
{
"cell_type": "code",
"execution_count": 8,
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "5338652366d1451faf333c73b04a8f0b",
"model_id": "3b7d54320abd4f259e8b26297c1364ba",
"version_major": 2,
"version_minor": 0
},
Expand All @@ -148,6 +148,71 @@
"v._gui_theme = 'light'\n",
"v"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"v.gui_style = None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Original GUI style (ipywidgets)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "455de3f1b70041c189a75116ee6afc36",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"NGLWidget(gui_style='ngl')"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"v2 = nv.demo()\n",
"v2.display(gui=True) # NGL style"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "00162feca1cc466099a66c426e85d021",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(NGLWidget(n_components=1), Tab(children=(Box(children=(Box(children=(Box(children=(Label(value=…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"v2.display(gui=True, style='ipywidgets')"
]
}
],
"metadata": {
Expand Down

0 comments on commit 0f04cab

Please sign in to comment.