Python Manim 绘制动态函数切线

1. 前言

  关于 Manim 的安装,github 上有多种版本,使用起来各不相同(运行方式、API等等)踩了一些坑,最终用的 Manim 社区版,里面有详细的教程和API介绍。

2. 绘制动态函数切线

在这里插入图片描述

from manim import *


def func(x):
    return np.sin(x*PI)


class PlotTangent(MovingCameraScene):
    def construct(self):
        self.camera.frame.save_state()
        
        # 标题函数公式, 放置在左上角
        title = MathTex("f(x) = sin(x)")
        title.to_corner(UL)
        
        # 绘制坐标系
        ax = Axes(x_range = [-2.5, 2.5, 0.5], 
                  y_range = [-1.5, 1.5], 
                  x_length = 10, 
                  axis_config={"include_numbers": True}, 
                 )
        graph = ax.get_graph(func, color=BLUE)  # 函数曲线
        x_space = np.linspace(-1.5, 1.5, 200)  # 设定切线的 x 取值范围
        
        '''
        绘制切线, get_secant_slope_group 是用来绘制割线的, 这里 dx 设的足够小看起来就像切线
        这里的 slopes 里面有3条线, 第三条是需要的切线, 另外两条是 dx 和 dy
        '''
        slopes = ax.get_secant_slope_group(
            x = x_space[0], 
            graph = graph,
            dx = 0.0001, 
            secant_line_length = 5,
            secant_line_color = RED_D,
        )
        dot = Dot(point=[ax.coords_to_point(x_space[0], func(x_space[0]))])  # 初始切点
		
		# 切点处标记的信息, 用 VGroup() 把公式和动态斜率数值绑定成一组
		text, decimal = label = VGroup(
            MathTex("f'(x) = "),
            DecimalNumber(
                0,
                num_decimal_places=3,
                include_sign=True
            )
        )
        label.arrange(RIGHT)		# 没有这行的话公式和数值会重合在一起
        label.scale(0.6)			# 比例缩放
        label.set_color(YELLOW_C)	# 颜色
        
        label.add_updater(lambda d: d.next_to(dot, UL))		# label 在 dot 的左上角
        # decimal 的数值设定为 dot 点的斜率
        decimal.add_updater(lambda d: d.set_value(
            np.cos(ax.point_to_coords(dot.get_center())[0] * PI)
        ))
        
        self.add(title, ax, graph, dot)  # 标题、坐标系、函数曲线、初始切点
        
        # 切点的xy轴垂线
        h_line = always_redraw(lambda: ax.get_lines_to_point(dot.get_center()))

        self.play(Create(h_line), Create(slopes[2]), Write(label))  # 切点垂线、切线、标签
        
        self.play(self.camera.frame.animate.scale(0.8).move_to(dot))  # 镜头跟踪切点位置
        def update_curve(mob):
            mob.move_to(dot.get_center())
        
        '''
        这里用循环来变换切点坐标和切线, 感觉不是最优的方法
        其实点可以通过 dot.add_updater(lambda x: x.move_to()) 来动态更新
        但是不知道切线怎么用 add_updater 的方式来变换, 只好先用循环实现
        '''
        for x in x_space[1:]:
            self.camera.frame.add_updater(update_curve)
            
            slopes_d = ax.get_secant_slope_group(
                x = x, 
                graph = graph, 
                dx = 0.0001, 
                secant_line_length = 5, 
                secant_line_color = RED_D,
            )
            dot_d = Dot(point=[ax.coords_to_point(x, func(x))])
            
            self.play(
                ReplacementTransform(slopes[2], slopes_d[2]), 
                ReplacementTransform(dot, dot_d), 
                run_time=0.015
            )
            
            slopes = slopes_d
            dot = dot_d
            
        self.camera.frame.remove_updater(update_curve)
        self.play(Restore(self.camera.frame))
        self.wait()
        
# jupyter notebook 的魔法函数运行方式
%manim -ql -v WARNING -i PlotTangent
Python中,`matplotlib`库主要用于数据可视化,而绘制曲线的切线通常需要用到`numpy`处理数值计算以及`matplotlib.pyplot`模块的`plot`和`annotate`函数。以下是一个简单的例子: ```python import numpy as np import matplotlib.pyplot as plt # 定义一个示例函数 def func(x): return x**2 + 2*x + 1 # 创建x值范围 x = np.linspace(0, 4, 100) # 创建等差数列,从0到4,包含100个点 # 计算对应曲线的y值 y = func(x) # 绘制函数曲线 plt.plot(x, y, label='Original function') # 对于特定的x_value,例如x=2,找到对应的切线 x_value = 2 y_value = func(x_value) dy_dx = 2 * x_value + 2 # 切线斜率就是函数在该点的一阶导数 x_intercept = (y_value - func(0)) / dy_dx # 计算切线与x轴的交点 # 绘制切线 plt.plot([x_value, x_intercept], [y_value, func(x_intercept)], 'r-', label=f'Derivative at {x_value}') # 添加标注 plt.annotate(f'y = {func(x_value)}', xy=(x_value, y_value), xytext=(-50, 20), textcoords='offset points', arrowprops=dict(facecolor='black', shrink=0.05)) # 设置图例和其他属性 plt.legend() plt.xlabel('x') plt.ylabel('y') plt.title('Drawing a tangent line to the curve') plt.grid(True) plt.show() ``` 在这个例子中,我们首先创建了一个函数,然后绘制了它的图像。接着,在给定的点上(这里是x=2),我们找到了切线的斜率,并计算出与x轴的交点。最后,我们在那个点处添加了切线并进行了标注。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值