ActionScript Graphing Cookbook
上QQ阅读APP看书,第一时间看更新

Graphing a spreadsheet

Graphing functions is nice, but visualizing a spreadsheet is probably the most popular use case for graphs. Having a visual representation of tabular data can result into insights previously hidden behind the numbers.

In this recipe, we will structure the code to use data from a fixed array in the ActionScript program. In the next chapter, we'll go into all kinds of ways to get the data into that array.

Getting ready

Create a new document class called Recipe5 and have it extend Sprite. Also make sure to copy the updated Graph class from the provided source package. It has enhanced and more flexible axes methods (if you implemented any of the items mentioned in the There's more... section of the Adding labels and axes recipe in this chapter, you may have already created a very similar one).

This time we'll focus on only positive numeric data, so we'll put the origin (0,0) of the graph in the bottom-left corner:

package  
{
  import flash.display.Sprite;

    private const MAX_X:int  = 700;
    private const MAX_Y:int  = 500;
    private const BORDER:int = 50;
    private const TICK:int   = 50;

  public class Recipe5 extends Sprite 
  {
    private var graph:Graph;

    public function Recipe5() 
    {
      graph = new Graph( -BORDER, MAX_Y + BORDER, MAX_X + BORDER, -BORDER);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, MAX_X, TICK, ["0", MAX_X]);
      graph.drawVerticalAxis(0, 0, MAX_Y, TICK, ["0", MAX_Y/2, MAX_Y]);
    }
  }
}

If you run this program, you should see both axes run from the bottom-left corner and there should be two labels on the horizontal axis and three on the vertical axis.

How to do it...

For now, we'll just show point charts. Feel free to convert this into a line chart (as shown in the Creating a line graph based on a function recipe in this chapter) and in later recipes you'll learn how to draw many different types of charts.

If we have the following table:

How to do it...

We want to draw two points: (10,40) and (20,60).

Storing data is easiest in a two dimensional array. In the next chapter, we'll go over many different ways of storing data (such as in files and on the Internet). The array mimics how you represent this data in a program such as MS Excel:

private var graph2d:Array = [[0,20],[50,70],[100,0],[150,150],[200,300],[250,200],
[300,400],[350,20],[400,60],[450,250],[500,90],[550,400],
[600,500],[650,450],[700,320]];

All the points are grouped together. Each entry in the array is one (x , y) coordinate on the graph.

The code to draw this dataset is just a simple loop:

for (i = 0; i < graph2d.length; i++)
{
  graph.drawPoint(graph2d[i][0], graph2d[i][1], 0x3399ff);
}

This structure does have one problem: it's not easy to manipulate the data. You may want to change the data, for instance, if this was connected to live web statistics that are updated every minute (we'll see more on that in the next chapter). Say you want to change the point (150,150) to (150,200). How would you do that? You need to loop over the array and find the correct entry and change it.

However, searching this way in a large array can become slow quite quickly. If the array is always sorted, like in the preceding example, you could implement your own version of a search algorithm to make it quicker. But then you'd need to create your own insertion algorithm to make sure the data remains in order.

No matter how you solve this, if you need to manipulate the data a lot, this is not a good data structure.

See the There's more... section of this recipe for other solutions to these problems.

How it works...

The data we want to display is a simple data mapping from one value to the another. Imagine an Excel spreadsheet with two columns. One column holds the x-axis values while the other holds the y-axis value. Two numbers on the same row present one (x , y) point.

That is why a two-dimensional array is one of the best ways to represent data: it's an easy structure to program and it's easy to read. However, it is hard to manipulate. If you have a fixed data set, this is the structure you want.

There's more...

There are an endless number of possible ways to represent data. Depending on your data source or your specific data set, you may want to look into other options. In the following section, we present the two most popular ones, each with its own advantages and disadvantages. Ultimately, it is possible to combine most advantages into one structure, but it will require additional development.

Two arrays

The easiest solution to store data is in two arrays, one for each column in the spreadsheet:

private var graph1x:Array = 
[0, 50, 100, 150, 200, 250, 300, 350, 400, 
450, 500, 550, 600, 650, 700];
private var graph1y:Array = 
[20, 70, 0, 150, 300, 200, 400, 20, 60, 250, 90, 400, 500, 450, 320];

And you can draw the graph with a simple loop:

for (var i:int = 0; i < graph1x.length; i++)
{
  graph.drawPoint(graph1x[i], graph1y[i], 0xff9933);
}

This works effectively and is completely understandable. There is a major drawback to this approach that is already clear in this simple example.

There's no easy way to quickly verify that you have the same number of elements in both arrays. You can write a test in your code, but if you want to edit the data, it's hard to see which value belongs to which.

For instance, the 400 x-value maps to 60 on the y-axis. That isn't readily apparent from the code. If you forget to add a y-value, you run the risk of breaking your entire program.

Associative array

If inserting and updating data is important, you may want to look into a third solution: the object or associative array.

private var graphObject:Object = { 0:20,50:70,100:0,150:150,200:300,250:200,
300:400,350:20,400:60,450:250,500:90,550:400,
600:500,650:450,700:320 };

Although the notation looks similar to the previous one, the data structure that is created internally is quite different. Drawing it is a little more complicated and requires the usage of the for-in loop (again we shift the points to demonstrate the difference):

for (var s:String in graphObject)
{
  graph.drawPoint(Number(s) + 8, graphObject[s], 0xff3399);
}

Because the x coordinate is stored as an object property, it is stored as a string. Before we can draw it, we need to convert it back to a number.

This data structure is perfect for manipulation. Instead of having to search through it to find the item we want to change, we just write the following:

graphObject[150] = 200;

However, there is one very major disadvantage of the associate array and the for-in loop: you should not rely, in any way, on the order in which elements are looped over. So there's no guarantee that the loop will first draw (0,20) and then (50,70), and so on.

Order will become important if you want to draw more complicated charts than the point chart shown. In that case, you need to first convert the object to an array and then sort the array.

Vectors

If you like to work in a more object-oriented manner, and to avoid some of the pitfalls of arrays and increase performance, you may want to look into vectors.

Although the code that you need to write tends to be much more verbose than arrays and objects, they offer a very high level of type safety and have many convenience functions.

For instance, you can store points in the Point objects:

var point:Point = new Point(0,20);

And store these points in a point vector:

var graphVector:Vector.<Point> = new Vector.<Point>();
graphVector.push(point);

Associative array to two-dimensional array conversion

If you intend to manipulate your data inside your ActionScript program you will probably want to write at least a conversion function from the associate array to the ordered two-dimensional arrays. Potentially, you'll also need to do this the other way around.

What you need to do is:

  • Use a for-in loop to construct a two-dimensional array
  • Use the Array.sort method and the custom order function to sort the array

See also

If you're not confident with manipulating (associative) arrays, it's best to look at one of the ActionScript fundamentals books. Both data structures are vital to understanding most of the recipes in this book.