Basic 2D Graphs ================== In the previous versions of Manim there was a special scene called ``GraphScene``, however, in the most recent versions it is no longer necessary, since all the functionalities of ``GraphScene`` were transferred to the ``Axes`` class, so we can have as many graphs as we want in the same scene (which could not be done in ``GraphScene``). Axes -------------- The ``Axes`` are made up of two ``NumberLines``, and you can configure each axis with all the ``NumberLine`` options. To define the axes the main thing is to define the scales and the size of the axes. Configurations """""""""""""""""" .. code-block:: python axes = Axes( # [start,end,step] x_range=[-1,5,1], y_range=[-1,5,1], # Size of each axis x_length=6, y_length=6, # axis_config: the settings you make here # will apply to both axis, you have to use the # NumberLine options axis_config={"include_numbers": True}, # While axis_config applies to both axis, # x_axis_config and y_axis_config only apply # to their respective axis. x_axis_config={ "color": RED, "numbers_to_exclude": [2,3], "decimal_number_config": { "color": TEAL, "unit": "\\rm m", "num_decimal_places": 0 } }, y_axis_config={ "color": YELLOW, "include_tip": False, "decimal_number_config": { "color": PINK, "unit": "^\\circ", "num_decimal_places": 1, "include_sign": True } }, ) .. raw:: html
Show result .. image:: ../_static/images/axes1.png .. raw:: html

Sometimes you will not want to define the length of the axes, sometimes you will want to define the size of each unit, if you do not specify the width of the axes you can define the ``unit_size``. .. code-block:: python axes = Axes( # [start,end,step] x_range=[-1,5,0.5], y_range=[-1,5,1], # Size of each axis y_length=6, x_axis_config={ # Instead x_lenght we can define "unit_size" "unit_size": 2, "numbers_with_elongated_ticks": list(range(-1,5)), "longer_tick_multiple": 3, # gap between axes and numbers "line_to_number_buff": 0.6, "numbers_to_include": list(range(-1,5)), "decimal_number_config": { "num_decimal_places": 0, }, "font_size": 70 }, y_axis_config={ "include_numbers": True }, ) self.add(axes) .. raw:: html
Show result .. image:: ../_static/images/axes2.png .. raw:: html

Get coord from axes """""""""""""""""""""""" There are two concepts to understand, the "coords" reference system and the "points" reference system. * **Points**: It is the reference system of the camera, and therefore it is absolute, we could say that it is our inertial system, the fixed system. * **Coords**: It is the reference system of each axis, if you create more than one axes then each one will have its own reference system. Axes has the method ``Axes.coords_to_point`` and ``Axes.point_to_coords``. * ``coords_to_point``/``c2p``: It receives a two-dimensional vector :math:`(x,y)`, and returns a three-dimensional vector :math:`(x,y,z)` which refers to the coordinates of your ``Axes`` using the reference system of the camera: **Points**. .. raw:: html

* ``point_to_coords``/``p2c``: This method is the inverse, we enter a three-dimensional vector :math:`(x,y,z)` and it returns a two-dimensional coordinate :math:`(x,y)` that refers to the axes system **coords**. .. raw:: html

Line graph ------------------------- Making graphs with points should be easy for the student, we only need to make a polyline by changing the reference system using ``c2p``, it is left as an exercise. .. raw:: html
Show solution .. code-block:: python def construct(self): axes = Axes( x_range = (0, 7), y_range = (0, 5), x_length = 7, axis_config={"include_numbers": True}, ) x_values = [0, 1.5, 2, 3, 4, 6.3] y_values = [1, 3, 2.5, 4, 2, 1.2] coords = [axes.c2p(x,y) for x,y in zip(x_values,y_values)] plot = VMobject(color=BLUE).set_points_as_corners(coords) self.add(axes,plot) .. image:: ../_static/images/axes4.png .. raw:: html

However, Manim already has a functionality that allows us to do the same. .. code-block:: python def construct(self): axes = Axes( x_range = (0, 7), y_range = (0, 5), x_length = 7, axis_config={"include_numbers": True}, ) axes.center() line_graph = axes.get_line_graph( x_values = [0, 1.5, 2, 3, 4, 6.3], y_values = [1, 3, 2.5, 4, 2, 1.2], line_color=BLUE, vertex_dot_style={"stroke_width": 3, "fill_color": RED}, stroke_width = 4, ) self.add(axes, line_graph) .. raw:: html
Show result .. image:: ../_static/images/axes3.png .. raw:: html

Use Text instead numbers in labels ------------------------------------ .. code-block:: python def construct(self): x_labels = [ "-\\frac{3\\pi}{2}", # -3pi/2 "-\\pi", # -pi "-\\frac{\\pi}{2}", # -pi/2 "0", # Blank "\\frac{\\pi}{2}", # pi/2 "\\pi",# pi "\\frac{3\\pi}{2}" # 3pi/2 ] axes = Axes( x_range = (-3*PI/2, 3*PI/2, PI/2), y_range = (-1.5, 1.5, 0.5), x_length = 10, axis_config={"include_tip": False} ) axes.center() x_tex_lables = VGroup(*[ MathTex(t).next_to(axes.x_axis.n2p(x),DOWN) if x >= 0 else # Shift pi<0 labels to left MathTex(t).next_to(axes.x_axis.n2p(x),DOWN).shift(LEFT*0.2) for t,x in zip(x_labels,np.arange(-3*PI/2, 3*PI/2+PI/2, PI/2)) if t != "0" # Ignore 0 value ]) self.add(axes,x_tex_lables) .. raw:: html
Show result .. image:: ../_static/images/axes5.png .. raw:: html

:math:`f(x)` plots ------------------------- Resolution """"""""""""""" The plots are only approximations by means of bézier curves, so it is good to indicate the resolution of the graph: .. code-block:: python def construct(self): # Define axes axes_left = Axes( x_range = (0, 7, 1), y_range = (0, 5, 1), x_length = 7, axis_config={"include_numbers": True}, ) axes_right = axes_left.copy() axes = VGroup(axes_left,axes_right).arrange(RIGHT) axes.width=config.frame_width-1 # Define graphs function = lambda x: np.sqrt(x) # good resolution left_graph = axes_left.get_graph(function, x_range=(0, 7, 0.05)) # bad resolution |-----> Resolution right_graph = axes_right.get_graph(function,x_range=(0, 7, 3)) self.add( axes, left_graph,right_graph ) .. raw:: html
Show result .. image:: ../_static/images/axes6.png .. raw:: html

Style """"""""" The plots are like any VMobject, so it accepts ``stroke_width``, ``stroke_color``, it can be converted to ``DashedVMobject``, etc. More methods """""""""""""""" This is another VMobject that has many more options, you already have the knowledge to be able to read the `official documentation `__. Parametric functions ------------------------- .. code-block:: python def construct(self): # Define axes axes = Axes( x_range = (-3, 3, 1), y_range = (-3, 3, 1), x_length = 7, y_length = 7, axis_config={"include_numbers": True}, ) parametric_func = axes.get_parametric_curve( lambda t: np.array([ np.cos(t), # x 2*np.sin(t), # y ]), t_range=(0,2*PI,0.1), # Domain <---| |----> resolution color=RED ) equations = MathTex(r""" c:\begin{cases} \cos(t)\\ 2\sin(t)\\ t\in [0,2\pi) \end{cases} """).scale(1.3) equations.to_corner(UR) self.add(axes,parametric_func,equations) .. raw:: html
Show result .. image:: ../_static/images/axes7.png .. raw:: html

NumberPlane -------------- It is the same as ``Axes`` but with background lines, it is ideal for making linear transformations, which we will see in the next course. `Official documentation `__. Transform Riemann rectangles ---------------------------------- With `this `__ we can do it using: .. code-block:: python def construct(self): axes = Axes( x_range = (-1, 12, 1), y_range = (-1, 3, 1), x_length = 12, y_length = 7, ) func = axes.get_graph(lambda x: 0.7*np.sqrt(x),x_range=[0,12,0.05]) rects = VGroup(*[ axes.get_riemann_rectangles( func, x_range=[1,11], dx=dx, input_sample_type="left", stroke_width=dx if dx > 0.1 else 0.8, ) .set_color_by_gradient(PURPLE,ORANGE) .set_stroke(color=BLACK if dx > 0.1 else None) for dx in [1/(i) for i in range(1,15)] ]) r = rects[0] self.add(axes,func,r) for rect in rects[1:]: self.play( Transform(r,rect) ) self.wait(0.3) self.wait() .. raw:: html
Show result