Complot


complot.h is a single-header simple complex number plotting library for the C programming language. It outputs farbfeld images from arrays of complex numbers. But also has two convenience functions to make plotting a breeze, see the code example.
Above is, in order of appearance, the logarithm, the exponential, the tangent, and the Möbius transform on the unit square.

Method


Complot uses so-called domain coloring to compensate for the fact that the complex-plane is two-dimensional. It can therefore not be plotted by standard methods since the domain is two-dimensional as well, which leaves us with four-dimensions, too much too plot regularly.

Usually one maps the complex argument to the hue of the color and optionally maps the modulus (absolute value) to saturation and/or value. For example one could map large absolute values to black and those around zero to white. Another option is to map the modolus discontinuosly to the saturation-value space. This is usually done to indicate contour lines, for example, paint a black strip when you pass every power of e. That is if x is close to 1, e, e², ..., then map those to a value of zero: black.

Most colorings use a one-to-one map of the argument to the hue. This leaves us with smooth gradients, which in my opinion make it harder to tell what is going on. Therefore I have opted to split the the argument into bands of different hue (see examples below.) I have also decided to go with the method of painting contour lines instead of turning black/white, this leaves us with some pretty fractal-like images in some cases.

Examples


Here is the ubiquitous exp(1/z) which has an essential singularity at zero. It is this singularity that makes the argument change "infinitely" close to zero. Note that the color bands keep changing when the values get closer to zero. Also note the black bands, as stated above these indicate growth of the function. On the right-half-plane the function diverges as z -> 0. But not on the left-half-plane. I think the bands exemplify clearly the argument changing even at low resolution pictures, this one is only 256x256 pixels. Compare with the gradient-coloring below.

Code

Below follows a small example that generates the image above.
/* cexpinvplot.c: plots e^(1/z) on the unit square */
#include <complex.h>

#include "complot.h"

#define DIM 256

complex double
cexpinv(complex double z)
{
	return cexp(1 / z);
}

int
main()
{
	/* plot cexpinv on the unit square to stdout */
	complot(cexpinv, DIM, BANDED_CONTOUR, stdout);
}
Compile to cexpinvplot and in a shell redirect its output to an image of farbfeld format.
$ ./cexpinvplot > cexpinv.ff
Optionally one can of course convert this to png or other formats.
$ ff2png < cexpinv.ff > cexpinv.png
Or directly pipe it through.
$ ./cexpinvplot | ff2png > cexpinv.png

Colorings


A coloring is defined to be a map from the complex plane into the red-green-blue color space or even the rgb-alpha space if transparency is asked for. My coloring with bands and black contour log-bands has its advantages and has a certain 'soul' to them (just look at the examples!) But perhaps more canonical is a coloring that is continuous and hence one that does not have banding. To create such a coloring we remove the banding above, and map the argument directly to the hue. Then what remains is to continously map the modulus into the saturation-value space or the saturation-lightness space. Here one maps white to zero, black to infinity, or one can switch these (simply pick one.) Usually one fixes the saturation to the maximum, so then you map the modulus to the value in other words the absolute value to the value (HA!). Disregarding this, it is more common to work with lightness rather than value. This is what I have done. Lightness is mapped to the function x / (1 + x), where x is the square root of the modulus. This generates the image above.

You can access the four builtin colorings in complot via the fourth argument. Use the macros BANDED, CONTOUR, SMOOTH, or RIEMANN to get banded, banded with black contours, smooth, and the canonical coloring described above, respectively. So for a smooth image with infinity mapped to black and zero mapped to white, one would call the function as
complot(vals, width, height, SMOOTH_RIEMANN, stream);

Comparisons

Here are come comparisons between the banded and smooth colorings.
First of are these gifs that animate z^w where w pass through different roots of unity. Here the black bands are actually the z's that map z^w close to modulus one. While the banded version is more interesting it is a bit jarring to look at.
Secondly, a Blaschke product with 16 random zeroes in the unit square. One can identify the Zeroes as the points where the color shifts through the whole spectrum. My favorite is the first picture, banded without contours.
Lastly let's check out the function that takes z to z / (1 - |z|^2), where |z| is the modulus of z. This maps the unit disk to the complex plane bijectively and the function is continuous, but it is not comformal (that is impossible.)

Resources and links


Here are some links that I found useful while making these. I especially recommend browsing the first.
  1. Colorful visualization of complex functions
  2. Domain coloring ~ Wikipedia
  3. Domain coloring on the riemann sphere ~ Mathematica journal
  4. farbfeld ~ Suckless