1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
"""
vispy backend for the IPython notebook (static approach).
We aim to have:
* ipynb_static - export visualization to a static notebook
* ipynb_vnc - vnc-approach: render in Python, send result to JS as png
* ipynb_webgl - send gl commands to JS and execute in webgl context
"""
from __future__ import division
from ..base import BaseApplicationBackend, BaseCanvasBackend
from .. import Application, Canvas
from ...util import logger
# Imports for screenshot
from ...gloo.util import _screenshot
from ...io import _make_png
from base64 import b64encode
# -------------------------------------------------------------------- init ---
capability = dict( # things that can be set by the backend
title=True, # But it only applies to the dummy window :P
size=True, # We cannot possibly say we dont, because Canvas always sets it
position=True, # Dito
show=True, # Note: we don't alow this, but all scripts call show ...
vsync=False,
resizable=True, # Yes, you can set to not be resizable (it always is)
decorate=False,
fullscreen=False,
context=True,
multi_window=True,
scroll=True,
parent=False,
always_on_top=False,
)
def _set_config(c):
_app.backend_module._set_config(c)
# Create our "backend" backend; The toolkit that is going to provide a
# canvas (e.g. OpenGL context) so we can render images.
# Note that if IPython has already loaded a GUI backend, vispy is
# probably going to use that as well, because it prefers loaded backends.
try:
# Explicitly use default (avoid using test-app)
_app = Application('default')
except Exception:
_msg = 'ipynb_static backend relies on a core backend'
available, testable, why_not, which = False, False, _msg, None
else:
# Try importing IPython
try:
from IPython.display import display_png
except Exception as exp:
available, testable, why_not, which = False, False, str(exp), None
else:
available, testable, why_not = True, False, None
which = _app.backend_module.which
# Use that backend's shared context
KEYMAP = _app.backend_module.KEYMAP
# ------------------------------------------------------------- application ---
# todo: maybe trigger something in JS on any of these methods?
class ApplicationBackend(BaseApplicationBackend):
def __init__(self):
BaseApplicationBackend.__init__(self)
self._backend2 = _app._backend
def _vispy_get_backend_name(self):
realname = self._backend2._vispy_get_backend_name()
return 'ipynb_static (via %s)' % realname
def _vispy_process_events(self):
return self._backend2._vispy_process_events()
def _vispy_run(self):
pass # We run in IPython, so we don't run!
#return self._backend2._vispy_run()
def _vispy_quit(self):
return self._backend2._vispy_quit()
def _vispy_get_native_app(self):
return self._backend2._vispy_get_native_app()
# ------------------------------------------------------------------ canvas ---
class CanvasBackend(BaseCanvasBackend):
# args are for BaseCanvasBackend, kwargs are for us.
def __init__(self, *args, **kwargs):
BaseCanvasBackend.__init__(self, *args)
self._initialized = False
# Test kwargs
# if kwargs['position']:
# raise RuntimeError('ipynb_static Canvas is not positionable')
if not kwargs['decorate']:
raise RuntimeError('ipynb_static Canvas is not decoratable')
if kwargs['vsync']:
raise RuntimeError('ipynb_static Canvas does not support vsync')
if kwargs['fullscreen']:
raise RuntimeError('ipynb_static Canvas does not support '
'fullscreen')
# Create real canvas. It is a backend to this backend
kwargs.pop('vispy_canvas', None)
kwargs['autoswap'] = False
canvas = Canvas(app=_app, **kwargs) # Pass kwargs to underlying canvas
self._backend2 = canvas.native
# Connect to events of canvas to keep up to date with size and draw
canvas.events.draw.connect(self._on_draw)
canvas.events.resize.connect(self._on_resize)
# Show the widget
canvas.show()
# todo: hide that canvas
# Raw PNG that will be displayed on canvas.show()
self._im = ""
def _vispy_warmup(self):
return self._backend2._vispy_warmup()
def _vispy_set_current(self):
return self._backend2._vispy_set_current()
def _vispy_swap_buffers(self):
return self._backend2._vispy_swap_buffers()
def _vispy_set_title(self, title):
return self._backend2._vispy_set_title(title)
#logger.warn('IPython notebook canvas has not title.')
def _vispy_set_size(self, w, h):
return self._backend2._vispy_set_size(w, h)
def _vispy_set_position(self, x, y):
logger.warn('IPython notebook canvas cannot be repositioned.')
def _vispy_set_visible(self, visible):
#self._backend2._vispy_set_visible(visible)
if not visible:
logger.warn('IPython notebook canvas cannot be hidden.')
else:
self._vispy_update()
self._vispy_canvas.app.process_events()
self._vispy_close()
display_png(self._im, raw=True)
def _vispy_update(self):
return self._backend2._vispy_update()
def _vispy_close(self):
return self._backend2._vispy_close()
# todo: can we close on IPython side?
def _vispy_get_position(self):
return 0, 0
def _vispy_get_size(self):
return self._backend2._vispy_get_size()
def _on_resize(self, event=None):
# Event handler that is called by the underlying canvas
if self._vispy_canvas is None:
return
size = self._backend2._vispy_get_size()
self._vispy_canvas.events.resize(size=size)
def _on_draw(self, event=None):
# Event handler that is called by the underlying canvas
if self._vispy_canvas is None:
return
# Handle initialization
if not self._initialized:
self._initialized = True
self._vispy_canvas.events.initialize()
self._on_resize()
# Normal behavior
self._vispy_canvas.set_current()
self._vispy_canvas.events.draw(region=None)
# Generate base64 encoded PNG string
self._gen_png()
def _gen_png(self):
# Take the screenshot
screenshot = _screenshot()
# Convert to PNG
png = _make_png(screenshot)
# Encode base64
self._im = b64encode(png)
|