|
|
import gradio as gr |
|
|
import matplotlib.pyplot as plt |
|
|
import numpy as np |
|
|
import sympy as sp |
|
|
from matplotlib.patches import Circle |
|
|
import io |
|
|
import base64 |
|
|
from PIL import Image |
|
|
import warnings |
|
|
warnings.filterwarnings('ignore') |
|
|
|
|
|
class MathVisualizer: |
|
|
def __init__(self): |
|
|
self.x = sp.Symbol('x') |
|
|
self.y = sp.Symbol('y') |
|
|
self.t = sp.Symbol('t') |
|
|
|
|
|
def safe_eval(self, expression, variables): |
|
|
"""Safely evaluate mathematical expressions""" |
|
|
try: |
|
|
|
|
|
expr = sp.sympify(expression) |
|
|
|
|
|
func = sp.lambdify(variables, expr, 'numpy') |
|
|
return func |
|
|
except Exception as e: |
|
|
raise ValueError(f"Invalid expression: {str(e)}") |
|
|
|
|
|
def plot_2d_function(self, equation, x_range, y_range, color, style, grid, title): |
|
|
"""Plot 2D function y = f(x)""" |
|
|
try: |
|
|
func = self.safe_eval(equation, self.x) |
|
|
x_vals = np.linspace(x_range[0], x_range[1], 1000) |
|
|
y_vals = func(x_vals) |
|
|
|
|
|
|
|
|
y_vals = np.real(y_vals) |
|
|
y_vals = np.where(np.abs(y_vals) > 1e10, np.nan, y_vals) |
|
|
|
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.plot(x_vals, y_vals, color=color, linewidth=2, linestyle=style) |
|
|
plt.xlim(x_range) |
|
|
plt.ylim(y_range) |
|
|
plt.xlabel('x', fontsize=12) |
|
|
plt.ylabel('y', fontsize=12) |
|
|
plt.title(title or f'y = {equation}', fontsize=14) |
|
|
plt.grid(grid, alpha=0.3) |
|
|
|
|
|
return plt.gcf() |
|
|
|
|
|
except Exception as e: |
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error in equation') |
|
|
return plt.gcf() |
|
|
|
|
|
def plot_parametric(self, x_equation, y_equation, t_range, color, style, grid, title): |
|
|
"""Plot parametric equations x = f(t), y = g(t)""" |
|
|
try: |
|
|
x_func = self.safe_eval(x_equation, self.t) |
|
|
y_func = self.safe_eval(y_equation, self.t) |
|
|
|
|
|
t_vals = np.linspace(t_range[0], t_range[1], 1000) |
|
|
x_vals = x_func(t_vals) |
|
|
y_vals = y_func(t_vals) |
|
|
|
|
|
|
|
|
x_vals = np.real(x_vals) |
|
|
y_vals = np.real(y_vals) |
|
|
|
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.plot(x_vals, y_vals, color=color, linewidth=2, linestyle=style) |
|
|
plt.xlabel('x', fontsize=12) |
|
|
plt.ylabel('y', fontsize=12) |
|
|
plt.title(title or f'x = {x_equation}, y = {y_equation}', fontsize=14) |
|
|
plt.grid(grid, alpha=0.3) |
|
|
plt.axis('equal') |
|
|
|
|
|
return plt.gcf() |
|
|
|
|
|
except Exception as e: |
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error in parametric equations') |
|
|
return plt.gcf() |
|
|
|
|
|
def plot_polar(self, equation, theta_range, color, style, grid, title): |
|
|
"""Plot polar equations r = f(θ)""" |
|
|
try: |
|
|
theta = sp.Symbol('theta') |
|
|
func = self.safe_eval(equation.replace('θ', 'theta').replace('theta', 'theta'), theta) |
|
|
|
|
|
theta_vals = np.linspace(theta_range[0], theta_range[1], 1000) |
|
|
r_vals = func(theta_vals) |
|
|
r_vals = np.real(r_vals) |
|
|
|
|
|
plt.figure(figsize=(10, 8)) |
|
|
ax = plt.subplot(111, projection='polar') |
|
|
ax.plot(theta_vals, r_vals, color=color, linewidth=2, linestyle=style) |
|
|
ax.set_title(title or f'r = {equation}', fontsize=14, pad=20) |
|
|
ax.grid(grid, alpha=0.3) |
|
|
|
|
|
return plt.gcf() |
|
|
|
|
|
except Exception as e: |
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error in polar equation') |
|
|
return plt.gcf() |
|
|
|
|
|
def plot_implicit(self, equation, x_range, y_range, color, grid, title): |
|
|
"""Plot implicit equations F(x,y) = 0""" |
|
|
try: |
|
|
|
|
|
expr = sp.sympify(equation) |
|
|
|
|
|
x_vals = np.linspace(x_range[0], x_range[1], 400) |
|
|
y_vals = np.linspace(y_range[0], y_range[1], 400) |
|
|
X, Y = np.meshgrid(x_vals, y_vals) |
|
|
|
|
|
|
|
|
func = sp.lambdify([self.x, self.y], expr, 'numpy') |
|
|
Z = func(X, Y) |
|
|
Z = np.real(Z) |
|
|
|
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.contour(X, Y, Z, levels=[0], colors=[color], linewidths=2) |
|
|
plt.xlim(x_range) |
|
|
plt.ylim(y_range) |
|
|
plt.xlabel('x', fontsize=12) |
|
|
plt.ylabel('y', fontsize=12) |
|
|
plt.title(title or f'{equation} = 0', fontsize=14) |
|
|
plt.grid(grid, alpha=0.3) |
|
|
|
|
|
return plt.gcf() |
|
|
|
|
|
except Exception as e: |
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error in implicit equation') |
|
|
return plt.gcf() |
|
|
|
|
|
def plot_3d_surface(self, equation, x_range, y_range, color_scheme, title): |
|
|
"""Plot 3D surface z = f(x,y)""" |
|
|
try: |
|
|
func = self.safe_eval(equation, [self.x, self.y]) |
|
|
|
|
|
x_vals = np.linspace(x_range[0], x_range[1], 50) |
|
|
y_vals = np.linspace(y_range[0], y_range[1], 50) |
|
|
X, Y = np.meshgrid(x_vals, y_vals) |
|
|
Z = func(X, Y) |
|
|
Z = np.real(Z) |
|
|
|
|
|
fig = plt.figure(figsize=(12, 10)) |
|
|
ax = fig.add_subplot(111, projection='3d') |
|
|
surf = ax.plot_surface(X, Y, Z, cmap=color_scheme, alpha=0.8) |
|
|
ax.set_xlabel('x', fontsize=12) |
|
|
ax.set_ylabel('y', fontsize=12) |
|
|
ax.set_zlabel('z', fontsize=12) |
|
|
ax.set_title(title or f'z = {equation}', fontsize=14) |
|
|
fig.colorbar(surf, shrink=0.5, aspect=5) |
|
|
|
|
|
return fig |
|
|
|
|
|
except Exception as e: |
|
|
fig = plt.figure(figsize=(12, 10)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error in 3D equation') |
|
|
return fig |
|
|
|
|
|
|
|
|
visualizer = MathVisualizer() |
|
|
|
|
|
def generate_plot(plot_type, equation, x_equation, y_equation, |
|
|
x_min, x_max, y_min, y_max, t_min, t_max, theta_min, theta_max, |
|
|
color, line_style, color_scheme, show_grid, custom_title): |
|
|
|
|
|
plt.close('all') |
|
|
|
|
|
try: |
|
|
if plot_type == "2D Function (y = f(x))": |
|
|
fig = visualizer.plot_2d_function( |
|
|
equation, (x_min, x_max), (y_min, y_max), |
|
|
color, line_style, show_grid, custom_title |
|
|
) |
|
|
|
|
|
elif plot_type == "Parametric (x = f(t), y = g(t))": |
|
|
fig = visualizer.plot_parametric( |
|
|
x_equation, y_equation, (t_min, t_max), |
|
|
color, line_style, show_grid, custom_title |
|
|
) |
|
|
|
|
|
elif plot_type == "Polar (r = f(θ))": |
|
|
fig = visualizer.plot_polar( |
|
|
equation, (theta_min, theta_max), |
|
|
color, line_style, show_grid, custom_title |
|
|
) |
|
|
|
|
|
elif plot_type == "Implicit (F(x,y) = 0)": |
|
|
fig = visualizer.plot_implicit( |
|
|
equation, (x_min, x_max), (y_min, y_max), |
|
|
color, show_grid, custom_title |
|
|
) |
|
|
|
|
|
elif plot_type == "3D Surface (z = f(x,y))": |
|
|
fig = visualizer.plot_3d_surface( |
|
|
equation, (x_min, x_max), (y_min, y_max), |
|
|
color_scheme, custom_title |
|
|
) |
|
|
|
|
|
return fig |
|
|
|
|
|
except Exception as e: |
|
|
plt.figure(figsize=(10, 8)) |
|
|
plt.text(0.5, 0.5, f'Error: {str(e)}', ha='center', va='center', |
|
|
transform=plt.gca().transAxes, fontsize=12, color='red') |
|
|
plt.title('Error generating plot') |
|
|
return plt.gcf() |
|
|
|
|
|
|
|
|
examples = { |
|
|
"2D Function (y = f(x))": [ |
|
|
"sin(x)", |
|
|
"x**2 + 2*x + 1", |
|
|
"exp(-x**2)", |
|
|
"tan(x)", |
|
|
"log(abs(x))" |
|
|
], |
|
|
"Parametric (x = f(t), y = g(t))": [ |
|
|
("cos(t)", "sin(t)"), |
|
|
("t*cos(t)", "t*sin(t)"), |
|
|
("cos(3*t)", "sin(2*t)"), |
|
|
], |
|
|
"Polar (r = f(θ))": [ |
|
|
"1 + cos(theta)", |
|
|
"sin(4*theta)", |
|
|
"theta", |
|
|
], |
|
|
"Implicit (F(x,y) = 0)": [ |
|
|
"x**2 + y**2 - 1", |
|
|
"(x**2 + y**2)**2 - 2*(x**2 - y**2)", |
|
|
"x**3 + y**3 - 3*x*y", |
|
|
], |
|
|
"3D Surface (z = f(x,y))": [ |
|
|
"sin(sqrt(x**2 + y**2))", |
|
|
"x**2 - y**2", |
|
|
"exp(-(x**2 + y**2))", |
|
|
] |
|
|
} |
|
|
|
|
|
def load_example(plot_type, example_idx): |
|
|
if plot_type in examples: |
|
|
example_list = examples[plot_type] |
|
|
if 0 <= example_idx < len(example_list): |
|
|
example = example_list[example_idx] |
|
|
if plot_type == "Parametric (x = f(t), y = g(t))": |
|
|
return example[0], example[1], "", "" |
|
|
else: |
|
|
return example, "", "", "" |
|
|
return "", "", "", "" |
|
|
|
|
|
|
|
|
with gr.Blocks(title="Mathematical Equation Visualizer", theme=gr.themes.Soft()) as demo: |
|
|
gr.Markdown(""" |
|
|
# 📊 Mathematical Equation Visualizer |
|
|
|
|
|
Generate beautiful visualizations of mathematical equations with various plot types and customization options. |
|
|
|
|
|
**Supported functions:** sin, cos, tan, exp, log, sqrt, abs, and basic arithmetic (+, -, *, /, **) |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(scale=1): |
|
|
plot_type = gr.Dropdown( |
|
|
choices=[ |
|
|
"2D Function (y = f(x))", |
|
|
"Parametric (x = f(t), y = g(t))", |
|
|
"Polar (r = f(θ))", |
|
|
"Implicit (F(x,y) = 0)", |
|
|
"3D Surface (z = f(x,y))" |
|
|
], |
|
|
value="2D Function (y = f(x))", |
|
|
label="Plot Type" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
equation = gr.Textbox( |
|
|
value="sin(x)", |
|
|
label="Equation", |
|
|
placeholder="e.g., sin(x), x**2 + 1, etc." |
|
|
) |
|
|
|
|
|
with gr.Row(visible=False) as parametric_inputs: |
|
|
x_equation = gr.Textbox( |
|
|
label="x = f(t)", |
|
|
placeholder="e.g., cos(t)" |
|
|
) |
|
|
y_equation = gr.Textbox( |
|
|
label="y = g(t)", |
|
|
placeholder="e.g., sin(t)" |
|
|
) |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("### Range Settings") |
|
|
with gr.Row(): |
|
|
x_min = gr.Number(value=-10, label="x min") |
|
|
x_max = gr.Number(value=10, label="x max") |
|
|
with gr.Row(): |
|
|
y_min = gr.Number(value=-10, label="y min") |
|
|
y_max = gr.Number(value=10, label="y max") |
|
|
with gr.Row(): |
|
|
t_min = gr.Number(value=0, label="t min") |
|
|
t_max = gr.Number(value=6.28, label="t max") |
|
|
with gr.Row(): |
|
|
theta_min = gr.Number(value=0, label="θ min") |
|
|
theta_max = gr.Number(value=6.28, label="θ max") |
|
|
|
|
|
with gr.Group(): |
|
|
gr.Markdown("### Style Settings") |
|
|
color = gr.ColorPicker(value="#1f77b4", label="Line Color") |
|
|
line_style = gr.Dropdown( |
|
|
choices=["-", "--", "-.", ":"], |
|
|
value="-", |
|
|
label="Line Style" |
|
|
) |
|
|
color_scheme = gr.Dropdown( |
|
|
choices=["viridis", "plasma", "inferno", "magma", "coolwarm", "RdYlBu"], |
|
|
value="viridis", |
|
|
label="3D Color Scheme" |
|
|
) |
|
|
show_grid = gr.Checkbox(value=True, label="Show Grid") |
|
|
custom_title = gr.Textbox(label="Custom Title (optional)") |
|
|
|
|
|
generate_btn = gr.Button("🎨 Generate Plot", variant="primary") |
|
|
|
|
|
|
|
|
gr.Markdown("### 📚 Examples") |
|
|
example_dropdown = gr.Dropdown( |
|
|
choices=["Select an example..."], |
|
|
label="Load Example" |
|
|
) |
|
|
|
|
|
with gr.Column(scale=2): |
|
|
output_plot = gr.Plot(label="Generated Plot") |
|
|
|
|
|
|
|
|
def update_inputs(plot_type): |
|
|
parametric_visible = plot_type == "Parametric (x = f(t), y = g(t))" |
|
|
|
|
|
|
|
|
if plot_type in examples: |
|
|
example_choices = ["Select an example..."] + [ |
|
|
f"Example {i+1}" for i in range(len(examples[plot_type])) |
|
|
] |
|
|
else: |
|
|
example_choices = ["Select an example..."] |
|
|
|
|
|
return ( |
|
|
gr.update(visible=parametric_visible), |
|
|
gr.update(choices=example_choices, value="Select an example...") |
|
|
) |
|
|
|
|
|
def load_example_equations(plot_type, example_choice): |
|
|
if example_choice == "Select an example...": |
|
|
return "", "", "", "" |
|
|
|
|
|
try: |
|
|
example_idx = int(example_choice.split()[-1]) - 1 |
|
|
return load_example(plot_type, example_idx) |
|
|
except: |
|
|
return "", "", "", "" |
|
|
|
|
|
plot_type.change( |
|
|
update_inputs, |
|
|
inputs=[plot_type], |
|
|
outputs=[parametric_inputs, example_dropdown] |
|
|
) |
|
|
|
|
|
example_dropdown.change( |
|
|
load_example_equations, |
|
|
inputs=[plot_type, example_dropdown], |
|
|
outputs=[equation, x_equation, y_equation, custom_title] |
|
|
) |
|
|
|
|
|
generate_btn.click( |
|
|
generate_plot, |
|
|
inputs=[ |
|
|
plot_type, equation, x_equation, y_equation, |
|
|
x_min, x_max, y_min, y_max, t_min, t_max, theta_min, theta_max, |
|
|
color, line_style, color_scheme, show_grid, custom_title |
|
|
], |
|
|
outputs=[output_plot] |
|
|
) |
|
|
|
|
|
|
|
|
equation.change( |
|
|
generate_plot, |
|
|
inputs=[ |
|
|
plot_type, equation, x_equation, y_equation, |
|
|
x_min, x_max, y_min, y_max, t_min, t_max, theta_min, theta_max, |
|
|
color, line_style, color_scheme, show_grid, custom_title |
|
|
], |
|
|
outputs=[output_plot] |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch(share=True) |