{"id":4118,"date":"2020-06-26T19:49:56","date_gmt":"2020-06-26T23:49:56","guid":{"rendered":"http:\/\/faculty.fiu.edu\/~theobald\/?page_id=4118"},"modified":"2022-12-16T17:05:20","modified_gmt":"2022-12-16T21:05:20","slug":"complex_fun","status":"publish","type":"page","link":"https:\/\/faculty.fiu.edu\/~theobald\/fun\/complex_fun\/","title":{"rendered":"complex_fun"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"4118\" class=\"elementor elementor-4118\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4184d44 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"4184d44\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-ab274ee\" data-id=\"ab274ee\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-5c7116f elementor-widget elementor-widget-text-editor\" data-id=\"5c7116f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Data analysis in many fields relies on complex functions, which take and return numbers with both real imaginary parts. Despite wide use, really understanding these functions is tough because, with two dimensional input and two dimensional output there is no obvious way to visualize them. You can still understand complex functions in a purely symbolic way, but below is a tool to explore them graphically. I wrote this when I took complex analysis to help understand the functions we were studying. The input (value of z) and output (value of w) are the fields below, with colors (or arrows) that represent angle (hue) and magnitude (brightness). Choose a function from the list, then place your mouse in the input field, where it&#8217;s position specifies the real (left and right) and complex (up and down) value of z. Grid lines are multiples of \u03c0\/2.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-aa40a8f elementor-section-stretched elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"aa40a8f\" data-element_type=\"section\" data-settings=\"{&quot;stretch_section&quot;:&quot;section-stretched&quot;}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-f7c18c8\" data-id=\"f7c18c8\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-549aa63 elementor-widget elementor-widget-html\" data-id=\"549aa63\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<!DOCTYPE HTML>\n<html>\n  <meta charset=\"utf-8\" \/>\n  <style>\n    #marker {\n\tposition: absolute;\n\tz-index: 9;\n\twidth: 8px;\n\theight: 8px;\n    }\n    #w_plot {\n\tmargin: 5px;\n\tdisplay: inline-block;\n\tvertical-align: middle;\n    }\n    #z_plot {\n\tmargin: 5px;\n\tdisplay: inline-block;\n\tvertical-align: middle;\n    }\n    h2.headertekst {\n\ttext-align: center;\n    }\n    .wrapper {\n\tdisplay: inline-block;\n\twhite-space: nowrap;\n    }\n\n  <\/style>\n\n  <head>\n    <script src=https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/mathjs\/7.1.0\/math.js><\/script>\n  <\/head>  \n  \n  <body>\n    <!-- choose a function -->\n    <form id=\"function_input\" onsubmit=\"return false\">\n      <b>Choose a function: <br>\n      <span class=\"wrapper\"><i>w<\/i> = &ensp;<\/b><input type=\"radio\" id=\"z\" name=\"func\" value=\"z\" checked=\"checked\">\n      <label for=\"z\"><i>z<\/i> &ensp; <\/label>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"z**2\" name=\"func\" value=\"z**2\">\n      <label for=\"z**2\"><i>z<\/i><sup>2<\/sup> &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"z**3\" name=\"func\" value=\"z**3\">\n      <label for=\"z**3\"><i>z<\/i><sup>3<\/sup> &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"z**4\" name=\"func\" value=\"z**4\">\n      <label for=\"z**4\"><i>z<\/i><sup>4<\/sup> &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"exp\" name=\"func\" value=\"exp\">\n      <label for=\"exp\">e<sup><i>z<\/i><\/sup> &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"ln\" name=\"func\" value=\"ln\">\n      <label for=\"ln\">ln(<i>z<\/i>) &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"sin\" name=\"func\" value=\"sin\">\n      <label for=\"sin\">sin(<i>z<\/i>) &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"cos\" name=\"func\" value=\"cos\">\n      <label for=\"cos\">cos(<i>z<\/i>) &ensp; <\/label><\/span>\n      <span class=\"wrapper\"><input type=\"radio\" id=\"tan\" name=\"func\" value=\"tan\">\n      <label for=\"tan\">tan(<i>z<\/i>) &ensp; <\/label><\/span><br><br>\n      <span class=\"wrapper\">Or enter a custom function of <i>z<\/i>, such as z^3+1 or sin(20\/z):<br> <b><i>w<\/i> = <\/b>\n      <input type=\"radio\" id=\"custom\" name=\"func\" value=\"custom\">\n      <input type=\"text\" id=\"customtext\" name=\"functext\" size=\"5\"><\/span><br><br>\n    <\/form>\n\n    <!-- draggable  marker -->\n    <svg id=\"marker\" width=\"8\" height=\"8\">\n      <circle id=\"outmark\" cx=\"4\" cy=\"4\" r=\"4\"\n    \t      stroke=\"white\" stroke-width=\"1\" fill=\"black\" \/>\n      Sorry, your browser does not support inline SVG.\n    <\/svg>\n\n    <!-- w and z plots -->\n    <div>\n      <h2 id=\"label_eq\" class=\"headertekst\"><i>z<\/i> = <i>z<\/i><\/h2>\n      <span id=\"z_plot\"> \n\t<label id=\"label z\"><i>z<\/i> (input - move mouse in here)<\/label>\n\t<label id=\"info_z\">z<\/label><br>\n\t<canvas id=\"canvas_z\" width=\"480\" height=\"480\" onmousemove=\"mouse_in_canvas_z(event)\"><\/canvas>\n      <\/span>\n      <span id=\"w_plot\"> \n\t<label id=\"label_w\"><i>w<\/i> (output)<\/label>\n\t<label id=\"info_w\">w<\/label><br>\n\t<canvas id=\"canvas_w\" width=\"480\" height=\"480\"><\/canvas>\n      <\/span>\n    <\/div>\n\n    <!-- color or quiver selection -->\n    <div>\n    <form id=\"domain_input\">     <b>domain representation: <\/b><br>\n      <input type=\"radio\" id=\"colors\" name=\"domain\" value=\"color\" checked=\"checked\">\n      <label for=\"z\">soapbubble, colors are beautiful! &ensp;<br> <\/label>\n      <input type=\"radio\" id=\"quiver\" name=\"domain\" value=\"quiver\">\n      <label for=\"z\">quiver arrows, I hate colors! &ensp; <\/label>\n    <\/div>\n\n    <!-- javascript -->\n    <script type=\"text\/javascript\">\n      'use strict';\n      var eq = document.getElementById(\"label_eq\");\n      var func_radio = document.getElementById(\"function_input\");\n      var dom_radio = document.getElementById(\"domain_input\");\n      const custom_input = document.getElementById(\"customtext\");\n\n      \/\/ soapbubble colors for complex magnitudes and angles \n      function cm_soapbubble(x, y) { \/\/x = 0 -- 1, y= -pi -- pi\n\t  var r = Math.min(Math.max(Math.round(-57.4*Math.sin(y + 4.5) +x*265.1 + -20.3), 0), 255);\n\t  var g = Math.min(Math.max(Math.round(20.6*Math.sin(y + -1.5) +x*253.5 + -14.3), 0), 255);\n\t  var b = Math.min(Math.max(Math.round(57.1*Math.sin(y + 3.2) +x*234.6 + -4.3), 0), 255);\n\t  return \"rgb(\"+r+\",\"+g+\",\"+b+\")\";\n      }\n      \n      function get_complex_color(r, i) {\n\t  var arg = Math.atan2(i, r) + .75*Math.PI;\n\t  var mod = Math.sqrt(r**2 + i**2);\n\t  var lmod = Math.log(mod) \/Math.log(1.9);\n\t  var llmod = 1\/(1 + Math.exp(-.5*Math.log(mod))); \/\/logistic curve---always 0 to 1\n\t  return cm_soapbubble(llmod, arg)\n      }\n\n      function mouse_in_canvas_z(e) {\n\t  var rect = zd.canvas.getBoundingClientRect();\n\t  var zx = e.clientX - rect.left;\n\t  var zy = e.clientY - rect.top;\n\t  var zval = zd.xy_to_ri(zx, zy);\n\t  var wval = zd.in_to_out(zval.r, zval.i);\n\t  var wxy = wd.ri_to_xy(wval.r, wval.i);\n\t  \/\/ var zpnt = \"(\" + Math.trunc(zval.r*100)\/100 + \" + \" + Math.trunc(zval.i*100)\/100 + \"i)\";\n\t  var zpnt = \"(\" + zval.r.toPrecision(3) + \" + \" + zval.i.toPrecision(3) + \"i)\";\n\t  document.getElementById(\"info_z\").innerHTML = zpnt;\n\t  \/\/ var wpnt = \"(\" + Math.trunc(wval.r*100)\/100 + \" + \" + Math.trunc(wval.i*100)\/100 + \"i)\";\n\t  var wpnt = \"(\" + wval.r.toPrecision(3) + \" + \" + wval.i.toPrecision(3) + \"i)\";\n\t  document.getElementById(\"info_w\").innerHTML = wpnt;\n\t  markout.style.left = Math.round(wxy.x-markout_width\/2)+\"px\";\n\t  markout.style.top = Math.round(wxy.y-markout_width\/2)+\"px\";\n      }\n\n      class Complex_display {\n\t  constructor(canvas) {\n\t      this.canvas = canvas;\n\t      this.ctx = canvas.getContext('2d');\n\t      this.rmin = -7;\n\t      this.rmax = 7;\n\t      this.imin = -7;\n\t      this.imax = 7;\n\t      this.wr = (r, i) => r;\n\t      this.wi = (r, i) => i;\n\t      this.cr;\n\t      this.ci;\n\t      this.dom = \"color\";\n\t      this.v1=0;\n\t      this.v2=0;\n\t      this.v3=0;\n\t      this.v4=0;\n\t  }\n\n\t  interp(x, x0, x1, y0, y1) {\n\t      return y0 + (x - x0)*((y1-y0)\/(x1-x0));\n\t  }\n\n\t  set_func_from_radio() {\n\t      var i;\n\t      var func = document.getElementsByName('func');\n\t      for(i = 0; i < func.length; i++) { \n                  if(func[i].checked) {\n\t\t      this.set_eq(func[i].value);\n\t\t      break;\n\t\t  }\n\t      }\n\t  }\n\n\t  set_dom_from_radio() {\n\t      var i;\n\t      var dom = document.getElementsByName('domain');\n\t      for(i = 0; i < dom.length; i++) { \n                  if(dom[i].checked) {\n\t\t      this.dom = dom[i].value;\n\t\t      break;\n\t\t  }\n\t      }\n\t  }\n\n\t  \n\t  set_eq(new_eq) {\n\t      var equation = \"z\";\n\t      switch (new_eq) {\n\t      case \"z\":\n\t\t  this.wr = (r, i) => r;\n\t\t  this.wi = (r, i) => i;\n\t\t  equation = \"<i>w<\/i> = <i>z<\/i> = |<i>z<\/i>|e<sup>i<i>&theta;<\/i><\/sup> = <i>x<\/i> + i<i>y<\/i>\";\n\t\t  break;\n\t      case \"z**2\":\n\t\t  this.wr = (r, i) => r**2 - i**2;\n\t\t  this.wi = (r, i) => 2*i*r;\n\t\t  equation = \"<i>w<\/i> = <i>z<\/i><sup>2<\/sup> = |<i>z<sup>2<\/sup><\/i>|e<sup>2i<i>&theta;<\/i><\/sup> = <i>x<\/i><sup>2<\/sup> + 2i<i>xy<\/i> - i<i>y<\/i><sup>2<\/sup>\";\n\t\t  break;\n\t      case \"z**3\":\n\t\t  this.wr = (r, i) => r**3 - 3*r*i**2;\n\t\t  this.wi = (r, i) => 3*r**2*i - i**3;\n\t\t  equation = \"<i>w<\/i> = <i>z<\/i><sup>3<\/sup> = |<i>z<sup>3<\/sup><\/i>|e<sup>3i<i>&theta;<\/i><\/sup> = <i>x<\/i><sup>3<\/sup> + 3i<i>x<\/i><sup>2<\/sup><i>y<\/i> - 3<i>x<\/i><i>y<\/i><sup>2<\/sup> - i<i>y<\/i><sup>3<\/sup>\";\n\t\t  break;\n\t      case \"z**4\":\n\t\t  this.wr = (r, i) => r**4 - 6*r**2*i**2 + i**4;\n\t\t  this.wi = (r, i) => 4*i*r**3 - 4*i**3*r;\n\t\t  equation = \"<i>w<\/i> = <i>z<\/i><sup>4<\/sup> = |<i>z<sup>4<\/sup><\/i>|e<sup>4i<i>&theta;<\/i><\/sup> = <i>x<\/i><sup>4<\/sup> + 4i<i>x<\/i><sup>3<\/sup><i>y<\/i> - 6<i>x<\/i><sup>2<\/sup><i>y<\/i><sup>2<\/sup> - 4i<i>x<\/i><i>y<\/i><sup>3<\/sup> + <i>y<\/i><sup>4<\/sup>\";\n\t\t  break;\n\t      case \"exp\":\n\t\t  this.wr = (r, i) => Math.exp(r)*Math.cos(i);\n\t\t  this.wi = (r, i) => Math.exp(r)*Math.sin(i);\n\t\t  equation = \"<i>w<\/i> = e<sup><i>z<\/i><\/sup>  = e<sup><i>x<\/i> + i<i>y<\/i><\/sup> = e<sup><i>x<\/i><\/sup>e<sup>i<i>y<\/i><\/sup> = e<sup><i>x<\/i><\/sup>(cos <i>y<\/i> + i sin <i>y<\/i>)\";\n\t\t  break;\n\t      case \"ln\":\n\t\t  this.wr = (r, i) => Math.log(Math.sqrt(r**2 + i**2));\n\t\t  this.wi = (r, i) => Math.atan2(i, r);\n\t\t  equation = \"<i>w<\/i> = ln<sub>e<\/sub> <i>z<\/i> = ln<sub>e<\/sub> |<i>z<\/i>| + i<i>&theta;<\/i> = ln<sub>e<\/sub> <math><msqrt><mi><i>x<\/i><sup>2<\/sup> + <i>y<\/i><sup>2<\/sup><\/mi><\/msqrt><\/math> + i tan<sup>-1<\/sup> y\/z\";\n\t\t  break;\n\t      case \"sin\":\n\t\t  this.wr = (r, i) => Math.sin(r)*Math.cosh(i);\n\t\t  this.wi = (r, i) => Math.cos(r)*Math.sinh(i);\n\t\t  equation = \"<i>w<\/i> = sin <i>z<\/i> = (e<sup>i<i>z<\/i><\/sup> - e<sup>-i<i>z<\/i><\/sup>)\/2i\";\n\t\t  break;\n\t      case \"cos\":\n\t\t  this.wr = (r, i) => Math.cos(r)*Math.cosh(i);\n\t\t  this.wi = (r, i) => -Math.sin(r)*Math.sinh(i);\n\t\t  equation = \"<i>w<\/i> = cos <i>z<\/i> = (e<sup>i<i>z<\/i><\/sup> + e<sup>-i<i>z<\/i><\/sup>)\/2\";\n\t\t  break;\n\t      case \"tan\":\n\t\t  this.wr = (r, i) => Math.sin(2*r)\/(Math.cos(2*r) + Math.cosh(2*i));\n\t\t  this.wi = (r, i) => Math.sinh(2*i)\/(Math.cos(2*r) + Math.cosh(2*i));\n\t\t  equation = \"<i>w<\/i> = tan <i>z<\/i> = (e<sup>i<i>z<\/i><\/sup> - e<sup>-i<i>z<\/i><\/sup>)\/(i e<sup>i<i>z<\/i><\/sup> + i e<sup>-i<i>z<\/i><\/sup>)\";\n\t\t  break;\n\t      case \"custom\":\n\t\t  var se = document.getElementById(\"customtext\").value;\n\t\t  se = se.replace(\/\\*\\*\/g, \"^\")\n\t\t  se = se.replace(\/z\/g, \"(x + y*i)\")\n\t\t  if (se==\"\") se = \"0\";\n\t\t  this.cr = math.compile(\"re(\"+se+\")\");\n\t\t  this.ci = math.compile(\"im(\"+se+\")\");\n\t\t  this.wr = (r, i) => this.cr.evaluate({x:r, y:i});\n\t\t  this.wi = (r, i) => this.ci.evaluate({x:r, y:i});\n\t\t  equation = \"<i>w<\/i> = \" + se;\n\t\t  break;\n\t      }\n\t      document.getElementById(\"label_eq\").innerHTML = equation;\n\t      \/\/ this.domain_color();\n\t      this.draw_domain();\n\t  }\n\t  \n\t  domain_color() {\n\t      var x, y, zr, zi;\n\t      for (x=0; x<this.canvas.width; x++) {\n\t\t  for (y=0; y<this.canvas.height; y++) {\n\t\t      zr = this.interp(x, 0, this.canvas.width, this.rmin, this.rmax);\n\t\t      zi = this.interp(y, this.canvas.height, 0, this.imin, this.imax);\n\t\t      this.ctx.fillStyle = get_complex_color(this.wr(zr, zi),this.wi(zr, zi));\n\t\t      this.ctx.fillRect(x,y,1,1);\n\t\t  }\n\t      }\n\t  }\n\n\t  draw_arrow(x, y, r, i) {\n\t      var lmod = Math.log(Math.sqrt(r**2 + i**2))\/Math.log(1.3);\n\t      var llmod = 6\/(1 + Math.exp(-.5*lmod)); \/\/logistic curve---always 0 to 1\n\t      var ang = Math.atan2(i, r);\n\t      var dx = llmod*Math.cos(ang);\n\t      var dy = llmod*Math.sin(ang);\n\t      var dx1 = .7*llmod*Math.cos(ang+Math.PI\/3);\n\t      var dy1 = .7*llmod*Math.sin(ang+Math.PI\/3);\n\t      var dx2 = .7*llmod*Math.cos(ang-Math.PI\/3);\n\t      var dy2 = .7*llmod*Math.sin(ang-Math.PI\/3);\n\t      this.ctx.strokeStyle = \"black\";\n\t      this.ctx.beginPath();\n\t      this.ctx.lineWidth = 2\/(1 + Math.exp(-.05*lmod)) + .1\n\t      this.ctx.moveTo(x-dx, y+dy);\n\t      this.ctx.lineTo(x+.3*dx, y-.3*dy);\n\t      this.ctx.stroke();\n\t      this.ctx.fillStyle = \"black\";\n\t      this.ctx.lineWidth = .5\n\t      this.ctx.beginPath();\n\t      this.ctx.moveTo(x+dx, y-dy);\n\t      this.ctx.lineTo(x+dx1, y-dy1);\n\t      this.ctx.lineTo(x+dx2, y-dy2);\n\t      this.ctx.fill();\n\t      \n\t  }\n\t  \n\t  \n\t  domain_quiver() {\n\t      var x, y, zr, zi;\n\t      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\n\t      for (x=40; x<this.canvas.width; x+=20) {\n\t\t  for (y=0; y<this.canvas.height-20; y+=20) {\n\t\t      zr = this.interp(x, 0, this.canvas.width, this.rmin, this.rmax);\n\t       \t      zi = this.interp(y, this.canvas.height, 0, this.imin, this.imax);\n\t       \t      this.draw_arrow(x, y, this.wr(zr, zi), this.wi(zr, zi));\n\t       \t  }\n\t       }\n\t  }\n\n\t  draw_line(x0, y0, x1, y1, color, dash) {\n\t      \/\/ this.ctx.setLineDash([1, dash]);\n\t      this.ctx.lineWidth = 1;\n\t      this.ctx.setLineDash(dash);\n\t      this.ctx.strokeStyle = color;\n\t      this.ctx.beginPath();\n\t      this.ctx.moveTo(x0, y0);\n\t      this.ctx.lineTo(x1, y1);\n\t      this.ctx.fillStyle = color;\n\t      this.ctx.stroke();\n\t  }\n\t  \n\t  write_label(posx, posy, symbol, aftersym, centerx, centery) {\n\t      this.ctx.font = \"12px Ariel\";\n\t      if (centery==1) this.ctx.textBaseline = \"middle\";\n\t      if (centery==0) this.ctx.textBaseline = \"bottom\";\n\t      if (centerx==1) this.ctx.textAlign = \"center\";\n\t      if (centerx==0) this.ctx.textAlign = \"right\";\n\t      this.ctx.fillText(symbol + aftersym, posx, posy);\n\t  }\n\n\t  draw_h_line(pos, start, stop, color, dash, symbol, aftersym, centerx, centery) {\n\t      var w0 = this.canvas.width*start;\n\t      var w1 = this.canvas.width*stop;\n\t      var y = Math.round(this.interp(pos, this.rmin, this.rmax, 0, this.canvas.width));\n\t      this.draw_line(w0, y, w1, y, color, dash);\n\t      this.write_label(this.canvas.width*start-2, y, symbol, aftersym, centerx, centery);\n\t  }\n\t  \n\t  draw_v_line(pos, start, stop, color, dash, symbol, aftersym, centerx, centery) {\n\t      var h0 = this.canvas.height*start;\n\t      var h1 = this.canvas.height*stop;\n\t      var x = Math.round(this.interp(pos, this.imin, this.imax, 0, this.canvas.height));\n\t      this.draw_line(x, h0, x, h1, color, dash);\n\t      this.write_label(x,this.canvas.height, symbol, aftersym, centerx, centery);\n\t  }\n\n\t  draw_lines (color) {\n\t      var i, dash;\n\t      \/\/ fractions of pi\n\t      for (i=this.rmin - (this.rmin%(Math.PI\/2)); i<this.rmax; i+=Math.PI\/2) {\n\t\t  if (i==0) dash=[1,1];\n\t\t  if (i!=0) dash=[1,4];\n\t\t  this.draw_h_line(i, 0.05, 1, color, dash, \"\", \"\", 0, 0);\n\t      }\n\t      for (i=this.imin - (this.imin%(Math.PI\/2)); i<this.imax; i+=Math.PI\/2) {\n\t\t  if (i==0) dash=[1,1];\n\t\t  if (i!=0) dash=[1,4];\n\t\t  this.draw_v_line(i, 0, .95, color, dash, \"\", \"\", 0, 0);\n\t      }\n\t      for (i=this.rmin - (this.rmin%1); i<this.rmax; i+=1) {\n\t      if (i<0) this.draw_v_line(i, .95, .97, color, [1,0], i, \" \", 1, 0);\n\t      if (i>=0) this.draw_v_line(i, .95, .97, color, [1,0], i, \"\", 1, 0);\n\t      }\n\t      for (i=this.imin - (this.imin%1); i<this.imax; i+=1) {\n\t\t  this.draw_h_line(i, .04, .06, color, [1,0], -i, \"i\", 0, 1);\n\t      }\n\t  }\n\n\t  draw_domain() {\n\t      switch (this.dom) {\n\t      case \"color\":\n\t       \t  this.domain_color();\n\t\t  this.draw_lines(\"white\");\n\t       \t  break;\n\t      case \"quiver\":\n\t       \t  this.domain_quiver();\n\t\t  this.draw_lines(\"black\");\n\t       \t  break;\n\t      }\n\t  }\n\n\n\t  \/\/ translate the pixel value inside the canvas to a number\n\t  \/\/ with real and imaginary components\n\t  xy_to_ri(x, y) {\n\t      var r = this.interp(x, 0, this.canvas.width, this.rmin, this.rmax);\n\t      var i = this.interp(y, 0, this.canvas.height, this.imax, this.imin);\n\t      return {\n\t\t  r: r,\n\t\t  i: i,\n\t      }\n\t  }\n\n\t  \/\/ translate an input value with real and imaginary\n\t  \/\/ components to a complex output depending on the current function\n\t  in_to_out(r, i) {\n\t      return {\n\t\t  r: this.wr(r, i),\n\t\t  i: this.wi(r, i),\n\t      }\n\t  }\n\n\t  \/\/ translate a real and imaginary component to an x and y\n\t  \/\/ value in pixels\n\t  ri_to_xy(r, i) {\n\t      var x = this.interp(r, this.rmin, this.rmax, this.canvas.offsetLeft, this.canvas.offsetLeft + this.canvas.offsetWidth);\n\t      var y = this.interp(i, this.imax, this.imin, this.canvas.offsetTop, this.canvas.offsetTop + this.canvas.offsetHeight);\n\t      return {\n\t\t  x: Math.min(Math.max(x, this.canvas.offsetLeft), this.canvas.offsetLeft + this.canvas.offsetWidth),\n\t\t  y: Math.min(Math.max(y, this.canvas.offsetTop), this.canvas.offsetTop + this.canvas.offsetHeight),\n\t      }\n\t  }\n      }\n\n\n\n\n      \n      var wd = new Complex_display(document.getElementById(\"canvas_w\"));\n      wd.set_dom_from_radio();\n      wd.set_eq(\"z\");\n      \n      var zd = new Complex_display(document.getElementById(\"canvas_z\"));\n      zd.set_dom_from_radio();\n      zd.set_func_from_radio();\n      func_radio.onchange = function () {zd.set_func_from_radio()};\n      dom_radio.onchange = function () {zd.set_dom_from_radio();\n\t\t\t\t\tzd.draw_domain();\n\t\t\t\t\twd.set_dom_from_radio();\n\t\t\t\t\twd.draw_domain();};\n      \n      \/\/ if you enter a custom function, select custom radio\n      custom_input.addEventListener('keyup', ({key}) => {\n\t  if (key === \"Enter\") {\n\t      document.getElementById(\"custom\").checked = true;\n\t      zd.set_func_from_radio();\n\t  }\n      })\n      \n      var markout = document.getElementById(\"marker\");\n      var markout_width = 8;\n      \n    <\/script>\n    \n\n  <\/body>\n<\/html>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-b7224f8 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"b7224f8\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-c5d7c8b\" data-id=\"c5d7c8b\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-d3451d0 elementor-widget elementor-widget-text-editor\" data-id=\"d3451d0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p><strong>Plotting functions<\/strong> with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Function_of_a_real_variable\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">real inputs and outputs<\/span><\/a> is straightforward &#8211; they have a one-dimensional input and a one-dimensional output, total of two dimensions that fit on a piece of paper. We have to rotate the output dimension compared to the input, even though input and output are actually both on the same, real line. But these plots give you a better understanding of a function than you could ever get from just reading an equation. For <a href=\"https:\/\/en.wikipedia.org\/wiki\/Complex_analysis\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">complex functions<\/span><\/a>, though, we need two dimensions just to specify input (the real and imaginary parts lie on different lines), so all the perpendicular directions on the paper are used up before we even get to the output. We can solve this problem with color.<\/p><p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_coloring\" target=\"_blank\" rel=\"noopener\"><strong><span style=\"color: #3366ff;\">Domain coloring<\/span><\/strong><\/a> is a way to visualize complex functions. The two dimensions of a plot are both for input, then the hue and brightness represent the function&#8217;s output. But this requires discerning both hue and brightness, and for most color maps those qualities are perceptually confounded, like those on <a href=\"https:\/\/en.wikipedia.org\/wiki\/Domain_coloring#Simple_color_function\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">wikipedia<\/span><\/a>., where the blues look much darker than the yellows even when they represent the same magnitude. <a href=\"https:\/\/matplotlib.org\/\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">Matplotlib<\/span><\/a> for the <a href=\"https:\/\/www.python.org\/\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">Python<\/span><\/a> programming language has spectacular color tools that let you create <a href=\"https:\/\/matplotlib.org\/tutorials\/colors\/colormaps.html\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">color maps<\/span><\/a>. We used the <code>colorspacious<\/code> module to generate a map (called soapbubble, approximated here in <a href=\"https:\/\/en.wikibooks.org\/wiki\/JavaScript\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">javascript<\/span><\/a>) for which hue and lightness are perceptually independent. This makes it easier to interpret the magnitude of, for example, the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Exponential_function\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">exponential function<\/span><\/a>, where the modulus, depends only on the real part of the input and stays the same over vertical tracts. Compare the domain coloring of the exponential here to that on <a href=\"https:\/\/en.wikipedia.org\/wiki\/Exponential_function#Complex_plane\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">wikipedia<\/span><\/a> to see the difference.<\/p><p><strong>Output pointer tracking<\/strong>. This color scheme is unfriendly for those with <a href=\"https:\/\/en.wikipedia.org\/wiki\/Color_blindness\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">color deficiencies<\/span><\/a>, a set of common conditions which make it difficult to discriminate hues (especially here, where hue is uncorrelated to lightness). So to complement domain coloring, you can move your pointer in the input plot and see the calculated output. The color under your pointer indicates where you will land on the output plot, roughly green and purple for positive and negative real numbers, blue and orange for positive and negative imaginary numbers. Additionally, set the domain representation to the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Vector_field\" target=\"_blank\" rel=\"noopener\"><span style=\"color: #3366ff;\">quiver plot<\/span><\/a> option, which requires no color vision. Here, the arrows in the z plot represent locations on the w, output plot. It&#8217;s tempting to see it as a flow field, but the arrows aren&#8217;t pointing to adjacent locations so much as they are indicating the location of a number on the complex plane. Again, move your pointer in the z plot to see its mapping in the w plot.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Data analysis in many fields relies on complex functions, which take and return numbers with both real imaginary parts. Despite wide use, really understanding these functions is tough because, with two dimensional input and two dimensional output there is no obvious way to visualize them. You can still understand complex functions in a purely symbolic [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":4040,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-4118","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/pages\/4118","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/comments?post=4118"}],"version-history":[{"count":60,"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/pages\/4118\/revisions"}],"predecessor-version":[{"id":4397,"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/pages\/4118\/revisions\/4397"}],"up":[{"embeddable":true,"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/pages\/4040"}],"wp:attachment":[{"href":"https:\/\/faculty.fiu.edu\/~theobald\/wp-json\/wp\/v2\/media?parent=4118"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}