### Install Matplotloom Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Installation commands for various package managers. ```bash pip install matplotloom ``` ```bash uv add matplotloom ``` ```bash poetry add matplotloom ``` ```bash conda install matplotloom ``` -------------------------------- ### Install matplotloom with uv Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Install the matplotloom package using uv. Ensure you have Python 3.10+. ```bash uv add matplotloom ``` -------------------------------- ### Install matplotloom with poetry Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Install the matplotloom package using poetry. Ensure you have Python 3.10+. ```bash poetry add matplotloom ``` -------------------------------- ### Double Pendulum Simulation Setup Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Initializes parameters for a double pendulum simulation. This snippet sets up physical constants and lengths for the pendulum arms and masses, preparing for integration. ```python import numpy as np import matplotlib.pyplot as plt from scipy.integrate import solve_ivp from tqdm import tqdm from matplotloom import Loom g = 9.80665 # standard acceleration of gravity [m/s²] l1, l2 = 1, 1 # pendulum arms lengths [m] m1, m2 = 1, 1 # pendulum masses [kg] ``` -------------------------------- ### Parallel Animation with Progress Tracking Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Uses joblib and tqdm to parallelize frame rendering for a physics simulation. Ensure all dependencies are installed and the environment supports multi-processing. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom from joblib import Parallel, delayed from tqdm import tqdm def simulate_trajectory(t_max, dt=0.01): """Simulate a bouncing ball trajectory.""" t = np.arange(0, t_max, dt) g = 9.81 v0, y0 = 10, 0 y = y0 + v0*t - 0.5*g*t**2 # Simple bounce model y = np.abs(y % 10) return t, y def render_frame(frame_idx, t_val, y_val, t_history, y_history, loom): """Render a single frame of the animation.""" fig, ax = plt.subplots(figsize=(10, 6)) # Plot trajectory history ax.plot(t_history[:frame_idx+1], y_history[:frame_idx+1], 'b-', alpha=0.5, linewidth=1) # Plot current ball position ax.scatter([t_val], [y_val], s=200, c='red', zorder=5) ax.set_xlim(0, t_history[-1]) ax.set_ylim(-0.5, 12) ax.set_xlabel('Time (s)') ax.set_ylabel('Height (m)') ax.set_title(f'Bouncing Ball Simulation - t = {t_val:.2f}s') ax.grid(True, alpha=0.3) loom.save_frame(fig, frame_idx) # Generate simulation data t, y = simulate_trajectory(5.0) # Sample frames (every 10th point for smoother playback) frame_indices = range(0, len(t), 10) with Loom("bouncing_ball.mp4", fps=30, parallel=True, overwrite=True) as loom: # Parallel rendering with progress bar Parallel(n_jobs=-1)( delayed(render_frame)(i, t[idx], y[idx], t, y, loom) for i, idx in tqdm(enumerate(frame_indices), total=len(list(frame_indices)), desc="Rendering frames") ) ``` -------------------------------- ### Install matplotloom with pip Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Install the matplotloom package using pip. Ensure you have Python 3.10+. ```bash pip install matplotloom ``` -------------------------------- ### Create a Sine Wave Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Generates a sine wave animation by iterating through different phases. Requires numpy and matplotlib. Ensure ffmpeg is installed for GIF generation. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom with Loom("sine_wave_animation.gif", fps=30) as loom: for phase in np.linspace(0, 2*np.pi, 100): fig, ax = plt.subplots() x = np.linspace(0, 2*np.pi, 200) y = np.sin(x + phase) ax.plot(x, y) ax.set_xlim(0, 2*np.pi) loom.save_frame(fig) ``` -------------------------------- ### Install matplotloom with conda Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Install the matplotloom package using conda. Ensure you have Python 3.10+. ```bash conda install matplotloom ``` -------------------------------- ### show Method Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Display the created animation in a Jupyter notebook. ```APIDOC ## show Method ### Description Display the created animation in a Jupyter notebook. This method returns an IPython display object that can be used to show the animation directly in a Jupyter notebook cell. The type of object returned depends on the file format of the animation. ### Notes This method is designed to work in Jupyter notebooks. It may not have the desired effect in other Python environments. The animation file must have been successfully created by the save_video method before calling this method. ### Parameters #### Optional Parameters - **kwargs** - Keyword arguments that will be passed to either IPython.display.Video or IPython.display.Image constructor depending on the file format. ### Returns - An IPython Video object for MP4 or MKV formats, or an IPython Image object for GIF or APNG formats. These objects can be displayed directly in a Jupyter notebook. - **Return type**: Union[IPython.display.Video, IPython.display.Image] ``` -------------------------------- ### Create Lorenz Attractor Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Demonstrates generating a 3D animation of a Lorenz attractor using matplotloom and Line3DCollection. ```python from dataclasses import dataclass, field import matplotlib.pyplot as plt import numpy as np from joblib import Parallel, delayed from matplotlib.colors import Normalize from matplotloom import Loom from mpl_toolkits.mplot3d.art3d import Line3DCollection @dataclass class Lorenz: dt: float = 0.01 sigma: float = 10.0 rho: float = 28.0 beta: float = 8.0 / 3.0 x: float = 1.0 y: float = 1.0 z: float = 1.0 def step(self): dx = self.sigma * (self.y - self.x) dy = self.x * (self.rho - self.z) - self.y dz = self.x * self.y - self.beta * self.z self.x += dx * self.dt self.y += dy * self.dt self.z += dz * self.dt @property def position(self) -> tuple[float, float, float]: return self.x, self.y, self.z @dataclass class LorenzPlotter: steps_per_frame: int = 20 attractor = Lorenz() points: list[tuple[float, float, float]] = field(default_factory=list) def initialize(self, steps: int): self.points = [self.attractor.position] for _ in range(steps): self.attractor.step() self.points.append(self.attractor.position) @property def frames(self) -> list[int]: return list(range(1, len(self.points) // self.steps_per_frame)) def get_frame(self, i: int, loom: Loom): fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={'projection': '3d'}) points = np.array(self.points[: i * self.steps_per_frame]) xs, ys, zs = points.T segments = np.array([points[:-1], points[1:]]).transpose(1, 0, 2) norm = Normalize(vmin=0, vmax=len(xs)) colors = plt.get_cmap('inferno')(norm(np.arange(len(xs) - 1))) lc = Line3DCollection(segments, colors=colors, linewidth=0.5) ax.add_collection3d(lc) ax.set_xlim(-30, 30) ax.set_ylim(-30, 30) ax.set_zlim(0, 50) ax.view_init( azim=(np.pi * 1.7 + 0.8 * np.sin(2.0 * np.pi * i * self.steps_per_frame / len(self.frames) / 10)) * 180.0 / np.pi ) ax.set_axis_off() ax.grid(visible=False) loom.save_frame(fig, i - 1) with Loom('lorenz.mp4', fps=60, parallel=True) as loom: attractor = LorenzPlotter() attractor.initialize(10000) Parallel(n_jobs=-1)(delayed(attractor.get_frame)(i, loom) for i in attractor.frames) ``` -------------------------------- ### Loom Class Initialization Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Initialize the Loom class to set up animation parameters. ```APIDOC ## Loom Class ### Description A class for creating animations from matplotlib figures. This class provides functionality to save individual frames and compile them into an animation (video or GIF) using ffmpeg. ### Parameters #### Path Parameters - **output_filepath** (Union[Path, str]) - Required - Path to save the final animation file. #### Optional Parameters - **fps** (int) - Optional - Frames per second for the output animation. Default is 30. - **frames_directory** (Union[Path, str, None]) - Optional - Directory to save individual frames. If None, a temporary directory is used. - **keep_frames** (bool) - Optional - Whether to keep individual frame files after creating the animation. Default is False. - **overwrite** (bool) - Optional - Whether to overwrite the output file if it already exists. Default is False. - **parallel** (bool) - Optional - Whether to enable parallel frame saving. Default is False. When True, this enables a mode where frames can be saved concurrently, significantly speeding up the animation creation process for computationally intensive plots or large numbers of frames. In parallel mode, the save_frame method requires an explicit frame number, frames can be created and saved in any order, and the user is responsible for parallelizing the frame creation process. - **odd_dimension_handling** (str) - Optional - How to handle odd pixel dimensions that some codecs (like H.264) cannot process. Options: "round_up" (default), "round_down", "crop", "pad", "none". - **savefig_kwargs** (dict) - Optional - Additional keyword arguments to pass to matplotlib’s savefig function. Default is {}. - **verbose** (bool) - Optional - Whether to print detailed information during the process. Default is False. - **show_ffmpeg_output** (bool) - Optional - Whether to show ffmpeg output when saving the video. Default is False. When True, the ffmpeg command and its stdout/stderr output will be printed during video creation. ### Raises - **FileExistsError** - If the output file already exists and overwrite is False. ``` -------------------------------- ### Configure Loom Constructor Parameters Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Customize animation output, frame storage, and encoding behavior using the Loom constructor. ```python from matplotloom import Loom # Full configuration example loom = Loom( output_filepath="animation.mp4", # Output file path (.mp4, .gif, .mkv, .apng) fps=60, # Frames per second (default: 30) frames_directory="./frames", # Custom frame storage (default: temp dir) keep_frames=True, # Keep frame PNGs after compilation overwrite=True, # Overwrite existing output file parallel=False, # Enable parallel frame saving mode odd_dimension_handling="round_up", # Handle odd pixel dimensions: "round_up", "round_down", "crop", "pad", "none" savefig_kwargs={ # Passed to matplotlib's fig.savefig() "dpi": 150, "bbox_inches": "tight", "facecolor": "white" }, verbose=True, # Print progress information show_ffmpeg_output=False # Show ffmpeg encoding output ) ``` -------------------------------- ### Parallelize Sine Wave Animation with Joblib Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Uses joblib to parallelize the frame generation process for a sine wave animation. Requires the Loom object to be initialized with parallel=True. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom from joblib import Parallel, delayed def plot_frame(phase, frame_number, loom): fig, ax = plt.subplots() x = np.linspace(0, 2*np.pi, 200) y = np.sin(x + phase) ax.plot(x, y) ax.set_xlim(0, 2*np.pi) loom.save_frame(fig, frame_number) with Loom("parallel_sine_wave.gif", fps=30, parallel=True) as loom: phases = np.linspace(0, 2*np.pi, 100) Parallel(n_jobs=-1)( delayed(plot_frame)(phase, i, loom) for i, phase in enumerate(phases) ) ``` -------------------------------- ### Display Animation in Jupyter Notebook Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Use the show() method to render animations directly within a Jupyter notebook environment. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom # Create animation with Loom("notebook_animation.gif", fps=15, overwrite=True) as loom: for i in range(30): fig, ax = plt.subplots(figsize=(6, 4)) theta = np.linspace(0, 2*np.pi, 100) r = 1 + 0.5 * np.sin(5*theta + i*0.2) x = r * np.cos(theta) y = r * np.sin(theta) ax.plot(x, y, 'purple', linewidth=2) ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) ax.set_aspect('equal') ax.set_title(f"Polar Rose - Frame {i}") loom.save_frame(fig) # Display in Jupyter notebook loom.show() # Returns IPython.display.Image for GIF # For MP4, use embed=True for inline playback # loom.show(embed=True) # Returns IPython.display.Video ``` -------------------------------- ### Create Animation with Loom Context Manager Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Use the Loom context manager to automatically compile frames into a video or GIF upon exiting the block. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom # Basic animation creation with context manager with Loom("sine_wave.gif", fps=30) as loom: for phase in np.linspace(0, 2*np.pi, 100): fig, ax = plt.subplots() x = np.linspace(0, 2*np.pi, 200) y = np.sin(x + phase) ax.plot(x, y) ax.set_xlim(0, 2*np.pi) ax.set_ylim(-1.2, 1.2) ax.set_title(f"Phase: {phase:.2f}") loom.save_frame(fig) # Video is automatically compiled when exiting the context ``` -------------------------------- ### save_video Method Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Compile saved frames into a video or GIF using ffmpeg. ```APIDOC ## save_video Method ### Description Compile saved frames into a video or GIF using ffmpeg. This method uses ffmpeg to create the final animation from the saved frames. The output format is determined by the file extension of the output filepath. ### Returns - None ``` -------------------------------- ### Create animation with parallel frame generation Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Utilize joblib's Parallel and delayed functions to distribute frame generation across CPU cores. ```python with Loom("parallel_sine.gif", fps=30, parallel=True) as loom: phases = np.linspace(0, 2*np.pi, 100) # Use all available CPU cores (-1) Parallel(n_jobs=-1)( delayed(create_frame)(phase, i, loom) for i, phase in enumerate(phases) ) ``` -------------------------------- ### Create Night Time Shading Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Uses Cartopy and matplotloom to generate an animation of night time shading across the globe. ```python import datetime import matplotlib.pyplot as plt import cartopy.crs as ccrs from cartopy.feature.nightshade import Nightshade from joblib import Parallel, delayed from matplotloom import Loom def plot_frame(day_of_year, loom, frame_number): date = datetime.datetime(2024, 1, 1, 12) + datetime.timedelta(days=day_of_year-1) fig = plt.figure(figsize=(15, 5)) proj1 = ccrs.Orthographic(central_longitude=0, central_latitude=30) proj2 = ccrs.Orthographic(central_longitude=120, central_latitude=0) proj3 = ccrs.Orthographic(central_longitude=240, central_latitude=-30) ax1 = fig.add_subplot(1, 3, 1, projection=proj1) ax2 = fig.add_subplot(1, 3, 2, projection=proj2) ax3 = fig.add_subplot(1, 3, 3, projection=proj3) fig.suptitle(f"Night time shading for {date} UTC") ax1.stock_img() ax1.add_feature(Nightshade(date, alpha=0.2)) ax2.stock_img() ax2.add_feature(Nightshade(date, alpha=0.2)) ax3.stock_img() ax3.add_feature(Nightshade(date, alpha=0.2)) loom.save_frame(fig, frame_number) loom = Loom( "night_time_shading.mp4", fps = 10, overwrite = True, parallel = True, verbose = True, savefig_kwargs = { "bbox_inches": "tight" } ) with loom: n_days_2024 = 366 days_of_year = range(1, n_days_2024 + 1) Parallel(n_jobs=-1)( delayed(plot_frame)(day_of_year, loom, i) for i, day_of_year in enumerate(days_of_year) ) ``` -------------------------------- ### Double Pendulum Simulation Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Simulates and animates a double pendulum system. Requires numpy, matplotlib, scipy, and tqdm. The animation is saved to 'double_pendulum.mp4'. ```python import numpy as np import matplotlib.pyplot as plt from scipy.integrate import solve_ivp from tqdm import tqdm from matplotloom import Loom g = 9.80665 # standard acceleration of gravity [m/s²] l1, l2 = 1, 1 # pendulum arms lengths [m] m1, m2 = 1, 1 # pendulum masses [kg] # Calculate dy/dt where y = [θ1, ω1, θ2, ω2]. def derivatives(t, state): θ1, ω1, θ2, ω2 = state dydt = np.zeros_like(state) dydt[0] = ω1 dydt[2] = ω2 Δθ = θ2 - θ1 denominator1 = (m1 + m2) * l1 - m2 * l1 * np.cos(Δθ)**2 dydt[1] = (m2 * l1 * ω1**2 * np.sin(Δθ) * np.cos(Δθ) + m2 * g * np.sin(θ2) * np.cos(Δθ) + m2 * l2 * ω2**2 * np.sin(Δθ) - (m1 + m2) * g * np.sin(θ1)) / denominator1 denominator2 = (l2 / l1) * denominator1 dydt[3] = (-m2 * l2 * ω2**2 * np.sin(Δθ) * np.cos(Δθ) + (m1 + m2) * g * np.sin(θ1) * np.cos(Δθ) - (m1 + m2) * l1 * ω1**2 * np.sin(Δθ) - (m1 + m2) * g * np.sin(θ2)) / denominator2 return dydt t_span = (0, 20) y0 = [np.pi/2, 0, np.pi/2, 0] sol = solve_ivp(derivatives, t_span, y0, dense_output=True) times = np.linspace(t_span[0], t_span[1], 1000) θ1, ω1, θ2, ω2 = sol.sol(times) x1 = l1 * np.sin(θ1) y1 = -l1 * np.cos(θ1) x2 = x1 + l2 * np.sin(θ2) y2 = y1 - l2 * np.cos(θ2) loom = Loom( "double_pendulum.mp4", fps = 60, overwrite = True, savefig_kwargs = {"bbox_inches": "tight"} ) with loom: for i, t in tqdm(enumerate(times), total=len(times)): fig, ax = plt.subplots(figsize=(8, 8)) ax.plot( [0, x1[i], x2[i]], [0, y1[i], y2[i]], linestyle = "solid", marker = "o", color = "black", linewidth = 3 ) ax.plot( x2[:i+1], y2[:i+1], linestyle = "solid", linewidth = 2, color = "red", alpha = 0.5 ) ax.set_title(f"Double Pendulum: t = {t:.3f}s") ax.set_xlim(-2.2, 2.2) ax.set_ylim(-2.2, 2.2) ax.set_aspect("equal", adjustable="box") loom.save_frame(fig) ``` -------------------------------- ### Bessel Wave Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Creates an animation of a Bessel wave, showing both a 2D pcolormesh plot and a cross-section. Requires numpy, matplotlib, scipy, and cmocean. The animation is saved to 'bessel_wave.mp4'. ```python import numpy as np import matplotlib.pyplot as plt from scipy.special import j0 from cmocean import cm from matplotloom import Loom def bessel_wave(r, t, k, omega, A): return A * j0(k*r - omega*t) def create_frame(x, y, t): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5)) r = np.sqrt(x**2 + y**2) z = bessel_wave(r, t, k=2, omega=1, A=1) pcm = ax1.pcolormesh(x, y, z, cmap=cm.balance, shading='auto', vmin=-1, vmax=1) fig.colorbar(pcm, ax=ax1) ax1.set_title(f"Bessel wave: t = {t:.3f}") ax1.set_xlabel("x") ax1.set_ylabel("y") ax1.set_xlim(-10, 10) ax1.set_ylim(-10, 10) ax1.set_aspect("equal", adjustable="box") mid = z.shape[0] // 2 ax2.plot(x[mid], z[mid]) ax2.set_xlim(x.min(), x.max()) ax2.set_ylim(-1.1, 1.1) ax2.set_title("Cross-section at y = 0") ax2.set_xlabel("x") ax2.set_ylabel("z") return fig loom = Loom( "bessel_wave.mp4", fps = 30, overwrite = True, verbose = True, savefig_kwargs = { "dpi": 100, "bbox_inches": "tight" } ) with loom: x = np.linspace(-10, 10, 500) y = np.linspace(-10, 10, 500) x, y = np.meshgrid(x, y) for t in np.linspace(0, 50, 300): fig = create_frame(x, y, t) loom.save_frame(fig) ``` -------------------------------- ### Generate Frames in Parallel Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Enable parallel mode to generate frames concurrently. An explicit frame_number is required when calling save_frame(). ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom from joblib import Parallel, delayed def create_frame(phase, frame_number, loom): """Function that creates a single frame - runs in parallel.""" fig, ax = plt.subplots() x = np.linspace(0, 2*np.pi, 200) y = np.sin(x + phase) ax.plot(x, y, 'b-', linewidth=2) ax.set_xlim(0, 2*np.pi) ax.set_ylim(-1.2, 1.2) ax.set_title(f"Sine Wave - Phase {phase:.2f}") # Must provide frame_number in parallel mode loom.save_frame(fig, frame_number) ``` -------------------------------- ### 3D Surface Animation with Rotation Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Generate a rotating 3D surface animation by updating the camera view angle in each frame. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom with Loom("rotating_surface.mp4", fps=10, overwrite=True) as loom: for angle in range(0, 360, 10): fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={"projection": "3d"}) # Create surface data X = np.arange(-5, 5, 0.25) Y = np.arange(-5, 5, 0.25) X, Y = np.meshgrid(X, Y) R = np.sqrt(X**2 + Y**2) Z = np.sin(R) # Plot surface with colormap surf = ax.plot_surface(X, Y, Z, cmap="coolwarm", linewidth=0, antialiased=True) # Rotate camera view ax.view_init(elev=30, azim=angle) ax.set_zlim(-1.5, 1.5) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') fig.colorbar(surf, shrink=0.5, aspect=10) loom.save_frame(fig) ``` -------------------------------- ### Rotating Circular Sine Wave Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/README.md Generates a rotating 3D circular sine wave animation. Requires numpy and matplotlib. The animation is saved to 'rotating_circular_sine_wave.mp4'. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom with Loom("rotating_circular_sine_wave.mp4", fps=10) as loom: for i in range(36): fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={"projection": "3d"}) X = np.arange(-5, 5, 0.25) Y = np.arange(-5, 5, 0.25) X, Y = np.meshgrid(X, Y) R = np.sqrt(X**2 + Y**2) Z = np.sin(R) surf = ax.plot_surface(X, Y, Z, cmap="coolwarm") ax.view_init(azim=i*10) ax.set_zlim(-1.01, 1.01) fig.colorbar(surf, shrink=0.5, aspect=5) loom.save_frame(fig) ``` -------------------------------- ### Double Pendulum Animation Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Calculates the physics of a double pendulum and renders the motion as an MP4 video using matplotloom. ```python # Calculate dy/dt where y = [θ1, ω1, θ2, ω2]. def derivatives(t, state): θ1, ω1, θ2, ω2 = state dydt = np.zeros_like(state) dydt[0] = ω1 dydt[2] = ω2 Δθ = θ2 - θ1 denominator1 = (m1 + m2) * l1 - m2 * l1 * np.cos(Δθ)**2 dydt[1] = (m2 * l1 * ω1**2 * np.sin(Δθ) * np.cos(Δθ) + m2 * g * np.sin(θ2) * np.cos(Δθ) + m2 * l2 * ω2**2 * np.sin(Δθ) - (m1 + m2) * g * np.sin(θ1)) / denominator1 denominator2 = (l2 / l1) * denominator1 dydt[3] = (-m2 * l2 * ω2**2 * np.sin(Δθ) * np.cos(Δθ) + (m1 + m2) * g * np.sin(θ1) * np.cos(Δθ) - (m1 + m2) * l1 * ω1**2 * np.sin(Δθ) - (m1 + m2) * g * np.sin(θ2)) / denominator2 return dydt t_span = (0, 20) y0 = [np.pi/2, 0, np.pi/2, 0] sol = solve_ivp(derivatives, t_span, y0, dense_output=True) times = np.linspace(t_span[0], t_span[1], 1000) θ1, ω1, θ2, ω2 = sol.sol(times) x1 = l1 * np.sin(θ1) y1 = -l1 * np.cos(θ1) x2 = x1 + l2 * np.sin(θ2) y2 = y1 - l2 * np.cos(θ2) loom = Loom( "double_pendulum.mp4", fps = 60, overwrite = True, savefig_kwargs = {"bbox_inches": "tight"} ) with loom: for i, t in tqdm(enumerate(times), total=len(times)): fig, ax = plt.subplots(figsize=(8, 8)) ax.plot( [0, x1[i], x2[i]], [0, y1[i], y2[i]], linestyle = "solid", marker = "o", color = "black", linewidth = 3 ) ax.plot( x2[:i+1], y2[:i+1], linestyle = "solid", linewidth = 2, color = "red", alpha = 0.5 ) ax.set_title(f"Double Pendulum: t = {t:.3f}s") ax.set_xlim(-2.2, 2.2) ax.set_ylim(-2.2, 2.2) ax.set_aspect("equal", adjustable="box") loom.save_frame(fig) ``` -------------------------------- ### Save Individual Frames Sequentially Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Use save_frame() to add figures to the animation sequence. Figures are closed by default to conserve memory. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom # Sequential frame saving (default mode) with Loom("sequential.mp4", fps=30, verbose=True) as loom: for i in range(60): fig, ax = plt.subplots(figsize=(8, 6)) ax.bar(range(5), np.random.rand(5)) ax.set_title(f"Frame {i}") ax.set_ylim(0, 1) # Automatically numbered, figure closed after save loom.save_frame(fig) # Or keep figure open for further manipulation # loom.save_frame(fig, close_fig=False) # plt.close(fig) # Manual close ``` -------------------------------- ### Cartopy Geospatial Animation Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Demonstrates integrating Cartopy with Matplotloom for geospatial visualizations. The savefig_kwargs parameter allows passing custom arguments to the underlying matplotlib savefig call. ```python import datetime import matplotlib.pyplot as plt import cartopy.crs as ccrs from cartopy.feature.nightshade import Nightshade from matplotloom import Loom from joblib import Parallel, delayed def plot_earth_frame(day_of_year, loom, frame_number): """Create a frame showing day/night on Earth for a specific day.""" date = datetime.datetime(2024, 1, 1, 12) + datetime.timedelta(days=day_of_year-1) fig = plt.figure(figsize=(12, 6)) ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson()) ax.stock_img() ax.coastlines(linewidth=0.5) ax.add_feature(Nightshade(date, alpha=0.3)) ax.set_title(f"Day/Night Terminator: {date.strftime('%B %d, %Y')}", fontsize=14) loom.save_frame(fig, frame_number) # Create year-long animation with parallel rendering loom = Loom( "earth_daynight.mp4", fps=15, parallel=True, overwrite=True, savefig_kwargs={"dpi": 100, "bbox_inches": "tight"} ) with loom: days = range(1, 366) # Full year Parallel(n_jobs=-1)( delayed(plot_earth_frame)(day, loom, i) for i, day in enumerate(days) ) ``` -------------------------------- ### Multi-Panel Figure Animation Source: https://context7.com/ali-ramadhan/matplotloom/llms.txt Construct animations containing multiple subplots, such as a heatmap and a corresponding cross-section plot. ```python import numpy as np import matplotlib.pyplot as plt from matplotloom import Loom def wave_function(x, y, t): """2D wave with time evolution.""" r = np.sqrt(x**2 + y**2) return np.sin(2*r - t) * np.exp(-0.1*r) loom = Loom( "multi_panel.mp4", fps=30, overwrite=True, savefig_kwargs={"dpi": 100, "bbox_inches": "tight"} ) with loom: x = np.linspace(-10, 10, 200) y = np.linspace(-10, 10, 200) X, Y = np.meshgrid(x, y) for t in np.linspace(0, 4*np.pi, 120): fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5)) # Left panel: 2D heatmap Z = wave_function(X, Y, t) pcm = ax1.pcolormesh(X, Y, Z, cmap='RdBu_r', shading='auto', vmin=-1, vmax=1) ax1.set_title(f"2D Wave at t = {t:.2f}") ax1.set_xlabel("x") ax1.set_ylabel("y") ax1.set_aspect("equal") fig.colorbar(pcm, ax=ax1, label="Amplitude") # Right panel: Cross-section at y=0 mid_idx = len(y) // 2 ax2.plot(x, Z[mid_idx, :], 'b-', linewidth=2) ax2.axhline(y=0, color='gray', linestyle='--', alpha=0.5) ax2.set_xlim(-10, 10) ax2.set_ylim(-1.2, 1.2) ax2.set_title("Cross-section at y = 0") ax2.set_xlabel("x") ax2.set_ylabel("Amplitude") ax2.grid(True, alpha=0.3) loom.save_frame(fig) ``` -------------------------------- ### save_frame Method Source: https://github.com/ali-ramadhan/matplotloom/blob/main/docs/index.md Save a single frame of the animation. ```APIDOC ## save_frame Method ### Description Save a single frame of the animation. ### Parameters #### Path Parameters - **fig** (matplotlib.figure.Figure) - Required - The matplotlib figure to save. #### Optional Parameters - **frame_number** (int | None) - Optional - The frame number (required if parallel=True). - **close_fig** (bool) - Optional - Whether to close the figure after saving. Default is True. ### Returns - None ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.