{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Vispy\n", "Vispy 0.3 (this two demos) is about building the low-level infrastructure\n", "\n", "see this tutorial about [opengl and vispy gloo module](http://www.labri.fr/perso/nrougier/teaching/opengl/)\n", "\n", "Vispy 0.4 starts to bring higher level structures" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Vispy demo: ray traycing\n", "# http://vispy.org/examples/demo/gloo/raytracing.html\n", "from math import cos\n", "from vispy import app, gloo\n", "\n", "vertex = \"\"\"\n", "#version 120\n", "\n", "attribute vec2 a_position;\n", "varying vec2 v_position;\n", "void main()\n", "{\n", " gl_Position = vec4(a_position, 0.0, 1.0);\n", " v_position = a_position;\n", "}\n", "\"\"\"\n", "\n", "fragment = \"\"\"\n", "#version 120\n", "\n", "const float M_PI = 3.14159265358979323846;\n", "const float INFINITY = 1000000000.;\n", "const int PLANE = 1;\n", "const int SPHERE_0 = 2;\n", "const int SPHERE_1 = 3;\n", "\n", "uniform float u_aspect_ratio;\n", "varying vec2 v_position;\n", "\n", "uniform vec3 sphere_position_0;\n", "uniform float sphere_radius_0;\n", "uniform vec3 sphere_color_0;\n", "\n", "uniform vec3 sphere_position_1;\n", "uniform float sphere_radius_1;\n", "uniform vec3 sphere_color_1;\n", "\n", "uniform vec3 plane_position;\n", "uniform vec3 plane_normal;\n", "\n", "uniform float light_intensity;\n", "uniform vec2 light_specular;\n", "uniform vec3 light_position;\n", "uniform vec3 light_color;\n", "\n", "uniform float ambient;\n", "uniform vec3 O;\n", "\n", "float intersect_sphere(vec3 O, vec3 D, vec3 S, float R) {\n", " float a = dot(D, D);\n", " vec3 OS = O - S;\n", " float b = 2. * dot(D, OS);\n", " float c = dot(OS, OS) - R * R;\n", " float disc = b * b - 4. * a * c;\n", " if (disc > 0.) {\n", " float distSqrt = sqrt(disc);\n", " float q = (-b - distSqrt) / 2.0;\n", " if (b >= 0.) {\n", " q = (-b + distSqrt) / 2.0;\n", " }\n", " float t0 = q / a;\n", " float t1 = c / q;\n", " t0 = min(t0, t1);\n", " t1 = max(t0, t1);\n", " if (t1 >= 0.) {\n", " if (t0 < 0.) {\n", " return t1;\n", " }\n", " else {\n", " return t0;\n", " }\n", " }\n", " }\n", " return INFINITY;\n", "}\n", "\n", "float intersect_plane(vec3 O, vec3 D, vec3 P, vec3 N) {\n", " float denom = dot(D, N);\n", " if (abs(denom) < 1e-6) {\n", " return INFINITY;\n", " }\n", " float d = dot(P - O, N) / denom;\n", " if (d < 0.) {\n", " return INFINITY;\n", " }\n", " return d;\n", "}\n", "\n", "vec3 run(float x, float y) {\n", " vec3 Q = vec3(x, y, 0.);\n", " vec3 D = normalize(Q - O);\n", " int depth = 0;\n", " float t_plane, t0, t1;\n", " vec3 rayO = O;\n", " vec3 rayD = D;\n", " vec3 col = vec3(0.0, 0.0, 0.0);\n", " vec3 col_ray;\n", " float reflection = 1.;\n", "\n", " int object_index;\n", " vec3 object_color;\n", " vec3 object_normal;\n", " float object_reflection;\n", " vec3 M;\n", " vec3 N, toL, toO;\n", "\n", " while (depth < 5) {\n", "\n", " /* start trace_ray */\n", "\n", " t_plane = intersect_plane(rayO, rayD, plane_position, plane_normal);\n", " t0 = intersect_sphere(rayO, rayD, sphere_position_0, sphere_radius_0);\n", " t1 = intersect_sphere(rayO, rayD, sphere_position_1, sphere_radius_1);\n", "\n", " if (t_plane < min(t0, t1)) {\n", " // Plane.\n", " M = rayO + rayD * t_plane;\n", " object_normal = plane_normal;\n", " // Plane texture.\n", " if (mod(int(2*M.x), 2) == mod(int(2*M.z), 2)) {\n", " object_color = vec3(1., 1., 1.);\n", " }\n", " else {\n", " object_color = vec3(0., 0., 0.);\n", " }\n", " object_reflection = .25;\n", " object_index = PLANE;\n", " }\n", " else if (t0 < t1) {\n", " // Sphere 0.\n", " M = rayO + rayD * t0;\n", " object_normal = normalize(M - sphere_position_0);\n", " object_color = sphere_color_0;\n", " object_reflection = .5;\n", " object_index = SPHERE_0;\n", " }\n", " else if (t1 < t0) {\n", " // Sphere 1.\n", " M = rayO + rayD * t1;\n", " object_normal = normalize(M - sphere_position_1);\n", " object_color = sphere_color_1;\n", " object_reflection = .5;\n", " object_index = SPHERE_1;\n", " }\n", " else {\n", " break;\n", " }\n", "\n", " N = object_normal;\n", " toL = normalize(light_position - M);\n", " toO = normalize(O - M);\n", "\n", " // Shadow of the spheres on the plane.\n", " if (object_index == PLANE) {\n", " t0 = intersect_sphere(M + N * .0001, toL,\n", " sphere_position_0, sphere_radius_0);\n", " t1 = intersect_sphere(M + N * .0001, toL,\n", " sphere_position_1, sphere_radius_1);\n", " if (min(t0, t1) < INFINITY) {\n", " break;\n", " }\n", " }\n", "\n", " col_ray = vec3(ambient, ambient, ambient);\n", " col_ray += light_intensity * max(dot(N, toL), 0.) * object_color;\n", " col_ray += light_specular.x * light_color *\n", " pow(max(dot(N, normalize(toL + toO)), 0.), light_specular.y);\n", "\n", " /* end trace_ray */\n", "\n", " rayO = M + N * .0001;\n", " rayD = normalize(rayD - 2. * dot(rayD, N) * N);\n", " col += reflection * col_ray;\n", " reflection *= object_reflection;\n", "\n", " depth++;\n", " }\n", "\n", " return clamp(col, 0., 1.);\n", "}\n", "\n", "void main() {\n", " vec2 pos = v_position;\n", " gl_FragColor = vec4(run(pos.x*u_aspect_ratio, pos.y), 1.);\n", "}\n", "\"\"\"\n", "\n", "\n", "class Canvas(app.Canvas):\n", " def __init__(self):\n", " app.Canvas.__init__(self, position=(300, 100),\n", " size=(800, 600), keys='interactive')\n", "\n", " self.program = gloo.Program(vertex, fragment)\n", " self.program['a_position'] = [(-1., -1.), (-1., +1.),\n", " (+1., -1.), (+1., +1.)]\n", " self.program['sphere_position_0'] = (.75, .1, 1.)\n", " self.program['sphere_radius_0'] = .6\n", " self.program['sphere_color_0'] = (0., 0., 1.)\n", "\n", " self.program['sphere_position_1'] = (-.75, .1, 2.25)\n", " self.program['sphere_radius_1'] = .6\n", " self.program['sphere_color_1'] = (.5, .223, .5)\n", "\n", " self.program['plane_position'] = (0., -.5, 0.)\n", " self.program['plane_normal'] = (0., 1., 0.)\n", "\n", " self.program['light_intensity'] = 1.\n", " self.program['light_specular'] = (1., 50.)\n", " self.program['light_position'] = (5., 5., -10.)\n", " self.program['light_color'] = (1., 1., 1.)\n", " self.program['ambient'] = .05\n", " self.program['O'] = (0., 0., -1.)\n", "\n", " self._timer = app.Timer('auto', connect=self.on_timer, start=True)\n", "\n", " def on_timer(self, event):\n", " t = event.elapsed\n", " self.program['sphere_position_0'] = (+.75, .1, 2.0 + 1.0 * cos(4*t))\n", " self.program['sphere_position_1'] = (-.75, .1, 2.0 - 1.0 * cos(4*t))\n", " self.update()\n", "\n", " def on_resize(self, event):\n", " width, height = event.size\n", " gloo.set_viewport(0, 0, width, height)\n", " self.program['u_aspect_ratio'] = width/float(height)\n", "\n", " def on_draw(self, event):\n", " self.program.draw('triangle_strip')\n", "\n", "if __name__ == '__main__':\n", " canvas = Canvas()\n", " canvas.show()\n", " app.run()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Vispy demo : mandelbrot interactive\n", "#\n", "# http://vispy.org/examples/demo/gloo/mandelbrot.html\n", "# -*- coding: utf-8 -*-\n", "# vispy: gallery 30\n", "# -----------------------------------------------------------------------------\n", "# Copyright (c) 2014, Vispy Development Team. All Rights Reserved.\n", "# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n", "# -----------------------------------------------------------------------------\n", "# Author: John David Reaver\n", "# Date: 04/29/2014\n", "# -----------------------------------------------------------------------------\n", "\n", "from vispy import app, gloo\n", "\n", "# Shader source code\n", "# -----------------------------------------------------------------------------\n", "vertex = \"\"\"\n", "attribute vec2 position;\n", "\n", "void main()\n", "{\n", " gl_Position = vec4(position, 0, 1.0);\n", "}\n", "\"\"\"\n", "\n", "fragment = \"\"\"\n", "uniform vec2 resolution;\n", "uniform vec2 center;\n", "uniform float scale;\n", "uniform int iter;\n", "\n", "// Jet color scheme\n", "vec4 color_scheme(float x) {\n", " vec3 a, b;\n", " float c;\n", " if (x < 0.34) {\n", " a = vec3(0, 0, 0.5);\n", " b = vec3(0, 0.8, 0.95);\n", " c = (x - 0.0) / (0.34 - 0.0);\n", " } else if (x < 0.64) {\n", " a = vec3(0, 0.8, 0.95);\n", " b = vec3(0.85, 1, 0.04);\n", " c = (x - 0.34) / (0.64 - 0.34);\n", " } else if (x < 0.89) {\n", " a = vec3(0.85, 1, 0.04);\n", " b = vec3(0.96, 0.7, 0);\n", " c = (x - 0.64) / (0.89 - 0.64);\n", " } else {\n", " a = vec3(0.96, 0.7, 0);\n", " b = vec3(0.5, 0, 0);\n", " c = (x - 0.89) / (1.0 - 0.89);\n", " }\n", " return vec4(mix(a, b, c), 1.0);\n", "}\n", "\n", "void main() {\n", " vec2 z, c;\n", "\n", " // Recover coordinates from pixel coordinates\n", " c.x = (gl_FragCoord.x / resolution.x - 0.5) * scale + center.x;\n", " c.y = (gl_FragCoord.y / resolution.y - 0.5) * scale + center.y;\n", "\n", " // Main Mandelbrot computation\n", " int i;\n", " z = c;\n", " for(i = 0; i < iter; i++) {\n", " float x = (z.x * z.x - z.y * z.y) + c.x;\n", " float y = (z.y * z.x + z.x * z.y) + c.y;\n", "\n", " if((x * x + y * y) > 4.0) break;\n", " z.x = x;\n", " z.y = y;\n", " }\n", "\n", " // Convert iterations to color\n", " float color = 1.0 - float(i) / float(iter);\n", " gl_FragColor = color_scheme(color);\n", "\n", "}\n", "\"\"\"\n", "\n", "\n", "# vispy Canvas\n", "# -----------------------------------------------------------------------------\n", "class Canvas(app.Canvas):\n", "\n", " def __init__(self, *args, **kwargs):\n", " app.Canvas.__init__(self, *args, **kwargs)\n", " self.program = gloo.Program(vertex, fragment)\n", "\n", " # Draw a rectangle that takes up the whole screen. All of the work is\n", " # done in the shader.\n", " self.program[\"position\"] = [(-1, -1), (-1, 1), (1, 1),\n", " (-1, -1), (1, 1), (1, -1)]\n", "\n", " self.scale = self.program[\"scale\"] = 3\n", " self.center = self.program[\"center\"] = [-0.5, 0]\n", " self.iterations = self.program[\"iter\"] = 300\n", " self.program['resolution'] = self.size\n", "\n", " self.bounds = [-2, 2]\n", " self.min_scale = 0.00005\n", " self.max_scale = 4\n", "\n", " self._timer = app.Timer('auto', connect=self.update, start=True)\n", "\n", " def on_initialize(self, event):\n", " gloo.set_clear_color(color='black')\n", "\n", " def on_draw(self, event):\n", " self.program.draw()\n", "\n", " def on_resize(self, event):\n", " width, height = event.size\n", " gloo.set_viewport(0, 0, width, height)\n", " self.program['resolution'] = [width, height]\n", "\n", " def on_mouse_move(self, event):\n", " \"\"\"Pan the view based on the change in mouse position.\"\"\"\n", " if event.is_dragging and event.buttons[0] == 1:\n", " x0, y0 = event.last_event.pos[0], event.last_event.pos[1]\n", " x1, y1 = event.pos[0], event.pos[1]\n", " X0, Y0 = self.pixel_to_coords(float(x0), float(y0))\n", " X1, Y1 = self.pixel_to_coords(float(x1), float(y1))\n", " self.translate_center(X1 - X0, Y1 - Y0)\n", "\n", " def translate_center(self, dx, dy):\n", " \"\"\"Translates the center point, and keeps it in bounds.\"\"\"\n", " center = self.center\n", " center[0] -= dx\n", " center[1] -= dy\n", " center[0] = min(max(center[0], self.bounds[0]), self.bounds[1])\n", " center[1] = min(max(center[1], self.bounds[0]), self.bounds[1])\n", " self.program[\"center\"] = self.center = center\n", "\n", " def pixel_to_coords(self, x, y):\n", " \"\"\"Convert pixel coordinates to Mandelbrot set coordinates.\"\"\"\n", " rx, ry = self.size\n", " nx = (x / rx - 0.5) * self.scale + self.center[0]\n", " ny = ((ry - y) / ry - 0.5) * self.scale + self.center[1]\n", " return [nx, ny]\n", "\n", " def on_mouse_wheel(self, event):\n", " \"\"\"Use the mouse wheel to zoom.\"\"\"\n", " delta = event.delta[1]\n", " if delta > 0: # Zoom in\n", " factor = 0.9\n", " elif delta < 0: # Zoom out\n", " factor = 1 / 0.9\n", " for _ in range(int(abs(delta))):\n", " self.zoom(factor, event.pos)\n", "\n", " def on_key_press(self, event):\n", " \"\"\"Use + or - to zoom in and out.\n", "\n", " The mouse wheel can be used to zoom, but some people don't have mouse\n", " wheels :)\n", "\n", " \"\"\"\n", " if event.text == '+':\n", " self.zoom(0.9)\n", " elif event.text == '-':\n", " self.zoom(1/0.9)\n", "\n", " def zoom(self, factor, mouse_coords=None):\n", " \"\"\"Factors less than zero zoom in, and greater than zero zoom out.\n", "\n", " If mouse_coords is given, the point under the mouse stays stationary\n", " while zooming. mouse_coords should come from MouseEvent.pos.\n", "\n", " \"\"\"\n", " if mouse_coords is not None: # Record the position of the mouse\n", " x, y = float(mouse_coords[0]), float(mouse_coords[1])\n", " x0, y0 = self.pixel_to_coords(x, y)\n", "\n", " self.scale *= factor\n", " self.scale = max(min(self.scale, self.max_scale), self.min_scale)\n", " self.program[\"scale\"] = self.scale\n", "\n", " # Translate so the mouse point is stationary\n", " if mouse_coords is not None:\n", " x1, y1 = self.pixel_to_coords(x, y)\n", " self.translate_center(x1 - x0, y1 - y0)\n", "\n", "\n", "if __name__ == '__main__':\n", " canvas = Canvas(size=(800, 800), keys='interactive')\n", " canvas.show()\n", " app.run()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# -*- coding: utf-8 -*-\n", "\"\"\"\n", "Demonstrate a simple data-slicing task: given 3D data (displayed at top), select \n", "a 2D plane and interpolate data along that plane to generate a slice image \n", "(displayed at bottom). \n", "\n", "\n", "\"\"\"\n", "\n", "## Add path to library (just for examples; you do not need this)\n", "\n", "import numpy as np\n", "from pyqtgraph.Qt import QtCore, QtGui\n", "import pyqtgraph as pg\n", "\n", "app = QtGui.QApplication([])\n", "\n", "## Create window with two ImageView widgets\n", "win = QtGui.QMainWindow()\n", "win.resize(800,800)\n", "win.setWindowTitle('pyqtgraph example: DataSlicing')\n", "cw = QtGui.QWidget()\n", "win.setCentralWidget(cw)\n", "l = QtGui.QGridLayout()\n", "cw.setLayout(l)\n", "imv1 = pg.ImageView()\n", "imv2 = pg.ImageView()\n", "l.addWidget(imv1, 0, 0)\n", "l.addWidget(imv2, 1, 0)\n", "win.show()\n", "\n", "roi = pg.LineSegmentROI([[10, 64], [120,64]], pen='r')\n", "imv1.addItem(roi)\n", "\n", "x1 = np.linspace(-30, 10, 128)[:, np.newaxis, np.newaxis]\n", "x2 = np.linspace(-20, 20, 128)[:, np.newaxis, np.newaxis]\n", "y = np.linspace(-30, 10, 128)[np.newaxis, :, np.newaxis]\n", "z = np.linspace(-20, 20, 128)[np.newaxis, np.newaxis, :]\n", "d1 = np.sqrt(x1**2 + y**2 + z**2)\n", "d2 = 2*np.sqrt(x1[::-1]**2 + y**2 + z**2)\n", "d3 = 4*np.sqrt(x2**2 + y[:,::-1]**2 + z**2)\n", "data = (np.sin(d1) / d1**2) + (np.sin(d2) / d2**2) + (np.sin(d3) / d3**2)\n", "\n", "def update():\n", " global data, imv1, imv2\n", " d2 = roi.getArrayRegion(data, imv1.imageItem, axes=(1,2))\n", " imv2.setImage(d2)\n", " \n", "roi.sigRegionChanged.connect(update)\n", "\n", "\n", "## Display the data\n", "imv1.setImage(data)\n", "imv1.setHistogramRange(-0.01, 0.01)\n", "imv1.setLevels(-0.003, 0.003)\n", "\n", "update()\n", "\n", "## Start Qt event loop unless running in interactive mode.\n", "if __name__ == '__main__':\n", " import sys\n", " if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):\n", " QtGui.QApplication.instance().exec_()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "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.4.3" } }, "nbformat": 4, "nbformat_minor": 0 }