TooDee Plotting Classes for REALbasic

Jim Harrison
jhrsn@pitt.edu
University of Pittsburgh
1/22/2000

Introduction

TooDee is a set of two-dimensional plotting classes for REALbasic embedded in a simple demo app. The plotting classes were were originally created for the clinical data analysis package "Labscanner" and their features/limitations reflect that heritage. LabScanner and TooDee can be found at http://jhh.cbmi.upmc.edu/labscanner.

This source code distribution is not meant to be a Þnished product ready to drop into another project, but more a demonstration of techniques that might be of interest to others. They may provide a framework for modiÞcation that could save work. This source code is being made available to the REALbasic developer community for unrestricted usage and distribution. I would appreciate attribution if you use the code, but it's not required. On the flip side, no warranties are implied and bugs may well exist in this code. LabScanner displays charts on both Mac and Windows machines, so the TooDee code is expected to function on both platforms. However, I've tested this distribution only on the Mac.

These plotting routines were created for displaying proÞles of change in clinical laboratory test results from individual patients over time, and allowing users to focus on speciÞc sequences of interest within longer sequences. Because of that, they have signiÞcant limitations for general plotting, but they also have some unique features. I'd like the make TooDee more general and flexible, but it's going to be some time before I can get to that, so I decided to release this now in case there are some who would beneÞt from it.

Limitations:

Of course, these limitations can be addressed by extending the programming in the appropriate methods.

Features:

TooDee is based on two primary classes, a plotting window (called 'Display') that contains the plotting canvas and the graphing methods, and a Plot class that functions as a data container for a plot. An instance of the Plot class is attached to the plotting window as an attribute called 'thePlot.' The linear regression method and data is in a separate class ('LinearReg'). To create a plot, you just need to fill 'thePlot' with data and call the desired graphing method of the window. The demo app includes some data entry boxes in the window along with the plotting canvas, allowing you to enter data (which is transferred to 'thePlot' in that window) and call the graphing methods. If you implement this in another setting, all you need to do is fill 'thePlot' with data by any procedure you wish, and then call the appropriate graphing method.

Each kind of graph has its own method (linear, semilog, linear fit and semilog fit). The 'fit' methods also create an instance of the linear regression class for that processing. This is modular, so you can delete any of the plotting methods you don't intend to use and you can delete the linear regression class if you aren't going to do curve fits.

Execution sequence:

Data points are entered by typing them into the entry boxes and then transferred to the data listbox. The listbox sorts the data numerically by the X value because the methods expect the data points to be ordered by X value (actually, I think this is only important for the line drawings, since the lines are drawn from point-to-point in the sequence the points are listed). The sorting is done using a specially-formatted hidden column in the listbox as suggested by Matt in his REALbasic book (p. 375). The 'clear' button can be used to clear the whole data list (if no rows are selected) or to clear only selected rows. Optionally, a reference range can be entered in the labeled boxes below the data list.

The popup list allows you to select the desired type of graph. When the plot button (actually named 'ReplotButton') is clicked, the 'FillPlot' method of the Display window is called to load the data from the data list and the reference range boxes into the Xvalue, Yvalue and Aref arrays of 'thePlot.' The type of plot selected is loaded into the type attribute of 'thePlot.' The ListItem array is loaded with the indexes (from the data list) of the data points stored in the Xvalue and Yvalue arrays. This is used to keep track of which data points are being plotted and allow selection of the corresponding data points in the data list when parts of the graph are dragged over. As an aside, the inset, offset and scale attributes of 'thePlot' relate to the size and location of the graph on the canvas and are also used in the method 'selectPoints' to figure out which points should be selected when the mouse is dragged on the graph. They are currently set from within the plotting methods, but could be set elsewhere, if desired.

Then the 'Regraph' method is called, which checks to see whether enough points are available in 'thePlot' to create a graph and calls the appropriate graphing method (PlotLinear, PlotSemilog, Fitlinear, or FitSemilog) based on the contents of thePlot.type . The plot is drawn to an offscreen bitmap and then 'Regraph' calls the 'refreshCanv' method to paint the new plot on the canvas (see below). 'Regraph' is also called when the window is resized, to redraw the graph from the data stored in 'thePlot' and repaint the canvas at the new size, and when the canvas Paint method is called.

The plotting is done to an off-screen bitmap because the graph needs to be relatively flicker-free when its cursors are dragged across the graph to select data sequences directly. The offscreen picture is an attribute of 'thePlot.' It is drawn onto the canvas by the 'refreshCanv' method, which is called by the 'Regraph' method above and is also called during MouseDrags and MouseUps in the plot canvas.

When a portion of the graph is dragged over, the MouseDown and MouseDrag methods of the plot canvas store the X values of the start and end of the drag, corrected for the X offset and inset of the graph, in the selectRange array attribute of 'thePlot.' The MouseUp method calls the 'selectPoints' method of the Display window to figure out the range of the drag within the data using the drag dimensions and the Xscale attribute. It then selects the data points in the data list that fall within the correct range.

That's pretty much it, I think. This documentation and the comments in the code will improve in the future, I hope. Enjoy.

JH