绘制方向字段

时间:2013-09-16 16:17:09

标签: python math

有没有办法在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()

然而,我从中获得的最佳图像是。 enter image description here 如何获得看起来更像第一张图像的输出?另外,如何添加三条实线?

3 个答案:

答案 0 :(得分:11)

您可以使用此matplotlib代码作为基础。根据您的需要进行修改。 我已更新代码以显示相同长度的箭头。

也可以将轴形式“框”更改为“箭头”。如果您需要更改,请告诉我,我可以添加它。

enter image description here

import matplotlib.pyplot as plt
from scipy import *
from scipy import integrate
from scipy.integrate import ode
import numpy as np

fig = plt.figure(num=1)
ax=fig.add_subplot(111)

## Vector field function
def vf(t,x):
  dx=np.zeros(2)
  dx[0]=1
  dx[1]=x[0]**2-x[0]-2
  return dx

#Solution curves
t0=0; tEnd=10; dt=0.01;
r = ode(vf).set_integrator('vode', method='bdf',max_step=dt)
ic=[[-3.5,-10], [-3,-10], [-2.5,-10]]
color=['r','b','g']
for k in range(len(ic)):
    Y=[];T=[];S=[];
    r.set_initial_value(ic[k], t0).set_f_params()
    while r.successful() and r.t +dt < tEnd:
        r.integrate(r.t+dt)
        Y.append(r.y)

    S=np.array(np.real(Y))
    ax.plot(S[:,0],S[:,1], color = color[k], lw = 1.25)

#Vector field
X,Y = np.meshgrid( np.linspace(-5,5,20),np.linspace(-10,10,20) )
U = 1
V = X**2-X-2
#Normalize arrows
N = np.sqrt(U**2+V**2)  
U2, V2 = U/N, V/N
ax.quiver( X,Y,U2, V2)


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

答案 1 :(得分:1)

我很高兴使用pygame将其中一个作为业余爱好项目。我绘制了每个像素的斜率,使用蓝色阴影表示正值,使用红色阴影表示阴性。黑色是未定义的。这是dy/dx = log(sin(x/y)+cos(y/x))

dy/dx=log(sin(x/y)+cos(y/x) http://oi43.tinypic.com/90umn4.jpg

你可以放大&amp; out - 这里放大了中间的上半部分:

as above zoomed in

并点击一个点来绘制通过该点的直线:

and as it is such so also as such is it unto you

这只是440行代码,所以here is the .zip of all the files。我想我会在这里摘录相关内容。

等式本身作为字符串中的有效Python表达式输入,例如"log(sin(x/y)+cos(y/x))"。然后是compile d。此函数在此处绘制颜色字段,其中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)

它向后运行&amp;从那一点开始转发:

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)

我从来没有画过实际线条,因为像素方法看起来太酷了。

答案 2 :(得分: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文件。