Python数学编程 第二章 数据可视化 第四节 公式绘图

第四节 用公式绘图

到目前为止,我们已经学会了在给定x、y轴数据的情况下进行绘图。在本节,主要来学习使用数学公式来创建图形。

2.4.1 牛顿万有引力定律

根据牛顿万有引力定律,质量为的物体对另一个质量为的物体的吸引力F,有如下计算公式:

其中r是两个物体之间的距离,G是引力常数,我们想观察当两个物体之间的距离增加时,力会如何变化。

考虑两个物体:第一个物体的质量,第二个物体的质量。重力常数值为。现在我们准备计算两个物体之间19种不同距离的引力:100m、150m、200m、250m、300m以此类推,直到1000m。以下程序可以执行这些计算,并且绘制图形:


 ''' The relationship between gravitational force and distance between two bodies '''  import matplotlib.pyplot as plt # Draw the graph def draw_graph(x, y):     plt.plot(x, y, marker='o')     plt.xlabel('Distance in meters')     plt.ylabel('Gravitational force in newtons')     plt.title('Gravitational force and distance')     plt.show()  def caculate_F():     # Generate values of distance     r = range(100, 1001, 50)     F = []     # Constant G     G = 6.674 * (10 ** (-11))     # Two bodies' masses     m1 = 0.5     m2 = 1.5     # Caculate force and add it to the list,F     for dist in r:         F.append((G * m1 * m2) / (dist ** 2))          # call the draw_graph function     draw_graph(r, F)  if __name__ == '__main__':     caculate_F()

caculate_F()函数完成了大部分的工作,首先在其中使用range()函数生成了一个距离列表r,列表步长为50,截至值为1001,这样子会包含1000在内;其次,创建了一个空列表F用来存储不同距离对应的万有引力,还创建了重力常量G和两个物体的质量m1、m2;最后,使用一个for循环计算不同的r对应的引力F,并将其加入到列表F中。然后距离为x周数据,F为y轴数据传入draw_graph()函数,进行绘图显示。

引力F随距离r的变化

由图可知,随着距离r增加,引力减小,且图像非直线,即距离和引力非线性关系,且成反比。

2.4.2 抛物运动

现在,我们来绘制一些日常生活中熟悉的图形。如果你把一个球扔出,他将会遵循如下图所示轨迹:

抛物运动

图中,球从A点抛出并在B点落地,这种类型的运动被称为抛物运动。我们的目标是使用抛物运动的方程来绘制物体的运动轨迹。显示球从投掷点开始直到再次击中地面的位置。

当你扔球时,球具有一定的初始速度,该速度的方向与地面形成了一定的角度,我们称初始速度为u及其与地面的角度为θ (theta),如图4-1所示。球具有两个速度分量:一个沿x方向,由计算;另一个沿y方向,由计算。 当球移动时,其速度发生变化,我们将使用v表示变化的速度:水平分量为,垂直分量为。简单起见,假设水平分量在物体运动期间不改变,而垂直分量由于重力而不断减少,根据方程式计算。在该方程中,g是重力加速度,t是测量速度时的时间。因为我们可以替换得到:

由于速度的水平分量保持不变,因此物体的水平距离给出。速度的垂直分量不断变化,运动的垂直距离由以下公式给出:


换句话说,给出了球在飞行期间任意时间点的x和y坐标。我们使用程序会之轨迹时,将会使用这些方程式。在我们使用这些方程时,时间(t)单位为s,速度单位为m/s,投射角度(θ)单位为度,重力加速度(g)单位为

然而,在我们编写程序之前,我们首先需要知道球在落地之前的飞行时间,以便知道程序何时停止,从而绘制球的轨迹。要做到这一点我们先来看看求到达最高点所需的时间。当速度的垂直分量时,球达到最高点,即时,我们求解t,可得:


我们记这个时间为,求在到达最高点后,将在空中飞行另一个后击中地面,所以球的总飞行时间为


我们投掷一个球,假设,计算总飞行时间,可将这些值代入上述公式:


求在这段时间内处于飞行状态,为了绘制轨迹,我们将计算这段时间内x与y坐标。我们应该多久计算一次呢?理想情况下计算越频繁越好,在本节中间,我们每隔0.0001s计算一次坐标。

(1)生成等间隔的浮点数

我们使用range()函 数来生成等间隔的整数,也就是说, 如果我们想要一一个1到10之间的整数列表,每个整数用1分隔,我们将使用range(1,10)。如果我们想要一个不同的步长值,我们可以给range()函数指定第三个参数。遗憾的是,对于浮点数来说没有这样的内置函数,即没有什么函数可以让我们创建一一个从0到0.72的数字列表,其中两个连续的数字用0.001分隔。我们可以使用while循环来创建我们自己的函数,如下所示:


 ''' Generate equally spaced floating point number between two given values '''  def frange(start, final, increment):     numbers = []     while start < final:         numbers.append(start)         start += increment     return numbers

我们定义了一个frange()函数,它接受三个参数,起始值start,截至值final,步长increment来模拟实现一个类似于整数range()的函数。创建以来列表numbers用来存储等间隔数字,for循环每次迭代都将start值存入到列表numbers中,然后start再加上increment,最终返回numbers列表。

我们将在绘制轨迹图形程序中使用这个函数。

(2)绘制轨迹

以下程序以一定的速度和角度绘制出跑去哦出的球的轨迹,速度和角度均作为程序的输入:


 ''' Generate equally spaced floating point number between two given values '''  def frange(start, final, increment):     numbers = []     while start < final:         numbers.append(start)         start += increment     return numbers  ''' Draw the trajectory of a body in projectile motion ''' from matplotlib import pyplot as plt import math  def draw_graph(x, y):     plt.plot(x, y, marker='o')     plt.xlabel('x-coordinate')     plt.ylabel('x-coordinate')     plt.title('Projectile motion of a ball')  def draw_tarjectory(u, theta):     theta = math.radians(theta)     g = 9.8      # Time of flight     t_flight = 2 * (u * math.sin(theta)) / g     # Find time intervals     intervals = frange(0, t_flight, 0.1)     # List of a and y coordinate     x, y = [], []     for t in  intervals:         x.append(u * math.cos(theta) * t)         y.append((u * math.sin(theta) * t - 0.5 * g * (t ** 2)))     draw_graph(x, y)  if __name__ == '__main__':     try:         u = float(input('Enter the initial velocity (m/s) : '))         theta = float(input('Enter the angle of projection (degree) : '))     except ValueError:         print('You entered an invalid input')     else:         draw_tarjectory(u, theta)         plt.show()

在这个程序中,我们需要使用math模块中的radians()函数、cos()函数和sin()函数,我们我们在写程序一开始就导入math模块。draw_tarjectory()函数接受两个参数u和theta,分别对应于抛球时的速度和角度。math模块的正弦函数和余弦函数要求参数为弧度,因此使用math.radians()将角度转换为弧度。接下来创建一个g标签来指代重力加速度,赋值为。然后调用frange()函数对0~之间的数做等间隔划分,然后利用这个时间列表去计算该时刻下的x,y轴坐标,将x、y坐标单独存储在两个列表中。

最后用draw_graph()传入x,y作为参数来绘制轨迹。此时draw_graph()不调用show()函数(原因在下一段程序中讲)。然后在main函数中使用try...except程序块,控制用户输入为任意整数和浮点数,否则提示无效输入,运行程序:


 Enter the initial velocity (m/s) : 25 Enter the angle of projection (degree) : 60

u = 25, theta = 60时的运动轨迹

(3)比较以不同的初始速度投球时的轨迹

上面的程序以及绘图就是一个球的轨迹。但是假如我们要比较三个球以相同的角度,不同的初速度抛掷时的轨迹,该怎么办呢?很简单,只需要替换上述代码中的main代码块:


 if __name__ == '__main__':     # List of three different initial velocities     u_list = [20, 40, 60]     theta = 45     for u in u_list:         draw_tarjectory(u, theta)      # Add a legend and show the graph     plt.legend(['20', '40', '60'])     plt.show()

这里,我们不要求用户输入速度和抛射角度,而是创建了一个初速度列表u_list和抛射角度theta。然后对u_list中的每个值和theta都调用draw_tarjecrory()函数,分别计算不同初速度对应的x、有、坐标,然后绘制轨迹图形

u=20,40,60(m/s),theta = 45°时不同的运动轨迹

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章