본문 바로가기

Programming/Manim Lectures

[05-5-B] Graph Line: NumberLine

반응형

In this page, we will look at the NumberLine responsible for the axis line, such as the x-axis and y-axis of the graph.

 

The axis is not only responsible for drawing the horizontal line corresponding to the x-axis and the vertical line corresponding to the y-axis, but also serves to map the value of (x,y) by the function expression to the coordinates of the actual screen. 

 

If (x,y) by the formula is used as the value of the screen coordinate system as it is, the meaning of the axis is a simple horizontal line or vertical line.

However, if the coordinate system is enlarged or reduced, you need something to convert the (x,y) value to the screen coordinate system, which is handled by the NumberLine and Axes classes. (Axes consists of 2 NumberLines)

NumberLine class

object > Container > Mobject > VMobject > TipableVMobject > Line > NumberLine
manimlib.mobject.number_line.NumberLine(self, **kwargs)

Create lines that can be used as graph axes.


It can achieve its own scale by the minimum and maximum values and the length of the line, and it has a conversion method for where the value in the scale corresponds to the point on the line.

 

CONFIG = {
        "color": LIGHT_GREY,
        "x_min": -FRAME_X_RADIUS,
        "x_max": FRAME_X_RADIUS,
        "unit_size": 1,
        "include_ticks": True,
        "tick_size": 0.1,
        "tick_frequency": 1,
        # Defaults to value near x_min s.t. 0 is a tick
        # TODO, rename this
        "leftmost_tick": None,
        # Change name
        "numbers_with_elongated_ticks": [0],
        "include_numbers": False,
        "numbers_to_show": None,
        "longer_tick_multiple": 2,
        "number_at_center": 0,
        "number_scale_val": 0.75,
        "label_direction": DOWN,
        "line_to_number_buff": MED_SMALL_BUFF,
        "include_tip": False,
        "tip_width": 0.25,
        "tip_height": 0.25,
        "decimal_number_config": {
            "num_decimal_places": 0,
        },
        "exclude_zero_from_default_numbers": False,
    }

 

Parameters: **kwargs
    CONFIG values of NumberLine and Line/VMobject/Mobject
 
    Frequently used variables are:
    
    - color=LIGHT_GREY: Line color
    
    - x_min=-FRAME_X_RADIUS: Minimum value of the line
    
    - x_max=FRAME_X_RADIUS: Maximum value of the line
    
    - unit_size=1: The ratio between the value on the axis and the position value on the screen.
                   If it is 0.1, 1/10 of the value on the axis becomes the value on the screen 
                   (values from -50 to 50 correspond to -5 to 5 position values on the screen)
  
    - include_ticks=True: Decide whether to display tick marks on the axis. 
                          The scale unit size is determined by tick_frequency.
                          
    - tick_size=0.1: Size of tick to display on the axis
    - tick_frequency=1: The interval to display the tick
    - leftmost_tick=None: Leftmost tick value on the axis.
    
                          When the axis range is [-50, 50], and leftmost_tick=-45, tick_frequency=10, 
                          the scale is drawn at the position of [-45, -35, -25, ..., 30, 45]. 
                          
                          This is the same value as np.arange(-45,50,10).
                          
    - numbers_with_elongated_ticks=[0]: Specify where to draw the large tick. 
                          The default is 0, the tick at 0 is the normal tick size multiplied 
                          by longer_tick_multiple. 
                          
    - include_numbers = False: Decide whether to display the numeric value of the axis
    
    - numbers_to_show=None: Specify a list of numeric values to display on the axis.     
                            The value is displayed below the axis corresponding to that value.
                          
    - longer_tick_multiple=2: When drawing the scale of the number specified 
                              in numbers_with_elongated_ticks, a value that determines 
                              how many times the normal scale size is drawn. 
                              If the value is 2, a scale twice the size of the normal 
                              scale is drawn.
                              
    - number_at_center=0: Specifies what value is placed at the center of the screen.
                          Default is zero.
                          
    - number_scale_val=0.75: Specify the font size scale when displaying axis values. 
                             The numeric value is made of DecimalNumber, 
                             and the scale of the created DecimalNumber object is specified 
                             as number_scale_val. 
                             
                             The smaller the number_scale_val value, the smaller the text.
                             
    - label_direction=DOWN: The direction in which the numerical values of the axes 
                            are displayed. 
                            
                            If it is DOWN, it is displayed at the bottom of the axis.
                            
    - line_to_number_buff=MED_SMALL_BUFF=0.25: Margin between axis and number
    
    - include_tip=False: 
    
    - decimal_number_config={
            "num_decimal_places": 0,
        } 
       : Format the DecimalNumber to display the numeric values of the axes. 
       All CONFIG values of DecimalNumber can be used
       
   - exclude_zero_from_default_numbers=False: Decide whether to display 0 value. 
                               Applies only when displaying the default number, 
                               not when the number specified by numbers_to_show is displayed.

    - stroke_width=DEFAULT_STROKE_WIDTH=4: Line thickness

 

The range of values to be used on the axis can be specified by x_min and x_max.


Note that the value on the axis is changed by unit_size.

 

For example, when unit_size=1, the value on the axis and the coordinate value on the screen are the same. 

 

Below is the NumberLine when x_min=-5, x_max=5, unit_size=1.

 

        n_line = NumberLine(
            x_min=-5,  x_max=5,
            unit_size=1,
            include_numbers=True,
            tick_frequency=1,
        )
        self.add(n_line)
        self.wait()

 

The rightmost scale value of 5 is not displayed. This is caused by obtaining np.arange(x_min, x_max) when generating the scale value. If you want to display the rightmost value, you can use the trick of setting x_max=5.001.

 


The 'unit_size' is actually correct to be expressed as unit_size_rate, which represents the ratio of the unit length of the axis.

For example, if you want to display an axis with a minimum value of -50 and a maximum value of 50 in size 10 on the screen, you can set unit_size=0.1


In other words, the range of numbers on the axis is 100, and the actual length of the screen is 10, so the number size and the actual screen size should be 10:1 scale, and the value representing this is unit_size.

 

        n_line = NumberLine(
            x_min=-50,  x_max=50,
            tick_frequency=10,
            unit_size=0.1,
            include_numbers=True,
            numbers_to_show=np.arange(-50,50.1,10),
        )

 

 

In the above code, the minimum and maximum values were specified as x_min and x_max, and tick_frequency=10 to display the scale every 10 sizes.


And, as explained above, by setting unit_size=0.1, there is a 10:1 relationship between the actual value on the axis and the value on the screen.


This will convert all values between -50 and 50 to values between -5 and 5 on the screen.

 

The method of displaying the scale value is a bit unusual. I decided to display the scale value with include_numbers=True, and I used the numbers_to_show to specify the value to display directly.


If only include_numbers=True without numbers_to_show, numbers are displayed for every 1 unit by default, and the numbers are overlapped, making it unreadable. (Picture below)

 

include_numbers=True without numbers_to_show : too dense


The tick mark size can be adjusted with tick_size and the default is 0.1. It feels a bit big, and it looks good about 0.05 in size.

 

tick_size = 0.05


In the example above, if you want the tick position to be [-45, -35, ..., 35, 45], you can set leftmost_tick=-45

 

And if you want to display the numbers according to this scale unit,

you must also do numbers_to_show=np-arange(-45,50,10).

 

        n_line = NumberLine(
            x_min=-50,  x_max=50,
            tick_frequency=10,
            tick_size = 0.05,
            unit_size=0.1,
            include_numbers=True,
            numbers_to_show=np.arange(-45,50,10),
            leftmost_tick = -45,
        )


To include an arrow at the end of the axis, specify include_tip=True.

 

include_tip=True

 

There is a tip_width parameter that can control the length and height of the arrow, but it is not implemented in the Manim library yet till 2020, April.

To be adjustable, you need to modify it directly by yourself in number_line.py to be the code below.
        if self.include_tip:
            self.add_tip(tip_length=self.tip_width)

The numeric value of the axis is expressed using DecimalNumber

 

The format of the displayed DecimalNumber can be specified using the decimal_number_config value, and all of the CONFIG values in DecimalNumber can be changed using this decimal_number_config.

 

To display the numeric value up to one decimal place, you can specify as below.

 

    decimal_number_config= {
                "num_decimal_places": 1,
    }


If unit_size is not 1 or if the center position of the axis is moved using number_at_center, the value of the axis and the value on the screen are different.

Therefore, it is necessary to calculate where the value of the axis is located on the axis. The methods that calculate it are number_to_point and point_to_number.

 

 

number_to_point method

manimlib.mobject.number_line.NumberLine.number_to_point(self, number)

Convert the given number to a place value on the NumberLine axis.


Short for ntp(self.number)

 

Parameters: number
    Value on axis to convert. The value must be x_min and x_max

Returns:
    Position value on the axis of the given number

If the value on the axis and the position on the screen are not 1:1 scale, you need to calculate which value is on the screen's axis line.

When calculating, first, let's say that the desired value is x. Then, find the ratio of the x value between x_min and x_max on the axis.

That is, when the size between x_min and x_max is 1, it is to find out what the position value of x is.

 

Assuming this value is alpha, alpha will be calculated using the following equation.

 

alpha = float(number - self.x_min) / (self.x_max - self.x_min)

 

Next, find the position at the ratio of alpha between the start and end positions of the line on the screen, and use the interpolate function for calculating this position.

interpolate( self.get_start(), self.get_end(), alpha )

 

The number_to_point method is implemented with the above logic, and we can use this method to find the axis position for a value.

 


Let's write an example using number_to_point method.

 

Let's create an x-axis from -50 to 50, move the vertical arrow above it from x=-50 to x=50, and create an animation that displays the position value of the arrow while the arrow moving.

 

  • The x axis is created using NumberLine: x_min=-50, x_max=50
  • Use ValueTracker for animation moving on the x-axis: value changed from -50 to 50.
  • Arrow and DecimalNumber values change according ValueTracker value.
  • For the value of ValueTracker, use the number_to_point method to determine the position on the x-axis.
    def number_to_point_test(self):
        n_line = NumberLine(
            x_min=-50, x_max=50,
            tick_frequency=10,
            tick_size=0.05,
            unit_size=0.1,
            include_numbers=True,
            numbers_to_show=np.arange(-50,51,10),
        )

        self.add(n_line)
        self.wait()

        tracker = ValueTracker(-50)
        def get_line_obj():
            sp = n_line.number_to_point(tracker.get_value())
            ep = sp + UP*1.5
            arrow = Arrow(sp,ep,buff=0,color=RED)

            num = DecimalNumber(tracker.get_value(), color=RED)
            num.next_to(arrow, UP)
            return VGroup(arrow, num)

        obj = always_redraw(get_line_obj)
        self.add(obj)
        self.play(
            tracker.set_value, 50,
            run_time=5,
        )
        self.wait()

 

 


point_to_number method

manimlib.mobject.number_line.NumberLine.point_to_number(self, point)

Convert the position value on the given NumberLine to a value.


It can be used as a ptn as a short form.

 

Parameters: point
    Value on axis to convert. Must be a value between x_min and x_max

Returns:
    Numeric value for a given axis position

If a point (Dot) moves along an axis, you can find out what value this point is on the axis as follows.

 

axis.point_to_number(dot.get_center())

Next: [05-5-C] Graph Coordinate: Axes

 

[05-5-C] Graph Coordinate: Axes

NumberLine can be used to represent one axis. Two-dimensional coordinate systems require two axes, and the Axes class is used to represent the x-axis and y-axis required for a two-dimensional coordi..

infograph.tistory.com

Go To: [99] Table of Contents

반응형

'Programming > Manim Lectures' 카테고리의 다른 글

[05-5-D] Grid Background: NumberPlane  (0) 2020.06.07
[05-5-C] Graph Coordinate: Axes  (0) 2020.06.07
[05-5-A] Graph from ParametricFunction/FunctionGraph  (0) 2020.06.07
[05-5] Graph  (0) 2020.06.07
[05-4-B] Integer  (0) 2020.06.07