[Edu-sig] Going Graphical: Where Python Meets Descartes
Kirby Urner
pdx4d@teleport.com
Wed, 09 Feb 2000 18:01:35 -0800
Here's another good approximation of where I'm thinking to go
with "Python notation" in the context of a prototypical math
class.
In USA K-12, we're mostly working with calculators in early
2000, with relatively few kids having access to an interactive
command line (aka an REPL environment). The text books don't
have much beyond obsolete BASIC, if that, and nothing about
the object oriented paradigm.
Whereas some language gurus posting here have advocated forming
a united front against the hegemony of C/C++ (nevermind for
the moment that Python is written in C++), I have a slightly
different, perhaps complementary focus: helping math teachers
move beyond their graphing calculators into the world of
full-fledged computers.
This move from calculators to computers is likewise a move
"beyond flatland" into fully spatial geometry, and to a
broader treatment of symbolic operations, with a greater
range of data structures and operations making it into the
standard curriculum.[1]
These lesson plans are about showing how one can leverage Python
and other tools (e.g. Povray), along with pre-existing K-12
content (in this example coordinate geometry), to achieve a
usefully synergetic result.
Students learning enough Python to scan/write code such as
included below will be gaining insight into both computing
and mathematics at the same time, in the context of an inter-
active, self-reinforcing environment conducive to further
play and self-directed exploration.
The teacher in such a classroom will need to know enough
Python to keep students moving along towards their goals,
but need not be a top-level Python guru. A good grasp of
the underlying mathematics remains the more important
qualification for successful communication of this content,
plus experience in various time-tested methods of pedagogy.
Kirby
4D Solutions
[1] See: http://www.inetarena.com/~pdx4d/ocn/trends2000.html
===========
Another Lesson Plan (first draft):
Going Graphical: Where Python Meets Descartes
by Kirby Urner, Oregon Curriculum Network
Ver. 1.0, Feb 09, 2000
Originally posted to edu-sig@python.org
Coming soon: web version
Concepts typically introduced in K-12 include many relating to
coordinate geometry. Renaissance painters figured out a lot
of this stuff, in their efforts to master the art of painting
in perspective.
Descartes brought a lot of their methods together in the
context of his "I think therefore I am" philosophy, giving
us the Cartesian coordinate system.
Considering the contributions by the art schools to this
heritage, it's appropriate that we will be bringing more color
into our graphics than 1900s text books typically permitted
(more perspective, too).
A vector is an object with magnitude and direction, typically
shown as an arrow in Cartesian space. Vector addition involves
placing two such arrows tip-to-tail, to get a third: their
vector sum. (a,b,c) + (d,e,f) = (a+d,b+e,c+f).
def __add__(self,addvector):
# add a vector to this object (self)
# return a new vector
newcoords=[0,0,0]
for i in range(3):
newcoords[i]=addvector.coords[i] + self.coords[i]
return Vector(newcoords)
Likewise, we can scale a vector, meaning cause it to grow or
shrink without changing its orientation. Or, if we apply a
negative scalar, the operation of negation will cause our
arrow to flip, and point 180 degrees oppositely to its original
direction.
So to scale by 2 is to double a vector's length, whereas to
scale it by -0.5 is to flip it by 180 degrees, and shrink
it to 1/2 its original magnitude. (a,b,c) * s = (as,bs,cs).
def __mul__(self,scalar):
# scale and this vector (self) by scalar
# return a new vector
newcoords=[0,0,0]
for i in range(3):
newcoords[i]=scalar * self.coords[i]
return Vector(newcoords)
Let's look at Vectors as a class of object. Here's a complete
class template for our vector objects:
class Vector:
def __init__(self,arg):
# initialize a vector at an (x,y,z) tuple (= arg)
self.coords = arg
def __mul__(self,scalar):
# scale and this vector (self) by scalar
# return a new vector
newcoords=[0,0,0]
for i in range(3):
newcoords[i]=scalar * self.coords[i]
return Vector(newcoords)
def __add__(self,addvector):
# add a vector object to this object (self)
# return a new vector
newcoords=[0,0,0]
for i in range(3):
newcoords[i]=addvector.coords[i] + self.coords[i]
return Vector(newcoords)
def length(self):
# return this vector's length
sum = 0
for i in range(3):
sum = sum + self.coords[i]**2
return sum ** 0.5
[ Note that in saying "complete" I don't mean we can't further
add to and enhance our vectors. Dot and cross products are
examples of additional operations we might usefully define.
"Complete" means "in working condition" -- even if we have
plans to brainstorm lots of enhancements ]
Let's see our Vector objects in action:
>>> from coords import Vector
>>> v1 = Vector((1,0,0))
>>> v2 = Vector((0,2,1))
>>> v3 = v1 + v2
>>> v3.coords
[1, 2, 1]
>>> v1.length()
1.0
>>> v2.length()
2.2360679775
>>> v3.length()
2.44948974278
>>> v4 = v1 * 10.0
>>> v4.coords
[10.0, 0.0, 0.0]
Now we'd like to "paint" our vectors. We'll use the freeware ray
tracing program known as POV-ray (www.povray.org) for this
purpose.
Once again, we can choose to look at a Povray file (.pov extension)
as an object. You instantiate it with a file name...
>>> from povray import Povray
>>> myfile = Povray("sine.pov")
then feed vectors to its two write methods: writecyl and writepoint.
For example:
>>> i = 0.75
>>> point = Vector((i,math.sin(i),0))
>>> myfile.writepoint(point)
>>> posx = Vector((3,0,0))
>>> myfile.cylcolor = 'Green'
>>> myfile.writecyl(posx)
>>> myfile.writecyl(posx * -1.0)
myfile.writecyl(vector) draws a slender cylinder from (0,0,0)
to our vector tip:
def writecyl(self,v1):
# write cylinder from (0,0,0) to v1.coords
tip = tuple(v1.coords)
self.file.write(("cylinder{<0, 0, 0>"
+ ",<%s, %s, %s>," % tip
+ " %s pigment {color %s} no_shadow}\n"
% (self.cylradius, self.cylcolor)))
[ Here we're looking inside the povray.py module (gives the
class template for a Povray object) ]
myfile.writesph(vector) just puts a little sphere at the vector
tip, a graphical point.
def writepoint(self,v1):
# write sphere at v1.coords
center = tuple(v1.coords)
self.file.write(("sphere{<%s, %s, %s>, " % center
+ " %s pigment {color %s} no_shadow }\n"
% (self.sphradius, self.sphcolor)))
All these write operations end generating a povray text file
with a lot of instructions for the ray tracing engine. Here's
an excerpt from 'parabola.pov':
cylinder{<0, 0, 0>,<0, 0, 3>, 0.02 pigment {color Cyan} no_shadow}
cylinder{<0, 0, 0>,<0.0, 0.0, -3.0>, 0.02 pigment {color Cyan} no_shadow}
sphere{<-1.5, 2.25, 0>, 0.02 pigment {color Red} no_shadow }
sphere{<-1.49, 2.2201, 0>, 0.02 pigment {color Red} no_shadow }
Now that we have all this infrastructure in place, we have the
wherewithall to start doing some serious graphics -- more
sophisticated than any graphing calculator can do.
For example, we might want to start building a little "functions
library" for showing favorite text book graphs, such as
parabola(x) = sin(x) or
sinewave(x) = x^2
Here's some Python for doing both:
def sinewave():
# graph a sine wave from -pi to pi
myfile = Povray("sine.pov")
xyzaxes(myfile) # include multi-color xyz axes
i = - math.pi
while (i < math.pi):
point = Vector((i,math.sin(i),0))
myfile.writepoint(point)
i = i+0.01
myfile.close()
def parabola():
# graph a parabola from -2.0 to 2.0
myfile = Povray("parabola.pov")
xyzaxes(myfile) # include multi-color xyz axes
i = - 1.5
while (i < 1.5):
point = Vector((i,i**2,0))
myfile.writepoint(point)
i = i+0.01
myfile.close()
Note that both functions invoke an xyz axis function, to draw
green/orange/cyan xyz axes (part of our functions library):
def xyzaxes(file):
posx = Vector((3,0,0))
file.cylcolor = 'Green'
file.writecyl(posx)
file.writecyl(posx * -1.0)
posy = Vector((0,3,0))
file.cylcolor = 'Orange'
file.writecyl(posy)
file.writecyl(posy * -1.0)
posz = Vector((0,0,3))
file.cylcolor = 'Cyan'
file.writecyl(posz)
file.writecyl(posz * -1.0)
Below is a command line session, wherein we simply execute these
functions.
Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> import functions
>>> functions.sinewave()
>>> functions.parabola()
The output of these two functions may be viewed with your web
browser at:
http://www.inetarena.com/~pdx4d/ocn/graphics/sinewave.gif
http://www.inetarena.com/~pdx4d/ocn/graphics/parabola.gif
Kirby