import plotly.graph_objects as go
import numpy as np
Plotly version of the HSV colorscale, corresponding to S=1, V=1, where S is saturation and V is the value.
pl_hsv = [[0.0, 'rgb(0, 255, 255)'],
[0.0833, 'rgb(0, 127, 255)'],
[0.1667, 'rgb(0, 0, 255)'],
[0.25, 'rgb(127, 0, 255)'],
[0.3333, 'rgb(255, 0, 255)'],
[0.4167, 'rgb(255, 0, 127)'],
[0.5, 'rgb(255, 0, 0)'],
[0.5833, 'rgb(255, 127, 0)'],
[0.6667, 'rgb(254, 255, 0)'],
[0.75, 'rgb(127, 255, 0)'],
[0.8333, 'rgb(0, 255, 0)'],
[0.9167, 'rgb(0, 255, 127)'],
[1.0, 'rgb(0, 255, 255)']]
def evaluate_function(func, re=(-1,1), im=(-1,1), N=100):
# func is the complex function to be ploted
# re, im are the interval ends on the real and imaginary axes, defining the rectangular region in the complex plane
# N gives the number of points in an interval of length 1
l = re[1]-re[0]
h = im[1]-im[0]
resL = int(N*l) #horizontal resolution
resH = int(N*h) #vertical resolution
X = np.linspace(re[0], re[1], resL)
Y = np.linspace(im[0], im[1], resH)
x, y = np.meshgrid(X,Y)
z = x+1j*y
return X, Y, z
For a particular parameter, the corresponding function of the given family is represented as heatmap of its argument, which illustrates its zeros and poles position.
Define tickvals and ticktext for the heatmap colorbar
tickvals = [-np.pi, -2*np.pi/3, -np.pi/3, 0, np.pi/3, 2*np.pi/3, np.pi]
ticktext=['-\u03c0', '-2\u03c0/3', '-\u03c0/3', '0', '\u03c0/3', '2\u03c0/3', '\u03c0']
Define a family of complex functions, depending on the parameter t. To animate the motion of function zeros and poles, as t varies,
we use functools.partial
to get the
function corresponding to a particular parameter:
from functools import partial
def func(t, z):
return z**4+np.exp(2*t*1j)/z**2*np.exp(1j*t)
f0 = partial(func, 0)
x, y, z = evaluate_function(f0, re=(-1.5, 1.5), im=(-1.5,1.5), N=50)
w = f0(z)
argument = np.angle(w)
fig = go.Figure(go.Heatmap(x=x, y=y, z=argument, colorscale=pl_hsv,
colorbar=dict(thickness=20, tickvals=tickvals,
ticktext=ticktext,
title='arg(f(z))')))
frames = []
t = np.linspace(0, 3, 45) #6, 85
for s in t:
g = partial(func, s)
w = g(z)
argument = np.angle(w)
frames.append(go.Frame(data=[go.Heatmap(z=argument)]))
fig.update(frames=frames);
fig.update_layout(width=500, height=475,
updatemenus=[dict(type='buttons',
y=1,
x=1.45,
active=0,
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=10,
redraw=True),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate')])])]);
fig.show()