from ipywidgets import interact, interactive, fixed, interact_manual, Layout
import ipywidgets as widgets
# todo: chaos analysis

class Attractor[source]

Attractor()

class IteratedFunctionSystem[source]

IteratedFunctionSystem() :: Attractor

rotation_matrix[source]

rotation_matrix(a)

rotate[source]

rotate(a, b, t)

simulate_accelerated[source]

simulate_accelerated(speeds, pivots, center, angles, start, points, steps=100, clip=True)

Efficiently simulate a system of rotating segments joined by pivots using Numba to JIT-compile operations on NumPy arrays.

  • steps: integer >=1; the number of timesteps to simulate
  • clip: boolean; whether to limit the maximum angle of each section (if True, the values will wrap around to 0; defaults to True)

Returns an ndarray of the generated points

doc(simulate_accelerated)

simulate_accelerated[source]

simulate_accelerated(speeds, pivots, center, angles, start, points, steps=100, clip=True)

Efficiently simulate a system of rotating segments joined by pivots using Numba to JIT-compile operations on NumPy arrays.

  • steps: integer >=1; the number of timesteps to simulate
  • clip: boolean; whether to limit the maximum angle of each section (if True, the values will wrap around to 0; defaults to True)

line[source]

line(start, stop, bg, width=1.0, quality=5.0)

Draw a line onto an array using NumPy.

-start: ndarray; the start point -stop: ndarray; the end point -bg (background): ndarray; the array to draw the line onto -width: int or float >= 1; the thickness of the line -quality: int or float >= 1; the number of points to draw for each unit of distance between the points

Returns the modified bg array with the line drawn

im = line(
    np.array([5., 10.]),
    np.array([40., 40.]),
    np.zeros((50, 50)),
    width=1
)
# print(im.max())
plt.close('all')
fig, ax = plt.subplots()
ax.imshow(im, interpolation='none')
plt.show()

class RouletteCurve[source]

RouletteCurve(center=[0, 0], num_sections=4, lengths=None, speeds=None, random_distribution='uniform') :: Attractor

import matplotlib.pyplot as plt
plt.cm.colors.Colormap('cool')
<matplotlib.colors.Colormap at 0x23dba31bd60>
m = 2
plt.close('all')
R = RouletteCurve(num_sections=m)
# R = RouletteCurve(lengths=[10]*m, speeds=[1]*m)
# print(R.pivots, R.points)
# print(R.start, R.lengths)
# R.simulate(live_rendering=False, duration=5).render(mode='hist', blending='add', hist_args=dict(bins=100)
#                           cmap=random.choice(plt.colormaps())
#                          )
# todo: estimate completion time
# print(R.start, R.lengths)

R.simulate_accelerated(steps=100).render(discard=True, mode='line', blending='add', point_value=1, hist_args=dict(bins=150))
print(R.pivots, R.center)
[[ 0.         -1.09736288]
 [-0.06505168  1.22416644]] [0. 0.]
doc(RouletteCurve.render)

RouletteCurve.render[source]

RouletteCurve.render(discard=False, clip=False, axis=None, recenter=True, zoom=None, mode='line', blending='add', hist_args={}, cmap='random', point_value=1, **kwargs)

Render an image from the list of points stored in the class instance.

  • discard: boolean; if True, clear this Attractor's points after rendering to free up memory
  • axis: A Matplotlib axis to render the finished image to (if one is not provided, it will be created)
  • zoom: A scaling factor by which to resize points relative to the center before rendering
  • mode: str, one of pixel, dist/brush, line, or hist
    • pixel: Convert each point coordinate to the (integer) coordinate of the nearest pixel
    • dist: Generate a "brush" based on a distance function relative to the point coordinates, then (for each point) paint this over a region of the canvas centered on that point
    • line: Draw a line from the last rendered point to the current one (helpful for reducing the total number of points that must be rendered)
    • hist: Generate a 2D histogram using NumPy and display this (similar to pixel)
  • blending: str, one of set, add, or mul; how the new pixel value (while rendering a point) should be combined with the current one
  • cmap: random or a Matplotlib colormap; the colormap to pass to imshow - if random, one will be selected from the sequential colormaps listed in RouletteCurve().cmaps
  • point_value
  • **kwargs
np.interp([0.1, 0.2], [0,1], [0,5])
array([0.5, 1. ])
R2 = RouletteCurve(num_sections=3).simulate_accelerated(steps=1000, duration=1)
R2.render(mode='hist', blending='add', point_value=1, hist_args=dict(bins=200))
# why is this so fast?
print(len(R2.points))
255255
1 ** np.array([5, 6, 0])
array([1, 1, 1], dtype=int32)
x = 3
plt.close('all')
continuous_update = False
checkbox = {'Continuous': widgets.Checkbox()}
seed = np.random.normal(0, 0.1, [x])
layout = Layout(width='500px')
slider_settings = dict(continuous_update=continuous_update, layout=layout)
speeds = {str(i+1): widgets.FloatSlider(
              min = -2.0, 
              max = 2.0, 
              step = 0.01, 
              value = seed[i], **slider_settings) for i in range(x)}
fig = plt.figure()
ax = fig.add_subplot()
quality = {'Quality': widgets.FloatSlider(value=0.1, min=0, max=5, step=0.01, continuous_update=continuous_update)}
# widgets.FloatLogSlider
quality = {'Points': widgets.FloatLogSlider(value=100, base=10, min=1, max=6, step=0.1, **slider_settings)}
resolution = {'Resolution': widgets.IntSlider(value=100, min=1, max=1000, step=1, **slider_settings)}
interact_options = speeds | quality | checkbox | resolution
@interact(**interact_options)
def generate(c=R.cmaps, **interact_options):
    for widget in [quality]:
        widget[list(widget.keys())[0]].continuous_update = interact_options['Continuous']
    
#     global speeds
    speeds = np.array(list(interact_options.values())[:x])
    R = RouletteCurve(lengths=[1]*x, speeds=speeds)
    fig.canvas.draw()
#     cmap='Blues'
    render_options = dict(discard=True, clip=(0, 5), axis=ax, mode='hist', blending='add', hist_args=dict(bins=interact_options['Resolution']), cmap=c)
#     R.simulate(live_rendering=False, duration=interact_options['Quality'], render_each=2000, render_settings=render_options)

    R.simulate_accelerated(round(interact_options['Points']))
    print(len(R.points), R.speeds)
    R.render(**render_options)
    
# update vs setdata vs imshow vs... ?
#     plt.show()
# todo: simulate multiple tracks in parallel
# reuse existing results when changing resolution, colormap, etc.
dict
v = resolution['Resolution']
v
R.canvas.max()
6.0
R.cmaps
['rainbow',
 'hot',
 'cool',
 'autumn',
 'winter',
 'summer',
 'Greys',
 'Purples',
 'Blues',
 'Greens',
 'Oranges',
 'Reds',
 'YlOrBr',
 'YlOrRd',
 'OrRd',
 'PuRd',
 'RdPu',
 'BuPu',
 'GnBu',
 'PuBu',
 'YlGnBu',
 'PuBuGn',
 'BuGn',
 'YlGn']
x = 2
seed = np.random.normal(0, 0.1, [x**2])
seed[seed.size//2] = 1
kernel = {str(i+1): widgets.FloatSlider(
              min = -2.0, 
              max = 2.0, 
              step = 0.01, 
              value = seed[i]) for i in range(x**2)}

conv_settings = dict(mode='full', boundary='symm')
@interact(**kernel)
def convolve(**kernel):
    kernel = np.reshape(list(kernel.values()), [x, x])
    plt.imshow(signal.convolve2d(R.canvas, kernel, ), interpolation='none', cmap='Blues')
# convolve(kernel)
    
# iterated convolutions
# learning to produce dynamical system rules that fit some objective *
# approximate distribution of sample with smooth function?
 
R.canvas
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])
 
 
theta = 2*math.pi*0.01
rMatrix = [
    [np.cos(theta), -np.sin(theta)],
    [np.sin(theta), np.cos(theta)]
]
rMatrix = np.array(rMatrix)
# rMatrix = np.array([rMatrix]*2).swapaxes(1,2)
print(rMatrix)
h = np.array([0, 0]).astype(float)
X = np.array([[0, 4], [0, 3]])[0].astype(float)
Y = np.array([0, 7]).astype(float)
Z = np.array([0, 10]).astype(float)
print(X.shape)
# ((X-h)[0] @ (rMatrix)[0])+h

xs, ys, zs = [], [], []
al2d = np.atleast_2d
def W(j, k):
    return ((rMatrix@(al2d(j).T-al2d(k).T))+al2d(k).T).T.squeeze()
for I in range(1001):
#     X=(X-h)@rMatrix+h
#     Y=(rMatrix@(Y-X))+X

    c = map(np.copy, [X, Y, Z])
    X_, Y_, Z_ = c
    X=W(X,h)
    Y=W(Y,X_)
#     Z=W(Z,Y_)
    
    xs+=[X]
    ys+=[Y]
#     zs+=[Z]
print(X)
print(Y)
print(Z)
q=2
plt.plot(np.transpose([np.arange(0,1001)]*q),np.array([xs, ys, zs][:q])[:,:,0].T)
# print(Z)
# loop aggregators
isinstance(R.angles[0], float)
# plt.plot(np.array(R.pivots_)[:,2,:].sum(axis=1))
# np.array(R.pivots_)[:5,1,0]
# R.points