Visualizing Complex Functions
Complex functions are known to be difficult to visualize because doing so requires operating in four dimensions -- the two dimensions of the domain and the two dimensions of the image. Unfortunately, we only have three spatial dimensions for visualizing things. This is in stark contrast with the case of real functions, which only require two dimensions and can be readily visualized.
For a long time, I thought that complex functions couldn't really be visualized. When I entered the world of data science and learned more about data visualization techniques, I learned that one way to incorporate an additional dimension is to use color in your plots. As it turns out, this is a great tool for adding the extra dimension that we need to visualize complex functions!
In the visualization shown above the \(x\) and \(y\) dimensions are used for the domain of the complex function. The \(z\) dimension represents the magnitude of the evaluated function (Actually it represents \(\log(1 + |f(z)|)\) just so that the values don't go off to infinity too quickly). For the final dimension, I used color to represent the polar angle.
I took a quick look around and it seems like I'm not the first person to think about using color for the polar angle. In some of these visualizations, the luminescence of the color is used to encode the magnitude of the function value instead of the vertical coordinate, to keep the plot in two dimensions. I think this loads too much information on to the color to easily interpret.
For complex functions that are a power of \(n\), by focusing on the colors you can see how increasing the \(n\) parameter increases the number of revolutions of the polar angle as one goes around the origin.
For the \(n\)th roots, the use of color allows us to clearly identify the discontinuity when viewing these functions as functions of the complex plane, as opposed to the Riemann surfaces obtained by analytic continuation.
It is also easy to see where the zeros of the function are. They are just the points that sprout the entire rainbow spectrum of colors. The reason for this is that we know that non-constant analytic functions are open maps topologically speaking, and so a neighborhood of a zero gets mapped to an open neighborhood containing the origin, and therefore contains points with every possible polar angle.
We can also see very clearly the difference in behavior of the different kinds of isolated singularities. For \(z^{-n}\), the isolated singularity at zero is a pole, and we see that the magnitude of the values are bounded away from zero as you get closer to the singularity.
On the other hand, we see that \(\exp(1/z)\) is not a pole because its magnitude is not bounded below near the singularity, nor does it converge to any value near the singularity. From the classification of isolated singularities, we know that the only other possibility is that \(z=0\) is an essential singularity. One of Picard's Theorems states that a function with an essential singularity takes on all complex values infinitely many times nearby the singularity, with possibly the exception of one value. Indeed we see that around the essential singularity, the magnitude of \(\exp(1/z)\) ranges from zero to infinity and that the polar angle takes on all values of the rainbow.
If you look at the gamma function, \(Γ(z)\), many recognizable features stand out. We see that it grows very quickly in magnitude for increasing real values of \(z\) which is understandable since it is an extension of the factorial function. We also see the first several poles at the negative integers. As you go further to the left, the poles for the higher negative integers seem to go missing. The coefficient of the pole in the Laurent expansion around \(-n\) is \(1/n!\) and so, for more negative values of \(-n\), the resolution of the visualization quickly becomes insufficient to capture the divergence to infinity. We can nonetheless still identify that there are poles at the negative integers from the fact that the entire rainbow of polar angles can be seen in a small area around those points.
For the color scheme, I wanted a cyclical gradient of colors to reflect the cyclical nature of the polar angle. I achieved this after being inspired by the sinebow color scheme in the Vega Javascript package.
The offset parameter determines where the center of the domain is placed. By changing it, you can see what the function looks like for various parts of the complex plane.
To visualize the Riemann zeta function, I needed a Javascript implementation, and was delighted to find a whole library implementing many special functions by Paul Masson. At his website, Paul Masson has already created all of the visualizations I have shown here along with many others.