Icons
All of the site favicons that I use have been generated by contour plots of the complex logarithm and complex exponential functions.
Experiments
HSV | Viridis | Cividis | Inferno | Jet | Magma | Plasma | Rainbow | Turbo
Real
Imaginary
Absolute
HSV | Viridis | Cividis | Inferno | Jet | Magma | Plasma | Rainbow | Turbo
Real
Imaginary
Absolute
Mathematics
Wolfram Alpha does a better job regarding this than I can. I do not understand the behaviour of these functions, especially at the branch points:
https://functions.wolfram.com/ElementaryFunctions/Log/visualizations/5/
https://functions.wolfram.com/ElementaryFunctions/Exp/visualizations/5/
Code
GPT o1 model produced these figures for me, here are the included code-blocks that have been version controlled as part of a larger icons repository.
#!/usr/bin/env python3
"""
Generate three separate SVG images:
1) Re[ln(x + i y)]
2) Im[ln(x + i y)]
3) |ln(x + i y)|
All plotted over x,y in [-4,4], with discrete color bands.
Usage:
python plot_ln_complex.py [--cmap CMAP]
Example:
python plot_ln_complex.py --cmap rainbow
This will produce:
real_part.svg,
imag_part.svg,
abs_part.svg
"""
import numpy as np
import matplotlib.pyplot as plt
import argparse
def main():
# A list of common matplotlib colormaps you might try for discrete color blocks
all_cmaps = [
'rainbow', 'hsv', 'jet', 'plasma', 'inferno', 'magma',
'cividis', 'viridis', 'turbo'
]
parser = argparse.ArgumentParser(
description="Generate discrete color-band plots for Re, Im, and |ln(x + i y)| over [-4,4]x[-4,4]."
)
parser.add_argument(
'--cmap',
type=str,
default='rainbow',
help=(
"Colormap to use. Some options include:\n"
f"{', '.join(all_cmaps)}\n"
"For more, see: https://matplotlib.org/stable/tutorials/colors/colormaps.html"
)
)
args = parser.parse_args()
# ---------------------------------------------------
# Domain: x,y in [-4,4]
# We'll include 401 points per axis so that 0 is included.
# ---------------------------------------------------
n_points = 401
x_vals = np.linspace(-4, 4, n_points)
y_vals = np.linspace(-4, 4, n_points)
X, Y = np.meshgrid(x_vals, y_vals)
# Avoid log(0) by masking out the point z=0
Z = X + 1j * Y
zero_mask = (X == 0) & (Y == 0)
Z[zero_mask] = np.nan
# Compute principal branch of the complex log
with np.errstate(divide='ignore', invalid='ignore'):
Z_ln = np.log(Z)
# Extract real part, imaginary part, and magnitude
ln_real = np.real(Z_ln)
ln_imag = np.imag(Z_ln)
ln_abs = np.abs(Z_ln)
# Decide how many discrete levels to use
n_levels = 12 # Adjust if you want more or fewer color bands
# ---------------------------------------------------
# 1) Real part of ln(z)
# ---------------------------------------------------
fig_re, ax_re = plt.subplots(figsize=(6, 5), dpi=100)
cs_re = ax_re.contourf(
X, Y, ln_real,
levels=n_levels,
cmap=args.cmap
)
ax_re.set_aspect('equal', 'box')
ax_re.axis('off')
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
fig_re.savefig("real_part.svg", format="svg", bbox_inches='tight', pad_inches=0)
plt.close(fig_re)
# ---------------------------------------------------
# 2) Imag part of ln(z)
# ---------------------------------------------------
fig_im, ax_im = plt.subplots(figsize=(6, 5), dpi=100)
cs_im = ax_im.contourf(
X, Y, ln_imag,
levels=n_levels,
cmap=args.cmap
)
ax_im.set_aspect('equal', 'box')
ax_im.axis('off')
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
fig_im.savefig("imag_part.svg", format="svg", bbox_inches='tight', pad_inches=0)
plt.close(fig_im)
# ---------------------------------------------------
# 3) Absolute value of ln(z)
# ---------------------------------------------------
fig_abs, ax_abs = plt.subplots(figsize=(6, 5), dpi=100)
cs_abs = ax_abs.contourf(
X, Y, ln_abs,
levels=n_levels,
cmap=args.cmap
)
ax_abs.set_aspect('equal', 'box')
ax_abs.axis('off')
plt.subplots_adjust(left=0, right=1, top=1, bottom=0)
fig_abs.savefig("abs_part.svg", format="svg", bbox_inches='tight', pad_inches=0)
plt.close(fig_abs)
if __name__ == "__main__":
main()
import numpy as np
import matplotlib
matplotlib.use('Agg') # Use non-interactive backend
import matplotlib.pyplot as plt
import argparse
import os
def get_available_colormaps():
"""Returns a list of all available colormaps in matplotlib."""
return plt.colormaps()
def exp_inv_complex(Z):
"""Compute exp(1/z) for a complex array Z."""
with np.errstate(divide='ignore', invalid='ignore'):
return np.exp(1 / Z)
def plot_complex_exp(cmap='RdYlBu_r', output_file=None, resolution=1001, singularity_size=0.01):
"""
Plot the real component of exp(1/z) using the specified colormap.
Args:
cmap (str): Name of the matplotlib colormap to use.
Must be one of the available matplotlib colormaps.
output_file (str, optional): Path to save the SVG file.
If None, displays the plot instead.
resolution (int): Number of points in each dimension. Higher values give better detail.
singularity_size (float): Radius around z=0 to mask for the singularity.
"""
# Generate grid points with high resolution
x_vals = np.linspace(-1, 1, resolution)
y_vals = np.linspace(-1, 1, resolution)
X, Y = np.meshgrid(x_vals, y_vals)
# Create complex grid Z = X + iY with smaller singularity
Z = X + 1j * Y
Z[np.abs(Z) < singularity_size] = np.nan
# Compute exp(1/Z)
W = exp_inv_complex(Z)
real_part = np.real(W)
real_part = np.clip(real_part, -2, 2)
# Create minimal plot
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
im = ax.imshow(
real_part,
extent=[-1, 1, -1, 1],
cmap=cmap,
origin='lower',
aspect='equal',
interpolation='bilinear'
)
# Remove all decorations
ax.set_xticks([])
ax.set_yticks([])
ax.set_frame_on(False)
plt.tight_layout()
if output_file:
# Ensure the output directory exists
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else '.', exist_ok=True)
plt.savefig(output_file, format='svg', bbox_inches='tight', pad_inches=0)
plt.close()
else:
plt.show()
def plot_imaginary_exp(cmap='RdYlBu_r', output_file=None, resolution=1001, singularity_size=0.01):
"""
Plot the imaginary component of exp(1/z) using the specified colormap.
Args:
cmap (str): Name of the matplotlib colormap to use.
Must be one of the available matplotlib colormaps.
output_file (str, optional): Path to save the SVG file.
If None, displays the plot instead.
resolution (int): Number of points in each dimension. Higher values give better detail.
singularity_size (float): Radius around z=0 to mask for the singularity.
"""
# Generate grid points with high resolution
x_vals = np.linspace(-1, 1, resolution)
y_vals = np.linspace(-1, 1, resolution)
X, Y = np.meshgrid(x_vals, y_vals)
# Create complex grid Z = X + iY with smaller singularity
Z = X + 1j * Y
Z[np.abs(Z) < singularity_size] = np.nan
# Compute exp(1/Z)
W = exp_inv_complex(Z)
imag_part = np.imag(W)
imag_part = np.clip(imag_part, -2, 2)
# Create minimal plot
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
im = ax.imshow(
imag_part,
extent=[-1, 1, -1, 1],
cmap=cmap,
origin='lower',
aspect='equal',
interpolation='bilinear'
)
# Remove all decorations
ax.set_xticks([])
ax.set_yticks([])
ax.set_frame_on(False)
plt.tight_layout()
if output_file:
# Ensure the output directory exists
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else '.', exist_ok=True)
plt.savefig(output_file, format='svg', bbox_inches='tight', pad_inches=0)
plt.close()
else:
plt.show()
def plot_absolute_exp(cmap='hsv', output_file=None, resolution=1001, singularity_size=0.01):
"""
Plot the absolute value of exp(1/z) using the specified colormap.
The color represents the argument (phase) of the complex number.
Args:
cmap (str): Name of the matplotlib colormap to use.
Must be one of the available matplotlib colormaps.
output_file (str, optional): Path to save the SVG file.
If None, displays the plot instead.
resolution (int): Number of points in each dimension. Higher values give better detail.
singularity_size (float): Radius around z=0 to mask for the singularity.
"""
# Generate grid points with high resolution
x_vals = np.linspace(-1, 1, resolution)
y_vals = np.linspace(-1, 1, resolution)
X, Y = np.meshgrid(x_vals, y_vals)
# Create complex grid Z = X + iY with smaller singularity
Z = X + 1j * Y
Z[np.abs(Z) < singularity_size] = np.nan
# Compute exp(1/Z)
W = exp_inv_complex(Z)
abs_val = np.abs(W)
arg_val = np.angle(W, deg=True)
# Normalize absolute value for better visualization
abs_val = np.clip(abs_val, 0, 2)
# Create minimal plot
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111)
# Plot the absolute value with phase coloring
im = ax.imshow(
abs_val, # Use absolute value for the data
extent=[-1, 1, -1, 1],
cmap=cmap,
origin='lower',
aspect='equal',
interpolation='bilinear'
)
# Remove all decorations
ax.set_xticks([])
ax.set_yticks([])
ax.set_frame_on(False)
plt.tight_layout()
if output_file:
# Ensure the output directory exists
os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else '.', exist_ok=True)
plt.savefig(output_file, format='svg', bbox_inches='tight', pad_inches=0)
plt.close()
else:
plt.show()
def main():
"""Main function to handle command line arguments and create the plots."""
parser = argparse.ArgumentParser(
description='Visualize various components of exp(1/z) with customizable colormap.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
'--cmap',
type=str,
default='RdYlBu_r',
choices=get_available_colormaps(),
help='Matplotlib colormap to use for visualization'
)
parser.add_argument(
'--output-prefix',
type=str,
default=None,
help='Prefix for output SVG files. If not provided, displays the plots instead.'
)
parser.add_argument(
'--resolution',
type=int,
default=1001,
help='Number of points in each dimension. Higher values give better detail.'
)
parser.add_argument(
'--singularity-size',
type=float,
default=0.01,
help='Radius around z=0 to mask for the singularity.'
)
args = parser.parse_args()
# Generate all three visualizations
if args.output_prefix:
real_output = f"{args.output_prefix}_real.svg"
imag_output = f"{args.output_prefix}_imag.svg"
abs_output = f"{args.output_prefix}_abs.svg"
else:
real_output = None
imag_output = None
abs_output = None
# Plot real part
plot_complex_exp(args.cmap, real_output, args.resolution, args.singularity_size)
# Plot imaginary part
plot_imaginary_exp(args.cmap, imag_output, args.resolution, args.singularity_size)
# Plot absolute value with the same colormap as the others
plot_absolute_exp(args.cmap, abs_output, args.resolution, args.singularity_size)
if __name__ == '__main__':
main()
Final Orbs
There has been a degree of iteration across functions and heatmaps, but ultimately here are the 5 plots that I have settled on for my 5 products; abaj.ai, bots.abaj.ai, games.abaj.ai, trades.abaj.ai, tools.abaj.ai.