{ "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 }