티스토리 뷰

1일 1마님 시리즈는 예제 코드를 하루에 하나씩 따라하면서 마님 라이브러리 사용에 익숙해지기 위해 만든 시리즈입니다! 간단하게 코드 + 코드 리뷰 + 실행 결과만 작성합니다!

# 나만의 fucntion 만들기
def get_horizontal_line2graph(axes, function, x, width, color):
    result = VGroup()
    line = DashedLine(
        start = axes.c2p(0, function.underlying_function(x)),
        end   = axes.c2p(x, function.underlying_function(x)),
        stroke_width = width,
        stroke_color = color,
    )
    dot = Dot().set_color(color).move_to(axes.c2p(x, function.underlying_function(x)))
    result.add(line, dot)
    return result

class Derivatives(Scene):
    def construct(self):
		
        # 1. Set ValueTracker
        k = ValueTracker(-3)

        # 2. Adding Mobjects for the first plane
        # 2.1 Make Plane : NumberPlane
        plane1 = NumberPlane(
            x_range=[-3,4,1], x_length=5,
            y_range=[-8,9,2], y_length=5
        ).add_coordinates().shift(LEFT * 3.5)

		# 2.2 plot your function1 on plane1
        func1 = plane1.plot(
            lambda x : (1/3)*x**3, x_range=[-3, 3], color=RED_C
        )

		# 2.3 Make label for function1
        func1_label = MathTex("f(x)=\\frac{1}{3}x^3").set(width=2.5)\
        .next_to(plane1, UP, buff=0.2).set_color(RED_C)

		# 2.4 plot your secant_slope_group on function1
        moving_slope = always_redraw(lambda :
            plane1.get_secant_slope_group(
            x     = k.get_value(),
            graph = func1,
            dx    = 0.05,
            secant_line_length = 4,
            secant_line_color  = YELLOW)
            )
        
        # 2.5 plot a dot on the center of slope
        dot = always_redraw(lambda :
                            Dot().move_to(
            plane1.c2p(k.get_value(), func1.underlying_function(k.get_value()))
                    )
                )
        
        # Plane2, Same with plane1
        plane2 = NumberPlane(x_range=[-3,4,1], x_length=5,
                             y_range=[0,11,2], y_length=5).add_coordinates().shift(RIGHT * 3.5)
        
        # x_range=[-3, k.get_value()]를 통해서 x^2이 plot되는 x_range를 계속해서 update한다.
        # 실행 결과를 참고하면 이해가 될것임
        func2 = always_redraw(lambda : plane2.plot(
            lambda x : x **2, x_range=[-3, k.get_value()], color=GREEN,
            )
        )

        func2_label = MathTex("f'(x)=x^2").set(width=2.5)\
        .next_to(plane2, UP, buff=0.2).set_color(GREEN)

		# Use Your Own Function in this line
        moving_h_line = always_redraw(
            lambda : get_horizontal_line2graph(
                axes=plane2, function=func2, x = k.get_value(),
                width=4, color=YELLOW
            )
        )

        slope_value_text = (
            Tex("slope value : ")
            .next_to(plane1, DOWN, buff=0.1)
            .set_color(YELLOW)
            .add_background_rectangle()
        )

        slope_value = always_redraw(
            lambda : DecimalNumber(num_decimal_places=1)
            .set_value(func2.underlying_function(k.get_value()))
            .next_to(slope_value_text, RIGHT, buff=0.1)
            .set_color(YELLOW)
            .add_background_rectangle()
        )

        self.play(
            LaggedStart(
                DrawBorderThenFill(plane1),
                DrawBorderThenFill(plane2),
                Create(func1),
                Write(func1_label),
                Write(func2_label),
                run_time=5,
                lag_ratio=0.5
            )
        )

        self.play(FadeIn(moving_slope, moving_h_line, func2, slope_value, slope_value_text, dot))
        self.wait(2)

        self.play(k.animate.set_value(3), run_time=10, rate_func=smooth)
        self.wait(4)

 

오늘은 나만의 새로운 def를 생성해보고 사용해보는 과정이 핵심이다. Manim이라고 해봐야 어쨋든 python library이고 python 기본 문법은 그대로 사용한다.

따라서 def를 통한 함수 생성도 완전히 동일한 방식으로 진행하면 된다.

  • DashedLine() class를 이용해서 점선을 만들 수 있다.
  • Dot() class를 이용해 점을 찍을 수 있다. 
  • 특정 function을 지정했다면, function.underlying_function(x) 메소드를 이용해서 그 함수의 x값을 지정해서 f(x)값을 얻어올 수 있다. 아주 유용한 기능이니 반드시 기억하자.
  • result에 VGroup으로 묶어서 만든 line과 dot을 전달한다.
  • ValueTracker 기능은 이전에도 설명했지만, Updator 기능을 적용하기 위해 필요한 class이다. Manim에서 아주, 아주 핵심적으로 사용되는 class이니 반드시 사용법을 익혀야 한다.
  • 특히 ValueTracker는 .get_value()와 .animate.set_value() 기능과 단짝처럼 사용된다. 기능은 이름 그대로이다.
  • NumberPlane() class를 이용해서 좌표평면계를 그릴 수 있다.
  • NumberPlane.plot(lambda x : YOUR FUNCTION) 메서드를 이용해서 생성한 특정 numberplane 위에 그래프를 그릴 수 있다. (예전에는 get_graph 메서드였는데 plot으로 변경됨)
  • MathTex는 LaTex기반으로 수식을 나타낼 때 사용하는 class이다. LaTex 문법을 알아야 사용 가능하다.
  • always_redraw(lambda : YOUR Mobject) 기능을 통해서 특정 Mobject의 animate를 Update할 수 있다. ValueTracker와 함께 아주 유용하게 사용되니 사용법을 반드시 익혀야 할 함수중의 하나이다.
  • moving_slope에는 get_secant_slope_group이라는 메서드가 저장되는데 이것은 어떤 그래프위에서 두 점사이의 평균 변화율 (기울기)을 plot하는 메서드이다. 사용법은 plane.get_secant_slope_group() 내부에서 특히 plane위의 특정한 graph를 지정하고, x값을 전달하면 x부터 dx만큼 떨어진 위치의 dy를 이용해 기울기를 그린다. 
  • 따라서 dx값을 0.01처럼 아주 작은값으로 설정하면 접선에서의 기울기 (= 미분계수 = 도함수)를 plot할 수 있고, dx값을 1처럼 크게 잡으면 평균 변화율을 plot 할 수 있다. 이것은 그냥 dx를 직접 바꿔보면서 실행해보는게 이해가 빠를 듯
  • moving_h_line 변수에는 우리가 직접 지정한 get_horizontal_line2graph함수가 저장되었다. 실행결과를 참고하면 get_horizontal_line2graph함수의 기능이 눈에 보일 것이다.
  • DecimalNumber는 표면적으로는 십진수라는 뜻이지만 대략 python의 Float와 비슷한 type의 class라고 생각하면 될 것 같다. num_decimal_places는 소수점 이하를 n자리 까지 나타내겠다는 의미이다.
  • LaggedStart()를 이용해서 약간씩의 delay를 준 상태로 애니메이션을 시작할 수 있다.
  • ValueTracker.animate.set_value(n)을 통해서 기존의 ValueTracker의 값을 n으로 바꿀 수 있다. 이때 변화하는 속도를 상당히 다양하게 지정할 수 있는데 그것은 아래 사이트를 참고하자

https://docs.manim.community/en/stable/reference/manim.utils.rate_functions.html

 

rate_functions

A selection of rate functions, i.e., speed curves for animations. Please find a standard list at https://easings.net/. Here is a picture for the non-standard ones There are primarily 3 kinds of sta...

docs.manim.community

 


댓글