Logo type; graphing functions with Logo. Robert V. Ludwig.
The thing for which the Logo language is best known is turtle graphics. And what could be a more natural use of graphics than graphing functions? With the Logo Graphing Program presented here, it is easy to graph a function in either rectangular or polar coordinates and to watch the function being traced on the screen. It is also possible to get a printed copy of the graph if desired.
The Logo Graphing Program (Listing 1) is written in Apple Logo to run on the Apple II computer. Users of other versions of Logo may need to make some changes. While the program makes use of the graphics capability of Logo, it is also a good demonstration of the power of some of the other features of the language.
All of the following characteristics are present in the program.
* Logo is procedural.
* Logo is interactive.
* Logo is recursive.
* Logo is extensible.
* Logo has list handling capability.
The program consists of some 20 independent modules or procedures and begins with the main procedure GRAPH. GRAPH consists of calls to procedures ENTER.DATA, DRAW.XAXIS, DRAW.YAXIS, CHOOSE.TYPE, PRINT.GRAPH and very little else. If a program is written by first writing a main part consisting mostly of procedure calls, followed by the writing of the called procedures, we say it has been written "top down." Top down programming is considered by many to be a highly effective and efficient way of writing programs.
The first procedure called by GRAPH is ENTER.DATA which begins by asking if the screen is to be cleared. This feature demonstrates the interactive ability of Logo. It is included here to allow you to graph one (or more) functions and then, by rerunning GRAPH, to change the coordinate scales and super-impose new graphs on top of the old.
Notice that the first three lines of ENTER.DATA make you "get it right." If you do not answer either Y or N to the question posed, the procedure calls itself and the question is repeated. This is the first use of recursion in the program.
Positioning the Axes
Next ENTER.DATA calls the procedure GET.INTERVAL which is also recursive, in this case to insure that the left-hand endpoint of the interval over which the function is to be graphed is entered before the righthand endpoint. When the program returns to ENTER.DATA after executing GET.INTERVAL, the position on the screen for the y-axis is determined.
Following the calculation of YAXIS.POS, ENTER.DATA asks for the position of the x-axis. Entering 0 here will put the x-axis in the middle of the screen; entering a -79 will put it where it will just show at the bottom of the split screen.
The last thing that ENTER.DATA does is to ask for the ratio y-axis scale:x-axis scale. This allows the y-axis scale if it is desirable to distort the graph for any reason. For example, if the zeros of a function are very close together, the scale on the y-axis may be stretched out so that the zeros are more visible. Figure 1 is a graph of the function
x.sup.3 - .006x.sup.2 + .000011x - .000000006 over the interval [0.004] which is generated by the program in such a way as to separate the zeros. If the same scale had been used on the y-axis as on the x-axis (a scale ratio of 1), the graph would have been so close to the x-axis as to be indistinguishable from it. The graph of Figure 1 was produced by using a y-axis:x-axis ratio of 1,000,000.
Note that ENTER.DATA uses the procedures LINEFEED and SPACE, which do exactly what their names suggest. They are excellent examples of the extensible nature of Logo in that when they are used, they are indistinguishable from primitive commands. After ENTER.DATA has been completed, the program returns to GRAPH where DRAW.XAXIS and DRAW.YAXIS are executed.
Entering the Function
Following the drawing of the two aces, the program calls the procedure CHOOSE.TYPE. In CHOOSE.TYPE a decision must be made to use either a rectangular coordinate system or a polar coordinate system, and to plot either individual points only or the points connected by line segments.
The two procedures ENTER.FUNCTION and ENTER.P.FUNCTION provide for the entry of the function to be graphed, with respect to the coordinate system chosen. The entered function is saved as a list with the variable name FUNCTION. If you have chosen to graph in polar coordinates, ENTER.P.FUNCTION also requests the interval over which the angle is to vary. Once again you are required to enter the smaller number first. The interval entered in the earlier procedure GET.INTERVAL is used to put a scale on the polar axis.
GRAPH.FUNCTION and PLOT.POINT (GRAPH.P.FUNCTION and PLOT.P.POINT for polar coordinates) are the procedures which do the actual graphing. Keep in mind that you must use the coordinate system supplied by Logo in which x varies from -140 to 139 (this program uses -139 to 139 so that the y-axis can be centered on the screen) and by varies from -119 to 120 (or from -79 to 120 on the splitscreen).
For rectangular coordinates this program attempts to plot one point for each of the 279 pixels across the horizontal dimension of the screen. When the procedure GRAPH.FUNCTION is called at the end of procedure ENTER.FUNCTION, it is instructed to begin graphing at pixel -139.
The first line in GRAPH.FUNCTION will stop the graphing process when pixel 139 has been reached, at which time GRAPH.FUNCTION sounds the "bell" (CHAR 7) and branches to the procedure GRAPH.ANOTHER. In the second line of GRAPH.FUNCTION, the pen is raised before the first point is plotted so that the turtle does not "drag the pen" as he travels to that point.
Graphing the Function
You impose a scale on the x-axis when you choose an interval over which to graph in the procedure GET.INTERVAL. That interval and the value chosen for RATIO in ENTER.DATA also impose a scale on the y-axis. In general the scale on the x-axis will not be the scale of -139 to 139 which Log uses. Likewise, the scale on the y-axis will not be that of Logo.
The third line of the procedure GRAPH.FUNCTION performs a transformation from the Logo scale to your scale so that the function you have entered can be evaluated properly in the first line of PLOT.POINT. After this evaluation takes place, in the second line of PLOT.POINT a second transformation converts the y value back to its equivalent value in the Logo coordinate system.
X and FX are the variable names for the x and y values to be plotted with respect to x-axis and y-axis scales you have chosen. XPOINT and YPOINT are the variable names for the x and y values with respect to the Logo scales. Lines 4 and 5 of GRAPH.FUNCTION display the abscissa of the point to be plotted.
Line 6 of GRAPH.FUNCTION is for the purpose of error trapping. The instruction CATCH "ERROR begins execution of the instructions (in this case PLOT.POINT) contained within the following square brackets. If, however, an error occurs during the execution of those instructions, execution will be abandoned, and the program will branch to the line following CATCH. Since that line is a recursive call to plot the next pixel, the program continues as though no error had occurred, except that the most recent point is not plotted.
Line 1 of PLOT.POINT demonstrates the magic of Logo string handling. The Logo primitive RUN is the instruction which causes execution of the string having variable name FUNCTION as if that string were substituted for the words RUN:FUNCTION in the program. If no error occurs during the execution of PLOT.POINT up to line 3, PLOT.POINT next displays at the bottom of the screen the ordinate of the point to be plotted. Lines 5 and 6 determine whether points are only plotted or plotted and connected.
A troublesome error can occur in PLOT.POINT if your function has incorrect syntax. In this case the program cannot plot any points as it cannot interpret the function. The CATCH "ERROR command, however, causes Logo not to cease running and not to print an error message.
If the value of the abscissa displayed on the bottom of the screen is changing "like a spinning odometer" it means that several consecutive errors are occurring. If the error is a syntax error, the entered function will still be visible at the bottom of the screen. If the odometer effect is present and the function is not visible, there is no syntax error, and the program may eventually begin to plot.
If, however, the spinning odometer effect is present and the function is visible at the bottom, the error may be syntax or it may be "turtle out of bounds" or "division by zero" or possibly something else. Since no error message is displayed when the program is within the scope of a CATCH command, in this last case you can only wait to see if points will be plotted.
After GRAPH.FUNCTION or GRAPH.P.FUNCTION has finished execution, the first line of either procedure passes control to GRAPH.ANOTHER. If you choose to graph another function, control passes back to CHOOSE.TYPE where you again have the option of choosing either rectangular or polar coordinates, but do not have the option of changing the coordinate system scale or the value of RATIO. To change those inputs you must first quit the program and then restart it.
Printing the Graphics
The procedure PRINT.GRAPH is designed to dump to the printer a copy of whatever graphs appear on the screen. It is written to work with the Pkaso printer interface card and the Epson MX-80 printer with Graftrax Plus.
The two lines starting with .DEPOSIT are needed so that after an image is dumped to the printer, output will return to the screen without a reboot of Logo. I believe that these two lines are required by the Pkaso card, although they are not required for the Krell version of Logo. This is a trick I learned from the Logo Tool Kit which contains utilities that may be helpful for otherprinter, interface products.
The procedures SINR, COSR, and PI are included to help enter certain trigonometric functions and values. If you wish to get the typical graph of the sine function, for example, you must use SINR X. The Logo function SIN X returns the sine of an angle measured in degrees while the typical sine curve is for angles measured in radians. This example brings up another point. You will note that I have suggested using SINR X instead of the traditional Logo notation SINR :X.
Using SINR X instead of SINR :X is possible because of the inclusion of a procedure with the acutely short name X. The only thing this procedure does it to return the value of X (or :X as it is written in Logo). Thus when you write something such as PRINT SINR X, the X on the end is really a call to execute the procedure X which returns :X which then serves as input to the procedure SINR. This little trick saves you from having to write :X when you enter the function to be graphed.
Additions and Enhancements
I do not wish to leave you with the impression that I consider this to be a completed "commercially acceptable" program. The program as it now stands will, for example, quit with an appropriate error message if non-numeric data are entered when numeric data are expected. I would consider such a response unacceptable in commercial software.
There are other features which might have been included in this program. For example, you might want to graph different functions in different colors or to graph using parametric equations. Another possibility would be to include procedures to evaluate functions such as the log, exponential, and power functions, which Apple Logo does not provide.
I have not added more to the program for two reasons. The first is that it was my intention to present the program as a tutorial for those who are not advanced Logo programmers.
An even more compelling reason for not extending the scope of the program is that I am starting to run out of space. I am not sure how much the program can be expanded within the confines of a 64K Apple, but some compromises might have to be made to do so. Expanding the scope of the program would almost certainly require the use of shorter names, fewer redundancies, more multiple command lines, and other tricks to reduce the size of the program.
One final note. The program runs slowly. Although a Basic program to produce graphs would probably run faster, it is very much more difficult to write the function input routine in Basic. This is the kind of application in which the list handling capability of Logo really shines.