In creating this website I wanted to begin with a visually interesting project that showcased mathematical principles. After some thought, I settled on using randomly generated vector fields to visualize Jacobian-related values in various ways. In order to create additional depth for this project I also ended up throwing in my Principal Component Analysis (PCA) implementation used elsewhere on this website.
Let nrows and ncols denote the numbers of rows and columns in the background image we are going to generate. We can then randomly choose a number nbase of "base vectors" using a Poisson distribution. These base vectors will be assigned both a random direction and magnitude as well as a random location chosen within the bounds of the image. More specifically, let us use the 4-tuple B to represent the base vectors and their associated locations where (1) c represents the vector's column index, (2) r represents the vector's row index, (3) x represents the x-component of the vector, and (4) y represents the y-component of the vector:
From here, all additional vectors in the field are interpolated from the base vectors using the _computeRemainingVectors method of the VectorFieldGenerator class. The idea is that we provide a "softmax normalizer" parameter snorm which controls the relative contributions of each base vector; small normalizer values mean that vectors closely resemble their nearest base vector while large values mean that the field will tend to be more uniform. To elaborate further, the interpolated vector (x,y) at column index c and row index r is defined in the following way:
As an added feature, it is possible to apply affine transformations to the vector field in order to experiment with creating interesting visualizations. More specifically, the applyAffineTransformation method of the VectorField class takes in several m and b values as arguments which transform old vector values into new ones in the following way:
Note that for the vector fields shown below an affine transformation defined by (m11,m12,m21,m22) = (1,0,1,1) and (b1,b2) = (0,0) was used in all cases.
With this definition in place we can now start generating our vector fields. Once generated by a VectorFieldGenerator object, the VectorField class allows us to visualize the vector fields in two possible formats using the plotVectorField method:
(Left) Quiver representation of the generated vector field made with 1080 rows, 1920 columns, seed of 0 and softmax normalizer of 480.
(Right) Streamplot representation of the same vector field.
From here we can simply compute the needed Jacobian-related values of our vector fields using the commonly known equations for these quantities. In terms of the exact meaning of the following images seen below, blue regions represent positive values of curl/divergence/Jacobian determinant whereas red regions represent negative values.
Shared settings for these images: seed of 0, softmax normalizer of 480
Notice the region of strong negative curl corresponding to the vectors turning clockwise on the right side of the image
Also notice the region of strong positive divergence and determinant near the top-middle where the arrows grow in length
While these separate representations of Jacobian-related values are visually interesting in their own right, they are not exactly what I had in mind to take this project over the finish line. To push this concept further I wanted to develop a way of combining these red/blue images into a full RGB image. The idea for doing so is to create a higher-dimensional data set constructed from the pixels of the other images. For example, if I wanted to combine the curl and divergence images I would create a 4-dimensional data set in the following way:
The 1st component is the blue-intensity of the curl image
The 2nd component in the red-intensity of the curl image
The 3rd component is the blue-intensity of the divergence image
The 4th component in the red-intensity of the divergence image
This 4-dimensional data can then be "compressed" into 3-dimensional data using PCA. The three components of the compressed data can then be used as a basis for the red, green and blue channels of a newly generated image. Note that I have implemented four possible ways of using this PCA algorithm to obtain associated RGB values: (1) combine curl and divergence into a 4-dimensional data set, (2) combine curl and the Jacobian determinant into a 4-dimensional data set, (3) combine divergence and the Jacobian determinant into a 4-dimensional data set, and (4) combine all three sets of values into a 6-dimensional data set.
The following examples are a selection of generated images that showcase common outputs the algorithm described above. The main goal of this section is to show the results of PCA as well as the effect that the softmax normalizer has on the underlying vector field.
Shared settings for these images: seed of 0, softmax normalizer of 480
Notice how features from the individual "Curl Only", "Divergence Only", and "Jacobian Determinant Only" images are recognizable in these PCA images
However, it is important to note that the "PCA - All Three" image is more than simply the result of overlaying the other PCA images
Shared settings for these images: seed of 0, PCA of all three Jacobian-related values
The same base vectors are used for these vector fields; the only difference is the relative strength at which base vectors affect their neighboring points
Notice the sharp boundaries when the softmax normalizer is small; this is due to the fact that the interpolated vectors are effectively only affected by their nearest base vector
Shared settings for these images: softmax normalizer of 480, PCA of all three Jacobian-related values
Notice how the colors in each image can vary significantly as a result of PCA on the underlying vector field information
Background image generation from the background_generator folder of the active_projects repository
Script with image settings from generate_image.py
Curl and divergence combination from the dimensional_analysis folder of the infrastructure repository
PCA algorithm from dimension_reduction.py
Additional basic functionality from the common_needs folder of the infrastructure repository
Attribute privacy from privacy_helper.py
File dialogs from tkinter_helper.py
Object type checks from type_helper.py
VectorField and VectorFieldGenerator classes from vector_helper.py