# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2015-2017 Tiago Baptista
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
"""
This module provides several ready-made visual classes. Used mainly for the
examples given in the Complex Systems course. In this current version, these
should not be considered stable in terms of API.
"""
from __future__ import division
from . import MplVisual, Simulator, Visual
from .simulators import FunctionIterator, FunctionIterator2D, FinalStateIterator
import numpy as np
import pyglet
import matplotlib as mpl
__docformat__ = 'restructuredtext'
__author__ = 'Tiago Baptista'
[docs]class Line(MplVisual):
def __init__(self, sim: Simulator, x: list, y: list, auto_size=True,
**kwargs):
super(Line, self).__init__(sim, **kwargs)
self._auto_size = auto_size
self._x = x
self._y = y
self.ax = self.figure.add_subplot(111)
self.l, = self.ax.plot(self._x, self._y)
[docs] def draw(self):
self.l.set_data(self._x, self._y)
if self._auto_size:
self.ax.relim()
self.ax.autoscale_view()
[docs]class Lines(MplVisual):
def __init__(self, sim: Simulator, auto_size=True, **kwargs):
super(Lines, self).__init__(sim, **kwargs)
self._auto_size = auto_size
self.ax = self.figure.add_subplot(111)
self._lines = []
for i in range(len(self.sim.y)):
line, = self.ax.plot(self.sim.x, self.sim.y[i])
self._lines.append(line)
[docs] def draw(self):
for i in range(len(self._lines)):
self._lines[i].set_data(self.sim.x, self.sim.y[i])
if self._auto_size:
self.ax.relim()
self.ax.autoscale_view()
[docs]class TimeSeries(Lines):
def __init__(self, sim: FunctionIterator, **kwargs):
super(TimeSeries, self).__init__(sim, **kwargs)
self.ax.set_title('Time Series')
self.ax.set_xlabel('Time')
self.ax.set_ylabel('State')
[docs]class PhaseSpace2D(Line):
def __init__(self, sim: FunctionIterator2D, name_x, name_y, **kwargs):
super(PhaseSpace2D, self).__init__(sim, sim.y[0], sim.y[1], **kwargs)
self.ax.set_title('Phase Space')
self.ax.set_xlabel(name_x)
self.ax.set_ylabel(name_y)
[docs]class CobWebVisual(MplVisual):
def __init__(self, sim: FunctionIterator, min_x, max_x, func_string='',
**kwargs):
super(CobWebVisual, self).__init__(sim, **kwargs)
self.ax = self.figure.add_subplot(111)
# PLot function
x = np.linspace(min_x, max_x, 1000)
func_vec = np.frompyfunc(self.sim.func, 1, 1)
y = func_vec(x)
self.ax.plot(x, y, label='$f(x)=$' + func_string)
# Plot f(x) = x
self.ax.plot(x, x, ':k', label='$f(x)=x$')
# Create initial cobweb plots
self._cobx = [[x[0]] for x in self.sim.y]
self._coby = [[0] for x in self.sim.y]
self._cobweb_lines = []
for i in range(len(self.sim.y)):
line, = self.ax.plot(self._cobx[i], self._coby[i],
label='$x_0=' + str(self.sim.y[i][0]) + '$')
self._cobweb_lines.append(line)
[docs] def draw(self):
for i in range(len(self._cobweb_lines)):
self._cobx[i].append(self.sim.y[i][-2])
self._coby[i].append(self.sim.y[i][-2])
self._cobx[i].append(self.sim.y[i][-2])
self._coby[i].append(self.sim.y[i][-1])
self._cobweb_lines[i].set_data(self._cobx[i], self._coby[i])
[docs]class FinalStateDiagram(MplVisual):
def __init__(self, sim: FunctionIterator, discard_initial=1000, **kwargs):
super(FinalStateDiagram, self).__init__(sim, **kwargs)
self._discard_initial = discard_initial
self._seeds = [y[0] for y in self.sim.y]
self.ax = self.figure.add_subplot(111)
self.ax.set_title('Final State Diagram')
x_min = min([y[0] for y in self.sim.y])
x_max = max([y[0] for y in self.sim.y])
self.ax.set_xlim(x_min - 0.5, x_max + 0.5)
self.ax.set_xlabel('$t={}$'.format(self.sim.time))
self.ax.set_ylabel('Final Value(s)')
[docs] def draw(self):
self.ax.set_xlabel('$t={}$'.format(self.sim.time))
if self.sim.time >= self._discard_initial:
for i in range(len(self.sim.y)):
self.ax.scatter([self._seeds[i]], self.sim.y[i][-1:], c='black')
[docs]class BifurcationDiagram(MplVisual):
def __init__(self, sim: FinalStateIterator, **kwargs):
super(BifurcationDiagram, self).__init__(sim, **kwargs)
self.ax = self.figure.add_subplot(111)
self.ax.set_title('Bifurcation Diagram')
self.ax.set_xlabel('a')
self.ax.set_ylabel('Final Value(s)')
self.ax.set_xlim(sim.start, sim.end)
self.ax.set_ylim(kwargs.get('ymin', 0), kwargs.get('ymax', 1))
self.ax.grid()
[docs] def draw(self):
self.ax.scatter(self.sim.x, self.sim.y, s=0.5, c='black')
[docs]class Points2D(Visual):
def __init__(self, sim, min_x=0., max_x=1., min_y=0., max_y=1., **kwargs):
super(Points2D, self).__init__(sim, **kwargs)
self._scale_x = self.width / abs(max_x - min_x)
self._scale_y = self.height / abs(max_y - min_y)
self._translate_x = -min_x
self._translate_y = -min_y
self._batch = pyglet.graphics.Batch()
[docs] def draw(self):
if self.sim.draw_points:
points = self.sim.draw_points
for i in range(len(points)):
self._batch.add(1, pyglet.gl.GL_POINTS, None, ('v2f', points[i]),
('c3B', (255, 255, 255)))
self.sim.draw_points.clear()
pyglet.gl.glPushMatrix()
pyglet.gl.glScalef(self._scale_x, self._scale_y, 1.)
pyglet.gl.glTranslatef(self._translate_x, self._translate_y, 0.)
self._batch.draw()
pyglet.gl.glPopMatrix()
[docs]class FractalVisual(MplVisual):
def __init__(self, sim, gamma=1.0, **kwargs):
super(FractalVisual, self).__init__(sim, **kwargs)
norm = mpl.colors.PowerNorm(gamma)
self.figure.figimage(self.sim.data, cmap=kwargs.get('cmap', 'hot'),
norm=norm)