Lab 9: Python Plotting

Comp 150, Dordal, Mar 31, 2006

Graphics

To load the graphics module, first download it and put it in your working directory. There are two versions; at this point I recommend the newer one, although it does frequently fail to start properly: Start python in the same directory that you saved the graphics*.py into, and load the graphics module as follows:
    from graphics import *

Plotting some graphs

Create a graphics window with the following:
    w = GraphWin("plots", 500, 400)
The "raw" coordinates are 0..500, 0..400. This isn't always convenient for graphing; you may want to graph something for x in the range [0..10], or [-10..10], or [0..10000]. What you can do is use w.setCoords(lowx, lowy, highx, highy) to choose a new coordinate system. For example, if you want to plot in the range [-200, 400], with vertical range 0..100, and want a little space to show below the x-axis, you might choose w.setCoords(-200, -10, 400, 100).

Let's assume for a moment that the coordinates are rescaled so x runs from -100 to 1000, and y from -50 to 500. To draw the axes:
    xaxis=Line(Point(-100,0), Point(1000,0))
    yaxis=Line(Point(0,-50), Point(0,500))
    xaxis.draw(w)
    yaxis.draw(w)

Now we plot some points. We'll plot y = x0.8, as x runs from 0 to 1000. The "red" below is optional, and can of course be replaced by any other recognized color.

for x in range(1001):
    y = x**0.8
    w.plot(x, y, "red")

Now suppose we want to plot y = (1-x2)0.5, from x = -1.0 to 1.0. We can adjust the coordinates relatively easily, with w.setCoord(-1.1, -1.1, 1.1, 1.1) (I choose these values because I know the y values, like x, are in the range -1..1, and I'd like 0.1 of "border".) However, we have a problem with for x in range(???):, in that that only selects integer x and we clearly need a whole bunch of fractional points. So let's select an integer range that's wide enough to hit every pixel; as the window is 500 pixels wide the range -250..250 should work. Then, to get numbers in the range -1.0..1.0, we simply divide by 250.0:

for i in range(-250, 251):
    x = i/250.0
    y = (1-x*x)**0.5
    w.plot(x,y)
At the ends, the plotted pixels aren't really touching, because the graph is too steep. The fix is to draw a line between each pair of consecutive points rather than plotting each point individually and in isolation, but that's sort of tricky to implement so we'll skip it.

What you are to plot

1. The collatz(n) function, for n from 1 to 1000 (integer values only). Recall that
def collatz(n):
     count = 0
     while n != 1:
         count += 1;
         if n % 2 == 0:
            n = n/2
         else:
            n = 3*n+1
     return count

2. The function y = x4 - 2x2, for -2.0 ≤ x ≤ 2.0. Choose a y-range that "works": not too small to cut off the graph, not too big to lose detail.

3. The function y = math.sin(x)/x, for -20 ≤ x ≤ 20. Note that you will have to handle x=0 as a special case, if x=0, choose y=1. The easiest way to deal with this is to define a function f(x) to be math.sin(x)/x for all x except x=0, when it is 0.0. Note that you need import math here.

Reference

Operations on a window:

Basic shapes:

Operations on a shape s: