{ "cells": [ { "cell_type": "markdown", "id": "substantial-impact", "metadata": {}, "source": [ "# Vítej!" ] }, { "cell_type": "markdown", "id": "first-armenia", "metadata": {}, "source": [ "Tento dokument obsahuje zdrojové kódy animací ke čtvrté sérii seriálu KSP. Před spouštěním opět nezapomeň Manim importovat spuštěním následujícího řádku!" ] }, { "cell_type": "code", "execution_count": null, "id": "e03b150c", "metadata": {}, "outputs": [], "source": [ "from manim import *" ] }, { "cell_type": "markdown", "id": "45897e9c", "metadata": {}, "source": [ "## Booleovské operace" ] }, { "cell_type": "code", "execution_count": null, "id": "6aa5ba0f", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh BooleanOperations\n", "\n", "\n", "class BooleanOperations(Scene):\n", " def construct(self):\n", "\n", " circle = Circle(fill_opacity=0.75, color=RED).scale(2).shift(LEFT * 1.5)\n", " square = Square(fill_opacity=0.75, color=GREEN).scale(2).shift(RIGHT * 1.5)\n", "\n", " group = VGroup(circle, square)\n", "\n", " self.play(Write(group))\n", "\n", " self.play(group.animate.scale(0.5).shift(UP * 1.6))\n", "\n", " union = Union(circle, square, fill_opacity=1, color=BLUE)\n", "\n", " # postupně voláme Union(), Intersection() a Difference()\n", " for operation, position, name in zip(\n", " [Intersection, Union, Difference],\n", " [LEFT * 3.3, ORIGIN, RIGHT * 4.5],\n", " [\"Průnik\", \"Sjednocení\", \"Rozdíl\"],\n", " ):\n", " result = operation(circle, square, fill_opacity=1, color=DARK_BLUE)\n", " result_position = DOWN * 1.3 + position\n", " \n", " label = Tex(name).move_to(result_position).scale(0.8)\n", " \n", " self.play(\n", " AnimationGroup(\n", " FadeIn(result),\n", " result.animate.move_to(result_position),\n", " FadeIn(label),\n", " lag_ratio=0.5,\n", " )\n", " )" ] }, { "cell_type": "markdown", "id": "3da40017", "metadata": {}, "source": [ "## Vlastní objekty" ] }, { "cell_type": "code", "execution_count": null, "id": "cf1fb3b5", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh StackExample\n", "\n", "\n", "class Stack(VMobject):\n", " def __init__(self, size, *args, **kwargs):\n", " # inicializace VGroup objektu\n", " super().__init__(**kwargs)\n", "\n", " self.squares = VGroup()\n", " self.labels = VGroup()\n", " self.index = 0\n", " self.pointer = Arrow(ORIGIN, UP * 1.2)\n", "\n", " for _ in range(size):\n", " self.squares.add(Square(side_length=0.8))\n", "\n", " self.squares.arrange(buff=0.15)\n", "\n", " self.pointer.next_to(self.squares[0], DOWN)\n", " self.add()\n", "\n", " # DŮLEŽITÉ - přidáme do objektu všechny podobjekty!\n", " self.add(self.squares, self.labels, self.pointer)\n", "\n", " def __get_index_rectangle_color(self):\n", " \"\"\"Vrátí barvu aktuálního obdelníků stacku.\"\"\"\n", " return self.squares[self.index].get_color()\n", "\n", " def __create_label(self, element):\n", " \"\"\"Vytvoření labelu daného prvku (podle barvy a rozměrů čtverců stacku).\"\"\"\n", " return (\n", " Tex(str(element))\n", " .scale(self.squares[0].height)\n", " .set_color(self.__get_index_rectangle_color())\n", " )\n", "\n", " def push(self, element):\n", " \"\"\"Přidá prvek do zásobníku. Vrátí odpovídající animace.\"\"\"\n", " self.labels.add(self.__create_label(element).move_to(self.squares[self.index]))\n", " self.index += 1\n", "\n", " return AnimationGroup(\n", " FadeIn(self.labels[-1]),\n", " self.pointer.animate.next_to(self.squares[self.index], DOWN),\n", " Indicate(\n", " self.squares[self.index - 1], color=self.__get_index_rectangle_color()\n", " ),\n", " )\n", "\n", " def pop(self):\n", " \"\"\"Odebere prvek ze zásobníku. Vrátí odpovídající animace.\"\"\"\n", " label = self.labels[-1]\n", " self.labels.remove(label)\n", " self.index -= 1\n", "\n", " return AnimationGroup(\n", " FadeOut(label),\n", " self.pointer.animate.next_to(self.squares[self.index], DOWN),\n", " Indicate(\n", " self.squares[self.index],\n", " color=self.__get_index_rectangle_color(),\n", " scale_factor=1 / 1.2,\n", " ),\n", " )\n", "\n", " def clear(self):\n", " \"\"\"Vyčistí zásobník. Vrátí odpovídající animaci.\"\"\"\n", " result = AnimationGroup(*[self.pop() for _ in range(self.index)], lag_ratio=0)\n", "\n", " self.index = 0\n", "\n", " return result\n", "\n", "\n", "class StackExample(Scene):\n", " def construct(self):\n", " stack = Stack(10)\n", "\n", " # na objekt fungují správně libovolné animace\n", " self.play(Write(stack))\n", "\n", " self.wait(0.5)\n", "\n", " for i in range(5):\n", " self.play(stack.push(i))\n", "\n", " self.play(stack.pop())\n", "\n", " self.wait(0.5)\n", "\n", " # můžeme používat i animate syntax!\n", " # měnění barvy se rekurzivně aplikuje na všechny podobjekty\n", " self.play(stack.animate.scale(1.3).set_color(BLUE))\n", "\n", " self.wait(0.5)\n", "\n", " for i in range(2):\n", " self.play(stack.push(i))\n", "\n", " self.play(stack.pop())\n", "\n", " self.play(stack.clear())\n", "\n", " self.play(FadeOut(stack))" ] }, { "cell_type": "markdown", "id": "88f6f285", "metadata": {}, "source": [ "## Jiné grafy" ] }, { "cell_type": "code", "execution_count": null, "id": "0906f798", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh GraphExample\n", "\n", "from math import sin\n", "\n", "\n", "class GraphExample(Scene):\n", " def construct(self):\n", " # osy - rozmezí a značení os x, y\n", " axes = Axes(x_range=[-5, 5], y_range=[-3, 7])\n", " labels = axes.get_axis_labels(x_label=\"x\", y_label=\"y\")\n", "\n", " def f1(x):\n", " return x ** 2\n", "\n", " def f2(x):\n", " return sin(x)\n", "\n", " # objekty vykreslených funkcí\n", " g1 = axes.plot(f1, color=RED)\n", " g2 = axes.plot(f2, color=BLUE)\n", "\n", " self.play(Write(axes), Write(labels))\n", "\n", " self.play(AnimationGroup(Write(g1), Write(g2), lag_ratio=0.5))\n", "\n", " self.play(Unwrite(axes), Unwrite(labels), Unwrite(g1), Unwrite(g2))" ] }, { "cell_type": "code", "execution_count": null, "id": "84978263", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh DiscontinuousGraphExample\n", "\n", "from math import sin\n", "\n", "\n", "class DiscontinuousGraphExample(Scene):\n", " def construct(self):\n", " axes = Axes(x_range=[-5, 5], y_range=[-3, 7])\n", " labels = axes.get_axis_labels(x_label=\"x\", y_label=\"y\")\n", "\n", " def f(x):\n", " return 1 / x\n", "\n", " g_bad = axes.plot(f, color=RED)\n", "\n", " # rozdělení na dvě části podle hodnot x\n", " g_left = axes.plot(f, x_range=[-5, -0.1], color=GREEN)\n", " g_right = axes.plot(f, x_range=[0.1, 5], color=GREEN)\n", "\n", " self.play(Write(axes), Write(labels))\n", "\n", " self.play(Write(g_bad))\n", " self.play(FadeOut(g_bad))\n", "\n", " self.play(AnimationGroup(Write(g_left), Write(g_right), lag_ratio=0.5))\n", "\n", " self.play(Unwrite(axes), Unwrite(labels), Unwrite(g_left), Unwrite(g_right))" ] }, { "cell_type": "code", "execution_count": null, "id": "521d3286", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh ParametricGraphExample\n", "\n", "from math import sin, cos\n", "\n", "\n", "class ParametricGraphExample(Scene):\n", " def construct(self):\n", " axes = Axes(x_range=[-10, 10], y_range=[-5, 5])\n", " labels = axes.get_axis_labels(x_label=\"x\", y_label=\"y\")\n", "\n", " def f1(t):\n", " \"\"\"Parametrická funkce kružnice.\"\"\"\n", " return (cos(t) * 3 - 4.5, sin(t) * 3)\n", "\n", " def f2(t):\n", " \"\"\"Parametrická funkce <3.\"\"\"\n", " return (\n", " 0.2 * (16 * (sin(t)) ** 3) + 4.5,\n", " 0.2 * (13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t)),\n", " )\n", "\n", " # objekty vykreslených funkcí\n", " # místo axes.plot používáme axes.plot_parametric_curve\n", " # parametr t_range určuje, jaké je rozmezí parametru t\n", " g1 = axes.plot_parametric_curve(f1, color=RED, t_range=[0, 2 * PI])\n", " g2 = axes.plot_parametric_curve(f2, color=BLUE, t_range=[-PI, PI])\n", "\n", " self.play(Write(axes), Write(labels))\n", "\n", " self.play(AnimationGroup(Write(g1), Write(g2), lag_ratio=0.5))\n", "\n", " self.play(Unwrite(axes), Unwrite(labels), Unwrite(g1), Unwrite(g2))" ] }, { "cell_type": "code", "execution_count": null, "id": "c0e61a1b", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh LineGraphExample\n", "\n", "from random import random, seed\n", "\n", "\n", "class LineGraphExample(Scene):\n", " def construct(self):\n", " seed(0xDEADBEEF2) # hezčí hodnoty :P\n", "\n", " # hodnoty ke grafování (x a y)\n", " # u np.arange(l, r, step) vrátí pole hodnot od l do r (nevčetně) s kroky velikosti step\n", " x_values = np.arange(-1, 1 + 0.25, 0.25)\n", " y_values = [random() for _ in x_values]\n", "\n", " # osy (tentokrát s čísly)\n", " axes = Axes(\n", " x_range=[-1, 1, 0.25],\n", " y_range=[-0.1, 1, 0.25],\n", " # nastavení čísel - hodnoty a počet desetinných míst\n", " x_axis_config={\"numbers_to_include\": x_values},\n", " y_axis_config={\"numbers_to_include\": np.arange(0, 1, 0.25)},\n", " axis_config={\"decimal_number_config\": {\"num_decimal_places\": 2}},\n", " )\n", "\n", " labels = axes.get_axis_labels(x_label=\"x\", y_label=\"y\")\n", "\n", " # místo axes.plot používáme axes.plot_line_graph\n", " graph = axes.plot_line_graph(x_values=x_values, y_values=y_values)\n", "\n", " self.play(Write(axes), Write(labels))\n", "\n", " self.play(Write(graph), run_time=2)\n", "\n", " self.play(Unwrite(axes), Unwrite(labels), Unwrite(graph))" ] }, { "cell_type": "markdown", "id": "bb5423f4", "metadata": {}, "source": [ "## 3D operace" ] }, { "cell_type": "code", "execution_count": null, "id": "ab85ca2d", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh Axes3DExample\n", "\n", "\n", "class Axes3DExample(ThreeDScene):\n", " def construct(self):\n", " # 3D osy\n", " axes = ThreeDAxes()\n", "\n", " x_label = axes.get_x_axis_label(Tex(\"x\"))\n", " y_label = axes.get_y_axis_label(Tex(\"y\")).shift(UP * 1.8)\n", "\n", " # 3D varianta Dot() objektu\n", " dot = Dot3D()\n", "\n", " # zmenšení zoomu, abychom viděli osy\n", " self.set_camera_orientation(zoom=0.5)\n", "\n", " self.play(FadeIn(axes), FadeIn(dot), FadeIn(x_label), FadeIn(y_label))\n", "\n", " self.wait(0.5)\n", "\n", " # animace posunutí kamery tak, aby byly osy dobře vidět\n", " self.move_camera(phi=75 * DEGREES, theta=30 * DEGREES, zoom=1, run_time=1.5)\n", "\n", " # vestavěný updater, který kameru začne rotovat (aby na scénu bylo lépe vidět)\n", " self.begin_ambient_camera_rotation(rate=0.15)\n", "\n", " # jedna tečka za každý směr\n", " upDot = dot.copy().set_color(RED)\n", " rightDot = dot.copy().set_color(BLUE)\n", " outDot = dot.copy().set_color(GREEN)\n", "\n", " self.wait(1)\n", "\n", " self.play(\n", " upDot.animate.shift(UP),\n", " rightDot.animate.shift(RIGHT),\n", " outDot.animate.shift(OUT),\n", " )\n", "\n", " self.wait(2)" ] }, { "cell_type": "code", "execution_count": null, "id": "efc147d5", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh Rotation3DExample\n", "\n", "\n", "class Rotation3DExample(ThreeDScene):\n", " def construct(self):\n", " # přidání jednoduché základní krychle\n", " cube = Cube(side_length=3, fill_opacity=1)\n", "\n", " self.begin_ambient_camera_rotation(rate=0.3)\n", "\n", " # posunutí orientace kamery bez animace\n", " self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n", "\n", " self.play(Write(cube), run_time=2)\n", "\n", " self.wait(3)\n", "\n", " self.play(Unwrite(cube), run_time=2)" ] }, { "cell_type": "code", "execution_count": null, "id": "127ccd71", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh Basic3DExample\n", "\n", "\n", "class Basic3DExample(ThreeDScene):\n", " def construct(self):\n", " # přidání jednoduché základní krychle\n", " cube = Cube(side_length=3, fill_opacity=0.5)\n", "\n", " self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)\n", "\n", " self.play(FadeIn(cube))\n", "\n", " for axis in [RIGHT, UP, OUT]:\n", " self.play(Rotate(cube, PI / 2, about_point=ORIGIN, axis=axis))\n", "\n", " self.play(FadeOut(cube))" ] }, { "cell_type": "markdown", "id": "98daca2b", "metadata": {}, "source": [ "## Kostry úloh" ] }, { "cell_type": "markdown", "id": "8746ae11", "metadata": {}, "source": [ "### Simulace binomického rozložení [6b]" ] }, { "cell_type": "code", "execution_count": null, "id": "18fb5e35", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh BinomialDistributionSimulation\n", "\n", "\n", "class BinomialDistributionSimulation(Scene):\n", " def construct(self):\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "id": "b7139b0d", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh BezierExample\n", "\n", "from random import choice, seed\n", "\n", "\n", "class MoveAndFade(Animation):\n", " def __init__(self, mobject: Mobject, path: VMobject, **kwargs):\n", " self.path = path\n", " self.original = mobject.copy()\n", " super().__init__(mobject, **kwargs)\n", "\n", " def interpolate_mobject(self, alpha: float) -> None:\n", " point = self.path.point_from_proportion(self.rate_func(alpha))\n", "\n", " # tohle není úplně čisté, jelikož pokaždé vytváříme nový objekt\n", " # je to kvůli tomu, že obj.fade() nenastavuje průhlednost ale přidává jí\n", " self.mobject.become(self.original.copy()).move_to(point).fade(alpha)\n", "\n", "\n", "class BezierExample(Scene):\n", " def construct(self):\n", " # křivku definujeme přes čtyři body:\n", " # 2 krajní, ve kterých začíná a končí\n", " # 2 kontrolní, které určují tvar\n", " positions = [\n", " UP + LEFT * 3, # počáteční\n", " UP + RIGHT * 2, # 1. kontrolní\n", " DOWN + LEFT * 2, # 2. kontrolní\n", " DOWN + RIGHT * 3, # koncový\n", " ]\n", "\n", " points = VGroup(*[Dot().move_to(position) for position in positions]).scale(1.5)\n", "\n", " # rozlišíme kontrolní body\n", " points[1].set_color(BLUE)\n", " points[2].set_color(BLUE)\n", "\n", " bezier = CubicBezier(*positions).scale(1.5)\n", "\n", " self.play(Write(bezier), Write(points))\n", "\n", " # animace posunu\n", " circle = Circle(fill_opacity=1, stroke_opacity=0).scale(0.25).move_to(points[0])\n", "\n", " self.play(FadeIn(circle, shift=RIGHT * 0.5))\n", " self.play(MoveAlongPath(circle, bezier))\n", "\n", " self.play(FadeOut(circle))\n", "\n", " # animace posunu s mizením\n", " circle = (\n", " Circle(fill_color=GREEN, fill_opacity=1, stroke_opacity=0)\n", " .scale(0.25)\n", " .move_to(points[0])\n", " )\n", "\n", " self.play(FadeIn(circle, shift=RIGHT * 0.5))\n", " self.play(MoveAndFade(circle, bezier))\n", "\n", " self.play(FadeOut(bezier), FadeOut(points), FadeOut(circle))" ] }, { "cell_type": "markdown", "id": "4de93509", "metadata": {}, "source": [ "### 3D Game of Life [9b]" ] }, { "cell_type": "markdown", "id": "eee60fd6", "metadata": {}, "source": [ "#### Dvoustavový [5b]" ] }, { "cell_type": "code", "execution_count": null, "id": "d95d2328", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh GOLTwoState\n", "\n", "\n", "class GOLTwoState(ThreeDScene):\n", " def construct(self):\n", " pass" ] }, { "cell_type": "markdown", "id": "3fd9c87c", "metadata": {}, "source": [ "#### Vícestavový [3b]" ] }, { "cell_type": "code", "execution_count": null, "id": "9525cea2", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh GOLMultiState\n", "\n", "\n", "class GOLMultiState(ThreeDScene):\n", " def construct(self):\n", " pass" ] }, { "cell_type": "markdown", "id": "464edd8b", "metadata": {}, "source": [ "#### Vlastní [1b]" ] }, { "cell_type": "code", "execution_count": null, "id": "01394a96", "metadata": {}, "outputs": [], "source": [ "%%manim -v WARNING -qh GOLCustom\n", "\n", "\n", "class GOLCustom(ThreeDScene):\n", " def construct(self):\n", " pass" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.2" } }, "nbformat": 4, "nbformat_minor": 5 }