Imaginary Numbers in Python
Why use Imaginary Numbers ?¶
Imaginary numbers help us solve problems that involve rotation, it introduces the gaussian dimension (imaginary plane) that can help us visualize the rotation of vectors.
A practical example:
In [1]:
import numpy as np
import matplotlib.pyplot as plt
# Complex vector example
a = 1 + 1j
def complexCalc(complexNum):
""" Returns the Real, imaginary, phase and magnitude of a complex number
Parameters
----------
complexNum: Complex number
Returns
----------
Ra: Real Part
Ima: Imaginary Part
phia: Angle in Radians
maga: Magnitude
"""
# Real and imaginary parts
Ra = complexNum.real
Ima = complexNum.imag
# Phase of the complex vector, in radians (pi radians = 180 degree)
phia = np.angle(complexNum)
# Magnitude of the complex vector
maga = np.abs(complexNum)
print("The Vector", complexNum)
print("Real:",Ra )
print("Imaginary:", Ima)
print("Phase:", (180/np.pi)*phia, "degree")
print("Magnitude:", maga)
return Ra, Ima, phia, maga
Ra, Ima, phia, maga = complexCalc(a)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951
We can use the phase and magnitude to represent the vector in polar coordinates $$ z = r e^{j\varphi} $$
In [78]:
# Converting from polar to rectangular
a = 1 + 1j
Ra, Ima, phia, maga = complexCalc(a)
# Calculate real and imaginary parts
Ra = maga * np.cos(phia)
Ima = maga * np.sin(phia)
# Combine into a complex number
aRect = Ra + 1j * Ima
print("--- Back to Rectangular ---")
Ra, Ima, phia, maga = complexCalc(aRect)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 --- Back to Rectangular --- The Vector (1.0000000000000002+1j) Real: 1.0000000000000002 Imaginary: 1.0 Phase: 44.99999999999999 degree Magnitude: 1.4142135623730951
Visualizing the vector¶
In [13]:
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Magnitude from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
r_max = maga * 1.2 # Extend radius for label positioning
ax.text(0, r_max, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, r_max, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
In [15]:
a = 1 + 1j
b = 0 + 1j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Mag from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
r_max = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, r_max, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, r_max, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector 1j Real: 0.0 Imaginary: 1.0 Phase: 90.0 degree Magnitude: 1.0
In [24]:
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Radii from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
ax.plot(
[0, phib], # Angles from 0 to angle of a
[0, magb], # Mag from 0 to magnitude of a
marker='o', # Marker at the end
color='g', # Color blue
label=f'Vector {b}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
rmax = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, rmax, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, rmax, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
In [55]:
complexArr = np.array([1 + 1j, 1 - 1j, 4 - 3j, 2 + 4j])
complexUnpacked = np.zeros((4,4))
def visualIzeComplexNums(complexArr):
""" Plots an array of complex numbers
Parameters
----------
complexArr: Array of complex numbers
Uses a matrix complexUnpacked to store the extracted values
"""
# Check for array
if (isinstance(complexArr, list) or isinstance(complexArr, np.ndarray)):
complexUnpacked = np.zeros((len(complexArr),4))
# complexUnpacked is a matrix -> [0, (0,1,2,3)] = Ra, Ima, phia, maga
else:
print("Not an array of complex numbers")
return 0
# Iterate through each array index
for arrInd, arr in enumerate(complexArr):
complexUnpacked[arrInd,0],complexUnpacked[arrInd,1],complexUnpacked[arrInd,2],complexUnpacked[arrInd,3] = complexCalc(arr)
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
cmap = plt.cm.get_cmap('tab10', len(complexArr))
colors = [cmap(i) for i in range(len(complexArr))]
# Plot vectors
for arrInd, arr in enumerate(complexArr):
ax.plot([0, complexUnpacked[arrInd,2]],[0, complexUnpacked[arrInd,3]],marker='o',color=colors[arrInd],label=f'Vector {arr}')
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
rmax = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, rmax, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, rmax, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
# Calling the function
visualIzeComplexNums(complexArr)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector (1-1j) Real: 1.0 Imaginary: -1.0 Phase: -45.0 degree Magnitude: 1.4142135623730951 The Vector (4-3j) Real: 4.0 Imaginary: -3.0 Phase: -36.86989764584402 degree Magnitude: 5.0 The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958
Operations with complex numbers¶
In [92]:
a = 2+ 4j
# Rotate by 90 degrees
rota = 1j * a
print(rota)
complexArr = [a, rota]
visualIzeComplexNums(complexArr)
(-4+2j) The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958 The Vector (-4+2j) Real: -4.0 Imaginary: 2.0 Phase: 153.434948822922 degree Magnitude: 4.47213595499958
Complex Conjugate of a complex vector:¶
If a = 2 + 4j, then a* = 2 - 4j
Keeping the real part the same and taking the reflection of the imaginary part, magnitude stays the same, but angle is now shifted by 2pi (opposite)
In [88]:
a = 2+4j
aconj = np.conj(a)
complexArr = [a, aconj]
visualIzeComplexNums(complexArr)
The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958 The Vector (2-4j) Real: 2.0 Imaginary: -4.0 Phase: -63.43494882292201 degree Magnitude: 4.47213595499958
In [82]:
# Arithmetic
a = 1+ 0.5j
b = 0 + 0.5j
# Sum
z = a + b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(1+1j) The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951
In [72]:
# Multiplication
z = a*b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(-0.25+0.5j) The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (-0.25+0.5j) Real: -0.25 Imaginary: 0.5 Phase: 116.56505117707799 degree Magnitude: 0.5590169943749475
In [73]:
# Multiplication in polar
# Addition of the phase and multiplication of the magnitude
a = 1+ 0.5j
b = 0 + 0.5j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
magz = maga * magb
phiz = phia + phib
# Converting from polar to rectangular
# Calculate real and imaginary parts
Rz = magz * np.cos(phiz)
Imz = magz * np.sin(phiz)
# Combine into a complex number
z = Rz + 1j * Imz
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (-0.25+0.5j) Real: -0.25 Imaginary: 0.5 Phase: 116.56505117707799 degree Magnitude: 0.5590169943749475
In [79]:
# Complex Division
z = a/b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(2-2j) The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (2-2j) Real: 2.0 Imaginary: -2.0 Phase: -45.0 degree Magnitude: 2.8284271247461903
Mathematically the complex conjugate helps us achieve division, read more here: https://betterexplained.com/articles/intuitive-arithmetic-with-complex-numbers/
In [81]:
# Division in polar
# Subtraction of the phase and division of the magnitude
a = 1+ 0.5j
b = 0 + 0.5j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
magz = maga / magb
phiz = phia - phib
# Converting from polar to rectangular
# Calculate real and imaginary parts
Rz = magz * np.cos(phiz)
Imz = magz * np.sin(phiz)
# Combine into a complex number
z = Rz + 1j * Imz
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1.0000000000000002-2j) Real: 1.0000000000000002 Imaginary: -2.0 Phase: -63.43494882292201 degree Magnitude: 2.23606797749979