Skip to content

Instantly share code, notes, and snippets.

@klarh
Last active July 26, 2019 17:46
Show Gist options
  • Save klarh/a924c3f698897c9e41a01cf6a9fc99bb to your computer and use it in GitHub Desktop.
Save klarh/a924c3f698897c9e41a01cf6a9fc99bb to your computer and use it in GitHub Desktop.
Docker images to test vispy jupyter notebook backend installation

This gist holds a docker recipe for testing vispy's jupyter integration. It can be run like:

docker run -p 127.0.0.1:8899:8888 -it --rm mspells/vispy_notebook_tests /bin/bash 
# (setup vispy)
# jupyter notebook --ip 0.0.0.0 --port 8888 --allow-root 
#!/bin/sh
set -e
OWNER=mspells
PACKAGE=vispy_notebook_tests
TAG=$(date +%Y%m%d)
core_tag="${OWNER}/${PACKAGE}:${TAG}"
latest_tag="${OWNER}/${PACKAGE}:latest"
docker build -f Dockerfile -t "${core_tag}" .
docker tag "${core_tag}" "${latest_tag}"
#docker push "${core_tag}"
#docker push "${latest_tag}"
FROM ubuntu:latest
RUN apt-get update && apt-get install -y \
build-essential \
cython3 \
git \
npm \
python3-fontconfig \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y nano && rm -rf /var/lib/apt/lists/* && \
npm install -g npm@latest && \
pip3 install --no-cache-dir --upgrade pip setuptools
RUN pip3 install --no-cache-dir jupyter plato-draw && \
jupyter nbextension enable --py --sys-prefix widgetsnbextension
COPY *.ipynb /
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from collections import defaultdict, namedtuple\n",
"from itertools import repeat\n",
"import numpy as np\n",
"import vispy\n",
"from vispy import app\n",
"app.use_app('ipynb_webgl')\n",
"from vispy import gloo\n",
"\n",
"from plato.mesh import unfoldProperties"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"PLANE_COUNT = 8\n",
"\n",
"quatGLSL = \"\"\"\n",
"vec4 quatquat(vec4 a, vec4 b)\n",
"{\n",
" float real = a.x*b.x - dot(a.yzw, b.yzw);\n",
" vec3 imag = a.x*b.yzw + b.x*a.yzw + cross(a.yzw, b.yzw);\n",
" return vec4(real, imag);\n",
"}\n",
"\n",
"vec3 rotate(vec3 point, vec4 quat)\n",
"{\n",
" vec4 pointquat = vec4(0.0, point);\n",
" vec4 quatconj = vec4(-quat.x, quat.yzw);\n",
" return quatquat(quat, quatquat(pointquat, quatconj)).yzw;\n",
"}\n",
"\"\"\"\n",
"\n",
"vertexShader = \"\"\"\n",
"\n",
"uniform mat4 camera;\n",
"\"\"\" + \"uniform vec4 planeEquations[{}];\".format(PLANE_COUNT) + \"\"\"\n",
"uniform vec4 cam_rotation;\n",
"uniform vec3 cam_translation;\n",
"uniform float radius;\n",
"\n",
"attribute vec4 orientation;\n",
"attribute vec4 color;\n",
"attribute vec3 position;\n",
"attribute vec2 image;\n",
"\n",
"varying vec4 v_color;\n",
"varying vec4 v_orientation;\n",
"varying vec2 v_image;\n",
"\n",
"\"\"\" + quatGLSL + \"\"\"\n",
"\n",
"void main()\n",
"{\n",
" vec3 vertexPos = position;\n",
" vertexPos = rotate(vertexPos, cam_rotation) + vec3(image*radius, 0.0) + cam_translation;\n",
" vec4 screenPosition = camera * vec4(vertexPos, 1.0);\n",
"\n",
" // transform to screen coordinates\n",
" gl_Position = screenPosition;\n",
" v_color = color;\n",
" v_orientation = quatquat(cam_rotation, orientation);\n",
" v_image = image;\n",
"}\n",
"\"\"\"\n",
"\n",
"fragmentShader = \"\"\"\n",
"\n",
"varying vec4 v_color;\n",
"varying vec2 v_image;\n",
"varying vec4 v_orientation;\n",
"\n",
"// base light level\n",
"uniform float ambientLight;\n",
"// (x, y, z) direction*intensity\n",
"uniform vec3 diffuseLight;\n",
"\"\"\" + \"uniform vec4 planeEquations[{}];\".format(PLANE_COUNT) + \"\"\"\n",
"\n",
"uniform float radius;\n",
"\n",
"\"\"\" + quatGLSL + \"\"\"\n",
"\n",
"void main()\n",
"{\n",
" vec3 normal = vec3(0.0, 0.0, 0.0);\n",
" float mindist = 1.0e6;\n",
" float rsq = dot(v_image, v_image);\n",
"\n",
" if(rsq > radius*radius)\n",
" discard;\n",
"\n",
" vec3 r_local = vec3(v_image.xy, sqrt(radius*radius - rsq));\n",
"\n",
" mindist = sqrt(radius*radius - rsq);\n",
" float maxdist = -mindist;\n",
" normal = (1.0/sqrt(dot(r_local, r_local)))*r_local;\n",
"\n",
"\"\"\" + \"for(int planeidx = 0; planeidx < {}; ++planeidx)\".format(PLANE_COUNT) + \"\"\"\n",
" {\n",
" vec3 planeNormal = rotate(planeEquations[planeidx].xyz, v_orientation);\n",
" vec4 planeEquation = vec4(planeNormal, planeEquations[planeidx].w);\n",
"\n",
" float planeZ = (planeEquation.w -\n",
" dot(v_image, planeEquation.xy))/planeEquation.z;\n",
"\n",
" vec3 planeIntersection = vec3(v_image.xy, planeZ);\n",
"\n",
" // plane is facing viewer and the intersection is outside the sphere\n",
" if(planeZ < maxdist && planeEquation.z >= 0.0)\n",
" discard;\n",
" // plane is facing viewer, intersection is inside the sphere\n",
" else if(planeEquation.z >= 0.0 && planeZ < mindist &&\n",
" dot(planeIntersection, planeIntersection) < radius*radius)\n",
" {\n",
" mindist = planeZ;\n",
" normal = planeEquation.xyz;\n",
" }\n",
" // plane is not facing viewer, intersection is outside the sphere\n",
" else if(planeEquation.z < 0.0 && planeZ >= mindist)\n",
" discard;\n",
"\n",
" if(planeZ > maxdist && planeZ < mindist)\n",
" maxdist = planeZ;\n",
" }\n",
"\n",
" float light = max(0.0, dot(normal, diffuseLight));\n",
" light += ambientLight;\n",
" gl_FragColor = vec4(v_color.xyz*light, v_color.w);\n",
"}\n",
"\"\"\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"class MouseManager:\n",
" def __init__(self, canvas, program, translation=[0, 0, 0], orientation=[1, 0, 0, 0], camera=np.eye(4)):\n",
" self._canvas = canvas\n",
" self._program = program\n",
" self._translation = np.asarray(translation, dtype=np.float32)\n",
" self._orientation = np.asarray(orientation, dtype=np.float32)\n",
" self._camera = np.asarray(camera, dtype=np.float32)\n",
"\n",
" self._program['camera'] = self._camera\n",
"\n",
" self._mouse_origin = np.array([0, 0], dtype=np.float32)\n",
" self._canvas_size = np.sqrt(1280*1024)\n",
"\n",
" self._canvas.connect(self.on_mouse_move)\n",
" self._canvas.connect(self.on_mouse_press)\n",
" self._canvas.connect(self.on_mouse_wheel)\n",
" self._canvas.connect(self.on_resize)\n",
"\n",
" def on_mouse_move(self, event):\n",
" if 1 in event.buttons:\n",
" delta = (event.pos - self._mouse_origin)/self._canvas_size\n",
" self._mouse_origin[:] = event.pos\n",
" self.updateRotation(delta)\n",
"\n",
" def on_mouse_press(self, event):\n",
" self._mouse_origin[:] = event.pos\n",
"\n",
" def on_mouse_wheel(self, event):\n",
" self._camera[[0, 1], [0, 1]] *= 1.1**event.delta[1]\n",
" self._program['camera'] = self._camera\n",
" self._canvas.update()\n",
"\n",
" def on_resize(self, event):\n",
" self._canvas_size = np.sqrt(event.size[0]*event.size[1])\n",
"\n",
" def updateRotation(self, delta=(0, 0)):\n",
" delta = np.asarray(delta, dtype=np.float32)[::-1]\n",
" theta = np.sqrt(np.sum(delta**2))\n",
"\n",
" if theta > 1e-5:\n",
" norm = delta/theta\n",
" theta *= 3.\n",
" quat = np.array([np.cos(theta/2), np.sin(theta/2)*norm[0], np.sin(theta/2)*norm[1], 0])\n",
" real = self._orientation[0]*quat[0] - np.dot(self._orientation[1:], quat[1:])\n",
" imag = self._orientation[0]*quat[1:] + quat[0]*self._orientation[1:] + np.cross(quat[1:], self._orientation[1:])\n",
" self._orientation[0] = real\n",
" self._orientation[1:] = imag\n",
"\n",
" self._program['cam_rotation'] = self._orientation\n",
" self._canvas.update()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"positions = [[0, 0, 0], [.55, 0, 0]]\n",
"orientations = [[1,0,0,0] for _ in positions]\n",
"orientations[1] = [np.cos(np.pi/6), 0, np.sin(np.pi/6), 0]\n",
"colors = [[.5, .5, .75, 1] for _ in positions]\n",
"# radii = [0.5 for _ in positions]\n",
"# planeEqn = [(1, 0, 0, 0.25) for _ in positions]\n",
"# planeEqn2 = [(0.15, 0.7, 0, 0.28) for _ in positions]\n",
"planeEqns = np.zeros((PLANE_COUNT, 4))\n",
"planeEqns[:, 0] = 1\n",
"planeEqns[:, 3] = 0.5\n",
"\n",
"planeEqns[0] = (0, 0, 1, .45)\n",
"planeEqns[1] = (1, 1, 0, .25)\n",
"planeEqns[2] = (-1, -.15, 0, .4)\n",
"\n",
"image = np.array([[2*np.sqrt(2)*1.05, -1.05],\n",
" [-1.05, 2*np.sqrt(2)*1.05],\n",
" [-1.05, -1.05]])\n",
"\n",
"indices = np.array([0, 1, 2], dtype=np.uint32)\n",
"\n",
"[positions, orientations, colors, image] = unfoldProperties([positions, orientations, colors], [image])\n",
"indices = np.arange(positions.shape[0])[:, np.newaxis, np.newaxis]*positions.shape[1] + indices"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"c = app.Canvas(keys='interactive')\n",
"program = gloo.Program(vertexShader, fragmentShader)\n",
"\n",
"program['ambientLight'] = 0.5\n",
"program['diffuseLight'] = np.array([.25, .5, .75], dtype=np.float32)/np.sqrt(3)\n",
"program['cam_rotation'] = np.array([1, 0, 0, 0], dtype=np.float32)\n",
"program['cam_translation'] = np.array([0, 0, -5], dtype=np.float32)\n",
"program['radius'] = 0.5\n",
"for (i, eqn) in enumerate(planeEqns):\n",
" program['planeEquations[{}]'.format(i)] = eqn\n",
"\n",
"indicesBuf = vispy.gloo.IndexBuffer(np.asarray(indices.flat, dtype=np.uint16))\n",
"program['orientation'] = np.asarray(orientations.reshape((-1, 4)), dtype=np.float32)\n",
"program['position'] = np.asarray(positions.reshape((-1, 3)), dtype=np.float32)\n",
"program['color'] = np.asarray(colors.reshape((-1, 4)), dtype=np.float32)\n",
"program['image'] = np.asarray(image.reshape((-1, 2)), dtype=np.float32)\n",
"\n",
"(width, height) = c.size\n",
"camera = vispy.util.transforms.perspective(90, float(width)/height, 4, 6)\n",
"camera[[0, 1], [0, 1]] *= 6\n",
"mouse = MouseManager(c, program, camera=camera)\n",
"\n",
"@c.connect\n",
"def on_resize(event):\n",
" gloo.set_viewport(0, 0, *event.size)\n",
"\n",
"@c.connect\n",
"def on_draw(event):\n",
" gloo.clear((1,1,1,1))\n",
" program.draw('triangles', indices=indicesBuf)\n",
"\n",
"gloo.set_state('opaque')\n",
"c.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment