Make interactive scatterplots of atomic orbitals and animate them.
python orbital.py 5 3 . 6000 . "both(plt.get_cmap('rainbow'))"
- Matplotlib
- NumPy
- SymPy
- SciPy
- FFmpeg (for MP4 / WebM output)
Download orbital.py
to a folder and open a terminal there, then enter python orbital.py
or
On Windows
orbital.py
On Linux/macOS
chmod +x orbital.py # Only the first time
./orbital.py
If no arguments are given, the script will ask for the following inputs:
n (default 1) =
l (default 0) =
m (default 0) =
Number of dots (default 4000):
Background color (default 'black'):
Change colormap to (optional):
View/Draw/Animate [V/D/A] (default Draw):
To choose the default option, simply press Enter
.
The input for background color will be treated as a string. See ways of specifying color here. Support for (semi-)transparent backgrounds depends on the output format.
The input()
function for the colormap is enclosed by the eval()
function, so colormaps can be specified using functions like pyplot.get_cmap
, ListedColormap
, and LinearSegmentedColormap
, imported respectively as plt.get_cmap
, lc
, and lsc
. Visit the following links to see ways of choosing and creating colormaps.
The color mapping is based on the value of the real wavefunction both()
. The default colormap is 'cool'
and 'spring'
concatenated.
python orbital.py 3 2 -1
Caution
Due to the eval()
function, be careful allowing others to run the script. Enter appropriate values, the script does not attempt to catch errors.
When asked to choose between View, Draw, and Animate, anything that in lowercase does not become v
, view
, d
, or draw
results in an animation. Choosing View produces an interactive plot. Choosing Draw results in the following prompts:
Elevation in degrees (default 0):
Azimuth in degrees (default 0):
Format (default PNG):
The supported formats depend on the backend used. The drawings
folder is created if not already present, and the output is saved to it. If Animate is chosen, the prompts are:
Elevation in degrees (default 0):
Initial azimuth in degrees (default 0):
Format [mp4/webm/gif] (default WebM):
Duration in sec (default 12):
A video of the orbital rotating 360° degrees within the specified duration, is saved to the animations
folder.
Note
The actual duration may be very slightly less, so that the duration times the FPS results in an integer number of frames.
Image and video filenames consist of (n, l, m)
, the number of dots, and as a suffix, the Unix timastamp in base 36, to avoid similar outputs overwriting each other. The orbital names s, p, d, f, ... are not used, to facilitate regex.
Instead of inputting values one by one, you can also supply them as arguments in the same order given above. To choose the default values, use a period. If one or more but not all the values are specified, the remaining will take their default values.
For example,
python orbital.py 3 2 . . . "both(plt.get_cmap('plasma'))" a 25
refers to a both(plt.get_cmap('plasma'))
colormap. It will produce an animation viewed from an elevation of 25° and initial azimuth of 0°, in the WebM format, lasting 12 s.
3.2.0.orbital.4000.-.S9Y0PK.webm
The options given so far are plenty to play around with and generate beautiful animations in your desired format. To change the defaults, or for further options, go to the directory containing orbital.py
, and create an override.conf
file in the TOML format containing any of the following keys (in any order) with their desired values.
n = 1
l = 0
m = 0
dots = 4000
bgcolor = "black"
colormap = "lc(np.vstack((plt.get_cmap('cool')(np.linspace(0,1,256)),plt.get_cmap('spring')(np.linspace(0,1,256)))))"
mode = "draw"
elevation = 0
azimuth = 0 # Also the initial azimuth for animation
format = ["png", "webm"]
duration = 12
resolution = 1080
mp4codec = "libx264" # Try libx265
webmcodec = "libvpx-vp9" # Try libsvtav1
fps = 30
dotsize = 32 # In px^2
dotshape = "o" # See matplotlib.markers
dotalpha = 0.5 # Transparency
The default resolution is 1080x1080 so that the output can be displayed without image scaling when fullscreen on a common Full HD (1080p) monitor. The FPS is 30 which seems appropriate for a continuously rotating animation. You may want to increase or decrease these to balance detail and filesize. The GIF format is preferred in some cases, but it uses lossless compression (albeit a severely limited color space), so the relatively high resolution and FPS can lead to a large file size. Modern internet is fast, so these values are not reduced for GIFs by default, but you may want to do so nonetheless.
The newer codecs suggested achieve better compression but much higher encoding and decoding complexity. Ensure that FFmpeg has been built with support for the codec(s) you wish to use. It is also to be noted that unlike MPEG formats, WebM and its associated codecs are free and open, which is why they have been made the defaults.
This script uses the Monte Carlo rejection sampling algorithm to generate points according to their probability distribution function (PDF). The three spherical coordinates have separable PDFs, so the three sets can be found independently and then combined.
The algorithm can be inferred from the above image. First we pick a domain for the variable
The domains for
I.e., the average distance is
The same graph also shows that the maximum value of the radial probability
It is common, especially in chemistry, to use real atomic orbitals, which arise from simple linear combinations of complex orbitals. Their azimuthal probability is
The polar probability is
where the double factorial
For
From Eq. (23), p. 183, of Lohöfer (1998),4
Thus we have obtained all the bounds we need to proceed with rejection sampling.
python orbital.py 4 2 . 6000 . "both(plt.get_cmap('gist_earth'))"
Footnotes
-
van Dommelen, L. (2012). Quantum mechanics for engineers. https://websites.umich.edu/~ners312/CourseLibrary/Dommelen.pdf ↩
-
Antonov, V. A., & Holsevnikov, K. V. (1981). An estimate of the remainder in the expansion of the generating function for the Legendre polynomials (generalization and improvement of Bernstein's inequality). Vestnik Leningrad. Univ. Mat. 13, 163–166. ↩
-
Lorch, L. (1983). Alternative proof of a sharpened form of Bernstein's inequality for Legendre polynomials, Appl. Anal. 14, 237–240. ↩
-
Lohöfer, G. (1998). Inequalities for the associated Legendre functions. J. Approx. Theory, 95 (2), 178–193. https://doi.org/10.1006/jath.1998.3207 ↩