Contact Us!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Avatar for stephanie's main branch.

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

| Download

"Guiding Future STEM Leaders through Innovative Research Training" ~ thinkingbeyond.education

Views: 1165
Image: ubuntu2204
{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": [],
      "authorship_tag": "ABX9TyMie/9tJVpOnaI2FhwUvsTH",
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/ThinkingBeyond/BeyondAI-2024/blob/main/shaana-karuna/Continuity_Video_Final.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#Summary of code\n",
        "\n",
        "This code creates a video explaining the epsilon-delta definition of continuity. It is divided into 2 parts."
      ],
      "metadata": {
        "id": "JEyIrK1HZxNe"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "#Setting up Manim\n"
      ],
      "metadata": {
        "id": "Uxfsc247Z94w"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "This section installs Manim and IPython."
      ],
      "metadata": {
        "id": "x51Xk38NeE6u"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!sudo apt update\n",
        "!sudo apt install libcairo2-dev ffmpeg \\\n",
        "    texlive texlive-latex-extra texlive-fonts-extra \\\n",
        "    texlive-latex-recommended texlive-science \\\n",
        "    tipa libpango1.0-dev\n",
        "!pip install manim==0.18.1\n",
        "!pip install IPython==8.21.0"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rqUI4fVf5vPD",
        "outputId": "7cd772be-17ab-488e-894e-c0589f4e7156",
        "collapsed": true
      },
      "execution_count": 2,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[33m\r0% [Working]\u001b[0m\r            \rHit:1 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ InRelease\n",
            "\u001b[33m\r0% [Connecting to archive.ubuntu.com (185.125.190.82)] [Connecting to security.\u001b[0m\r                                                                               \rHit:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64  InRelease\n",
            "\u001b[33m\r0% [Connecting to archive.ubuntu.com (185.125.190.82)] [Waiting for headers] [C\u001b[0m\r                                                                               \rHit:3 http://security.ubuntu.com/ubuntu jammy-security InRelease\n",
            "Hit:4 http://archive.ubuntu.com/ubuntu jammy InRelease\n",
            "Hit:5 https://r2u.stat.illinois.edu/ubuntu jammy InRelease\n",
            "Hit:6 http://archive.ubuntu.com/ubuntu jammy-updates InRelease\n",
            "Hit:7 http://archive.ubuntu.com/ubuntu jammy-backports InRelease\n",
            "Hit:8 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease\n",
            "Hit:9 https://ppa.launchpadcontent.net/graphics-drivers/ppa/ubuntu jammy InRelease\n",
            "0% [Waiting for headers]\u001b[0m^C\n",
            "Reading package lists... Done\n",
            "Building dependency tree... Done\n",
            "Reading state information... Done\n",
            "libcairo2-dev is already the newest version (1.16.0-5ubuntu2).\n",
            "texlive is already the newest version (2021.20220204-1).\n",
            "texlive-fonts-extra is already the newest version (2021.20220204-1).\n",
            "texlive-latex-extra is already the newest version (2021.20220204-1).\n",
            "texlive-latex-recommended is already the newest version (2021.20220204-1).\n",
            "texlive-science is already the newest version (2021.20220204-1).\n",
            "tipa is already the newest version (2:1.3-21).\n",
            "libpango1.0-dev is already the newest version (1.50.6+ds-2ubuntu1).\n",
            "ffmpeg is already the newest version (7:4.4.2-0ubuntu0.22.04.1).\n",
            "0 upgraded, 0 newly installed, 0 to remove and 51 not upgraded.\n",
            "Requirement already satisfied: manim==0.18.1 in /usr/local/lib/python3.10/dist-packages (0.18.1)\n",
            "Requirement already satisfied: Pillow>=9.1 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (11.0.0)\n",
            "Requirement already satisfied: Pygments>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (2.18.0)\n",
            "Requirement already satisfied: click>=8.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (8.1.7)\n",
            "Requirement already satisfied: cloup>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (3.0.5)\n",
            "Requirement already satisfied: decorator>=4.3.2 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (4.4.2)\n",
            "Requirement already satisfied: isosurfaces>=0.1.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (0.1.2)\n",
            "Requirement already satisfied: manimpango<1.0.0,>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (0.6.0)\n",
            "Requirement already satisfied: mapbox-earcut>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (1.0.2)\n",
            "Requirement already satisfied: moderngl<6.0.0,>=5.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (5.12.0)\n",
            "Requirement already satisfied: moderngl-window>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (3.0.3)\n",
            "Requirement already satisfied: networkx>=2.6 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (3.4.2)\n",
            "Requirement already satisfied: numpy>=1.26 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (1.26.4)\n",
            "Requirement already satisfied: pycairo<2.0.0,>=1.13 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (1.27.0)\n",
            "Requirement already satisfied: pydub>=0.20.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (0.25.1)\n",
            "Requirement already satisfied: rich>=12.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (13.9.4)\n",
            "Requirement already satisfied: scipy>=1.6.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (1.13.1)\n",
            "Requirement already satisfied: screeninfo>=0.7 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (0.8.1)\n",
            "Requirement already satisfied: skia-pathops>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (0.8.0.post2)\n",
            "Requirement already satisfied: srt>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (3.5.3)\n",
            "Requirement already satisfied: svgelements>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (1.9.6)\n",
            "Requirement already satisfied: tqdm>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (4.66.6)\n",
            "Requirement already satisfied: typing-extensions>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (4.12.2)\n",
            "Requirement already satisfied: watchdog>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from manim==0.18.1) (6.0.0)\n",
            "Requirement already satisfied: glcontext>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from moderngl<6.0.0,>=5.0.0->manim==0.18.1) (3.0.0)\n",
            "Requirement already satisfied: pyglet>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from moderngl-window>=2.0.0->manim==0.18.1) (2.0.20)\n",
            "Requirement already satisfied: pyglm<3,>=2.7.0 in /usr/local/lib/python3.10/dist-packages (from moderngl-window>=2.0.0->manim==0.18.1) (2.7.3)\n",
            "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich>=12.0.0->manim==0.18.1) (3.0.0)\n",
            "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich>=12.0.0->manim==0.18.1) (0.1.2)\n",
            "Requirement already satisfied: IPython==8.21.0 in /usr/local/lib/python3.10/dist-packages (8.21.0)\n",
            "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (4.4.2)\n",
            "Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (0.19.2)\n",
            "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (0.1.7)\n",
            "Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (3.0.48)\n",
            "Requirement already satisfied: pygments>=2.4.0 in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (2.18.0)\n",
            "Requirement already satisfied: stack-data in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (0.6.3)\n",
            "Requirement already satisfied: traitlets>=5 in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (5.7.1)\n",
            "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (1.2.2)\n",
            "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from IPython==8.21.0) (4.9.0)\n",
            "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->IPython==8.21.0) (0.8.4)\n",
            "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->IPython==8.21.0) (0.7.0)\n",
            "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from prompt-toolkit<3.1.0,>=3.0.41->IPython==8.21.0) (0.2.13)\n",
            "Requirement already satisfied: executing>=1.2.0 in /usr/local/lib/python3.10/dist-packages (from stack-data->IPython==8.21.0) (2.1.0)\n",
            "Requirement already satisfied: asttokens>=2.1.0 in /usr/local/lib/python3.10/dist-packages (from stack-data->IPython==8.21.0) (3.0.0)\n",
            "Requirement already satisfied: pure-eval in /usr/local/lib/python3.10/dist-packages (from stack-data->IPython==8.21.0) (0.2.3)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "from manim import *"
      ],
      "metadata": {
        "id": "QXeDXoIW5z2g"
      },
      "execution_count": 1,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#Setting up colours"
      ],
      "metadata": {
        "id": "9eQlgBLMaAuy"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "This section uses specific hex codes to define colours to be used later."
      ],
      "metadata": {
        "id": "Lxg3kDxUhK1b"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "GREENISHWHITE = ManimColor.from_hex(\"#e6ebd5\")\n",
        "NEWGREEN = ManimColor.from_hex(\"#93c280\")\n",
        "NEWDARKGREEN = ManimColor.from_hex(\"#17282a\")\n",
        "NEWMEDIUMGREEN = ManimColor.from_hex(\"#0a5936\")"
      ],
      "metadata": {
        "id": "GRjN8R2GDa2o"
      },
      "execution_count": 5,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "#Part 1\n",
        "\n",
        "The first part of the video introduces the concept of a continuous function as a 'function you can draw without lifting your pen off the page'. It uses an animation of a straight line bending into different continuous functions to illustrate this idea.\n",
        "\n",
        "Then, it adds more formality to this concept by introducing the idea that as 2 inputs approach each other, so should the outputs at these 2 points."
      ],
      "metadata": {
        "id": "b7D-jBggaFo5"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class Continuity(Scene):\n",
        "   def construct(self):\n",
        "\n",
        "#Set the background colour.\n",
        "      self.camera.background_color = NEWDARKGREEN\n",
        "\n",
        "#Define the axes and set the colour of the axes.\n",
        "      axes = Axes(\n",
        "          x_range=[-5, 6, 1],\n",
        "          y_range=[-3, 3, 1],\n",
        "          axis_config={\"color\": GREENISHWHITE}\n",
        "    )\n",
        "\n",
        "#Add numbers to the axes.\n",
        "      numbered_axes = axes.add_coordinates()\n",
        "\n",
        "#Define a straight line on the axes.\n",
        "      line = axes.plot_line_graph(\n",
        "          x_values=[-5, 5],\n",
        "          y_values=[1, 1],\n",
        "          add_vertex_dots=False,\n",
        "          line_color=NEWGREEN,\n",
        "      )\n",
        "\n",
        "#Define a quadratic on the axes, with the same start and end points as the line for smooth transformation.\n",
        "      quadratic = axes.plot(\n",
        "          lambda x: (x**2 - 25)/12+1,\n",
        "          x_range=[-5, 5],\n",
        "          color=NEWGREEN\n",
        "        )\n",
        "\n",
        "#Define a sine curve on the axes, with the same start and end points as the line for smooth transformation.\n",
        "      sin = axes.plot(\n",
        "          lambda x: np.sin(5*x/6),\n",
        "          x_range=[-5, 5],\n",
        "          color=NEWGREEN\n",
        "      )\n",
        "\n",
        "#Define cubic on the axes, with the same start and end points as the line for smooth transformation.\n",
        "      cubic = axes.plot(\n",
        "          lambda x: x*(x-5)*(x+5)/35+1,\n",
        "          x_range=[-5, 5],\n",
        "          color=NEWGREEN\n",
        "        )\n",
        "\n",
        "#Define and position the point y.\n",
        "      point_coords = (-1.5, 1.975)\n",
        "      point_location = axes.coords_to_point(*point_coords)\n",
        "      y = Dot(point_location, color=NEWMEDIUMGREEN)\n",
        "\n",
        "#Define and position text describing a continuous function.\n",
        "      text = Tex(\"A continuous function is often described as 'a function that you can draw without lifting your pen off the page'.\", font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "\n",
        "##Sets up a variable tracking the position of x (dot) and a function used to update its position.\n",
        "#The starting position of dot is at x = -3.\n",
        "      x_tracker = ValueTracker(-3)\n",
        "\n",
        "#Defines a function for updating the position of dot. Updates the position depending on the tracking variable x_tracker and the y value at this point.\n",
        "      def update_dot(dot):\n",
        "          x1 = x_tracker.get_value()\n",
        "          y1 = x1*(x1-5)*(x1+5)/35+1\n",
        "          dot.move_to(axes.coords_to_point(x1, y1))\n",
        "\n",
        "#Defines dot (x) and assignes it the previously defined update function update_dot.\n",
        "\n",
        "      dot = Dot(color=GREENISHWHITE)\n",
        "      dot.add_updater(update_dot)\n",
        "\n",
        "##Sets up a variable tracking the position of x2 (dot2) and a function used to update its position.\n",
        "#The starting position of dot2 is at x = -0.9.\n",
        "      x2_tracker = ValueTracker(-0.9)\n",
        "\n",
        "#Defines a function for updating the position of dot2. Updates the position depending on the tracking variable x2_tracker and the y value at this point.\n",
        "      def update_dot2(dot2):\n",
        "          x2 = x2_tracker.get_value()\n",
        "          y2 = x2*(x2-5)*(x2+5)/35+1\n",
        "          dot2.move_to(axes.coords_to_point(x2, y2))\n",
        "\n",
        "#Defines dot2 (x2) and assignes it the previously defined update function update_dot2.\n",
        "      dot2 = Dot(color=GREENISHWHITE)\n",
        "      dot2.add_updater(update_dot2)\n",
        "\n",
        "#Defines fx, a horizontal line through dot to illustrate the output at x approaching the output at y. This line is always drawn at the y value of dot.\n",
        "      fx = always_redraw(lambda: DashedLine(\n",
        "    start=axes.c2p(-5, dot.get_y()),\n",
        "    end=axes.c2p(5, dot.get_y()),\n",
        "    color=GREENISHWHITE,\n",
        "      ))\n",
        "\n",
        "#Defines fx, a horizontal line through dot to illustrate the output at x2 approaching the output at y. This line is always drawn at the y value of dot2.\n",
        "      fx2 = always_redraw(lambda: DashedLine(\n",
        "    start=axes.c2p(-5, dot2.get_y()),\n",
        "    end=axes.c2p(5, dot2.get_y()),\n",
        "    color=GREENISHWHITE,\n",
        "      ))\n",
        "\n",
        "#Defines fy, a horizontal line through dot to illustrate the output at y.\n",
        "      fy = DashedLine(start=axes.c2p(-5, 1.975),\n",
        "    end=axes.c2p(5, 1.975),\n",
        "    color=GREEN)\n",
        "\n",
        "## Start the animation\n",
        "\n",
        "#Writes 'A continuous function is often described as 'a function that you can draw without lifting your pen off the page'.', then waits 1 second.\n",
        "      self.play(Write(text))\n",
        "      self.wait(1)\n",
        "\n",
        "#Adds the axes and line. Then transforms the line to the quadratic, then the sine curve, then the cubic, then fades out the text.\n",
        "      self.play(Create(numbered_axes))\n",
        "      self.play(Create(line))\n",
        "      self.play(Transform(line, quadratic))\n",
        "      self.play(Transform(line, sin))\n",
        "      self.play(Transform(line, cubic))\n",
        "      self.play(FadeOut(text))\n",
        "\n",
        "#Changes the text, then writes it and waits 1 second.\n",
        "      text = Tex(\"But how can we define a continuous function more precisely?\", font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      self.wait(1)\n",
        "\n",
        "#Fades out the text, changes it then writes it, adds y to the scene then waits 1 second.\n",
        "      self.play(FadeOut(text))\n",
        "      text = Tex(\"Consider a fixed point on the function, $(y, f(y))$.\",font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      self.wait(0.5)\n",
        "      self.play(Create(y))\n",
        "      self.wait(1)\n",
        "\n",
        "#Fades out the text, changes it then writes it, adds x to the scene and waits 1 second.\n",
        "      self.play(FadeOut(text))\n",
        "      text = Tex(\"Now consider another variable point on the function, $(x,f(x))$.\",font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      self.wait(0.5)\n",
        "      dot.move_to(axes.coords_to_point(-3, 2.37))\n",
        "      self.add(dot)\n",
        "      self.wait(1)\n",
        "\n",
        "#Fades out the text, changes the text and rewrites it.\n",
        "#Adds fx and fy to the scene and animates x to approach y (and therefore fx to approach fy) using x_tracker, and waits 2 seconds.\n",
        "      self.play(FadeOut(text))\n",
        "      text = Tex(\"The function is continuous at the point $y$, if as x approaches y, f(x) approaches $f(y)$.\",font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      self.add(fy,fx)\n",
        "      self.play(x_tracker.animate.set_value(-1.5), run_time=3, rate_func=linear)\n",
        "      self.wait(2)\n",
        "\n",
        "#Fades out the text, dot (x) and fx, replaces the text and rewrites it.\n",
        "#Resets the value of x_tracker and adds dot and fx back.\n",
        "#Also adds dot2 (x2) and fx2.\n",
        "#Animates dot and dot2 to approach y.\n",
        "#Waits 2 seconds, then fades out text then removes fx, fx2, dot and dot2.\n",
        "\n",
        "      self.play(FadeOut(text, dot, fx))\n",
        "      text = Tex(\"This has to work on both sides of $y$.\",font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      x_tracker = ValueTracker(-3)\n",
        "      self.add(dot, dot2, fx, fx2)\n",
        "      self.play(x_tracker.animate.set_value(-1.5), x2_tracker.animate.set_value(-1.5), run_time=3, rate_func=linear)\n",
        "      self.wait(2)\n",
        "      self.play(FadeOut(text))\n",
        "      self.remove(fx, fx2, dot, dot2)\n",
        "      self.wait()\n",
        "\n"
      ],
      "metadata": {
        "id": "rsq3mb8xbwi-"
      },
      "execution_count": 12,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "Finally, the following command is used to render the scene and save it in the subfolder 'jupyter' in the folder 'media'.\n"
      ],
      "metadata": {
        "id": "4sD46Q5Vhyjq"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "%%manim -qm -v WARNING Continuity"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 204
        },
        "id": "UUND1SyWhnJK",
        "outputId": "cf48ae9c-725f-4fc7-8af3-dcd2f332d4ad"
      },
      "execution_count": 13,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "Manim Community \u001b[32mv0.\u001b[0m\u001b[32m18.1\u001b[0m\n",
              "\n"
            ],
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Manim Community <span style=\"color: #008000; text-decoration-color: #008000\">v0.18.1</span>\n",
              "\n",
              "</pre>\n"
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": []
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Video object>"
            ],
            "text/html": [
              "<video src=\"media/jupyter/Continuity@2024-12-18@16-44-26.mp4\" controls autoplay loop style=\"max-width: 60%;\"  >\n",
              "      Your browser does not support the <code>video</code> element.\n",
              "    </video>"
            ]
          },
          "metadata": {}
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#Part 2\n",
        "\n",
        "The second and final part of the animation links what has been previously shown to the formal definition of continuity, and applies this definition to another example."
      ],
      "metadata": {
        "id": "hTrqa6GoaSV5"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class Continuity2(Scene):\n",
        "   def construct(self):\n",
        "\n",
        "#Set the background colour.\n",
        "      self.camera.background_color = NEWDARKGREEN\n",
        "      axes = Axes(\n",
        "          x_range=[-5, 6, 1],\n",
        "          y_range=[-3, 3, 1],\n",
        "          axis_config={\"color\": GREENISHWHITE}\n",
        "    )\n",
        "\n",
        "#Add numbers to the axes.\n",
        "      numbered_axes = axes.add_coordinates()\n",
        "\n",
        "#Define a cubic on the axes.\n",
        "      cubic = axes.plot(\n",
        "    lambda x: x*(x-5)*(x+5)/35+1,\n",
        "    x_range=[-5, 5],\n",
        "    color=NEWGREEN\n",
        "  )\n",
        "\n",
        "#Define a sine curve on the axes.\n",
        "      sin = axes.plot(\n",
        "          lambda x: np.sin(5*x/6),\n",
        "          x_range=[-5, 5],\n",
        "          color=NEWGREEN\n",
        "      )\n",
        "\n",
        "#Define and position text.\n",
        "      text = Tex(\"We have now seen that if we want $|f(x)-f(y)|<\\epsilon$ for at a point $y$, we can find a $\\delta$ such that if $|x-y|<\\delta$ then this is true.\", font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "\n",
        "#Defines fy, a horizontal line through dot to illustrate the output at y.\n",
        "      fy = DashedLine(start=axes.c2p(-5, 1.975),\n",
        "    end=axes.c2p(5, 1.975),\n",
        "    color=GREEN)\n",
        "\n",
        "#Defines fx1, a horizontal line.\n",
        "      fx1 = DashedLine(start=axes.c2p(-5, 2.25),\n",
        "    end=axes.c2p(5, 2.25),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "#Defines fx2, a horizontal line. fx2 and fx1 are equidistant from fy and are on the opposite sides of fy.\n",
        "      fx2 = DashedLine(start=axes.c2p(-5, 1.75),\n",
        "    end=axes.c2p(5, 1.75),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "#Defines y.\n",
        "      point_coords = (-1.5, 1.975)\n",
        "      point_location = axes.coords_to_point(*point_coords)\n",
        "      y = Dot(point_location, color=NEWMEDIUMGREEN)\n",
        "\n",
        "## Animation starts here\n",
        "#Axes, the cubic, y and dy are added to the scene. Creates fx1 and fx2 and then writes the text, then waits 2 seconds.\n",
        "      self.add(axes, cubic, y, fy)\n",
        "      self.play(Create(fx1))\n",
        "      self.play(Create(fx2))\n",
        "      self.play(Write(text))\n",
        "      self.wait(2)\n",
        "\n",
        "#Fades out the text then changes and rewrites it. Waits 0.5 seconds, then fades fx1, fx2, y and fy, waits 0.1 seconds then transforms the cubic into a sin curve.\n",
        "      self.play(FadeOut(text))\n",
        "      text = Tex(\"This is the epsilon-delta definition of a continuous function, as used in our proof. Let's look at another function to see that this definition works.\", font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "      self.play(Write(text))\n",
        "      self.wait(0.5)\n",
        "      self.play(FadeOut(fx1, fx2, y, fy))\n",
        "      self.wait(0.1)\n",
        "      self.play(Transform(cubic, sin))\n",
        "\n",
        "\n",
        "#Redefines fx1 and fx2 to change their positions.\n",
        "      fx1 = DashedLine(start=axes.c2p(-5, 0.75),\n",
        "    end=axes.c2p(5, 0.75),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "      fx2 = DashedLine(start=axes.c2p(-5, 0.25),\n",
        "    end=axes.c2p(5, 0.25),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "#Redefines y and fy to change their positions.\n",
        "      point_coords = (0.65, np.sin(5*0.65/6))\n",
        "      point_location = axes.coords_to_point(*point_coords)\n",
        "      y = Dot(point_location, color=NEWMEDIUMGREEN)\n",
        "\n",
        "      fy = DashedLine(start=axes.c2p(-5, np.sin(5*0.65/6)),\n",
        "    end=axes.c2p(5, np.sin(5*0.65/6)),\n",
        "    color=GREEN)\n",
        "\n",
        "#Defines a brace to show where 'epsilon' is measured and defines a label for the brace.\n",
        "      brace = BraceBetweenPoints(axes.coords_to_point(5, np.sin(5*0.65/6)), axes.coords_to_point(5, 0.75))\n",
        "      label = brace.get_text(r\"$\\epsilon$\")\n",
        "\n",
        "#Waits 0.5 seconds, then creates y, fy, fx1, fx2, and the brace and its label.\n",
        "      self.wait(0.5)\n",
        "      self.play(Create(y))\n",
        "      self.play(Create(fy))\n",
        "      self.play(Create(fx1))\n",
        "      self.play(Create(fx2))\n",
        "      self.play(Create(brace), Write(label))\n",
        "\n",
        "#Fades out the text then replaces it.\n",
        "      self.play(FadeOut(text))\n",
        "      text = Tex(\"If we want $|f(x) - f(y)| < \\epsilon$, where $y$ is the green dot, it is clear to see that we can choose a $\\delta$ such that when $|x-y| < \\delta$, this is true.\", font_size=20)\n",
        "      text.move_to([0,3.5,0])\n",
        "\n",
        "#Defines fx3, fx4 and fy2, vertical lines illustrating the position of the x values at all 3 positions focused on in the animation.\n",
        "      fx3 = DashedLine(start=axes.c2p(1, -3),\n",
        "    end=axes.c2p(1,3),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "      fx4 = DashedLine(start=axes.c2p(0.25, -3),\n",
        "    end=axes.c2p(0.25, 3),\n",
        "    color=GREENISHWHITE)\n",
        "\n",
        "      fy2 = DashedLine(start=axes.c2p(0.65, -3),\n",
        "    end=axes.c2p(0.65, 3),\n",
        "    color=GREEN)\n",
        "\n",
        "#Defines a second brace, brace2 to show where 'delta' is measured and defines a label for the brace.\n",
        "      brace2 = BraceBetweenPoints(axes.coords_to_point(0.65, -3), axes.coords_to_point(1, -3))\n",
        "      label2 = Tex(\"$\\delta$\", font_size=30)\n",
        "      label2.next_to(brace2, direction=DOWN)\n",
        "\n",
        "#Writes the text and creates fx3, fy2, fx4 and the second brace and its label.\n",
        "      self.play(Write(text))\n",
        "      self.play(Create(fx3))\n",
        "      self.play(Create(fy2))\n",
        "      self.play(Create(fx4))\n",
        "      self.play(Create(brace2), Write(label2))\n",
        "      self.wait()"
      ],
      "metadata": {
        "id": "7sf4Pu8wi4kv"
      },
      "execution_count": 19,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "The following command is used to render the scene and save it in the subfolder 'jupyter' in the folder 'media'."
      ],
      "metadata": {
        "id": "f4yiUMsCqZjg"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "%%manim -qm -v WARNING Continuity2"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 204
        },
        "id": "yVqHCuMrqZ8U",
        "outputId": "762bf1dd-01a5-450e-91db-95598b7d14de"
      },
      "execution_count": 20,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "Manim Community \u001b[32mv0.\u001b[0m\u001b[32m18.1\u001b[0m\n",
              "\n"
            ],
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Manim Community <span style=\"color: #008000; text-decoration-color: #008000\">v0.18.1</span>\n",
              "\n",
              "</pre>\n"
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": []
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.Video object>"
            ],
            "text/html": [
              "<video src=\"media/jupyter/Continuity2@2024-12-18@17-10-00.mp4\" controls autoplay loop style=\"max-width: 60%;\"  >\n",
              "      Your browser does not support the <code>video</code> element.\n",
              "    </video>"
            ]
          },
          "metadata": {}
        }
      ]
    }
  ]
}