point_set_topology.py
1from manim import *2import numpy as np3import random4 5class PointSetTopology(Scene):6 def construct(self):7 # 设置标题8 title = Text("平面点集基本概念", font="SimHei")9 title.to_corner(UL)10 self.play(Write(title))11 self.wait(1)12 13 # 创建坐标系14 axes = Axes(15 x_range=[-5, 5, 1],16 y_range=[-3, 3, 1],17 axis_config={"include_tip": True, "include_numbers": False},18 x_length=10,19 y_length=620 )21 axes_labels = axes.get_axis_labels(x_label="x", y_label="y")22 23 # 显示坐标系24 self.play(Create(axes), Create(axes_labels))25 self.wait(1)26 27 # 定义一个圆形点集(作为我们研究的主要集合)28 circle = Circle(radius=2, color=BLUE)29 circle.move_to(axes.coords_to_point(0, 0))30 31 # 添加圆形到场景32 self.play(Create(circle))33 34 # 添加集合标签35 set_label = MathTex("A", color=BLUE).next_to(circle, UP)36 self.play(Write(set_label))37 38 # 集合定义:平面点集,不显示具体表示39 set_definition = Text("平面点集A", font="SimHei", font_size=24)40 set_definition.to_corner(UR)41 self.play(Write(set_definition))42 self.wait(1)43 44 # 清除定义45 self.play(FadeOut(set_definition))46 47 # ------ 内点演示 ------48 interior_title = Text("内点", font="SimHei", font_size=32)49 interior_title.to_edge(UP)50 # 淡出主标题,显示内点标题51 self.play(FadeOut(title), Write(interior_title))52 53 # 选择集合内的一点54 interior_point = Dot(axes.coords_to_point(0, 0), color=GREEN)55 interior_label = Text("内点", font="SimHei", font_size=24, color=GREEN).next_to(interior_point, UP)56 57 # 添加这个点到场景58 self.play(Create(interior_point), Write(interior_label))59 60 # 创建邻域小圆61 neighborhood = Circle(radius=0.5, color=GREEN, fill_opacity=0.2)62 neighborhood.move_to(interior_point.get_center())63 64 # 显示邻域65 self.play(Create(neighborhood))66 67 # 内点定义68 interior_def = Text("内点:点p存在一个邻域完全包含在集合A中", font="SimHei", font_size=24)69 interior_def.to_edge(DOWN)70 self.play(Write(interior_def))71 self.wait(2)72 73 # 清除内点说明74 self.play(FadeOut(interior_title), FadeOut(interior_def))75 76 # ------ 外点演示 ------77 exterior_title = Text("外点", font="SimHei", font_size=32)78 exterior_title.to_edge(UP)79 self.play(Write(exterior_title))80 81 # 选择集合外的一点82 exterior_point = Dot(axes.coords_to_point(4, 0), color=RED)83 exterior_label = Text("外点", font="SimHei", font_size=24, color=RED).next_to(exterior_point, UP)84 85 # 添加这个点到场景86 self.play(Create(exterior_point), Write(exterior_label))87 88 # 移动邻域到外点89 self.play(90 neighborhood.animate.set_color(RED).move_to(exterior_point.get_center())91 )92 93 # 外点定义94 exterior_def = Text("外点:点p存在一个邻域完全不与集合A相交", font="SimHei", font_size=24)95 exterior_def.to_edge(DOWN)96 self.play(Write(exterior_def))97 self.wait(2)98 99 # 清除外点说明100 self.play(FadeOut(exterior_title), FadeOut(exterior_def))101 102 # ------ 界点演示 ------103 boundary_title = Text("界点", font="SimHei", font_size=32)104 boundary_title.to_edge(UP)105 self.play(Write(boundary_title))106 107 # 选择圆上的一点(界点)108 boundary_point = Dot(axes.coords_to_point(2, 0), color=YELLOW)109 boundary_label = Text("界点", font="SimHei", font_size=24, color=YELLOW).next_to(boundary_point, RIGHT)110 111 # 添加这个点到场景112 self.play(Create(boundary_point), Write(boundary_label))113 114 # 移动邻域到界点115 self.play(116 neighborhood.animate.set_color(YELLOW).move_to(boundary_point.get_center())117 )118 119 # 界点定义120 boundary_def = Text("界点:点p的任何邻域既包含A中的点,又包含不在A中的点", font="SimHei", font_size=24)121 boundary_def.to_edge(DOWN)122 self.play(Write(boundary_def))123 self.wait(2)124 125 # 清除界点说明和邻域126 self.play(FadeOut(boundary_title), FadeOut(boundary_def), FadeOut(neighborhood))127 128 # ------ 分界展示所有点类型 ------129 all_types_title = Text("点的分类总结", font="SimHei", font_size=32)130 all_types_title.to_edge(UP)131 self.play(Write(all_types_title))132 133 # 添加更多示例点134 more_interior_points = [135 Dot(axes.coords_to_point(-1, 0), color=GREEN),136 Dot(axes.coords_to_point(0, 1), color=GREEN),137 Dot(axes.coords_to_point(1, 1), color=GREEN)138 ]139 140 more_exterior_points = [141 Dot(axes.coords_to_point(-3, 0), color=RED),142 Dot(axes.coords_to_point(0, -3), color=RED),143 Dot(axes.coords_to_point(3, 3), color=RED)144 ]145 146 more_boundary_points = [147 Dot(axes.coords_to_point(0, 2), color=YELLOW),148 Dot(axes.coords_to_point(-2, 0), color=YELLOW),149 Dot(axes.coords_to_point(1.414, 1.414), color=YELLOW) # 约等于√2150 ]151 152 # 添加这些点到场景153 self.play(154 *[Create(p) for p in more_interior_points],155 *[Create(p) for p in more_exterior_points],156 *[Create(p) for p in more_boundary_points]157 )158 159 # 点的分类说明160 points_summary = Text(161 "绿色:内点 (Interior Points)\n"162 "红色:外点 (Exterior Points)\n"163 "黄色:界点 (Boundary Points)",164 font="SimHei",165 font_size=24166 ).to_corner(DR)167 self.play(Write(points_summary))168 self.wait(2)169 170 # 清除分类说明,保留点171 self.play(FadeOut(all_types_title), FadeOut(points_summary))172 173 # 所有点一起淡出,包括聚点(按照要求修改)174 self.play(175 FadeOut(interior_point),176 FadeOut(interior_label),177 FadeOut(exterior_point),178 FadeOut(exterior_label),179 FadeOut(boundary_point),180 FadeOut(boundary_label),181 *[FadeOut(p) for p in more_interior_points],182 *[FadeOut(p) for p in more_exterior_points],183 *[FadeOut(p) for p in more_boundary_points]184 )185 186 # ------ 聚点演示 ------187 accumulation_title = Text("聚点", font="SimHei", font_size=32)188 accumulation_title.to_edge(UP)189 self.play(Write(accumulation_title))190 191 # 选择圆内的一点作为聚点示例(恢复为原来的位置)192 accum_point = Dot(axes.coords_to_point(-1, 1), color=PURPLE)193 accum_label = Text("聚点", font="SimHei", font_size=24, color=PURPLE).next_to(accum_point, UP)194 195 # 添加聚点到场景196 self.play(Create(accum_point), Write(accum_label))197 198 # 创建聚点邻域199 accum_neighborhood = Circle(radius=0.7, color=PURPLE, fill_opacity=0.2)200 accum_neighborhood.move_to(accum_point.get_center())201 self.play(Create(accum_neighborhood))202 203 # 在邻域内添加一系列点204 accum_points = []205 for _ in range(20):206 r = random.uniform(0, 0.6)207 theta = random.uniform(0, 2 * np.pi)208 x = -1 + r * np.cos(theta)209 y = 1 + r * np.sin(theta)210 point = Dot(axes.coords_to_point(x, y), color=BLUE_A, radius=0.03)211 accum_points.append(point)212 213 # 逐渐添加这些点,展示无限多点的概念214 for point in accum_points:215 self.play(Create(point), run_time=0.1)216 217 # 聚点定义218 accum_def = Text("聚点:点p的任何邻域都包含A中无穷多个点", font="SimHei", font_size=24)219 accum_def.to_edge(DOWN)220 self.play(Write(accum_def))221 self.wait(2)222 223 # 清除聚点演示224 self.play(225 FadeOut(accumulation_title),226 FadeOut(accum_def),227 FadeOut(accum_neighborhood),228 FadeOut(accum_point),229 FadeOut(accum_label),230 *[FadeOut(p) for p in accum_points]231 )232 233 # ------ 孤立点演示 ------234 isolated_title = Text("孤立点", font="SimHei", font_size=32)235 isolated_title.to_edge(UP)236 self.play(Write(isolated_title))237 238 # 创建一个新的离散点集B239 set_B_label = MathTex("B", color=ORANGE).next_to(circle, DOWN+LEFT)240 self.play(Write(set_B_label))241 242 # 创建一些孤立点243 isolated_points = [244 Dot(axes.coords_to_point(-3, -2), color=ORANGE),245 Dot(axes.coords_to_point(3, -1), color=ORANGE),246 Dot(axes.coords_to_point(0, -2.5), color=ORANGE)247 ]248 249 # 添加孤立点到场景250 for point in isolated_points:251 self.play(Create(point))252 253 # 为其中一个孤立点添加标签和邻域254 isolated_label = Text("孤立点", font="SimHei", font_size=24, color=ORANGE).next_to(isolated_points[0], UP)255 self.play(Write(isolated_label))256 257 # 创建孤立点邻域258 isolated_neighborhood = Circle(radius=0.5, color=ORANGE, fill_opacity=0.2)259 isolated_neighborhood.move_to(isolated_points[0].get_center())260 self.play(Create(isolated_neighborhood))261 262 # 孤立点定义263 isolated_def = Text("孤立点:点p存在一个邻域,除p外不包含集合中的其他点", font="SimHei", font_size=24)264 isolated_def.to_edge(DOWN)265 self.play(Write(isolated_def))266 self.wait(2)267 268 # 清除孤立点演示269 self.play(270 FadeOut(isolated_title),271 FadeOut(isolated_def),272 FadeOut(isolated_neighborhood),273 FadeOut(isolated_label),274 FadeOut(set_B_label),275 *[FadeOut(p) for p in isolated_points]276 )277 278 # ------ 开集演示 ------279 open_set_title = Text("开集", font="SimHei", font_size=32)280 open_set_title.to_edge(UP)281 self.play(Write(open_set_title))282 283 # 创建一个开圆(不包含边界)284 open_circle = Circle(radius=2, color=GREEN, stroke_width=3)285 open_circle.move_to(axes.coords_to_point(0, 0))286 287 # 添加开集标签288 open_set_label = MathTex("U", color=GREEN).next_to(circle, UP+RIGHT)289 290 # 动画:把原来的圆变成开圆291 dashed_circle = DashedVMobject(circle.copy(), num_dashes=50)292 dashed_circle.set_color(GREEN)293 self.play(294 ReplacementTransform(circle, dashed_circle),295 Write(open_set_label),296 FadeOut(set_label)297 )298 299 # 在场景中添加一些内点来说明开集300 open_set_interior_points = [301 Dot(axes.coords_to_point(0, 0), color=GREEN),302 Dot(axes.coords_to_point(-1, 0), color=GREEN),303 Dot(axes.coords_to_point(1, 1), color=GREEN)304 ]305 306 self.play(*[Create(p) for p in open_set_interior_points])307 308 # 开集定义309 open_set_def = Text("开集:集合中的每个点都是其内点", font="SimHei", font_size=24)310 open_set_def.to_edge(DOWN)311 self.play(Write(open_set_def))312 self.wait(2)313 314 # 清除开集演示315 self.play(316 FadeOut(open_set_title),317 FadeOut(open_set_def),318 *[FadeOut(p) for p in open_set_interior_points]319 )320 321 # ------ 闭集演示 ------322 closed_set_title = Text("闭集", font="SimHei", font_size=32)323 closed_set_title.to_edge(UP)324 self.play(Write(closed_set_title))325 326 # 恢复为完整圆(包含边界)327 closed_circle = Circle(radius=2, color=BLUE)328 closed_circle.move_to(axes.coords_to_point(0, 0))329 330 # 替换开圆为闭圆331 self.play(332 ReplacementTransform(dashed_circle, closed_circle),333 FadeOut(open_set_label),334 Write(set_label)335 )336 337 # 添加界点338 closed_set_boundary_points = [339 Dot(axes.coords_to_point(2, 0), color=YELLOW),340 Dot(axes.coords_to_point(0, 2), color=YELLOW),341 Dot(axes.coords_to_point(-2, 0), color=YELLOW)342 ]343 344 self.play(*[Create(p) for p in closed_set_boundary_points])345 346 # 闭集定义347 closed_set_def = Text("闭集:包含所有聚点的集合", font="SimHei", font_size=24)348 closed_set_def.to_edge(DOWN)349 self.play(Write(closed_set_def))350 self.wait(2)351 352 # 清除闭集演示的标题和定义,但保留图形元素353 self.play(354 FadeOut(closed_set_title),355 FadeOut(closed_set_def)356 )357 358 # 最终结论359 final_title = Text("平面点集基本概念总结", font="SimHei", font_size=32)360 final_title.to_edge(UP)361 self.play(Write(final_title))362 363 # 删除黄色圆圈,直接添加最终总结文字364 final_summary = Text(365 "• 内点、外点、界点构成了平面上所有点的分类\n"366 "• 聚点是极限点或收敛点,邻域内有无穷多点\n"367 "• 孤立点邻域内没有其他点\n"368 "• 开集内每点都是内点\n"369 "• 闭集包含所有聚点",370 font="SimHei",371 font_size=24372 )373 final_summary.to_edge(DOWN)374 self.play(Write(final_summary))375 self.wait(3)376 377 # 注意:不清除整个场景,保留最后的显示内容378 self.wait(2)379 380 381class PointSetRelationships(Scene):382 def construct(self):383 # 设置标题384 title = Text("点集拓扑概念关系", font="SimHei")385 title.to_corner(UL)386 self.play(Write(title))387 self.wait(1)388 389 # 创建图示框架390 frame = Rectangle(height=6, width=10, color=WHITE)391 392 self.play(Create(frame))393 394 # 创建集合A示意图395 set_A_circle = Circle(radius=2, color=BLUE)396 set_A_circle.move_to(ORIGIN)397 398 # 添加集合标签399 set_A_label = MathTex("A", color=BLUE).next_to(set_A_circle, UP)400 401 self.play(402 Create(set_A_circle),403 Write(set_A_label)404 )405 406 # 创建点集概念之间的关系图407 408 # 定义概念节点409 concepts = {410 "int": {"text": "Int(A)\n内部", "pos": UP * 2 + LEFT * 3, "color": GREEN},411 "ext": {"text": "Ext(A)\n外部", "pos": UP * 2 + RIGHT * 3, "color": RED},412 "bdry": {"text": "Bdry(A)\n边界", "pos": DOWN * 2, "color": YELLOW},413 "cl": {"text": "Cl(A)\n闭包", "pos": UP * 0.5 + LEFT * 3, "color": PURPLE},414 "der": {"text": "A'\n导集", "pos": DOWN * 0.5 + LEFT * 3, "color": ORANGE}415 }416 417 # 创建节点418 nodes = {}419 for key, info in concepts.items():420 node = VGroup(421 Circle(radius=0.5, color=info["color"]),422 Text(info["text"], font="SimHei", font_size=20)423 )424 node.move_to(info["pos"])425 nodes[key] = node426 427 # 显示节点428 for key, node in nodes.items():429 self.play(Create(node), run_time=0.7)430 431 # 定义关系432 relations = [433 {"from": "cl", "to": "int", "text": "包含", "pos_adj": RIGHT * 0.5},434 {"from": "cl", "to": "bdry", "text": "包含", "pos_adj": DOWN * 0.5 + RIGHT * 0.5},435 {"from": "cl", "to": "der", "text": "包含", "pos_adj": DOWN * 0.2},436 {"from": "int", "to": "ext", "text": "互斥", "pos_adj": UP * 0.3},437 {"from": "int", "to": "bdry", "text": "互斥", "pos_adj": RIGHT * 0.3},438 {"from": "ext", "to": "bdry", "text": "互斥", "pos_adj": LEFT * 0.3}439 ]440 441 # 创建关系箭头和标签442 arrows = []443 for rel in relations:444 start = nodes[rel["from"]].get_center()445 end = nodes[rel["to"]].get_center()446 447 # 创建箭头448 if rel["text"] == "互斥":449 # 使用虚线和双箭头表示互斥关系450 arrow = DashedLine(451 start=start,452 end=end,453 color=GRAY454 )455 else:456 # 使用实线箭头表示包含关系457 arrow = Arrow(458 start=start,459 end=end,460 color=WHITE,461 buff=0.6 # 调整箭头与节点的距离462 )463 464 # 创建关系标签465 mid_point = (start + end) / 2 + rel["pos_adj"]466 label = Text(rel["text"], font="SimHei", font_size=18)467 label.move_to(mid_point)468 469 arrows.append(VGroup(arrow, label))470 471 # 显示关系472 for arrow in arrows:473 self.play(Create(arrow), run_time=0.7)474 475 # 添加重要公式476 formulas = [477 {"tex": r"A = \text{Int}(A) \cup \text{Bdry}(A)", "pos": DOWN * 3 + LEFT * 3},478 {"tex": r"\text{Cl}(A) = A \cup A'", "pos": DOWN * 3 + RIGHT * 3},479 {"tex": r"\text{Int}(A) \cap \text{Bdry}(A) = \emptyset", "pos": DOWN * 3.5}480 ]481 482 formula_objs = []483 for f in formulas:484 formula = MathTex(f["tex"])485 formula.move_to(f["pos"])486 formula_objs.append(formula)487 self.play(Write(formula))488 489 # 最后的概念总结490 summary = Text(491 "内点+边界=集合\n"492 "集合+导集=闭包\n"493 "内部、外部、边界两两互斥",494 font="SimHei",495 font_size=24496 )497 summary.to_edge(DOWN)498 499 self.play(500 FadeOut(set_A_circle),501 FadeOut(set_A_label),502 *[FadeOut(node) for node in nodes.values()],503 *[FadeOut(arrow) for arrow in arrows],504 *[FadeOut(formula) for formula in formula_objs],505 FadeOut(frame)506 )507 508 self.play(Write(summary))509 self.wait(3)510 511 # 结束动画512 self.play(FadeOut(summary), FadeOut(title))513 self.wait(1)514 515 516# 运行时请使用以下命令:517# manim -pql point_set_topology.py PointSetTopology518# manim -pql point_set_topology.py PointSetRelationships 讲解
这个视频围绕「平面点集基本概念」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。
开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。
画面中出现的文字「平面点集基本概念」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。
随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。
观察路径
观察路径可以分三步:先锁定「平面点集基本概念」中的核心对象,尤其留意平面点集、邻域、内点之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。
本页可以从平面点集、邻域、内点、边界点这些概念进入,继续沿相邻问题观察同一类数学结构。