[Edu-sig] the plot question (in another sense)
Kirby Urner
urnerk@qwest.net
Mon, 27 Jan 2003 00:27:24 -0800
At 01:28 PM 1/26/2003 -0800, Kirby Urner wrote:
>We could avoid the proofs for a bit and just play around with the first
>expansion, comparing outputs on both sides of the equals sign. I.e. in
>Python we have math.exp(x) for raising e to the xth power.
Clearly if we're doing a polynomial expansion equal to the cosine of
x, its graph'll have to be the same as cosine's. (x,cos(x)) crosses
the x-axis at all these roots (e.g. pi/2, 3pi/2, 5pi/2 etc.). So the
polynomial needs another root, and therefore one higher degree, for
every new x-axis crossing.
The polynomial expansion for cosine is [1/0!, 0, -1/2!, 0, 1/4!, 0, -1/6!...]
where these are coefficients for x^0 x^1 x^2 etc. --except the terms with odd
exponents have zero coefficients and so go away.
Using the generator approach again:
def costerms(x,t):
n,result = 0,1
maxterm = 2*t
if n==0: yield 1
while 1:
n += 2
if n >= maxterm: return # bug fixed (>=) -- one too many terms
before
result *= -x*x/(n*(n-1))
yield result
def polycos(x,t):
return reduce(add,[i for i in costerms(x,t)])
>>> polycos(3,20)
-0.98999249660044553
>>> math.cos(3)
-0.98999249660044542
So now I'd like see graphs of these ever higher degree polynomials that
criss-cross the x-axis, just like cosine does. In J, I'd just go something
like:
load 'plot';'trig'
polycos =: (cos t. i.20) & p. NB. coefficients out 20 terms, including
zeros
domain =: (i: 80) % 10 NB. from -8 to 8 in increments of 1/10
plot domain; polycos domain NB. do the graph
and I'd be looking at my wavy line on a graph in a window.
One approach I've used is to use a module I wrote for outputting to Povray,
the ray tracing engine. I just output the (x,y) points as little spheres
and link them with cylinders. This gives a graph with a pleasing 3d look
-- can be colorful too.
However, since I've recently added wxPython to Python 2.2 (and am using the
PyCrust that comes with it), tonight my experiment will by to use a package
I've not tried before: SciPy (VPython also has graphing capabilities BTW).
I've just grabbed the Windows binary from here:
http://www.scipy.org/site_content/download_list
It seems to install a *lot* of stuff, but then I see I still need Numeric,
which the VPython uninstaller recently stole off my machine (as Arthur
warned me it would). So I'll go to http://www.pfdubois.com/numpy/ and grab
another copy... (Numpy is pretty small, only like 446K -- downloading *very*
slowly though, looks like I need to try again... ah, *much* faster from
Chapel Hill, NC).
OK, now scipy imports without errors. Time to check the docs and see how
to do a quick plot... http://www.scipy.org/site_content/tutorials/plot_tutorial
Hmmmm... Strangely, when I used Vim to edit code, then reload my module
in PyCrust, I sometimes get error messages referring to old code that's
gone from the module. I wonder if there's a namespace conflict with
scipy somehow. This 'list' not callable error makes no sense anyway
-- cut and paste the same code to the prompt and it runs.
I notice it's important not to *close* the plt.plot window, if you want
to use it again same session. Just change domain and range and replot,
without closing the plot window in between.
Here's my result:
http://www.inetarena.com/~pdx4d/ocn/python/cospoly.png Notice this
polynomial crosses the x-axis 10 times! But it's a degree 40 equation no?
No. I've got 20 non-zero terms, but that starts from x^0, so I only get
up to x^38. 38th degree equation, with 38 roots. A quick check in J
shows it has these 10 real roots (where it crosses x), plus 14 conjugate
pairs of complex roots (J has a built-in for finding these roots).
The real roots are:
_14.1262 14.1262
_10.9956 10.9956
7.85398 _7.85398
4.71239 _4.71239
1.5708 _1.5708
which corresponds to plus/minus pi/2 3pi/2 5pi/2 7pi/2 and 9pi/2 --
except these values don't match the pi values. Because this 38 degree
poly is an *approximation* (gotta have infinite terms to be spot on).
The only Python functions I added, to create a domain and range for
plt.plot(domain,range), were:
def mkdomain(x): # kinda ugly, but it works
x *= 10
return map(lambda x: x*0.1, range(-x,0,1)) + map(lambda x: x*0.1,
range(x+1))
def mkrange(d):
return [cospoly(i,20) for i in d] # the 20 fixes the number of terms
So this graph was a result of going:
>>> from scipy import plt
>>> import plotplay # the generator, cospoly, and the above two
functions [1]
>>> d = plotplay.mkdomain(16) # from -16 to 16 in 0.1 increments
>>> r = plotplay.mkrange (d) # feed this domain to cospoly
>>> plt.plot(d,r)
and that's it!
Kirby
[1] recall that we need to import some stuff in plotplay:
from __future__ import generators, division
from operator import add