Plotly plot of the Riemann surface, real part of square root, $\Re(\sqrt{z})$


In [9]:
import numpy as np
from numpy import pi
import matplotlib.colors
import plotly.graph_objects as go
import plotly
plotly.offline.init_notebook_mode()


The following function defines a Plotly HSV (Hue, Saturation, Value) colorscale that will be used for coloring the branches of a Riemann surface according to the argument on each branch (i.e. using the domain coloring method; see here and here).


In [10]:
def hsv_colorscale(S=1, V=1, ty=1): 
    # S saturation in [0,1]
    # V value (brightness in [0,1])
    # ty a key that can take two values: 1, when the argument belongs to [-pi, pi) is mapped to the HSV colorscale,
    #                                    2,                              [0, 2*pi)
    if S < 0 or S > 1 or V < 0 or V > 1:
        raise ValueError('Parameters S (saturation), V (value, brightness) must be in [0,1]')
    if ty == 1:
        argument = np.array([-pi, -5*pi/6, -2*pi/3, -3*pi/6, -pi/3,  -pi/6, 0, 
                              pi/6, pi/3, 3*pi/6, 2*pi/3, 5*pi/6, pi])
        H = argument/(2*np.pi)+1               
        H = np.mod(H,1) # Hue
    elif ty == 2:
        argument = np.array([ 0, pi/6, pi/3, 3*pi/6, 2*pi/3, 5*pi/6, pi, 
                            7*pi/6, 4*pi/3, 3*pi/2, 5*pi/3, 11*pi/6, 2*pi])
        H = argument/(2*np.pi)
    else:
        raise ValueError("The key ty can get only the value 1 or 2")
     
    Sat = S*np.ones_like(H)
    Val = V*np.ones_like(H)
    
    HSV = np.dstack((H, Sat, Val))
    RGB = matplotlib.colors.hsv_to_rgb(HSV) 
   
    colormap = (255* np.squeeze(RGB)).astype(int) 
    
    #Define and return the Plotly hsv colorscale adapted to polar coordinates for complex valued functions
    step_size = 1/(colormap.shape[0]-1)
    #return [[round(k*step_size, 3), 'rgb'+str((int(c[0]), int(c[1]), int(c[2])))] for k, c in enumerate(colormap)]
    return [[round(k*step_size, 3), f'rgb{tuple(c)}'] for k, c in enumerate(colormap)]

Example of HSV colorscale:


In [11]:
mpl_hsv = hsv_colorscale(V=0.95)
mpl_hsv


Out[11]:
[[0.0, 'rgb(0, 242, 242)'],
 [0.083, 'rgb(0, 121, 242)'],
 [0.167, 'rgb(0, 0, 242)'],
 [0.25, 'rgb(121, 0, 242)'],
 [0.333, 'rgb(242, 0, 242)'],
 [0.417, 'rgb(242, 0, 121)'],
 [0.5, 'rgb(242, 0, 0)'],
 [0.583, 'rgb(242, 121, 0)'],
 [0.667, 'rgb(242, 242, 0)'],
 [0.75, 'rgb(121, 242, 0)'],
 [0.833, 'rgb(0, 242, 0)'],
 [0.917, 'rgb(0, 242, 121)'],
 [1.0, 'rgb(0, 242, 242)']]

Define two HSV colorscales, one for each branch:


In [12]:
pl_hsv1 = hsv_colorscale(S=1, V=0.95, ty=1)
pl_hsv2 = hsv_colorscale(S=1, V=0.95, ty=2)

In [13]:
rho = np.linspace(0, 1.0, 40)
phi = np.linspace(-np.pi, np.pi, 200)
rho, phi = np.meshgrid(rho,phi)
X = rho*np.cos(phi)
Y = rho*np.sin(phi)
Z = X + 1j * Y
r = np.absolute(Z)
argument = np.angle(Z)
wmod = r**0.5
argument /= 2# argument of w=sqrt[2](z) ; argument in [-pi/2, pi/2)
realf = wmod * np.cos(argument)

fig = go.Figure(go.Surface(x=X, y=Y, z=realf, 
                    colorscale=pl_hsv1,
                    surfacecolor= argument,
                    cmin=-pi, cmax=pi,
                    showscale=False))
   
argument += 2* pi / 2# argument for the second branch; argument in [-pi/2+pi, pi/2+pi)=[pi/2, 3 pi/2]
realf = wmod * np.cos(argument)
fig.add_surface(x=X, y=Y, z=realf, 
                colorscale=pl_hsv2,
                surfacecolor=np.copy(argument),
                cmin=0, cmax=2*pi,
                showscale=False) 
plot_title = 'Riemann surface Re(sqrt(z))), hsv colored<br> according to the argument values on each branch'
fig.update_layout(title_text=plot_title,
                  title_x=0.5,
                  font=dict(family='Balto'),
                  width=600,
                  height=600)
fig.update_scenes(xaxis_title='Re(z)',
                  yaxis_title='Im(z)', 
                  zaxis_title='Re(f(z))')



In [14]:
from IPython.core.display import HTML
def  css_styling():
    styles = open("./custom.css", "r").read()
    return HTML(styles)
css_styling()


Out[14]: