import numpy as np import pandas as pd import datashader as ds import panel as pn from numba import jit from datashader import transfer_functions as tf from colorcet import palette_n pn.extension() @jit(nopython=True) def clifford_trajectory(a, b, c, d, x0, y0, n): xs, ys = np.zeros(n), np.zeros(n) xs[0], ys[0] = x0, y0 for i in np.arange(n-1): xs[i+1] = np.sin(a * ys[i]) + c * np.cos(a * xs[i]) ys[i+1] = np.sin(b * xs[i]) + d * np.cos(b * ys[i]) return xs, ys ps = {k:p[::-1] for k,p in palette_n.items()} def clifford_plot(a=1.9, b=1.9, c=1.9, d=0.8, n=1000000, cmap=ps['kbc']): cvs = ds.Canvas(plot_width=600, plot_height=600) xs, ys = clifford_trajectory(a, b, c, d, 0, 0, n) df = pd.DataFrame(dict(x=xs,y=ys)) agg = cvs.points(df, 'x', 'y') return tf.shade(agg, cmap=cmap) pane = pn.interact(clifford_plot, a=(0,2), b=(0,2), c=(0,2), d=(0,2), n=(1,2e7), cmap=ps) logo = "https://tinyurl.com/y9c2zn65/logo_stacked_s.png" text = """

Use the widgets to vary the parameters of this Clifford attractor.

Note that many values result in nearly blank plots that contain only a few scattered points.

""" pn.Row(pn.Column(logo, text, pane[0]), pane[1]).servable()