|
import gradio as gr |
|
import numpy as np |
|
import matplotlib.pyplot as plt |
|
from io import BytesIO |
|
from PIL import Image |
|
def matrix_vector_multiplication_visualization(matrix, vector): |
|
try: |
|
|
|
matrix = np.array([[float(x) for x in row.split(",")] for row in matrix.split(";")]) |
|
vector = np.array([float(x) for x in vector.split(",")]) |
|
|
|
|
|
if matrix.shape != (2, 2): |
|
return "Error: Matrix must be 2x2.", None |
|
if vector.shape != (2,): |
|
return "Error: Vector must be 2D.", None |
|
|
|
|
|
transformed_vector = np.dot(matrix, vector) |
|
|
|
|
|
x = np.linspace(-1, 1, 10) |
|
y = np.linspace(-1, 1, 10) |
|
X, Y = np.meshgrid(x, y) |
|
grid = np.vstack([X.flatten(), Y.flatten()]) |
|
transformed_grid = np.dot(matrix, grid).reshape(2, -1, 10) |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6, 6)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ax.quiver(0, 0, vector[0], vector[1], angles="xy", scale_units="xy", scale=1, color="red", label="Original Vector") |
|
|
|
|
|
ax.quiver(0, 0, transformed_vector[0], transformed_vector[1], angles="xy", scale_units="xy", scale=1, color="blue", label="Transformed Vector") |
|
|
|
|
|
ax.axhline(0, color='black', linewidth=0.5) |
|
ax.axvline(0, color='black', linewidth=0.5) |
|
ax.set_xlim(-2, 2) |
|
ax.set_ylim(-2, 2) |
|
ax.set_aspect('equal') |
|
ax.grid(True) |
|
ax.legend() |
|
ax.set_title("Matrix-Vector Multiplication Visualization") |
|
|
|
|
|
buf = BytesIO() |
|
plt.savefig(buf, format="png") |
|
buf.seek(0) |
|
plt.close(fig) |
|
|
|
return f"Transformed Vector: {transformed_vector.tolist()}", Image.open(buf) |
|
except Exception as e: |
|
return f"Error: {str(e)}", None |
|
|
|
def visualize_points_and_vectors_with_start(points, vectors): |
|
try: |
|
|
|
points = [list(map(float, p.split(','))) for p in points.split(';') if p.strip()] |
|
|
|
|
|
vectors_with_start = [ |
|
list(map(float, v.split(','))) for v in vectors.split(';') if v.strip() |
|
] |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6, 6)) |
|
|
|
|
|
for point in points: |
|
ax.plot(point[0], point[1], 'o', label=f"Point ({point[0]}, {point[1]})") |
|
|
|
|
|
for vector in vectors_with_start: |
|
if len(vector) == 4: |
|
start_x, start_y, vec_x, vec_y = vector |
|
ax.quiver( |
|
start_x, start_y, vec_x, vec_y, angles='xy', scale_units='xy', scale=1, |
|
color='r', label=f"Vector from ({start_x},{start_y}) to ({start_x+vec_x},{start_y+vec_y})" |
|
) |
|
|
|
|
|
ax.axhline(0, color='black', linewidth=0.5) |
|
ax.axvline(0, color='black', linewidth=0.5) |
|
ax.set_xlim(-10, 10) |
|
ax.set_ylim(-10, 10) |
|
ax.set_aspect('equal') |
|
ax.grid(True) |
|
ax.legend() |
|
ax.set_title("Points and Vectors Visualization") |
|
|
|
|
|
buf = BytesIO() |
|
plt.savefig(buf, format='png') |
|
buf.seek(0) |
|
plt.close(fig) |
|
|
|
return Image.open(buf) |
|
except Exception as e: |
|
return f"Error: {str(e)}" |
|
|
|
def calculate_dot_product_and_angle(vector1, vector2): |
|
try: |
|
|
|
vec1 = np.array([float(x) for x in vector1.split(",")]) |
|
vec2 = np.array([float(x) for x in vector2.split(",")]) |
|
|
|
|
|
if len(vec1) != len(vec2): |
|
return "Error: Vectors must have the same length.", None |
|
|
|
|
|
dot_product = np.dot(vec1, vec2) |
|
|
|
|
|
magnitude_vec1 = np.linalg.norm(vec1) |
|
magnitude_vec2 = np.linalg.norm(vec2) |
|
|
|
|
|
normalized_dot_product = dot_product / (magnitude_vec1 * magnitude_vec2) |
|
|
|
|
|
angle_radians = np.arccos(np.clip(normalized_dot_product, -1.0, 1.0)) |
|
angle_degrees = np.degrees(angle_radians) |
|
|
|
explanation = ( |
|
f"Dot product: {dot_product}\n" |
|
f"Normalized dot product: {normalized_dot_product:.4f}\n" |
|
f"Angle (radians): {angle_radians:.4f}\n" |
|
f"Angle (degrees): {angle_degrees:.4f}" |
|
) |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6, 6)) |
|
ax.quiver(0, 0, vec1[0], vec1[1], angles='xy', scale_units='xy', scale=1, color='r', label="Vector 1") |
|
ax.quiver(0, 0, vec2[0], vec2[1], angles='xy', scale_units='xy', scale=1, color='b', label="Vector 2") |
|
|
|
|
|
ax.set_xlim(-max(abs(vec1[0]), abs(vec2[0])) - 1, max(abs(vec1[0]), abs(vec2[0])) + 1) |
|
ax.set_ylim(-max(abs(vec1[1]), abs(vec2[1])) - 1, max(abs(vec1[1]), abs(vec2[1])) + 1) |
|
ax.axhline(0, color='black', linewidth=0.5) |
|
ax.axvline(0, color='black', linewidth=0.5) |
|
ax.set_aspect('equal') |
|
ax.grid(True) |
|
ax.legend() |
|
ax.set_title("Vector Visualization") |
|
|
|
|
|
|
|
buf = BytesIO() |
|
plt.savefig(buf, format='png') |
|
buf.seek(0) |
|
plt.close(fig) |
|
|
|
return explanation, Image.open(buf) |
|
except ValueError: |
|
return "Error: Please enter valid numeric values separated by commas.", None |
|
|
|
def transformation_composition_with_vectors(matrix1, matrix2, vectors): |
|
try: |
|
|
|
matrix1 = np.array([[float(x) for x in row.split(",")] for row in matrix1.split(";")]) |
|
matrix2 = np.array([[float(x) for x in row.split(",")] for row in matrix2.split(";")]) |
|
|
|
|
|
if matrix1.shape != (2, 2) or matrix2.shape != (2, 2): |
|
return "Error: Both matrices must be 2x2.", None |
|
|
|
|
|
vectors = np.array([[float(x) for x in vector.split(",")] for vector in vectors.split(";")]).T |
|
if vectors.shape[0] != 2: |
|
return "Error: Vectors must be 2D (two components per vector).", None |
|
|
|
|
|
vectors_after_matrix1 = np.dot(matrix1, vectors) |
|
vectors_after_composition = np.dot(np.dot(matrix2, matrix1), vectors) |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(8, 8)) |
|
|
|
|
|
for vector in vectors.T: |
|
ax.quiver(0, 0, vector[0], vector[1], angles='xy', scale_units='xy', scale=1, color="gray", alpha=0.7) |
|
|
|
|
|
for vector in vectors_after_matrix1.T: |
|
ax.quiver(0, 0, vector[0], vector[1], angles='xy', scale_units='xy', scale=1, color="orange", alpha=0.7) |
|
|
|
|
|
for vector in vectors_after_composition.T: |
|
ax.quiver(0, 0, vector[0], vector[1], angles='xy', scale_units='xy', scale=1, color="blue", alpha=0.7) |
|
|
|
|
|
ax.legend(["Original Vectors", "After Matrix 1", "After Matrix 2 × Matrix 1"], loc="upper left") |
|
|
|
|
|
ax.axhline(0, color="black", linewidth=0.5) |
|
ax.axvline(0, color="black", linewidth=0.5) |
|
ax.set_xlim(-3, 3) |
|
ax.set_ylim(-3, 3) |
|
ax.set_aspect("equal") |
|
ax.grid(True) |
|
ax.set_title("Matrix-Matrix Multiplication as Transformation Composition") |
|
|
|
|
|
buf = BytesIO() |
|
plt.savefig(buf, format="png") |
|
buf.seek(0) |
|
plt.close(fig) |
|
|
|
return "Success", Image.open(buf) |
|
except Exception as e: |
|
return f"Error: {str(e)}", None |
|
|
|
with gr.Blocks() as app: |
|
with gr.Tab("Points vs. Vectors"): |
|
gr.Markdown("## Points and Vectors Visualization with Starting Points") |
|
gr.Markdown(""" |
|
- **Points**: Enter semicolon-separated 2D points, e.g., `1,2; 3,4`. |
|
- **Vectors**: Enter vectors with starting points in the format `start_x,start_y,vector_x,vector_y; ...`, e.g., `0,0,2,1; 3,4,-1,2`. |
|
""") |
|
|
|
with gr.Row(): |
|
points_input = gr.Textbox(label="Points (semicolon-separated)", placeholder="e.g., 1,2; 3,4") |
|
vectors_input = gr.Textbox(label="Vectors (with starting points)", placeholder="e.g., 0,0,2,1; 3,4,-1,2") |
|
|
|
output_image = gr.Image(label="Visualization") |
|
|
|
visualize_button = gr.Button("Visualize") |
|
visualize_button.click( |
|
fn=visualize_points_and_vectors_with_start, |
|
inputs=[points_input, vectors_input], |
|
outputs=output_image |
|
) |
|
with gr.Tab("Vector Dot Product"): |
|
gr.Markdown("## Dot Product, Normalized Dot Product, and Angle Calculator") |
|
gr.Markdown("Enter two vectors (comma-separated) to calculate their dot product, normalized dot product, and angle.") |
|
|
|
with gr.Row(): |
|
vector1_input = gr.Textbox(label="Vector 1", placeholder="e.g., 1, 2") |
|
vector2_input = gr.Textbox(label="Vector 2", placeholder="e.g., 4, 5") |
|
|
|
output_text = gr.Textbox(label="Result", lines=6) |
|
output_image = gr.Image(label="Visualization") |
|
|
|
calculate_button = gr.Button("Calculate and Visualize") |
|
calculate_button.click( |
|
fn=calculate_dot_product_and_angle, |
|
inputs=[vector1_input, vector2_input], |
|
outputs=[output_text, output_image] |
|
) |
|
with gr.Tab("Matrix-Vector Multiplication"): |
|
gr.Markdown("## Matrix-Vector Multiplication Visualization") |
|
gr.Markdown(""" |
|
- Enter a **2x2 matrix** as `a,b;c,d` (rows separated by semicolons). |
|
- Enter a **2D vector** as `x,y`. |
|
- See the original vector (red), transformed vector (blue), and grid transformation. |
|
""") |
|
with gr.Row(): |
|
matrix_input = gr.Textbox(label="Matrix (2x2, e.g., 1,0;0,1)", placeholder="e.g., 1,0;0,1") |
|
vector_input = gr.Textbox(label="Vector (2D, e.g., 1,1)", placeholder="e.g., 1,1") |
|
|
|
output_text = gr.Textbox(label="Result") |
|
output_image = gr.Image(label="Visualization") |
|
|
|
calculate_button = gr.Button("Visualize") |
|
calculate_button.click( |
|
fn=matrix_vector_multiplication_visualization, |
|
inputs=[matrix_input, vector_input], |
|
outputs=[output_text, output_image] |
|
) |
|
|
|
with gr.Tab('Matrix-Matrix Multiplication'): |
|
gr.Markdown("## Matrix Multiplication as Transformation Composition (Using Vectors)") |
|
gr.Markdown(""" |
|
- Enter two **2x2 matrices** in the format `a,b;c,d` (rows separated by semicolons). |
|
- Enter vectors in the format `x1,y1;x2,y2;...` (semicolon-separated pairs). |
|
- The app will show: |
|
- The original vectors. |
|
- The vectors after applying **Matrix 1**. |
|
- The vectors after applying the composition (**Matrix 2 × Matrix 1**). |
|
""") |
|
|
|
with gr.Row(): |
|
matrix1_input = gr.Textbox(label="Matrix 1 (2x2, e.g., 1,0;0,1)", placeholder="e.g., 1,0;0,1") |
|
matrix2_input = gr.Textbox(label="Matrix 2 (2x2, e.g., 2,0;0,1)", placeholder="e.g., 2,0;0,1") |
|
vectors_input = gr.Textbox(label="Vectors (e.g., 1,0;0,1)", placeholder="e.g., 1,0;0,1") |
|
|
|
output_text = gr.Textbox(label="Output") |
|
output_image = gr.Image(label="Visualization") |
|
|
|
calculate_button = gr.Button("Visualize") |
|
calculate_button.click( |
|
fn=transformation_composition_with_vectors, |
|
inputs=[matrix1_input, matrix2_input, vectors_input], |
|
outputs=[output_text, output_image] |
|
) |
|
|
|
app.launch() |