{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analytic lanscape of a complex function"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The colored analytic landscape of a complex function, f, is the graph of the function modulus or log-modulus, colored according to the argument of $f(z)$ at any z in the function domain.\n",
"\n",
"Here we illustrate how defining this surface as an instance of the Plotly class `plotly.graph_objects.Surface`, we can plot the contour lines as well as the surface projection onto a z-plane, that amounts to plotting the domain coloring of the function f.\n",
"We are using the cyclic HSV colorscale to color-encode the argument value. For details on HSV and domain coloring see this Jupyter notebook [https://nbviewer.jupyter.org/github/empet/Math/blob/master/DomainColoring.ipynb](https://nbviewer.jupyter.org/github/empet/Math/blob/master/DomainColoring.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from numpy import pi\n",
"import plotly.graph_objs as go"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def eval_modulus(f, re=(-2.5, 2.5), im=(-2.5, 2.5), N=50, log = False):\n",
" nrx = int(N * (re[1]-re[0]))\n",
" nry = int(N * (im[1]-im[0]))\n",
" x = np.linspace(re[0], re[1], nrx)\n",
" y = np.linspace(im[0], im[1], nry)\n",
" \n",
" x, y = np.meshgrid(x, y)\n",
" z = x + 1j*y\n",
" w = f(z)\n",
" w[np.isinf(w)] = np.nan\n",
" if log:\n",
" modf = np.log(np.absolute(w)) \n",
" else: \n",
" modf = np.absolute(w) # |f|\n",
" return x, y, np.angle(w), modf #np.angle(w) is the argument of f"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"HSV colorscale:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pl_hsv = [[0.0, 'rgb(0, 242, 242)'],\n",
" [0.083, 'rgb(0, 121, 242)'],\n",
" [0.167, 'rgb(0, 0, 242)'],\n",
" [0.25, 'rgb(121, 0, 242)'],\n",
" [0.333, 'rgb(242, 0, 242)'],\n",
" [0.417, 'rgb(242, 0, 121)'],\n",
" [0.5, 'rgb(242, 0, 0)'],\n",
" [0.583, 'rgb(242, 121, 0)'],\n",
" [0.667, 'rgb(242, 242, 0)'],\n",
" [0.75, 'rgb(121, 242, 0)'],\n",
" [0.833, 'rgb(0, 242, 0)'],\n",
" [0.917, 'rgb(0, 242, 121)'],\n",
" [1.0, 'rgb(0, 242, 242)']]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Define `tickvals` and `ticktext` for colorbar:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tickvals=[-np.pi, -2*np.pi/3, -np.pi/3, 0, np.pi/3, 2*np.pi/3, np.pi]\n",
"#define the above values as strings with pi-unicode\n",
"ticktext=['-\\u03c0', '-2\\u03c0/3', '-\\u03c0/3', '0', '\\u03c0/3', '2\\u03c0/3', '\\u03c0']\n",
"\n",
"coloraxis_settings = dict(colorscale= pl_hsv, \n",
" colorbar_thickness=25, \n",
" colorbar_len=0.7, \n",
" colorbar_tickvals=tickvals, \n",
" colorbar_ticktext=ticktext,\n",
" colorbar_title='arg(f)') \n",
"\n",
"def set_contours(min_mod, zrange_max, n=20, color = 'rgb(250, 250, 250)'):\n",
" return dict(start=min_mod,\n",
" end=zrange_max, highlight=True,\n",
" size=(zrange_max-min_mod)/n, \n",
" width=1.5, #contour line width \n",
" color= color,\n",
" project_z=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us plot the analytic landscape of the function f, defined below. \n",
"f has a zero multiple of order 3, and three simple poles."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"f = lambda z: z**3 / (z**3-1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"x, y, argf, modf = eval_modulus(f)\n",
"\n",
"fig1 = go.Figure(go.Surface(x=x[0, :], y=y[:, 0], z=modf, \n",
" surfacecolor=argf, coloraxis='coloraxis'))\n",
"z_range = (-4, 6)\n",
"fig1.update_layout(title_text = '$\\\\text{Analytic landscape of the function}\\: f(z)= \\\\displaystyle\\\\frac{z^3}{z^3-1}$',\n",
" title_x=0.5, \n",
" width=700, height=700,\n",
" coloraxis = coloraxis_settings,\n",
" scene_zaxis_range=z_range);\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Add the surface projection onto the z-plane of equation `z=z_range[0]`, and the contour lines of the plotted surface, and their projection, to illustrate the domain coloring plot of the function f(z) onto this z-plane:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"min_mod = np.min(modf)\n",
"fig1.add_surface(x=x[0, :], y=y[:, 0], z= z_range[0]*np.ones(modf.shape), \n",
" surfacecolor=argf, colorscale= pl_hsv, showscale=False)\n",
"\n",
"fig1.data[0].update(contours_z=dict(show=True, **set_contours(min_mod, z_range[1], n=28, color = 'rgb(250, 250, 250)'))); \n",
"fig1.update_scenes(camera_eye_z=0.75);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#fig1.show() #uncomment to display the fig1 in the next cell"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import IFrame \n",
"IFrame('https://chart-studio.plotly.com/~empet/15742', width=700, height=700)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally let us plot the log modulus of $h(z)= e^{1/z}$:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"h = lambda z: np.exp(1/z)\n",
"x, y, argh, modh = eval_modulus(h, log=True)\n",
"\n",
"fig2=go.Figure(go.Surface(x=x[0, :], y=y[:, 0], z=modh, \n",
" surfacecolor=argh, \n",
" coloraxis='coloraxis'))\n",
"\n",
"\n",
"z_range= (-6, 6)\n",
"\n",
"fig2.update_layout(title_text = '$\\\\text{Analytic landscape of the function}\\: f(z)= e^{1/z}$',\n",
" title_x=0.5, \n",
" width=700, height=700,\n",
" coloraxis = coloraxis_settings,\n",
" scene_zaxis_range=z_range);\n",
"#iplot(fig3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"min_mod = np.min(modh)\n",
"fig2.add_surface(x=x[0, :], y=y[:, 0], z= z_range[0]*np.ones(modh.shape), \n",
" surfacecolor=argh, colorscale= pl_hsv, showscale=False)\n",
"\n",
"fig2.data[0].update(contours_z=dict(show=True, \n",
" start=z_range[0],\n",
" end=z_range[1], highlight=True,\n",
" size=(z_range[1]-z_range[0])/26, \n",
" width=1.5, #contour line width \n",
" color= 'rgb(250,250,250)',\n",
" project_z=True))\n",
"fig2.update_scenes(camera_eye_x=-1.55, camera_eye_y=1.55, camera_eye_z=0.6);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#fig2.show()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
" \n",
" "
],
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"IFrame('https://chart-studio.plotly.com/~empet/15740', width=700, height=700)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Unlike the representation of modulus, $|f}$, the log-modulus, $log(|f|$, has negative values where $0<|f|<1$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}