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