Last active
March 11, 2016 04:50
-
-
Save NT7S/2c2f4faca3c650418a62 to your computer and use it in GitHub Desktop.
Strange Attractors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
# attractors.py | |
# 10 March 2016 | |
# | |
# Copyright 2016 Jason Milldrum | |
# | |
# Draw various attractors in a GTK window | |
# See: | |
# https://en.wikipedia.org/wiki/Lorenz_system | |
# https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor | |
# https://en.wikipedia.org/wiki/Chua%27s_circuit | |
import math | |
import gi | |
import cairo | |
gi.require_version('Gtk', '3.0') | |
from gi.repository import Gtk | |
class MyWindow(Gtk.Window): | |
def __init__(self): | |
Gtk.Window.__init__(self, title="Strange Attractors") | |
self.move(100, 100) | |
self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) | |
self.add(self.vbox) | |
self.stack = Gtk.Stack() | |
self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT) | |
self.stack.set_transition_duration(300) | |
self.lorenz_drawing = Gtk.DrawingArea() | |
self.lorenz_drawing.set_size_request(400, 400) | |
self.lorenz_drawing.connect("draw", self.draw_lorenz) | |
self.stack.add_titled(self.lorenz_drawing, "lorenz", "Lorenz Attractor") | |
#self.vbox.pack_start(self.drawing, True, True, 0) | |
#self.add(self.drawing) | |
self.rossler_drawing = Gtk.DrawingArea() | |
self.rossler_drawing.set_size_request(400, 400) | |
self.rossler_drawing.connect("draw", self.draw_rossler) | |
self.stack.add_titled(self.rossler_drawing, "rossler", "Rössler Attractor") | |
self.chua_drawing = Gtk.DrawingArea() | |
self.chua_drawing.set_size_request(400, 400) | |
self.chua_drawing.connect("draw", self.draw_chua) | |
self.stack.add_titled(self.chua_drawing, "chua", "Chua's Circuit") | |
self.stack_switcher = Gtk.StackSwitcher() | |
self.stack_switcher.set_stack(self.stack) | |
self.switcher_align = Gtk.Alignment(xalign=0.5, yalign=0.0, xscale=0.0, yscale=0.0) | |
self.switcher_align.add(self.stack_switcher) | |
self.vbox.pack_start(self.stack, True, True, 0) | |
self.vbox.pack_start(self.switcher_align, False, False, 0) | |
self.lorenz_coords = [] | |
self.rossler_coords = [] | |
self.chua_coords = [] | |
def draw_lorenz(self, widget, cr): | |
center_x = self.get_size()[0] / 2 | |
center_y = self.get_size()[1] / 2 | |
scale_x = self.get_size()[0] / 70.0 | |
scale_y = self.get_size()[1] / 70.0 | |
offset_y = center_y * 0.9 | |
cr.set_line_width(1) | |
cr.set_source_rgb(0.0, 0.0, 0.0) | |
cr.move_to(center_x, center_y - offset_y) | |
for i in self.lorenz_coords: | |
# Draw the X-Z view | |
cr.line_to((i[0] * scale_x) + center_x, (i[2] * scale_y) + center_y - offset_y) | |
cr.stroke() | |
# Draw axes legend | |
cr.set_source_rgb(0.6, 0.0, 0.0) | |
cr.select_font_face("Courier", cairo.FONT_SLANT_NORMAL, | |
cairo.FONT_WEIGHT_BOLD) | |
cr.set_font_size(24) | |
(x, y, width, height, dx, dy) = cr.text_extents("X") | |
cr.move_to(center_x - width / 2, self.get_size()[1] - 40) | |
cr.show_text("X") | |
(x, y, width, height, dx, dy) = cr.text_extents("Z") | |
cr.move_to(self.get_size()[0] - width - 10, center_y) | |
cr.show_text("Z") | |
def draw_rossler(self, widget, cr): | |
center_x = self.get_size()[0] / 2 | |
center_y = self.get_size()[1] / 2 | |
scale_x = self.get_size()[0] / 60.0 | |
scale_y = self.get_size()[1] / 60.0 | |
offset_y = center_y * 0.01 | |
cr.set_line_width(1) | |
cr.set_source_rgb(0.0, 0.0, 0.0) | |
cr.move_to(center_x, center_y - offset_y) | |
for i in self.rossler_coords: | |
# Draw the X-Y view | |
cr.line_to((i[0] * scale_x) + center_x, (i[1] * scale_y) + center_y - offset_y) | |
cr.stroke() | |
# Draw axes legend | |
cr.set_source_rgb(0.6, 0.0, 0.0) | |
cr.select_font_face("Courier", cairo.FONT_SLANT_NORMAL, | |
cairo.FONT_WEIGHT_BOLD) | |
cr.set_font_size(24) | |
(x, y, width, height, dx, dy) = cr.text_extents("X") | |
cr.move_to(center_x - width / 2, self.get_size()[1] - 40) | |
cr.show_text("X") | |
(x, y, width, height, dx, dy) = cr.text_extents("Y") | |
cr.move_to(self.get_size()[0] - width - 10, center_y) | |
cr.show_text("Y") | |
def draw_chua(self, widget, cr): | |
center_x = self.get_size()[0] / 2 | |
center_y = self.get_size()[1] / 2 | |
scale_x = self.get_size()[0] / 10.0 | |
scale_y = self.get_size()[1] / 10.0 | |
offset_y = center_y * 0.01 | |
cr.set_line_width(1) | |
cr.set_source_rgb(0.0, 0.0, 0.0) | |
cr.move_to(center_x, center_y - offset_y) | |
for i in self.chua_coords: | |
# Draw the X-Z view | |
cr.line_to((i[0] * scale_x) + center_x, (i[2] * scale_y) + center_y - offset_y) | |
cr.stroke() | |
# Draw axes legend | |
cr.set_source_rgb(0.6, 0.0, 0.0) | |
cr.select_font_face("Courier", cairo.FONT_SLANT_NORMAL, | |
cairo.FONT_WEIGHT_BOLD) | |
cr.set_font_size(24) | |
(x, y, width, height, dx, dy) = cr.text_extents("X") | |
cr.move_to(center_x - width / 2, self.get_size()[1] - 40) | |
cr.show_text("X") | |
(x, y, width, height, dx, dy) = cr.text_extents("Z") | |
cr.move_to(self.get_size()[0] - width - 10, center_y) | |
cr.show_text("Z") | |
def lorenz(self): | |
h = 0.01 | |
sigma = 10.0 | |
rho = 28.0 | |
beta = 8.0 / 3.0 | |
x0 = 0.1 | |
y0 = 0.0 | |
z0 = 0.0 | |
for i in range(10000): | |
x1 = x0 + h * sigma * (y0 - x0) | |
y1 = y0 + h * (x0 * (rho - z0) - y0) | |
z1 = z0 + h * (x0 * y0 - beta * z0) | |
x0 = x1 | |
y0 = y1 | |
z0 = z1 | |
self.lorenz_coords.append([x0, y0, z0]) | |
def rossler(self): | |
h = 0.02 | |
a = 0.1 | |
b = 0.1 | |
c = 14.0 | |
x0 = 0.1 | |
y0 = 0.0 | |
z0 = 0.0 | |
for i in range(15000): | |
x1 = x0 + h * (-y0 - z0) | |
y1 = y0 + h * (x0 + a * y0) | |
z1 = z0 + h * (b + z0 * (x0 - c)) | |
x0 = x1 | |
y0 = y1 | |
z0 = z1 | |
self.rossler_coords.append([x0, y0, z0]) | |
def chua(self): | |
h = 0.005 | |
alpha = 15.6 | |
beta = 28.0 | |
d = -5.0 / 7.0 | |
e = -8.0 / 7.0 | |
x0 = 0.7 | |
y0 = 0.0 | |
z0 = 0.0 | |
f = lambda x: d * x + 0.5 * (e - d) * (abs(x + 1) - abs(x - 1)) | |
for i in range(15000): | |
x1 = x0 + h * (alpha * (y0 - x0 - f(x0))) | |
y1 = y0 + h * (x0 - y0 + z0) | |
z1 = z0 + h * (-beta * y0) | |
x0 = x1 | |
y0 = y1 | |
z0 = z1 | |
self.chua_coords.append([x0, y0, z0]) | |
win = MyWindow() | |
win.connect("delete-event", Gtk.main_quit) | |
win.show_all() | |
win.lorenz() | |
win.rossler() | |
win.chua() | |
Gtk.main() |
Author
NT7S
commented
Mar 11, 2016
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment