17

Pythonで方向フィールドを描画する方法はありますか?

私の試みは、http://www.compdigitec.com/labs/files/slopefields.pyを変更することです

#!/usr/bin/python

import math
from subprocess import CalledProcessError, call, check_call

def dy_dx(x, y):
    try:
        # declare your dy/dx here:
        return x**2-x-2
    except ZeroDivisionError:
        return 1000.0

# Adjust window parameters
XMIN = -5.0
XMAX = 5.0
YMIN = -10.0
YMAX = 10.0
XSCL = 0.5
YSCL = 0.5

DISTANCE = 0.1

def main():
    fileobj = open("data.txt", "w")
    for x1 in xrange(int(XMIN / XSCL), int(XMAX / XSCL)):
        for y1 in xrange(int(YMIN / YSCL), int(YMAX / YSCL)):
            x= float(x1 * XSCL)
            y= float(y1 * YSCL)
            slope = dy_dx(x,y)
            dx = math.sqrt( DISTANCE/( 1+math.pow(slope,2) ) )
            dy = slope*dx
            fileobj.write(str(x) + " " + str(y) + " " + str(dx) + " " + str(dy) + "\n")
    fileobj.close()


    try:
        check_call(["gnuplot","-e","set terminal png size 800,600 enhanced font \"Arial,12\"; set xrange [" + str(XMIN) + ":" + str(XMAX) + "]; set yrange [" + str(YMIN) + ":" + str(YMAX) + "]; set output 'output.png'; plot 'data.txt' using 1:2:3:4 with vectors"])
    except (CalledProcessError, OSError):
        print "Error: gnuplot not found on system!"
        exit(1)
    print "Saved image to output.png"
    call(["xdg-open","output.png"])
    return 0

if __name__ == '__main__':
    main()

しかし、私がこれから得た最高のイメージは. ここに画像の説明を入力 最初の画像のように見える出力を得るにはどうすればよいですか? また、3 本の実線を追加するにはどうすればよいですか?

4

3 に答える 3

18

この matplotlib コードをベースとして使用できます。必要に応じて変更してください。同じ長さの矢印を表示するようにコードを更新しました。重要なオプションはanglesquiver(u, v) 角度を計算する場合)。

軸の形状を「ボックス」から「矢印」に変更することも可能です。その変更が必要な場合はお知らせください。追加できます。

import matplotlib.pyplot as plt
from scipy.integrate import odeint
import numpy as np

fig = plt.figure()

def vf(x, t):
    dx = np.zeros(2)
    dx[0] = 1.0
    dx[1] = x[0] ** 2 - x[0] - 2.0
    return dx


# Solution curves
t0 = 0.0
tEnd = 10.0

# Vector field
X, Y = np.meshgrid(np.linspace(-5, 5, 20), np.linspace(-10, 10, 20))
U = 1.0
V = X ** 2 - X - 2
# Normalize arrows
N = np.sqrt(U ** 2 + V ** 2)
U = U / N
V = V / N
plt.quiver(X, Y, U, V, angles="xy")

t = np.linspace(t0, tEnd, 100)
for y0 in np.linspace(-5.0, 0.0, 10):
    y_initial = [y0, -10.0]
    y = odeint(vf, y_initial, t)
    plt.plot(y[:, 0], y[:, 1], "-")

plt.xlim([-5, 5])
plt.ylim([-10, 10])
plt.xlabel(r"$x$")
plt.ylabel(r"$y$")

スロープフィールド

于 2013-09-16T16:56:07.990 に答える
2

私は pygame を使って趣味のプロジェクトとしてこれらの 1 つを作るのがとても楽しかったです。正の場合は青の色合い、負の場合は赤の色合いを使用して、各ピクセルの勾配をプロットしました。黒は未定義です。これはdy/dx = log(sin(x/y)+cos(y/x))次のとおりです。

dy/dx=log(sin(x/y)+cos(y/x)

ズームインおよびズームアウトできます。ここでは、中央上部をズームインしています。

上記のようにズームイン

また、点をクリックして、その点を通る線をグラフ化します。

そしてそれはそのようなものであり、あなたにはそのようなものです

わずか 440 行のコードなので、ここにすべてのファイルの .zip があります。ここで関連するビットを抜粋すると思います。

方程式自体は、文字列内の有効な Python 式として入力されます"log(sin(x/y)+cos(y/x))"。これがcompiled です。self.func.eval()この関数は、指定された点でを与えるカラー フィールドをグラフ化しますdy/dx。ここでのコードは少し複雑です。最初は 32x32 ブロック、次に 16x16 などのように段階的にレンダリングして、ユーザーにとってよりスマートにするためです。

def graphcolorfield(self, sqsizes=[32,16,8,4,2,1]):
    su = ScreenUpdater(50)
    lastskip = self.xscreensize
    quitit = False
    for squaresize in sqsizes:
        xsquaresize = squaresize
        ysquaresize = squaresize

        if squaresize == 1:
            self.screen.lock()
        y = 0
        while y <= self.yscreensize:
            x = 0
            skiprow = y%lastskip == 0
            while x <= self.xscreensize:
                if skiprow and x%lastskip==0:
                    x += squaresize
                    continue

                color = (255,255,255)
                try:
                    m = self.func.eval(*self.ct.untranscoord(x, y))
                    if m >= 0:
                        if m < 1:
                            c = 255 * m
                            color = (0, 0, c)
                        else:
                            #c = 255 - 255 * (1.0/m)
                            #color = (c, c, 255)
                            c = 255 - 255 * (1.0/m)
                            color = (c/2.0, c/2.0, 255)

                    else:
                        pm = -m
                        if pm < 1:
                            c = 255 * pm
                            color = (c, 0, 0)
                        else:
                            c = 255 - 255 * (1.0/pm)
                            color = (255, c/2.0, c/2.0)                        
                except:
                    color = (0, 0, 0)

                if squaresize > 1:
                    self.screen.fill(color, (x, y, squaresize, squaresize))
                else:
                    self.screen.set_at((x, y), color)

                if su.update():
                    quitit = True
                    break

                x += xsquaresize

            if quitit:
                break

            y += ysquaresize

        if squaresize == 1:
            self.screen.unlock()
        lastskip = squaresize
        if quitit:
            break

これは、点を通る線をグラフ化するコードです:

def _grapheqhelp(self, sx, sy, stepsize, numsteps, color):
    x = sx
    y = sy
    i = 0

    pygame.draw.line(self.screen, color, (x, y), (x, y), 2)
    while i < numsteps:
        lastx = x
        lasty = y

        try:
            m = self.func.eval(x, y)
        except:
            return

        x += stepsize            
        y = y + m * stepsize

        screenx1, screeny1 = self.ct.transcoord(lastx, lasty)
        screenx2, screeny2 = self.ct.transcoord(x, y)

        #print "(%f, %f)-(%f, %f)" % (screenx1, screeny1, screenx2, screeny2)

        try:
            pygame.draw.line(self.screen, color,
                             (screenx1, screeny1),
                             (screenx2, screeny2), 2)
        except:
            return

        i += 1

    stx, sty = self.ct.transcoord(sx, sy)
    pygame.draw.circle(self.screen, color, (int(stx), int(sty)), 3, 0)

そして、その時点から開始して前後に実行されます。

def graphequation(self, sx, sy, stepsize=.01, color=(255, 255, 127)):
    """Graph the differential equation, given the starting point sx and sy, for length
    length using stepsize stepsize."""
    numstepsf = (self.xrange[1] - sx) / stepsize
    numstepsb = (sx - self.xrange[0]) / stepsize

    self._grapheqhelp(sx, sy,  stepsize, numstepsf, color)
    self._grapheqhelp(sx, sy, -stepsize, numstepsb, color)

ピクセル アプローチがかっこよすぎたので、実際の線を描くことはできませんでした。

于 2013-09-17T05:08:53.263 に答える
0

パラメータの値を次のように変更してみてください。

XSCL = .2
YSCL = .2

これらのパラメーターは、軸上でサンプリングされるポイントの数を決定します。


あなたのコメントによると、派生 dy_dx(x, y) が適用される関数もプロットする必要があります。

現在、関数 dy_dx(x,y) によって計算された勾配線のみを計算してプロットしています。勾配に加えてプロットする関数 (この場合は 3 つ) を見つける必要があります。

関数を定義することから始めます。

def f1_x(x):
    return x**3-x**2-2x;

次に、ループ内で、関数に必要な値を fileobj ファイルに書き込む必要もあります。

于 2013-09-16T16:40:48.003 に答える