Created
March 24, 2025 14:08
-
-
Save asalt/1e5c78b976d0e001a9c656e939003291 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import argparse | |
| import os | |
| def generate_vectors(num_slots, num_values, spacing, variance, diff_variance, diff_positions, diff_weight=1, aligned=True): | |
| """Generate two vectors with specified characteristics.""" | |
| if spacing == "even": | |
| positions = np.linspace(0, num_slots - 1, num_values, dtype=int) | |
| else: | |
| positions = np.random.choice(np.linspace(0, num_slots-1, dtype=int), num_values) | |
| Va = np.zeros(num_slots) | |
| Vb = np.zeros(num_slots) | |
| values = np.random.uniform(1 - variance, 1 + variance, num_values) | |
| Va[positions] = values | |
| if aligned: | |
| Vb[positions] = values # Start with identical values | |
| else: | |
| shifted_positions = np.random.choice(np.linspace(0, num_slots-1, dtype=int), num_values) | |
| shifted_positions = np.clip(shifted_positions, 0, num_slots - 1) | |
| print(positions, shifted_positions) | |
| Vb[shifted_positions] = values # Start with identical values | |
| if diff_positions: | |
| for pos in diff_positions: | |
| Vb[pos] = np.random.uniform(1 - diff_variance, 1 + diff_variance)* np.random.uniform(.25, .75) * diff_weight # Add differing elements | |
| return Va, Vb | |
| def spectral_angle(Va, Vb): | |
| """Compute the spectral angle similarity measure.""" | |
| dot_product = np.dot(Va, Vb) | |
| norm_a = np.linalg.norm(Va) | |
| norm_b = np.linalg.norm(Vb) | |
| cos_theta = dot_product / (norm_a * norm_b) | |
| theta = np.arccos(np.clip(cos_theta, -1.0, 1.0)) | |
| return 1 - 2 * (theta / np.pi) | |
| def plot_vectors_orig(Va, Vb, title, save_path=None): | |
| """Plot side-by-side bar graphs for two vectors and optionally save the plot.""" | |
| num_slots = len(Va) | |
| fig, axes = plt.subplots(1, 2, figsize=(12, 5), sharex=True, sharey=True) | |
| axes[0].bar(range(num_slots), Va, color='blue', alpha=0.7) | |
| axes[1].bar(range(num_slots), Vb, color='red', alpha=0.7) | |
| axes[0].set_title("Va") | |
| axes[1].set_title("Vb") | |
| plt.suptitle(f"{title} | Spectral Angle: {spectral_angle(Va, Vb):.4f}") | |
| if save_path: | |
| # os.makedirs(os.path.dirname(save_path), exist_ok=True) | |
| plt.savefig(save_path) | |
| print(f"Plot saved to {save_path}") | |
| plt.close(fig) | |
| else: | |
| plt.show() | |
| def plot_vectors(Va, Vb, title, save_path=None): | |
| """Plot side-by-side bar graphs for two vectors and optionally save the plot.""" | |
| num_slots = max(len(Va), len(Vb)) # Ensure the x-axis covers both vectors | |
| # Extend Va with NaNs if necessary | |
| Va_extended = np.pad(Va, (0, num_slots - len(Va)), constant_values=np.nan) | |
| Vb_extended = np.pad(Vb, (0, num_slots - len(Vb)), constant_values=np.nan) | |
| fig, axes = plt.subplots(1, 2, figsize=(12, 5), sharex=True, sharey=True) | |
| axes[0].bar(range(len(Va)), Va, color='blue', alpha=0.7) | |
| # Set colors for Vb: red if Va has a value, gray otherwise | |
| colors = ['red' if Va_extended[i] > 0 else 'gray' for i in range(len(Vb))] | |
| axes[1].bar(range(len(Vb)), Vb, color=colors, alpha=0.7) | |
| axes[0].set_title("Va") | |
| axes[1].set_title("Vb") | |
| plt.suptitle(f"{title} | Spectral Angle: {spectral_angle(Va, Vb):.4f}") | |
| # savename = f"" | |
| if save_path: | |
| plt.savefig(save_path) | |
| print(f"Plot saved to {save_path}") | |
| plt.close(fig) | |
| else: | |
| plt.show() | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Generate and visualize spectral angle comparisons between two vectors.") | |
| parser.add_argument("--not-aligned", default=False, help="", action='store_true') | |
| parser.add_argument("--num-slots", type=int, default=100, help="Length of the vectors (default: 100)") | |
| parser.add_argument("--num-values", type=int, default=5, help="Number of nonzero values (default: 5)") | |
| parser.add_argument("--spacing", type=str, default="even", choices=["even", "random"], help="Spacing of nonzero values (default: even)") | |
| parser.add_argument("--variance", type=float, default=0.5, help="Variance in nonzero values (default: 0.5)") | |
| parser.add_argument("--diff-variance", type=float, default=0.5, help="Variance in nonzero values (default: 0.5)") | |
| parser.add_argument("--diff-weight", type=float, default=1, help="diff weigth") | |
| parser.add_argument("--diff-positions", type=int, nargs='*', default=None, help="Positions to add different values in Vb (default: None)") | |
| parser.add_argument("--save_path", type=str, default=None, help="Path to save the plot (default: None)") | |
| args = parser.parse_args() | |
| print(args.not_aligned) | |
| Va, Vb = generate_vectors(args.num_slots, args.num_values, args.spacing, args.variance, args.diff_variance, args.diff_positions, args.diff_weight, aligned=not args.not_aligned) | |
| plot_vectors(Va, Vb, "Spectral Angle Demonstration", args.save_path) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment