在Python中绘制椭圆轨道(使用numpy,matplotlib)

时间:2016-12-19 15:24:35

标签: python matplotlib orbit

我想知道如何使用方程ay 2 + bxy + cx + dy + e = x 2 绘制椭圆轨道?

我首先确定了a,b,c,d,e常数,现在我假设通过给出x值,我将得到y,这将给出我想要的图形,但我不能通过使用matplotlib来实现。

如果你能帮助我,我真的很感激!

编辑:我在这里添加了代码。

return Object.assign ( {}, baseParams, overrideParams )

编辑:以下是常数值:

from numpy import linalg
from numpy import linspace
import numpy as np
from numpy import meshgrid
import random
import matplotlib.pyplot as plt
from scipy import optimize

x = [1.02, 0.95, 0.87, 0.77, 0.67, 0.56, 0.44, 0.30, 0.16, 0.01]
y = [0.39, 0.32, 0.27, 0.22, 0.18, 0.15, 0.13, 0.12, 0.12, 0.15]

my_list = [] #It is the main list.
b = [0] * len(x) # That is the list that contains the results that are given as x^2 from the equation.

def fxn():  # That is the function that solves the given equation to find each parameter.
    global my_list
    global b
    for z in range(len(x)):
        w = [0] * 5
        w[0] = y[z] ** 2
        w[1] = x[z] * y[z]
        w[2] = x[z]
        w[3] = y[z]
        w[4] = 1
        my_list.append(w)
        b[z] = x[z] ** 2

    t = linalg.lstsq(my_list, b)[0]
    print 'List of list representation is', my_list
    print 'x^2, the result of the given equation is', b
    print '\nThe list that contains the parameters is', t

fxn()
t = linalg.lstsq(my_list, b)[0]

print '\nThe constant a is', t[0]
print 'The constant b is', t[1]
print 'The constant c is', t[2]
print 'The constant d is', t[3]
print 'The constant e is', t[4]

3 个答案:

答案 0 :(得分:2)

简介

最简单的方法是对这个等式进行参数化。正如@Escualo建议的那样,您可以引入变量t并参数化xy。参数化意味着根据x将您的等式分别分为yt两个单独的等式。因此,对于x = f(t)的某些值,您会有y = g(t)t。然后,您可以为x, y的每个值绘制t对的结果。

这里的问题是你的椭圆是旋转的(x*y耦合项是指示的)。要分离方程式,您必须首先转换方程式以消除耦合项。这与找到一组与椭圆旋转相同角度的轴相同,沿这些轴进行参数化,然后将结果旋转回来。查看this forum post以获取一般概述。

数学

首先需要找到椭圆轴相对于x-y坐标平面的旋转角度。

\theta = \frac{1}{2} tan^{-1}(\frac{b}{-1 - a})

然后你的等式转换为

a'x'^2+b'y'^2+c'x+d'y'+e=0

,其中

a'=-cos^2(\theta)+b*sin(\theta)cos(\theta)+a*sin^2(\theta)

b'=-sin^2(\theta)-b*sin(\theta)cos(\theta)+a*cos^2(\theta)

c'=c*cos(\theta)+d*sin(\theta)

d'=-c*sin(\theta)+d*cos(\theta)

e'=e

要找到椭圆的(近似)标准形式,您可以完成x'y'部分的方块并稍微重新排列等式:

\frac{(x'-h)^2}{a''^2}+\frac{(y'-k)^2}{b''^2}=c''

,其中

a''=\frac{1}{\sqrt{a'}}

b''=\frac{1}{\sqrt{b'}}

c''=\frac{c'^2}{4a'}+\frac{d'^2}{4b'}-e'

h=-\frac{c'}{2a'}

k=-\frac{d'}{2b'}

由于您知道\theta,现在可以参数化x'y'的等式:

x'=h+a''\sqrt{c''}sin(t)

y'=k+b''\sqrt{c''}cos(t)

然后,您将使用公式

旋转回正常的x-y空间

x=x'cos(\theta)-y'sin(\theta)

y=x'sin(\theta)+y'cos(\theta)

代码

将x和y数组传递给plt.plot的代码现在相对简单:

def computeEllipse(a, b, c, d, e):
    """
    Returns x-y arrays for ellipse coordinates.
    Equation is of the form a*y**2 + b*x*y + c*x + d*y + e = x**2
    """
    # Convert x**2 coordinate to +1
    a = -a
    b = -b
    c = -c
    d = -d
    e = -e
    # Rotation angle
    theta = 0.5 * math.atan(b / (1 - a))
    # Rotated equation
    sin = math.sin(theta)
    cos = math.cos(theta)
    aa = cos**2 + b * sin * cos + a * sin**2
    bb = sin**2 - b * cos * sin + a * cos**2
    cc = c * cos + d * sin
    dd = -c * sin + d * cos
    ee = e
    # Standard Form
    axMaj = 1 / math.sqrt(aa)
    axMin = 1 / math.sqrt(bb)
    scale = math.sqrt(cc**2 / (4 * aa) + dd**2 / (4 * bb) - ee)
    h = -cc / (2 * aa)
    k = -dd / (2 * bb)
    # Parametrized Equation
    t = np.linspace(0, 2 * math.pi, 1000)
    xx = h + axMaj * scale * np.sin(t)
    yy = k + axMin * scale * np.cos(t)
    # Un-rotated coordinates
    x = xx * cos - yy * sin
    y = xx * sin + yy * cos

    return x, y

实际使用代码:

from matplotlib import pyplot as plt

a = -4.10267300566
b = 1.10642410023
c = 0.39735696603
d = 3.05101004127
e = -0.370426134994

lines = plt.plot(*computeEllipse(a, b, c, d, e))

要在椭圆上绘制原始点:

x = [1.02, 0.95, 0.87, 0.77, 0.67, 0.56, 0.44, 0.30, 0.16, 0.01]
y = [0.39, 0.32, 0.27, 0.22, 0.18, 0.15, 0.13, 0.12, 0.12, 0.15]
ax = lines[0].axes
ax.plot(x, y, 'r.')

结果如下图所示:

plot

注意

请注意,我链接的论坛帖子使用的语法与您所使用的不同。它们的等式是 Ax 2 + Bxy + Cy 2 + Dx + Ey + F = 0。这比你的 2 + bxy - x 2 + cx + dy + e = 0的形式更标准。所有数学都是根据你的符号表达的。

答案 1 :(得分:1)

y可以解决问题,作为x

的函数

关键是每个有效x都有2个y值,而椭圆范围x之外没有(或虚构)y解

下面是3.5代码,sympy 1.0应该没问题但是打印,list comps可能不会向后兼容到2.x

from numpy import linalg
from numpy import linspace
import numpy as np
from numpy import meshgrid
import random
import matplotlib.pyplot as plt
from scipy import optimize
from sympy import *

xs = [1.02, 0.95, 0.87, 0.77, 0.67, 0.56, 0.44, 0.30, 0.16, 0.01]
ys = [0.39, 0.32, 0.27, 0.22, 0.18, 0.15, 0.13, 0.12, 0.12, 0.15]

b = [i ** 2 for i in xs] # That is the list that contains the results that are given as x^2 from the equation.

def fxn(x, y):  # That is the function that solves the given equation to find each parameter.
    my_list = [] #It is the main list.
    for z in range(len(x)):
        w = [0] * 5
        w[0] = y[z] ** 2
        w[1] = x[z] * y[z]
        w[2] = x[z]
        w[3] = y[z]
        w[4] = 1
        my_list.append(w)
    return my_list

t = linalg.lstsq(fxn(xs, ys), b)


def ysolv(coeffs):
    x,y,a,b,c,d,e = symbols('x y a b c d e')
    ellipse = a*y**2 + b*x*y + c*x + d*y + e - x**2
    y_sols = solve(ellipse, y)
    print(*y_sols, sep='\n')

    num_coefs = [(a, f) for a, f in (zip([a,b,c,d,e], coeffs))]
    y_solsf0 = y_sols[0].subs(num_coefs)
    y_solsf1 = y_sols[1].subs(num_coefs)

    f0 = lambdify([x], y_solsf0)
    f1 = lambdify([x], y_solsf1)
    return f0, f1

f0, f1 = ysolv(t[0])

y0 = [f0(x) for x in xs]
y1 = [f1(x) for x in xs]

plt.scatter(xs, ys)
plt.scatter(xs, y0, s=100, color = 'red', marker='+')
plt.scatter(xs, y1, s=100, color = 'green', marker='+')
plt.show()  

当上述内容在Spyder中运行时:

runfile('C:/Users/john/mypy/mySE_answers/ellipse.py', wdir='C:/Users/john/mypy/mySE_answers')
(-b*x - d + sqrt(-4*a*c*x - 4*a*e + 4*a*x**2 + b**2*x**2 + 2*b*d*x + d**2))/(2*a)
-(b*x + d + sqrt(-4*a*c*x - 4*a*e + 4*a*x**2 + b**2*x**2 + 2*b*d*x + d**2))/(2*a)

enter image description here
    生成的y值函数无处不在:

f0(0.1), f1(0.1)
Out[5]: (0.12952825130864626, 0.6411040771593166)

f0(2)
Traceback (most recent call last):

  File "<ipython-input-6-9ce260237dcd>", line 1, in <module>
    f0(2)

  File "<string>", line 1, in <lambda>

ValueError: math domain error


In [7]:

域名错误需要尝试/执行才能感觉到&#34;有效的x范围或更多的数学

喜欢尝试/以下:(编辑为&#34;关闭&#34;绘制评论)

def feeloutXrange(f, midx, endx):
    fxs = []
    x = midx
    while True:
        try: f(x)
        except:
            break
        fxs.append(x)
        x += (endx - midx)/100
    return fxs

midx = (min(xs) + max(xs))/2    

xpos = feeloutXrange(f0, midx, max(xs))
xnegs = feeloutXrange(f0, midx, min(xs))
xs_ellipse = xnegs[::-1] + xpos[1:]

y0s = [f0(x) for x in xs_ellipse]
y1s = [f1(x) for x in xs_ellipse]

ys_ellipse = y0s + y1s[::-1] + [y0s[0]] # add y start point to end to close drawing

xs_ellipse = xs_ellipse + xs_ellipse[::-1] + [xs_ellipse[0]] # added x start point


plt.scatter(xs, ys)
plt.scatter(xs, y0, s=100, color = 'red', marker='+')
plt.scatter(xs, y1, s=100, color = 'green', marker='+')
plt.plot(xs_ellipse, ys_ellipse)
plt.show()

enter image description here

编辑:将重复的起点添加到椭圆点列表的末尾以关闭绘图图

ys_ellipse = y0s + y1s[::-1] + [y0s[0]] # add y start point to end to close drawing

xs_ellipse = xs_ellipse + xs_ellipse[::-1] + [xs_ellipse[0]] # added x start point

enter image description here

答案 2 :(得分:0)

最简单的方法是以参数形式重写,以便最终得到表达式x = A cos(t); y = B sin(t)。然后,您可以通过指定t = [0, 2 * pi]并计算相应的xy来创建完整的椭圆。

阅读this article,其中介绍了如何从一般二次形式转换为参数形式。