diff --git a/.gitignore b/.gitignore index 5251fd9..2452dee 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ **/*.bbl **/**.dat **/**.script +**/venv/** diff --git a/plots/demo-plot-1/README.md b/plots/demo-plot-1/README.md new file mode 100644 index 0000000..c48d3ce --- /dev/null +++ b/plots/demo-plot-1/README.md @@ -0,0 +1,140 @@ +# Parametric Surface Plotter + +This project provides a simple way to **define and plot parametric 3D surfaces** (or curves) using Python. + +* A **surface** is defined with **two parameters**: + + $$ + x = x(t, u), \quad y = y(t, u), \quad z = z(t, u) + $$ + +* A **curve** is defined with a **single parameter**: + + $$ + x = x(t), \quad y = y(t), \quad z = z(t) + $$ + +The script will: + +* Generate a mesh of points (for surfaces) or a set of points (for curves) +* Plot the result in 3D with Matplotlib +* Save the plot as a high-definition `.svg` file, named after the parent directory of the script + +--- + +## Requirements + +Install dependencies: + +```bash +pip install -r requirements.txt +``` + +--- + +## Usage + +Run the script: + +```bash +python plot_surface.py +``` + +A window with the 3D plot will open, and an `.svg` will be saved in the same directory. + +--- + +## Defining Your Own Geometry + +### 1. Surfaces (two parameters: t, u) + +Surfaces require two parameters because they are 2D objects. +You define three functions in `plot_surface.py`: + +```python +def x_func(t, u): return ... +def y_func(t, u): return ... +def z_func(t, u): return ... +``` + +Examples: + +* **Cone** + + $$ + x = 4t\cos(u), \quad y = 4t\sin(u), \quad z = 10t + $$ + + ```python + def x_func(t, u): return 4 * t * np.cos(u) + def y_func(t, u): return 4 * t * np.sin(u) + def z_func(t, u): return 10 * t + ``` + +* **Sphere** (radius 1) + + $$ + x = \cos(u)\sin(t), \quad y = \sin(u)\sin(t), \quad z = \cos(t) + $$ + + ```python + def x_func(t, u): return np.cos(u) * np.sin(t) + def y_func(t, u): return np.sin(u) * np.sin(t) + def z_func(t, u): return np.cos(t) + ``` + +You can adjust parameter ranges in `generate_mesh()`: + +```python +def generate_mesh(t_range=(0, 5), u_range=(0, 2*np.pi), n_t=50, n_u=100): + ... +``` + +* Sphere → `t_range=(0, np.pi)`, `u_range=(0, 2*np.pi)` +* Cone → `t_range=(0, 5)`, `u_range=(0, 2*np.pi)` + +--- + +### 2. Curves (one parameter: t) + +If your object is not a surface but a **curve**, you only need one parameter $t$. + +Example: **Helix** + +$$ +x = \cos(t), \quad y = \sin(t), \quad z = t +$$ + +```python +def x_func(t): return np.cos(t) +def y_func(t): return np.sin(t) +def z_func(t): return t +``` + +Here you don’t need `u` at all. The code can be simplified to generate a 1D array of points and plot them as a line in 3D. + +--- + +## Which Should I Use? + +* **Two parameters (t, u):** Use this for **surfaces** (sphere, torus, cone, paraboloid, etc.). +* **One parameter (t):** Use this for **curves** (helix, circle, line, parametric trajectory). + +👉 A quick rule: + +* If your equation is like $z = f(x, y)$, or implicit in 3 variables, you usually need **two parameters**. +* If your equation is like $x = f(t), y = g(t), z = h(t)$, then **one parameter** is enough. + +--- + +## Notes + +* Always use `numpy` functions (`np.sin`, `np.cos`, etc.), not Python’s built-ins, since the parameters are arrays. +* Some surfaces (like cones, hyperboloids) have two branches; you can add an additional `z_func_neg` if needed. +* The SVG is automatically named after the script’s parent directory. + +--- + +✅ With this, you can parametrize and visualize **both surfaces (2D)** and **curves (1D)** by editing only a few functions. + + diff --git a/plots/demo-plot-1/demo-plot-1.png b/plots/demo-plot-1/demo-plot-1.png new file mode 100644 index 0000000..4506648 Binary files /dev/null and b/plots/demo-plot-1/demo-plot-1.png differ diff --git a/plots/demo-plot-1/main.py b/plots/demo-plot-1/main.py new file mode 100644 index 0000000..c0f91c8 --- /dev/null +++ b/plots/demo-plot-1/main.py @@ -0,0 +1,100 @@ +import os +import numpy as np +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D # needed for 3D plotting +from matplotlib import rcParams + +# ------------------------------- +# Parametric surface functions +# ------------------------------- +def x_func(t, u): + """Parametric x(t,u)""" + return 4 * t * np.cos(u) + +def y_func(t, u): + """Parametric y(t,u)""" + return 4 * t * np.sin(u) + +def z_func(t, u): + """Parametric z(t,u)""" + return 10 * t + +def z_func_neg(t, u): + """Optional lower branch""" + return -10 * t + +# ------------------------------- +# Generate mesh +# ------------------------------- +def generate_mesh(t_range=(0, 5), u_range=(0, 2*np.pi), n_t=200, n_u=400): + """High-resolution parametric mesh""" + t = np.linspace(t_range[0], t_range[1], n_t) + u = np.linspace(u_range[0], u_range[1], n_u) + T, U = np.meshgrid(t, u) + X = x_func(T, U) + Y = y_func(T, U) + Z1 = z_func(T, U) + Z2 = z_func_neg(T, U) + return X, Y, Z1, Z2 + +# ------------------------------- +# Plot surface with high-quality settings +# ------------------------------- +def plot_surface(): + # Generate high-res mesh + X, Y, Z1, Z2 = generate_mesh() + + # Create figure with high DPI + fig = plt.figure(figsize=(12, 10), dpi=600) + ax = fig.add_subplot(111, projection="3d") + + # Smooth shading, anti-aliasing + surf1 = ax.plot_surface( + X, Y, Z1, + cmap="viridis", + edgecolor="none", + rstride=1, + cstride=1, + antialiased=True, + linewidth=0, + alpha=0.95 + ) + + surf2 = ax.plot_surface( + X, Y, Z2, + cmap="viridis", + edgecolor="none", + rstride=1, + cstride=1, + antialiased=True, + linewidth=0, + alpha=0.95 + ) + + # Axis labels and title + ax.set_xlabel("X", labelpad=15) + ax.set_ylabel("Y", labelpad=15) + ax.set_zlabel("Z", labelpad=15) + ax.set_title("Parametric Surface", pad=20) + + # Optional: adjust viewing angle + ax.view_init(elev=30, azim=45) + + # Add colorbar + fig.colorbar(surf1, shrink=0.5, aspect=10, pad=0.1) + + # Save at maximum quality + parent_dir = os.path.basename(os.path.dirname(os.path.abspath(__file__))) + filename_png = f"{parent_dir}.png" + + plt.savefig(filename_png, format="png", dpi=1200, bbox_inches='tight') # ultra-high-res raster + print(f"and PNG as {filename_png}") + + # Show interactive window (optional) + +# ------------------------------- +# Main +# ------------------------------- +if __name__ == "__main__": + plot_surface() +