or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

3d-objects.mdadvanced-animations.mdanimation-system.mdboolean-operations.mdcoordinate-systems.mdindex.mdinteractive-controls.mdmathematical-objects.mdmatrix-visualization.mdprobability-stats.mdscene-framework.mdtext-and-latex.mdutilities-and-constants.mdvalue-tracking.mdvector-fields.md

vector-fields.mddocs/

0

# Vector Fields

1

2

ManimGL provides comprehensive tools for visualizing vector fields, essential for physics simulations and mathematical demonstrations. The vector field system includes static field visualization, time-dependent fields, streamline generation, and animated flow visualization using numerical integration and sophisticated rendering techniques.

3

4

## Capabilities

5

6

### Static Vector Field Visualization

7

8

Create visual representations of vector fields as arrays of arrows showing direction and magnitude at sample points.

9

10

```python { .api }

11

class VectorField(VMobject):

12

def __init__(

13

self,

14

func: Callable[[VectArray], VectArray],

15

coordinate_system: CoordinateSystem,

16

density: float = 2.0,

17

magnitude_range: Optional[Tuple[float, float]] = None,

18

color: Optional[ManimColor] = None,

19

color_map_name: Optional[str] = "3b1b_colormap",

20

color_map: Optional[Callable[[Sequence[float]], Vect4Array]] = None,

21

stroke_opacity: float = 1.0,

22

stroke_width: float = 3,

23

tip_width_ratio: float = 4,

24

tip_len_to_width: float = 0.01,

25

max_vect_len: float | None = None,

26

max_vect_len_to_step_size: float = 0.8,

27

flat_stroke: bool = False,

28

norm_to_opacity_func=None,

29

**kwargs

30

):

31

"""

32

Create a visual vector field representation.

33

34

Parameters:

35

- func: Vectorized function mapping coordinates to vectors

36

- coordinate_system: Axes or NumberPlane for coordinate mapping

37

- density: Sampling density for vector placement

38

- magnitude_range: Optional range for magnitude scaling

39

- color_map_name: Built-in color map for magnitude coloring

40

- stroke_width: Arrow thickness

41

- tip_width_ratio: Arrow head width relative to shaft

42

- max_vect_len: Maximum display length for vectors

43

- max_vect_len_to_step_size: Scaling factor for vector length

44

"""

45

46

def update_vectors(self):

47

"""Recompute and redraw all vector arrows based on function."""

48

49

def set_sample_coords(self, sample_coords):

50

"""Update the grid of sample points for vector placement."""

51

52

def set_stroke_width(self, width):

53

"""Adjust arrow thickness with proper tip scaling."""

54

```

55

56

### Time-Dependent Vector Fields

57

58

Handle dynamic vector fields that evolve over time for physics simulations and animated demonstrations.

59

60

```python { .api }

61

class TimeVaryingVectorField(VectorField):

62

def __init__(

63

self,

64

time_func: Callable[[VectArray, float], VectArray],

65

coordinate_system: CoordinateSystem,

66

**kwargs

67

):

68

"""

69

Create a time-dependent vector field.

70

71

Parameters:

72

- time_func: Function taking (coordinates, time) returning vectors

73

- coordinate_system: Coordinate system for field mapping

74

- kwargs: Additional VectorField parameters

75

"""

76

77

def increment_time(self, dt):

78

"""Advance the internal time counter by dt."""

79

```

80

81

### Streamline Generation

82

83

Generate smooth curves that follow vector field flow using numerical integration for fluid dynamics and field line visualization.

84

85

```python { .api }

86

class StreamLines(VGroup):

87

def __init__(

88

self,

89

func: Callable[[VectArray], VectArray],

90

coordinate_system: CoordinateSystem,

91

density: float = 1.0,

92

n_repeats: int = 1,

93

noise_factor: float | None = None,

94

solution_time: float = 3,

95

dt: float = 0.05,

96

arc_len: float = 3,

97

max_time_steps: int = 200,

98

n_samples_per_line: int = 10,

99

cutoff_norm: float = 15,

100

stroke_width: float = 1.0,

101

stroke_color: ManimColor = WHITE,

102

stroke_opacity: float = 1,

103

color_by_magnitude: bool = True,

104

magnitude_range: Tuple[float, float] = (0, 2.0),

105

taper_stroke_width: bool = False,

106

color_map: str = "3b1b_colormap",

107

**kwargs

108

):

109

"""

110

Generate streamlines following vector field flow.

111

112

Parameters:

113

- func: Vector field function

114

- coordinate_system: Coordinate system for integration

115

- density: Sampling density for streamline starting points

116

- n_repeats: Multiple lines per sample point

117

- noise_factor: Random offset for varied starting points

118

- solution_time: Integration time duration

119

- dt: Time step for numerical integration

120

- max_time_steps: Maximum integration steps

121

- cutoff_norm: Stop integration if field norm exceeds this

122

- color_by_magnitude: Color lines by local field strength

123

- taper_stroke_width: Varying line thickness along streamline

124

"""

125

126

def draw_lines(self):

127

"""Use ODE solver to generate streamline paths."""

128

129

def get_sample_coords(self):

130

"""Get starting points with optional noise."""

131

```

132

133

### Animated Flow Visualization

134

135

Create animated streamlines with flowing effects to show dynamic field behavior and flow patterns.

136

137

```python { .api }

138

class AnimatedStreamLines(VGroup):

139

def __init__(

140

self,

141

stream_lines: StreamLines,

142

lag_range: float = 4,

143

rate_multiple: float = 1.0,

144

line_anim_config: dict = {"rate_func": linear, "time_width": 1.0},

145

**kwargs

146

):

147

"""

148

Animate streamlines with flowing effects.

149

150

Parameters:

151

- stream_lines: StreamLines object to animate

152

- lag_range: Stagger animation start times

153

- rate_multiple: Animation speed multiplier

154

- line_anim_config: Animation configuration for flow effects

155

"""

156

```

157

158

### Object Movement Along Fields

159

160

Utility functions for making objects follow vector field flow in real-time simulations.

161

162

```python { .api }

163

def move_along_vector_field(

164

mobject: Mobject,

165

func: Callable[[Vect3], Vect3]

166

) -> Mobject:

167

"""

168

Add updater to move mobject along vector field flow.

169

170

Parameters:

171

- mobject: Object to move

172

- func: Vector field function

173

174

Returns:

175

Modified mobject with movement updater

176

"""

177

178

def move_points_along_vector_field(

179

mobject: Mobject,

180

func: Callable,

181

coordinate_system: CoordinateSystem

182

) -> Mobject:

183

"""

184

Move all points of a mobject along vector field.

185

186

Parameters:

187

- mobject: Object whose points will move

188

- func: Vector field function

189

- coordinate_system: Coordinate system for mapping

190

191

Returns:

192

Modified mobject with point movement updater

193

"""

194

```

195

196

### Field Analysis Utilities

197

198

Helper functions for vector field analysis and coordinate system integration.

199

200

```python { .api }

201

def get_sample_coords(

202

coordinate_system: CoordinateSystem,

203

density: float = 1.0

204

) -> np.ndarray:

205

"""

206

Generate sample coordinates for vector field evaluation.

207

208

Parameters:

209

- coordinate_system: Coordinate system to sample

210

- density: Sampling density

211

212

Returns:

213

Array of coordinate points for field evaluation

214

"""

215

216

def vectorize(pointwise_function: Callable) -> Callable:

217

"""

218

Convert pointwise function to vectorized form for efficient evaluation.

219

220

Parameters:

221

- pointwise_function: Function operating on single points

222

223

Returns:

224

Vectorized function operating on arrays

225

"""

226

227

def ode_solution_points(

228

function,

229

state0,

230

time,

231

dt: float = 0.01

232

) -> np.ndarray:

233

"""

234

Solve ODE system to generate solution points.

235

236

Parameters:

237

- function: Derivative function for ODE system

238

- state0: Initial state

239

- time: Time duration for solution

240

- dt: Time step

241

242

Returns:

243

Array of solution points

244

"""

245

```

246

247

## Usage Examples

248

249

### Electromagnetic Field Visualization

250

251

```python

252

from manimlib import *

253

254

class ElectricField(Scene):

255

def construct(self):

256

plane = NumberPlane(x_range=[-4, 4], y_range=[-3, 3])

257

self.add(plane)

258

259

# Define electric field from point charges

260

def electric_field(coords):

261

x, y = coords.T

262

263

# Positive charge at (-1, 0)

264

r1_squared = (x + 1)**2 + y**2 + 0.1 # Small offset to avoid singularity

265

E1_x = (x + 1) / r1_squared**(3/2)

266

E1_y = y / r1_squared**(3/2)

267

268

# Negative charge at (1, 0)

269

r2_squared = (x - 1)**2 + y**2 + 0.1

270

E2_x = -(x - 1) / r2_squared**(3/2)

271

E2_y = -y / r2_squared**(3/2)

272

273

# Total field

274

Ex = E1_x + E2_x

275

Ey = E1_y + E2_y

276

277

return np.array([Ex, Ey]).T

278

279

# Create vector field

280

field = VectorField(

281

electric_field,

282

plane,

283

density=1.5,

284

stroke_width=2,

285

max_vect_len=0.6

286

)

287

288

# Add charges

289

positive_charge = Circle(radius=0.1, color=RED, fill_opacity=1)

290

negative_charge = Circle(radius=0.1, color=BLUE, fill_opacity=1)

291

positive_charge.move_to(plane.c2p(-1, 0))

292

negative_charge.move_to(plane.c2p(1, 0))

293

294

# Labels

295

plus_label = Text("+", font_size=24, color=WHITE).move_to(positive_charge)

296

minus_label = Text("−", font_size=24, color=WHITE).move_to(negative_charge)

297

298

self.play(ShowCreation(field), run_time=3)

299

self.play(

300

ShowCreation(positive_charge),

301

ShowCreation(negative_charge),

302

Write(plus_label),

303

Write(minus_label)

304

)

305

306

# Add field lines

307

field_lines = StreamLines(

308

electric_field,

309

plane,

310

density=0.8,

311

stroke_width=1.5,

312

color_by_magnitude=True

313

)

314

315

self.play(ShowCreation(field_lines), run_time=4)

316

self.wait(2)

317

```

318

319

### Fluid Flow Simulation

320

321

```python

322

class FluidFlow(Scene):

323

def construct(self):

324

plane = NumberPlane(x_range=[-3, 3], y_range=[-2, 2])

325

self.add(plane)

326

327

# Define fluid velocity field (vortex + uniform flow)

328

def velocity_field(coords):

329

x, y = coords.T

330

331

# Vortex component

332

vortex_x = -y

333

vortex_y = x

334

335

# Uniform flow component

336

uniform_x = np.ones_like(x) * 0.5

337

uniform_y = np.zeros_like(y)

338

339

# Combine components

340

vx = vortex_x + uniform_x

341

vy = vortex_y + uniform_y

342

343

return np.array([vx, vy]).T

344

345

# Create streamlines

346

streamlines = StreamLines(

347

velocity_field,

348

plane,

349

density=1.5,

350

n_repeats=2,

351

noise_factor=0.1,

352

stroke_width=2,

353

color_by_magnitude=True,

354

magnitude_range=(0, 3)

355

)

356

357

# Animate the flow

358

animated_lines = AnimatedStreamLines(

359

streamlines,

360

lag_range=2,

361

rate_multiple=1.5

362

)

363

364

self.add(animated_lines)

365

366

# Add some particles that follow the flow

367

particles = VGroup(*[

368

Dot(radius=0.05, color=YELLOW).move_to(

369

plane.c2p(

370

3 * (np.random.random() - 0.5),

371

2 * (np.random.random() - 0.5)

372

)

373

)

374

for _ in range(20)

375

])

376

377

# Make particles follow the field

378

for particle in particles:

379

move_along_vector_field(particle, lambda p: velocity_field(np.array([plane.p2c(p)[:2]]))[0])

380

381

self.add(particles)

382

self.wait(10)

383

```

384

385

### Phase Space Visualization

386

387

```python

388

class PhasePortrait(Scene):

389

def construct(self):

390

plane = NumberPlane(x_range=[-3, 3], y_range=[-3, 3])

391

plane.add_coordinates()

392

self.add(plane)

393

394

# Simple harmonic oscillator phase space

395

def harmonic_flow(coords):

396

x, y = coords.T # x = position, y = velocity

397

dx_dt = y # dx/dt = velocity

398

dy_dt = -x # dy/dt = -x (acceleration)

399

400

return np.array([dx_dt, dy_dt]).T

401

402

# Create vector field

403

field = VectorField(

404

harmonic_flow,

405

plane,

406

density=1.2,

407

stroke_width=1.5,

408

max_vect_len=0.4,

409

color_map_name="viridis"

410

)

411

412

# Create phase trajectories

413

trajectories = StreamLines(

414

harmonic_flow,

415

plane,

416

density=0.6,

417

stroke_width=2,

418

solution_time=2*PI, # One period

419

color_by_magnitude=False,

420

stroke_color=YELLOW

421

)

422

423

self.play(ShowCreation(field), run_time=2)

424

self.play(ShowCreation(trajectories), run_time=3)

425

426

# Add labels

427

x_label = Text("Position", font_size=24).next_to(plane.x_axis, DOWN)

428

y_label = Text("Velocity", font_size=24).next_to(plane.y_axis, LEFT)

429

y_label.rotate(PI/2)

430

431

title = Text("Harmonic Oscillator Phase Portrait", font_size=32).to_edge(UP)

432

433

self.play(Write(title), Write(x_label), Write(y_label))

434

self.wait()

435

```

436

437

### Time-Dependent Magnetic Field

438

439

```python

440

class TimeVaryingField(Scene):

441

def construct(self):

442

plane = NumberPlane(x_range=[-2, 2], y_range=[-2, 2])

443

self.add(plane)

444

445

# Time-varying magnetic field (rotating)

446

def rotating_field(coords, t):

447

x, y = coords.T

448

449

# Rotating uniform field

450

field_strength = 1.0

451

omega = 1.0 # Angular frequency

452

453

Bx = field_strength * np.cos(omega * t) * np.ones_like(x)

454

By = field_strength * np.sin(omega * t) * np.ones_like(y)

455

456

return np.array([Bx, By]).T

457

458

# Create time-varying field

459

field = TimeVaryingVectorField(

460

rotating_field,

461

plane,

462

density=1.5,

463

stroke_width=3,

464

max_vect_len=0.8

465

)

466

467

# Add field indicator

468

field_arrow = Arrow(ORIGIN, RIGHT, color=RED, buff=0)

469

field_arrow.to_edge(UP + RIGHT)

470

471

def update_indicator(arrow):

472

t = field.time

473

direction = np.array([np.cos(t), np.sin(t), 0])

474

arrow.become(Arrow(ORIGIN, direction, color=RED, buff=0))

475

arrow.to_edge(UP + RIGHT)

476

477

field_arrow.add_updater(update_indicator)

478

479

# Labels

480

title = Text("Rotating Magnetic Field", font_size=32).to_edge(UP + LEFT)

481

time_label = Text("t = 0.0", font_size=24).to_edge(DOWN + RIGHT)

482

483

def update_time_label(label):

484

t = field.time

485

label.become(Text(f"t = {t:.1f}", font_size=24))

486

label.to_edge(DOWN + RIGHT)

487

488

time_label.add_updater(update_time_label)

489

490

self.add(field, field_arrow, title, time_label)

491

self.wait(8) # Let field rotate

492

```

493

494

### Interactive Field Exploration

495

496

```python

497

from manimlib.mobject.interactive import LinearNumberSlider

498

499

class InteractiveField(Scene):

500

def setup(self):

501

# Create parameter controls

502

self.strength_slider = LinearNumberSlider(

503

value=1.0, min_value=0.1, max_value=3.0, step=0.1

504

)

505

self.rotation_slider = LinearNumberSlider(

506

value=0.0, min_value=-PI, max_value=PI, step=0.1

507

)

508

509

self.strength_slider.to_edge(DOWN).shift(UP * 0.5)

510

self.rotation_slider.to_edge(DOWN)

511

512

self.add(self.strength_slider, self.rotation_slider)

513

514

def construct(self):

515

plane = NumberPlane(x_range=[-2, 2], y_range=[-2, 2])

516

517

# Interactive field function

518

def interactive_field(coords):

519

x, y = coords.T

520

strength = self.strength_slider.get_value()

521

angle = self.rotation_slider.get_value()

522

523

# Rotated uniform field

524

cos_a, sin_a = np.cos(angle), np.sin(angle)

525

field_x = strength * cos_a * np.ones_like(x)

526

field_y = strength * sin_a * np.ones_like(y)

527

528

return np.array([field_x, field_y]).T

529

530

# Create responsive field

531

field = VectorField(

532

interactive_field,

533

plane,

534

density=1.5,

535

stroke_width=2

536

)

537

538

# Add updater to redraw field when parameters change

539

field.add_updater(lambda f: f.update_vectors())

540

541

# Labels

542

strength_label = Text("Field Strength", font_size=20)

543

rotation_label = Text("Field Rotation", font_size=20)

544

545

strength_label.next_to(self.strength_slider, LEFT)

546

rotation_label.next_to(self.rotation_slider, LEFT)

547

548

self.add(plane, field, strength_label, rotation_label)

549

self.wait(15) # Interactive exploration time

550

```

551

552

## Advanced Features

553

554

### Performance Optimization

555

556

```python

557

# Vectorized field functions for efficiency

558

def optimized_field(coords):

559

# Use numpy operations on entire arrays

560

x, y = coords.T

561

return np.stack([np.sin(x) * np.cos(y), np.cos(x) * np.sin(y)], axis=1)

562

563

# Custom color mapping for large fields

564

def custom_color_map(magnitudes):

565

# Efficient color mapping using numpy

566

normalized = magnitudes / np.max(magnitudes)

567

return plt.cm.plasma(normalized)

568

```

569

570

### Coordinate System Integration

571

572

```python

573

# Works with any coordinate system

574

polar_plane = PolarPlane()

575

field_polar = VectorField(radial_field, polar_plane)

576

577

# 3D coordinate systems

578

axes_3d = ThreeDAxes()

579

# Note: Vector fields are primarily 2D, but can work with projections

580

```

581

582

The vector field system in ManimGL provides comprehensive tools for visualizing mathematical fields and physics simulations, from static field visualization to complex time-dependent flow animations with numerical integration and sophisticated rendering.