Home >
© 2009 Thomas W. Gonzalez
This purpose of this article is to introduce developers and data visualization specialists to Axiis, which is an open source data visualization project based on Adobe Flex and Actionscript 3. While you do not have to be an expert in Flex Builder or ActionScript 3, having experience in both will make understanding this tutorial easier. Throughout the article I will assume you are comfortable with the fundamentals of building an application with Flex, and understand some of the primary language constructs embodied within ActionScript 3 and the Flex SDK, primarily MXML and Binding.
My goal is for this article to cover both the theories underlying Axiis as well as a concrete step-by-step implementation of building something meaningful. I think this is important because Axiis is unique in a few distinct ways and does not follow the more conventional design patterns you see in many modern UI applications. Having a solid understanding of the concepts that went into building Axiis in conjunction with a concrete example of how to apply these concepts will better prepare you to get the most of the framework for your own needs.
So what is Axiis?
Axiis is an open source framework designed to support the conceptualization and implementation of a wide variety of interactive data visualizations ranging from common cartesian charting to yet-to-be-imagined forms of visualization. One of the primary differences between Axiis and many other charting or data visualization packages is that Axiis is NOT simply a collection of pre-built charting classes, but rather a specialized framework that implements specific design patterns that can be used to create your own visualizations.
I realize that for many people, the value in using a data visualization library or framework is to be able to quickly and easily define charts and graphs for their applications. In that vein, we have released a pre-built set of cartesian charts that are used for the more common business info-graphics you see many applications today which we talk about at the end of this article. While these charts are full-featured implementations, they were built more to demonstrate how to use Axiis to develop and customize your own charts, and not as a comprehensive charting component library.
A little background:
Day-to-day I work as a consultant helping companies to embed data visualization technology into their product offerings and internal applications. In almost every project I am engaged on I encounter unique sets of functional requirements that benefit greatly from customized data visualization approaches. In many cases, they can be subtle design decisions such as the type of gradient fill to use on a column or a the positioning of a label or hash mark. But the gestalt of these many subtle customizations results in a visualization that has markedly improved communicative value to the intended user base.
Because of these repeated needs for project specific customization, and in more specialized cases, unique innovation, working with pre-built charting components can make the implementation of my designs a cumbersome process at best, and impossible at worst. Thus, my primary motivation for building Axiis was to create a well thought out and organized framework that allowed me to more effortlessly realize my data visualization design goals.
Along with my personal and business motivations for building Axiis, I also have come to truly appreciate what can be done within the open source community, and I saw an emerging need to build something like Axiis to support a growing community of data visualization engineers and developers.
After working as a team member on the open source Degrafa project which focuses on a declarative graphics framework, I had also come to appreciate a new development design paradigm that has emerged with the success of MXML and Flex Binding that allows a developer to use a combination of markup syntax with inline expressions to define complex visual compositions. Graphically related programming tasks that were quite daunting in OO and procedural programming became infinitely more approachable and malleable when implemented directly in markup that leveraged dynamic binding and little pieces of procedural code. Until this experience, I had always thought of markup as a second-class citizen when it came to “programming”, but I now believe that this approach to developing graphically focused applications will really expose the power and efficiency of using a true 5GL language (http://en.wikipedia.org/wiki/Fifth-generation_programming_language.)
The major design goal for Axiis was to create concise and elegant domain specific framework that was suitably flexible in supporting the invention of a wide array of unique data visualizations through small modular building blocks that could be composited into complex outputs.
It is important to mention the Axiis builds upon the great work of the open source Degrafa project, and leverages Degrafa as a means to declaratively define shapes, geometries, and other visual compositions used to plot data. If you are not familiar with Degrafa, that is okay, it is just important to know that Axiis will be using the Degrafa library and syntax to create the visual aspects of its graphs and charts.
I give this background to help lay the conceptual foundation for what is to follow in my description of how to use Axiis for your own needs. This tutorial will focus on relative simple task of building a custom column chart from scratch using the primary building blocks of Axiis. In learning how to build this column chart you will be exposed to the primary set of fundamental design patterns embodied within Axiis. While the basic building blocks are not terribly complex or hard to understand by themselves, it does require a bit of mental fortitude to conceptualize the relationships between these building blocks and how to leverage them to produce data visualizations.
Getting Started
Lets start by downloading the examples project archive from the axiis repository (http://axiis.googlecode.com/files/Axiis_Examples.zip) and importing that project into Flex Builder 3. This will ensure that you have all the libraries and project settings configured correctly. Try compiling one of the examples and running it to verify that the project is set up correctly. I will assume you are familiar enough with Flex Builder to sort through any issues that may prevent you from getting to this stage.
Now that we have our example project up and running we will create a new Flex Application and start our coding. Create a new Flex Application and name it ColumnChartTutorial. Then add the Axiis namespace to the Application Tag: xmlns:axiis="http://www.axiis.org/2009"
To start, we are going to work with a very simple data set, the same one we use in the examples posted at http://www.axiis.org/examples , that shows the top 10 medal winning countries from the 2008 Olympics. To make things easy we are going to have the source data in a nested XML structure that maintains the simple hierarchal relationships between Countries and medal counts for each type of medal (gold, silver, bronze.)
For this data we want to build a simple column chart that shows total medals (irrespective of medal type) for each country. As with most data visualization our first step will be to perform a little pre-processing of the data to make it easier to bind to specific attributes of our column chart. Lets now add our data source and a bit of pre-processing code to our application by doing the following:
Add the following inside your root Application tag:
Create a script block with the following code at the top of your Application:
Add an event listener to the creationComplete event for the Application that calls the start() function:
Pre-Processing our Data
Now that we have set up some pre-processing logic for our source data, lets debug the application to see what our code is doing. In particular, we want to look at how the DataSet operates and understand what the two aggregateData calls are doing. Set a breakpoint on our trace statement and then launch the debugger.
In most data visualization work you are going to need to do some client side data processing prior to visualization. This pre-processing is usually required because source systems rarely publish data in a format that is conducive for visualization. The Axiis DataSet was created to serve two purposes. First, it is meant to be the loosely coupled bridge between source data and visualization data that can be used in a consistent manner across all Axiis visualizations. Second, it provides some common data transformation functionality that is usually required to transform source data into a format that is appropriate for visualization. Aggregation is one of those such functions. In future articles we will plan on spending more time talking in depth for the DataSet class, but for now there are only a few key points to keep in mind.
DataSet stores both its original source data as well as any subsequent transformations in various dynamic properties. In the case of our example we are taking raw XML string data and processing it into dynamic objects which are stored in the ds.data.object property. The Axiis DataSet also supports the processing and shaping of flattened CSV or recordset data into hierarchal data, but that will be left for a more advanced tutorial. For now, it is good enough to know that the DataSet class can process XML data into a dynamic object much like the Flex HTTPService can convert an XML stream into an E4X object.
One of the other key features of DataSet is the aggregateData function. The purpose of this function is to perform some client side aggregation calculations on groups of data elements within the data source. This can be helpful when wanting to create “drill-down” or “drill-across” visualizations that need summary level information about nested collections of data. When the aggregateData function is executed, the DataSet will then dynamically append an aggregates property to the root data property that is being aggregated. Currently the aggregate functions provides four calculations - min, max, sum, and average.
When you look at our watch window you will see several properties within the aggregates object, representing two layers of aggregation. The medal_count_X aggregates and the country_aggregates:medal_count_X_Y. In this case, since we have called two aggregation functions, one that aggregates the count property of each medal element for each country, and then another that aggregates the medal_count_sum at the country level. What we are seeing within the medal_count_X group is the min, max, average, and sum of all elements. Within the medal_count_X_Y group we then see the medal_count_X aggregates be aggregated again at the level. If you actually drill down into the elements within the ds.data.object.country collection you will also see these lower level aggregates as a property of each country node.
We do this aggregation for two purposes. First, we want to get total medal counts by country so we can easily visualize them, and since those values are not provided in our source data we use this function to provide them. Second, we want to know our min and max values so we can set a reasonable scale bounds to plot our data against. It is not always necessary to use these aggregation functions, but they have been built into Axiis because we (the authors) have found that this is a very common piece of pre-processing that often gets performed on source data prior to visualization.
Setting up our DataCanvas, Linear Scale, and Vertical Axis
Next we will be to set up the requisite visual components we will use to plot our data against. In Axiis, every visualization starts with a DataCanvas component, which serves as UIComponent container that handles the communication and integration of the various sub-components used to build a visualization, primarily the layouts, scales, axis, and geometries that we will be discussing. In Degrafa, the primary drawing elements are referred to as geometries - which can represent things like circles, polygons, curves, etc. As such, the DataCanvas has three main areas where we add these Degrafa geometries and they are broken down into backgroundGeometries, layouts, and foregroundGeometries. The backgroundGeometries and foregroundGeometries are simply two visual layers that allow the developer to place geometry elements beneath and above the primary data plot area that is represented in the layout property of the DataCanvas. All of the real magic happens within the Layouts layer, which is where the data will actually be plotted. Elements like grid lines, axis legends, and background images are put into the backgroundGeometries layer and callouts, annotation elements, etc can be put into the foregroundGeometries.
For right now we are going to create a DataCanvas with a simple VerticalAxis and a LinearScale , and then bind the max value of our LinearScale to total medals received by the country with the most medals. So we will add the following to our root Application:
Then we need add these two lines to our start() method:
Compile the application and see what is rendered to the screen. What we have done with the preceding code is to lay the foundation for our column chart by describing a LinearScale (vScale) with its upper range bound to the max medal count summed by country, and then drawn a vertical axis based on this range.
The Magic of Axiis - Layouts
Now we come to the fun part of building visualizations in Axiis, and the single most important concept , Layouts. Layouts are the primary mechanism by which you describe how a stream of data will be plotted to the display. This is accomplished with the use of two related elements - the referenceRepeater and drawingGeometries.
In Axiis you can think of the referenceRepeater as the set of constraint based rules that describe the bounds and positioning of the elements within your visual pattern, and the drawingGeometries are the definition of what will be drawn for each element contained within that pattern. For our column chart example, we are going to want to create referenceRepeater that describes a rectangle that is repeated across the screen horizontally that will serve as the bounds of our columns to be drawn.
While Axiis already has a pre-built layout HBoxLayout that will perform this function for us, we are going to create our own, since it is very easy to do, and goes a long way to explaining the core concepts that are used in the Axiis Layout.
To start we are going replace the empty tag within our DataCavas.layout MXML tag with this:
This block of code declares a Degrafa RegularRectangle (referenceRectangle) as the geometry that will repeat for our reference pattern, and for each iteration of our loop we want to offset the referenceRectangle horizontally by an amount equal to the width of the layout container divided by the number of elements within the dataProvider. The result should be a set of reference rectangles that stretch across our layout all right next to one another.
One concept that is a little tricky, but very important to understand is that the referenceRepeater and its associated geometries (in this case the referenceRectangle) DO NOT draw anything to the display, they simply provide a layout reference that will be used by our drawingGeometries. The reason why we have done this, is that it many cases it is helpful to have a primary pattern that can then be adjusted on an item by item basis for particular drawing effects. The other reason, is that it allows developers to define generic layout algorithms as encapsulated components that can be re-used independent of any specific rendering geometries. You can see examples of this in the concrete Axiis layouts (org.axiis.layouts) which are built in MXML and follow the same pattern we are discussing here.
In order to actually see something drawn to the screen we are going to have to create our drawing geometries. In the case of a column chart we are going to once again use a RegularRectangle to define our drawing geometry, and for right now we are going to just bind all of its properties directly to our referenceRepeater so you can see exactly what the referenceRepeater is doing. When you compile the application it should look like the image above.
The Reference Repeater and Drawing Geometry relationship
When we set out to build Axiis, after looking at large spectrum of a various data visualizations and wide variety of use cases, we came to realize that the one common thread that was universal to all data visualizations was the implicit definition of a set of rules that took source data and transformed it into a visual pattern of repeating elements. As result of this insight, we developed a design pattern that uses the concept of a dynamic constraint based repetition engine (the reference repeater) and a set of drawing geometries to give us the needed flexibility and extensibility we we were looking for as a the foundational building blocks to create our data visualizations from.
The referenceRepeater borrows directly from the same concepts that are used in the GeometryRepeater within Degrafa (but Axiis implements its own unique GeometryRepeater.) The referenceRepeater describes a simple or complex geometry, then loops through a set of property modifiers, which for a given iteration of the loop will modify specified properties of the geometry that has been declared. For instance, if you wanted to have a rectangle that is repeated horizontally across the screen 10 times, you would create a RegularRectangle, and then add a property modifier that modifies the “x” property of that rectangle by a given offset, and tell the repeater to loop 10 times. In Axiis we handle some of this for you, and automatically bind the referenceRepeater to a loop based on the number of elements in the dataProvider that is bound to the Layout.
Binding drawing geometries to the reference repeater
When you look at the properties declared within the drawingRectangle in our example code you can see we are binding to the hLayout.currentReference which is one of the current properties that exist in all Axiis Layout classes. In this context, current refers to the current iteration of the repeater loop being managed by the layout at render time and includes the following properties: currentDatum, currentIndex, currentLabel, currentValue and currentReference. In this case, currentReference is just referencing the referenceRectangle within the referenceRepeater, and we could have just as easily bound directly to it, but an Axiis best practice is to use the “current” properties of the layout itself to make it easier if you decide to re-factor your code at later time.
By binding our drawingGeometry directly to the currentReference of the AbsoluteLayout all we have done is mirrored the exact size and position of referenceRectangle with our drawingRectangle, but we have not bound it to any real data values. When you launch the application you will also notice some potential issues with the way we have created our hLayout, namely that our vertical axis is within the bounds of our layout, and that we have no separation between the various columns.
To fix these issues, modify the tag to look like this:
Then modify the width property of referenceRectangle like this:
If you re-launch the application you will now see something like the below, which now has a proper offset from the vertical axis and has provided some padding between the column elements.
Binding to our Data
Next we need bind our data to our drawingRectangle to make these columns more meaningful and representing our data values within the display. This is a relatively trivial task and can be accomplished by modifying the height property of our drawingRectangle like this:
When you launch the application now you will notice the columns now have the correct heights, but appear to be upside down! This is because we still need to also set the y position of the drawingRectangle correctly. Which can be accomplished by the following change to the y property of the drawingRectangle
Now when you launch the application you should see the following:
What we have done is to use the currentValue of our hLayout in conjunction with our vScale to translate the source data into a screen plot value. The scale classes in Axiis provide two convenient methods to translate data values into screen coordinates and vice versa. They are the valueToLayout(), and layoutToValue() methods. Should you have some unique scale requirements outside the pre-built scales that come with Axiis, it is relatively easy to write your own scale classes that implement the IScale interface.
For this chart we use the vScale’s valueToLayout calls both get the height of the column itself, as well as the relative y position. As you can see, we are really taking advantage of inline MXML binding in how we are writing our code. This inline binding feature of Flex is probably one of the most powerful features of the language and compiler and is really at the core of how you “code” with Axiis.
Labels
Now that we have our primary drawing geometry plotted it would be nice to add some labels so we know what each column actually represents. This is where using the abstraction of a reference repeater coupled with your drawing geometries starts to get more powerful, because we can add different drawing elements without having to modify our primary layout algorithm. If we add the following code right beneath our drawingRectangle, we should now see country labels positioned directly beneath each column when you launch the application.
If we want to get fancy we could also put a label above the column itself representing the numeric value of the column, which can sometimes be a nice data visualization technique that mitigates the need to even have a vertical axis. Lets try that by placing this code below the code you just entered.
As you build your own data visualizations, you have many choices in how you employ labeling. Something else to remember is that Axiis also supports dynamic interactive Data Tips (which we will not be covering in this article.) Data Tips provide yet another way that you can provide datum level information to the user either in a textual or visual form.
Styles
Styling your data visualizations is more than just making it pretty. Styles can help convey subtle meaning, nuances, and better communicate the story your visualization is trying to tell. Styles can also be used to add aesthetic qualities to your output that also enhance the appeal and accessibility of the work.
I will digress for a moment here to talk a bit about the role of styling in data visualization and the controversy that is sometimes raised when styles are used too much or too little. In the data visualization space there is a group of people who take the stance that you should use the absolute minimal amount of color, decoration, flourish than is absolutely necessary to convey the meaning of the visual, resulting in very effective, but rather sterile visuals. Another group of people focus more on the aesthetic appeal of the visualization and will sometimes employ stylistic treatments that can overshadow the communicative value or original purpose of the visualization in its attempt to make it “sexy.”
In my opinion, completely sterile visualizations do little to engage the user at an emotional level, and as a result may actually impair the communicative value of the visualization depending on the target market. I also believe that visualizations that have an egregious amount of visual flourish might (and often do) undermine the communicative value of the output, and in some cases actually distort the data being represented due to the visual effect (think 3D charts.)
In an effort to create compelling, engaging, and effective data visualizations that serve specific business and analysis functions I try to use color, contrast, size, position and other stylistic cues primarily to enhance the communicative value of the data visualization and support whatever analysis is supposed to be taking place within the visual. Secondarily, I want to make the visual as aesthetically pleasing as possible while erring on the side of communication versus decoration.
An analogy I use here, is thinking about the architecture of a building. While a well thought-out house made of cinder blocks, concrete floors, and steel doors might very effectively serve its purpose of providing shelter to its occupants, a home designed with a particular architectural style within the same functional constraints will provide a much more enjoyable and approachable experience for the people living within it. Data visualization can also be thought of in the same way, especially for commercial products. When you have an opportunity to add beauty to what you are doing without detracting from its primary purpose, why wouldn’t you? It can serve as huge competitive advantage and make the work itself more approachable and engaging to a wider audience.
So as you can imagine, when we designed Axiis, being able to easily add beauty to the visuals was something that was important to us. Fortunately, Degrafa provides the ability to easy adjust many of the variables that go into creating unique styles. For our column chart we just want to make a couple of minor adjustments to enhance the aesthetic value while at the same time helping to communicate the differences within the data being shown.
Fills and Gradients
Using fills and gradients is one of the easiest ways to add an enhanced aesthetic quality to your visualizations that does not have to detract from the communicative value of the work. As such, we have some helper classes that make this easy to do. Most visualizations will use color to distinguish elements from each other, or group them with each other for a given series of data. For our column chart we are going to use the LayoutAutoPalette to create a pleasing set of unique colors for each column. The LayoutAutoPalette makes it easy to describe a dynamic range of colors by specifying either an array of colors or a colorFrom and colorTo property that is bound to a specific layout. The LayoutAutoPalette will then dynamically create a unique set of colors based on how many data items are being rendered by the specified layout, and it will use the colors you specify as targets to interpolate the new colors against. Axiis also supports the LayoutPalette, which allows you to specify an array of static colors that will be rotated (via a modulo operation) against the number of items within the data provider of the targeted layout.
Lets add the following code at the bottom of your application file:
Then go back to your drawingRectangle and remove the stroke tag and add the fill and stroke properties inline like this:
For good measure we will also modify our country name label (the first one) by adding this property to its tag:
Now when you launch the application you should be looking at something like this:
In this code we are creating a LinearGradientFill and a LinearGradientStroke, and we are binding the color value of the GradientStops to the LayoutAutoPalette. So as the Layout is looping through its dataProvider and rendering the drawingRectangle, it is also triggering a change in the currentColor of the LayoutAutoPalette which is being used by the two gradients we defined. We also employ a nice little trick with an bitwise OR operator that makes it easy to whiten color values to a hex color as seen in the color="{ap.currentColor | 0x444444}" within the two GradientStop declarations.
With just the use of fills, strokes, and gradients you can create some very elegant and sophisticated styling that will both make your visualizations easier to interpret by your users, but also add a significant aesthetic appeal to them.
All of the examples found at www.axiis.org/examples.html use various combinations of these simple techniques.
Summarizing the Process
I could easily go on and enhance this chart even further with more sophisticated techniques, but I would like to leave that for another article and summarize the steps we have followed thus far to create this column chart. While the chart we have built within this tutorial is a relatively simple, single series chart, the steps we used to build it are universal to building ANY data visualization within Axiis. For your reference here are the steps below.
Import Data in the form of XML or CSV via embedding, remote object call, web service call, , etc.
For the complete source code of the final chart you can find it here at http://www.axiis.org/examples/ColumnChartTutorial.mxml
But All I Want Are Some Simple Charts
In this tutorial my goal was to demonstrate how you could build a data visualization completely from scratch. But, Axiis has also been designed for people who simply need to place a chart within their application and put some data into it, without worrying about the finer points of creating their own customized data visualization solution from scratch. Axiis can also be used for these more common use cases very easily, and in many cases more easily than other standard charting packages.
You should know also know that Axiis comes with a set of pre-built cartesian “grouping” classes (org.axiis.charts.groupings) that can be used in conjunction with the DataCanvas to build most of the common cartesian charts you are familiar with in most business applications. Groupings are very similar to the series classes you see in other charting packages, with one important additional capability. In Axiis, the grouping classes support a dynamic number of unique series within a grouping based on the data you provide the group. For instance if you look at the example here http://www.axiis.org/examples/HClusterStackExample.html you will see that it leverages two of the grouping classes - ColumnCluster and ColumnStack. Both of these groupings allow you dynamically define how many unique series there will be for a given grouping as seen here:
Because these groupings themselves are nested within an HBoxLayout, you can easily allow the data to determine how many unique series will be represented. This is something that is usually much more cumbersome to do in more traditional OO charting packages, because either you need to know how many series exist up front, or you need specialized code that dynamically creates series at run time based on your data. When you combine these grouping classes with the Axiis LayoutPalettes it is a rather straightforward affair to create charts and visualizations that can accommodate dynamic data payloads where the number of unique series may change based on the run-time queries used to generate the data.
For more details on how groupings are used, and how you can easily embed common cartesian charts within your applications, please refer to the examples on www.axiis.org. The benefit of starting with the Axiis groupings is that they are very succinct (less than 200 lines) composited MXML components that use the exact same technique described in this article. So if you need to start customizing and extending your charts based on specific project requirements it is very easy to re-factor the groupings into your own custom charting components that can be extended in a myriad of ways.
If you have worked your way through this tutorial and feel comfortable building the column chart described, then customizing the charts and examples that ship with Axiis should be a trivial affair because you understand all of the underlying principles and code needed to create a very customized solution within Axiis.
What is Next
Based on response to this first article I hope to continue this with a series of follow up tutorials that dive into some of the more advanced techniques of building visualizations with Axiis that cover adding user interactions, states, transitions, nested layouts, and more complex manipulation of data. Please post comments and suggestions, and if you are new to Axiis or data visualization let me know how well this article may or may not have helped you to come up to speed.
I will also be speaking about Axiis with Michael VanDaniker, the other founder and author of Axiis, at CFUnited in Leesburg VA, on August 14, and by myself at Adobe MAX October 5th and 6th in Los Angeles. You can also read more about Axiis on my blog at www.twgonzalez.com or Michaels blog at http://michaelvandaniker.com.
This purpose of this article is to introduce developers and data visualization specialists to Axiis, which is an open source data visualization project based on Adobe Flex and Actionscript 3. While you do not have to be an expert in Flex Builder or ActionScript 3, having experience in both will make understanding this tutorial easier. Throughout the article I will assume you are comfortable with the fundamentals of building an application with Flex, and understand some of the primary language constructs embodied within ActionScript 3 and the Flex SDK, primarily MXML and Binding.
My goal is for this article to cover both the theories underlying Axiis as well as a concrete step-by-step implementation of building something meaningful. I think this is important because Axiis is unique in a few distinct ways and does not follow the more conventional design patterns you see in many modern UI applications. Having a solid understanding of the concepts that went into building Axiis in conjunction with a concrete example of how to apply these concepts will better prepare you to get the most of the framework for your own needs.
So what is Axiis?
Axiis is an open source framework designed to support the conceptualization and implementation of a wide variety of interactive data visualizations ranging from common cartesian charting to yet-to-be-imagined forms of visualization. One of the primary differences between Axiis and many other charting or data visualization packages is that Axiis is NOT simply a collection of pre-built charting classes, but rather a specialized framework that implements specific design patterns that can be used to create your own visualizations.
I realize that for many people, the value in using a data visualization library or framework is to be able to quickly and easily define charts and graphs for their applications. In that vein, we have released a pre-built set of cartesian charts that are used for the more common business info-graphics you see many applications today which we talk about at the end of this article. While these charts are full-featured implementations, they were built more to demonstrate how to use Axiis to develop and customize your own charts, and not as a comprehensive charting component library.
A little background:
Day-to-day I work as a consultant helping companies to embed data visualization technology into their product offerings and internal applications. In almost every project I am engaged on I encounter unique sets of functional requirements that benefit greatly from customized data visualization approaches. In many cases, they can be subtle design decisions such as the type of gradient fill to use on a column or a the positioning of a label or hash mark. But the gestalt of these many subtle customizations results in a visualization that has markedly improved communicative value to the intended user base.
Because of these repeated needs for project specific customization, and in more specialized cases, unique innovation, working with pre-built charting components can make the implementation of my designs a cumbersome process at best, and impossible at worst. Thus, my primary motivation for building Axiis was to create a well thought out and organized framework that allowed me to more effortlessly realize my data visualization design goals.
Along with my personal and business motivations for building Axiis, I also have come to truly appreciate what can be done within the open source community, and I saw an emerging need to build something like Axiis to support a growing community of data visualization engineers and developers.
After working as a team member on the open source Degrafa project which focuses on a declarative graphics framework, I had also come to appreciate a new development design paradigm that has emerged with the success of MXML and Flex Binding that allows a developer to use a combination of markup syntax with inline expressions to define complex visual compositions. Graphically related programming tasks that were quite daunting in OO and procedural programming became infinitely more approachable and malleable when implemented directly in markup that leveraged dynamic binding and little pieces of procedural code. Until this experience, I had always thought of markup as a second-class citizen when it came to “programming”, but I now believe that this approach to developing graphically focused applications will really expose the power and efficiency of using a true 5GL language (http://en.wikipedia.org/wiki/Fifth-generation_programming_language.)
The major design goal for Axiis was to create concise and elegant domain specific framework that was suitably flexible in supporting the invention of a wide array of unique data visualizations through small modular building blocks that could be composited into complex outputs.
It is important to mention the Axiis builds upon the great work of the open source Degrafa project, and leverages Degrafa as a means to declaratively define shapes, geometries, and other visual compositions used to plot data. If you are not familiar with Degrafa, that is okay, it is just important to know that Axiis will be using the Degrafa library and syntax to create the visual aspects of its graphs and charts.
I give this background to help lay the conceptual foundation for what is to follow in my description of how to use Axiis for your own needs. This tutorial will focus on relative simple task of building a custom column chart from scratch using the primary building blocks of Axiis. In learning how to build this column chart you will be exposed to the primary set of fundamental design patterns embodied within Axiis. While the basic building blocks are not terribly complex or hard to understand by themselves, it does require a bit of mental fortitude to conceptualize the relationships between these building blocks and how to leverage them to produce data visualizations.
Getting Started
Lets start by downloading the examples project archive from the axiis repository (http://axiis.googlecode.com/files/Axiis_Examples.zip) and importing that project into Flex Builder 3. This will ensure that you have all the libraries and project settings configured correctly. Try compiling one of the examples and running it to verify that the project is set up correctly. I will assume you are familiar enough with Flex Builder to sort through any issues that may prevent you from getting to this stage.
Now that we have our example project up and running we will create a new Flex Application and start our coding. Create a new Flex Application and name it ColumnChartTutorial. Then add the Axiis namespace to the Application Tag: xmlns:axiis="http://www.axiis.org/2009"
To start, we are going to work with a very simple data set, the same one we use in the examples posted at http://www.axiis.org/examples , that shows the top 10 medal winning countries from the 2008 Olympics. To make things easy we are going to have the source data in a nested XML structure that maintains the simple hierarchal relationships between Countries and medal counts for each type of medal (gold, silver, bronze.)
<countries>
<country name="USA">
<medal category="Gold" count="36"/>
<medal category="Silver" count="36"/>
<medal category="Bronze" count="38"/>
</country>
....
</countries>
For this data we want to build a simple column chart that shows total medals (irrespective of medal type) for each country. As with most data visualization our first step will be to perform a little pre-processing of the data to make it easier to bind to specific attributes of our column chart. Lets now add our data source and a bit of pre-processing code to our application by doing the following:
Add the following inside your root Application tag:
<mx:String id="countryData" source="data/2008_Olympics.xml"/>
<mx:Object id="dataProvider"/>
Create a script block with the following code at the top of your Application:
<mx:Script>
<![CDATA[
import org.axiis.data.DataSet;
private var ds:DataSet = new DataSet();
public function start():void
{
ds.processXmlString(countryData);
ds.aggregateData(ds.data.object, "country.medal", ["count"]);
ds.aggregateData(ds.data.object, "country",
["aggregates.medal_count_sum"]);
dataProvider=ds.data.object.country;
trace(ds.data.object.aggregates.medal_count_sum);
}
]]>
</mx:Script>
Add an event listener to the creationComplete event for the Application that calls the start() function:
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:axiis="http://www.axiis.org/2009"
layout="absolute"
creationComplete="start();">
Pre-Processing our Data
Now that we have set up some pre-processing logic for our source data, lets debug the application to see what our code is doing. In particular, we want to look at how the DataSet operates and understand what the two aggregateData calls are doing. Set a breakpoint on our trace statement and then launch the debugger.
In most data visualization work you are going to need to do some client side data processing prior to visualization. This pre-processing is usually required because source systems rarely publish data in a format that is conducive for visualization. The Axiis DataSet was created to serve two purposes. First, it is meant to be the loosely coupled bridge between source data and visualization data that can be used in a consistent manner across all Axiis visualizations. Second, it provides some common data transformation functionality that is usually required to transform source data into a format that is appropriate for visualization. Aggregation is one of those such functions. In future articles we will plan on spending more time talking in depth for the DataSet class, but for now there are only a few key points to keep in mind.
DataSet stores both its original source data as well as any subsequent transformations in various dynamic properties. In the case of our example we are taking raw XML string data and processing it into dynamic objects which are stored in the ds.data.object property. The Axiis DataSet also supports the processing and shaping of flattened CSV or recordset data into hierarchal data, but that will be left for a more advanced tutorial. For now, it is good enough to know that the DataSet class can process XML data into a dynamic object much like the Flex HTTPService can convert an XML stream into an E4X object.
One of the other key features of DataSet is the aggregateData function. The purpose of this function is to perform some client side aggregation calculations on groups of data elements within the data source. This can be helpful when wanting to create “drill-down” or “drill-across” visualizations that need summary level information about nested collections of data. When the aggregateData function is executed, the DataSet will then dynamically append an aggregates property to the root data property that is being aggregated. Currently the aggregate functions provides four calculations - min, max, sum, and average.
When you look at our watch window you will see several properties within the aggregates object, representing two layers of aggregation. The medal_count_X aggregates and the country_aggregates:medal_count_X_Y. In this case, since we have called two aggregation functions, one that aggregates the count property of each medal element for each country, and then another that aggregates the medal_count_sum at the country level. What we are seeing within the medal_count_X group is the min, max, average, and sum of all
We do this aggregation for two purposes. First, we want to get total medal counts by country so we can easily visualize them, and since those values are not provided in our source data we use this function to provide them. Second, we want to know our min and max values so we can set a reasonable scale bounds to plot our data against. It is not always necessary to use these aggregation functions, but they have been built into Axiis because we (the authors) have found that this is a very common piece of pre-processing that often gets performed on source data prior to visualization.
Setting up our DataCanvas, Linear Scale, and Vertical Axis
Next we will be to set up the requisite visual components we will use to plot our data against. In Axiis, every visualization starts with a DataCanvas component, which serves as UIComponent container that handles the communication and integration of the various sub-components used to build a visualization, primarily the layouts, scales, axis, and geometries that we will be discussing. In Degrafa, the primary drawing elements are referred to as geometries - which can represent things like circles, polygons, curves, etc. As such, the DataCanvas has three main areas where we add these Degrafa geometries and they are broken down into backgroundGeometries, layouts, and foregroundGeometries. The backgroundGeometries and foregroundGeometries are simply two visual layers that allow the developer to place geometry elements beneath and above the primary data plot area that is represented in the layout property of the DataCanvas. All of the real magic happens within the Layouts layer, which is where the data will actually be plotted. Elements like grid lines, axis legends, and background images are put into the backgroundGeometries layer and callouts, annotation elements, etc can be put into the foregroundGeometries.
For right now we are going to create a DataCanvas with a simple VerticalAxis and a LinearScale , and then bind the max value of our LinearScale to total medals received by the country with the most medals. So we will add the following to our root Application:
<axiis:LinearScale id="vScale" minValue="0"
minLayout="0" maxLayout="{dc.height}"/>
<axiis:DataCanvas id="dc" width="800" height="800"
verticalCenter="0" horizontalCenter="0">
<axiis:backgroundGeometries>
<axiis:VAxis
verticalScale="{vScale}"
width="{dc.width}"
height="{dc.height}"
tickGap="5"
/>
</axiis:backgroundGeometries>
<axiis:layouts>
<mx:Array />
</axiis:layouts>
</axiis:DataCanvas>
Then we need add these two lines to our start() method:
vScale.maxValue = ds.data.object.aggregates['country_aggregates:medal_count_sum_max'];
dc.invalidateDisplayList();
Compile the application and see what is rendered to the screen. What we have done with the preceding code is to lay the foundation for our column chart by describing a LinearScale (vScale) with its upper range bound to the max medal count summed by country, and then drawn a vertical axis based on this range.
The Magic of Axiis - Layouts
Now we come to the fun part of building visualizations in Axiis, and the single most important concept , Layouts. Layouts are the primary mechanism by which you describe how a stream of data will be plotted to the display. This is accomplished with the use of two related elements - the referenceRepeater and drawingGeometries.
In Axiis you can think of the referenceRepeater as the set of constraint based rules that describe the bounds and positioning of the elements within your visual pattern, and the drawingGeometries are the definition of what will be drawn for each element contained within that pattern. For our column chart example, we are going to want to create referenceRepeater that describes a rectangle that is repeated across the screen horizontally that will serve as the bounds of our columns to be drawn.
While Axiis already has a pre-built layout HBoxLayout that will perform this function for us, we are going to create our own, since it is very easy to do, and goes a long way to explaining the core concepts that are used in the Axiis Layout.
To start we are going replace the empty
<axiis:AbsoluteLayout id="hLayout"
width="{dc.width}"
height="{dc.height}"
dataProvider="{dataProvider}"
dataField="aggregates.medal_count_sum"
labelField="name">
<axiis:referenceRepeater>
<axiis:GeometryRepeater>
<axiis:geometry>
<degrafa:RegularRectangle
id="referenceRectangle"
x="0"
y="0"
width="{hLayout.width / hLayout.itemCount}"
height="{hLayout.height}"/>
</axiis:geometry>
<axiis:modifiers>
<axiis:PropertyModifier property="x"
modifier="{hLayout.width/hLayout.itemCount}"/>
</axiis:modifiers>
</axiis:GeometryRepeater>
</axiis:referenceRepeater>
<axiis:drawingGeometries>
<degrafa:RegularRectangle
id="drawingRectangle"
width="{hLayout.currentReference.width}"
height="{hLayout.currentReference.height}"
x="{hLayout.currentReference.x}"
y="{hLayout.currentReference.y}">
<degrafa:stroke><degrafa:SolidStroke color="0"/></degrafa:stroke>
</degrafa:RegularRectangle>
</axiis:drawingGeometries>
</axiis:AbsoluteLayout>
This block of code declares a Degrafa RegularRectangle (referenceRectangle) as the geometry that will repeat for our reference pattern, and for each iteration of our loop we want to offset the referenceRectangle horizontally by an amount equal to the width of the layout container divided by the number of elements within the dataProvider. The result should be a set of reference rectangles that stretch across our layout all right next to one another.
One concept that is a little tricky, but very important to understand is that the referenceRepeater and its associated geometries (in this case the referenceRectangle) DO NOT draw anything to the display, they simply provide a layout reference that will be used by our drawingGeometries. The reason why we have done this, is that it many cases it is helpful to have a primary pattern that can then be adjusted on an item by item basis for particular drawing effects. The other reason, is that it allows developers to define generic layout algorithms as encapsulated components that can be re-used independent of any specific rendering geometries. You can see examples of this in the concrete Axiis layouts (org.axiis.layouts) which are built in MXML and follow the same pattern we are discussing here.
In order to actually see something drawn to the screen we are going to have to create our drawing geometries. In the case of a column chart we are going to once again use a RegularRectangle to define our drawing geometry, and for right now we are going to just bind all of its properties directly to our referenceRepeater so you can see exactly what the referenceRepeater is doing. When you compile the application it should look like the image above.
The Reference Repeater and Drawing Geometry relationship
When we set out to build Axiis, after looking at large spectrum of a various data visualizations and wide variety of use cases, we came to realize that the one common thread that was universal to all data visualizations was the implicit definition of a set of rules that took source data and transformed it into a visual pattern of repeating elements. As result of this insight, we developed a design pattern that uses the concept of a dynamic constraint based repetition engine (the reference repeater) and a set of drawing geometries to give us the needed flexibility and extensibility we we were looking for as a the foundational building blocks to create our data visualizations from.
The referenceRepeater borrows directly from the same concepts that are used in the GeometryRepeater within Degrafa (but Axiis implements its own unique GeometryRepeater.) The referenceRepeater describes a simple or complex geometry, then loops through a set of property modifiers, which for a given iteration of the loop will modify specified properties of the geometry that has been declared. For instance, if you wanted to have a rectangle that is repeated horizontally across the screen 10 times, you would create a RegularRectangle, and then add a property modifier that modifies the “x” property of that rectangle by a given offset, and tell the repeater to loop 10 times. In Axiis we handle some of this for you, and automatically bind the referenceRepeater to a loop based on the number of elements in the dataProvider that is bound to the Layout.
Binding drawing geometries to the reference repeater
When you look at the properties declared within the drawingRectangle in our example code you can see we are binding to the hLayout.currentReference which is one of the current properties that exist in all Axiis Layout classes. In this context, current refers to the current iteration of the repeater loop being managed by the layout at render time and includes the following properties: currentDatum, currentIndex, currentLabel, currentValue and currentReference. In this case, currentReference is just referencing the referenceRectangle within the referenceRepeater, and we could have just as easily bound directly to it, but an Axiis best practice is to use the “current” properties of the layout itself to make it easier if you decide to re-factor your code at later time.
By binding our drawingGeometry directly to the currentReference of the AbsoluteLayout all we have done is mirrored the exact size and position of referenceRectangle with our drawingRectangle, but we have not bound it to any real data values. When you launch the application you will also notice some potential issues with the way we have created our hLayout, namely that our vertical axis is within the bounds of our layout, and that we have no separation between the various columns.
To fix these issues, modify the
<axiis:AbsoluteLayout id="hLayout"
x="20"
width="{dc.width-20}"
height="{dc.height}"
dataProvider="{dataProvider}"
dataField="aggregates.medal_count_sum"
labelField="name">
Then modify the width property of referenceRectangle like this:
width="{(hLayout.width / hLayout.itemCount) - (hLayout.width/hLayout.itemCount)*.1}"
If you re-launch the application you will now see something like the below, which now has a proper offset from the vertical axis and has provided some padding between the column elements.
Binding to our Data
Next we need bind our data to our drawingRectangle to make these columns more meaningful and representing our data values within the display. This is a relatively trivial task and can be accomplished by modifying the height property of our drawingRectangle like this:
height="{vScale.valueToLayout(hLayout.currentValue)}"
When you launch the application now you will notice the columns now have the correct heights, but appear to be upside down! This is because we still need to also set the y position of the drawingRectangle correctly. Which can be accomplished by the following change to the y property of the drawingRectangle
y="{hLayout.currentReference.height-vScale.valueToLayout(hLayout.currentValue)}"
Now when you launch the application you should see the following:
What we have done is to use the currentValue of our hLayout in conjunction with our vScale to translate the source data into a screen plot value. The scale classes in Axiis provide two convenient methods to translate data values into screen coordinates and vice versa. They are the valueToLayout(), and layoutToValue() methods. Should you have some unique scale requirements outside the pre-built scales that come with Axiis, it is relatively easy to write your own scale classes that implement the IScale interface.
For this chart we use the vScale’s valueToLayout calls both get the height of the column itself, as well as the relative y position. As you can see, we are really taking advantage of inline MXML binding in how we are writing our code. This inline binding feature of Flex is probably one of the most powerful features of the language and compiler and is really at the core of how you “code” with Axiis.
Labels
Now that we have our primary drawing geometry plotted it would be nice to add some labels so we know what each column actually represents. This is where using the abstraction of a reference repeater coupled with your drawing geometries starts to get more powerful, because we can add different drawing elements without having to modify our primary layout algorithm. If we add the following code right beneath our drawingRectangle, we should now see country labels positioned directly beneath each column when you launch the application.
<degrafa:RasterText
text="{hLayout.currentLabel}"
fontFamily="Arial"
align="center"
x="{hLayout.currentReference.x}"
width="{hLayout.currentReference.width}"
y="{hLayout.height+5}"/>
If we want to get fancy we could also put a label above the column itself representing the numeric value of the column, which can sometimes be a nice data visualization technique that mitigates the need to even have a vertical axis. Lets try that by placing this code below the code you just entered.
<degrafa:RasterText
text="{hLayout.currentValue}"
fontFamily="Arial"
align="center"
x="{hLayout.currentReference.x}"
width="{hLayout.currentReference.width}"
y="{hLayout.currentReference.height-vScale.valueToLayout(hLayout.currentValue)-20}"/>
As you build your own data visualizations, you have many choices in how you employ labeling. Something else to remember is that Axiis also supports dynamic interactive Data Tips (which we will not be covering in this article.) Data Tips provide yet another way that you can provide datum level information to the user either in a textual or visual form.
Styles
Styling your data visualizations is more than just making it pretty. Styles can help convey subtle meaning, nuances, and better communicate the story your visualization is trying to tell. Styles can also be used to add aesthetic qualities to your output that also enhance the appeal and accessibility of the work.
I will digress for a moment here to talk a bit about the role of styling in data visualization and the controversy that is sometimes raised when styles are used too much or too little. In the data visualization space there is a group of people who take the stance that you should use the absolute minimal amount of color, decoration, flourish than is absolutely necessary to convey the meaning of the visual, resulting in very effective, but rather sterile visuals. Another group of people focus more on the aesthetic appeal of the visualization and will sometimes employ stylistic treatments that can overshadow the communicative value or original purpose of the visualization in its attempt to make it “sexy.”
In my opinion, completely sterile visualizations do little to engage the user at an emotional level, and as a result may actually impair the communicative value of the visualization depending on the target market. I also believe that visualizations that have an egregious amount of visual flourish might (and often do) undermine the communicative value of the output, and in some cases actually distort the data being represented due to the visual effect (think 3D charts.)
In an effort to create compelling, engaging, and effective data visualizations that serve specific business and analysis functions I try to use color, contrast, size, position and other stylistic cues primarily to enhance the communicative value of the data visualization and support whatever analysis is supposed to be taking place within the visual. Secondarily, I want to make the visual as aesthetically pleasing as possible while erring on the side of communication versus decoration.
An analogy I use here, is thinking about the architecture of a building. While a well thought-out house made of cinder blocks, concrete floors, and steel doors might very effectively serve its purpose of providing shelter to its occupants, a home designed with a particular architectural style within the same functional constraints will provide a much more enjoyable and approachable experience for the people living within it. Data visualization can also be thought of in the same way, especially for commercial products. When you have an opportunity to add beauty to what you are doing without detracting from its primary purpose, why wouldn’t you? It can serve as huge competitive advantage and make the work itself more approachable and engaging to a wider audience.
So as you can imagine, when we designed Axiis, being able to easily add beauty to the visuals was something that was important to us. Fortunately, Degrafa provides the ability to easy adjust many of the variables that go into creating unique styles. For our column chart we just want to make a couple of minor adjustments to enhance the aesthetic value while at the same time helping to communicate the differences within the data being shown.
Fills and Gradients
Using fills and gradients is one of the easiest ways to add an enhanced aesthetic quality to your visualizations that does not have to detract from the communicative value of the work. As such, we have some helper classes that make this easy to do. Most visualizations will use color to distinguish elements from each other, or group them with each other for a given series of data. For our column chart we are going to use the LayoutAutoPalette to create a pleasing set of unique colors for each column. The LayoutAutoPalette makes it easy to describe a dynamic range of colors by specifying either an array of colors or a colorFrom and colorTo property that is bound to a specific layout. The LayoutAutoPalette will then dynamically create a unique set of colors based on how many data items are being rendered by the specified layout, and it will use the colors you specify as targets to interpolate the new colors against. Axiis also supports the LayoutPalette, which allows you to specify an array of static colors that will be rotated (via a modulo operation) against the number of items within the data provider of the targeted layout.
Lets add the following code at the bottom of your application file:
<axiis:LayoutAutoPalette id="ap"
colorFrom="0xDD3333"
colorTo="0x3333DD"
layout="{hLayout}"/>
<degrafa:LinearGradientFill id="fill" angle="90">
<degrafa:GradientStop color="{ap.currentColor}"/>
<degrafa:GradientStop color="{ap.currentColor | 0x444444}" alpha=".7"/>
</degrafa:LinearGradientFill>
<degrafa:LinearGradientStroke id="stroke" angle="45">
<degrafa:GradientStop color="{ap.currentColor | 0x444444}"/>
<degrafa:GradientStop color="{ap.currentColor}"/>
</degrafa:LinearGradientStroke>
Then go back to your drawingRectangle and remove the stroke tag and add the fill and stroke properties inline like this:
<degrafa:RegularRectangle
width="{hLayout.currentReference.width}"
height="{vScale.valueToLayout(hLayout.currentValue)}"
x="{hLayout.currentReference.x}"
y="{hLayout.currentReference.height-vScale.valueToLayout(hLayout.currentValue)}"
fill="{fill}"
stroke="{stroke}"/>
For good measure we will also modify our country name label (the first one) by adding this property to its tag:
textColor="{ap.currentColor}"
Now when you launch the application you should be looking at something like this:
In this code we are creating a LinearGradientFill and a LinearGradientStroke, and we are binding the color value of the GradientStops to the LayoutAutoPalette. So as the Layout is looping through its dataProvider and rendering the drawingRectangle, it is also triggering a change in the currentColor of the LayoutAutoPalette which is being used by the two gradients we defined. We also employ a nice little trick with an bitwise OR operator that makes it easy to whiten color values to a hex color as seen in the color="{ap.currentColor | 0x444444}" within the two GradientStop declarations.
With just the use of fills, strokes, and gradients you can create some very elegant and sophisticated styling that will both make your visualizations easier to interpret by your users, but also add a significant aesthetic appeal to them.
All of the examples found at www.axiis.org/examples.html use various combinations of these simple techniques.
Summarizing the Process
I could easily go on and enhance this chart even further with more sophisticated techniques, but I would like to leave that for another article and summarize the steps we have followed thus far to create this column chart. While the chart we have built within this tutorial is a relatively simple, single series chart, the steps we used to build it are universal to building ANY data visualization within Axiis. For your reference here are the steps below.
Import Data in the form of XML or CSV via embedding, remote object call, web service call, , etc.
- Pre-Process data with a DataSet
- Declare one or more Axis scale(s) and set its min/max layout and data values.
- Create a DataCanvas
- Create Background Geometries (axis, grid lines, etc)
- Create (or use a provided) Layout and bind to data
a) Create a Reference Repeater
  b) Create one or more Drawing Geometries to plot your data
  c) Bind your drawing geometries to your reference geometries as needed - Create Fills and Strokes and bind to drawing geometries
For the complete source code of the final chart you can find it here at http://www.axiis.org/examples/ColumnChartTutorial.mxml
But All I Want Are Some Simple Charts
In this tutorial my goal was to demonstrate how you could build a data visualization completely from scratch. But, Axiis has also been designed for people who simply need to place a chart within their application and put some data into it, without worrying about the finer points of creating their own customized data visualization solution from scratch. Axiis can also be used for these more common use cases very easily, and in many cases more easily than other standard charting packages.
You should know also know that Axiis comes with a set of pre-built cartesian “grouping” classes (org.axiis.charts.groupings) that can be used in conjunction with the DataCanvas to build most of the common cartesian charts you are familiar with in most business applications. Groupings are very similar to the series classes you see in other charting packages, with one important additional capability. In Axiis, the grouping classes support a dynamic number of unique series within a grouping based on the data you provide the group. For instance if you look at the example here http://www.axiis.org/examples/HClusterStackExample.html you will see that it leverages two of the grouping classes - ColumnCluster and ColumnStack. Both of these groupings allow you dynamically define how many unique series there will be for a given grouping as seen here:
<groupings:ColumnCluster id="myCluster"
width="{hLayout.currentReference.width*.83}"
height="{hLayout.currentReference.height}"
y="0"
x="0"
dataProvider="{hLayout.currentValue}"
dataField="{childDataField}"
labelField="{childLabelField}"
percentGap=".07"
fill="{clusterFill}"
stroke="{colStroke}"
verticalScale="{vScale}"
fontFamily="Myriad Pro"
fontColor="{outerPalette.currentColor}"/>
Because these groupings themselves are nested within an HBoxLayout, you can easily allow the data to determine how many unique series will be represented. This is something that is usually much more cumbersome to do in more traditional OO charting packages, because either you need to know how many series exist up front, or you need specialized code that dynamically creates series at run time based on your data. When you combine these grouping classes with the Axiis LayoutPalettes it is a rather straightforward affair to create charts and visualizations that can accommodate dynamic data payloads where the number of unique series may change based on the run-time queries used to generate the data.
For more details on how groupings are used, and how you can easily embed common cartesian charts within your applications, please refer to the examples on www.axiis.org. The benefit of starting with the Axiis groupings is that they are very succinct (less than 200 lines) composited MXML components that use the exact same technique described in this article. So if you need to start customizing and extending your charts based on specific project requirements it is very easy to re-factor the groupings into your own custom charting components that can be extended in a myriad of ways.
If you have worked your way through this tutorial and feel comfortable building the column chart described, then customizing the charts and examples that ship with Axiis should be a trivial affair because you understand all of the underlying principles and code needed to create a very customized solution within Axiis.
What is Next
Based on response to this first article I hope to continue this with a series of follow up tutorials that dive into some of the more advanced techniques of building visualizations with Axiis that cover adding user interactions, states, transitions, nested layouts, and more complex manipulation of data. Please post comments and suggestions, and if you are new to Axiis or data visualization let me know how well this article may or may not have helped you to come up to speed.
I will also be speaking about Axiis with Michael VanDaniker, the other founder and author of Axiis, at CFUnited in Leesburg VA, on August 14, and by myself at Adobe MAX October 5th and 6th in Los Angeles. You can also read more about Axiis on my blog at www.twgonzalez.com or Michaels blog at http://michaelvandaniker.com.




Facebook Application Development
Very nice intro to Axiis Tom. I hope to have my Smith Chart example fully completed and ready for you to show off before you head to CFUnited.
http://www.flexjunk.com/2009/05/30/developing-a-smith-chart-using-axiis-and-degrafa/
There's a tremendous amount of power to the framework you and Michael have created with Axiis. The possibilities for unique visualizations and charts are almost limitless.
This is a great introduction to the fundamental concepts of Axiis. I've been working my way through the package for a while with no background in Flex/Actionscript and this answered a lot of my questions.
I'm looking forward to reading articles on all of the subjects you've listed. Especially the complex data manipulation, states, and transitions. Just these well described thoughts have already given me a few ideas of other options for making our data more accessible to our less technical consumers.
Thank you for sharing, Tom!
Does Axiis support automation test like Adobe's Flex visualization components?
@flashflexpro, I am not sure what automation testing you are referring to, but Axiis does not have any intrinsic support for automation testing. We have considered building in a bitmapData testing class, but that probably would not happen for several releases.
Tom, does your framework provide a timeline component? Something in which I can plot an "event" against a time, watch the timeline march forward in time, zoom my timeframe in or out, etc? Degrafa? Perhaps a component from some other framework?
Thanks, Garry
I appreciate your tutorial. Worked on my Mac on the second try... I'm not very good at flex (yet). I hope you continue with more. I would like to see something that was calendar orientated. Like a year of timeline data as a stack of weeks with events shown as markers. For example a weekly preventative workorder. a circle marker for completed. an x for cancelled. Beside the weekly there would be biweekly, monthly, quarterly, etc. Unlike a gantt I don't want time extending off to the left beyond the schedule duration. The week example would have a grid of 7 days in it. A monthly might do a grid of 4 (resolution of 4?). Good for historical review.
again thanks...
the art in the number/presentation is great.
Tom and Michael thank you. Great stuff.
I have spent a few days evaluating Axiis for an imminent project. I quickly solved some problems that I still have to solve using Flare, great (!!!), although ultimately have decided to stick with Flare.
The main reason is that the methodology for Axiis seems to be exactly as you have described here and I could not get it to sit inside the rest of my project's framework (PureMVC) as neatly as Flare does.
The crucial point of no return was the Axis automatically renders where I need to process some data first and then set things like HAxis.__totalMajorTicks to try and get a very specific set of of scale values.
If future versions of Axiis allow developers to throw a list of sorts at a Scale, or Axis, and it have these exact values render using a method call that would be a fantastic win.
Good luck with your great project, I am sure I will be diving into it again sometime.
Gareth
@gareth
thanks for the detailed feeback. There are actually specific events and methods exposed in axiis that let you do exactly what you proposed. Look at the LineSeriesGroup to get an idea of in-process render logic. That said, we have not evaluated Axiis inside PureMVC.
This is an excellent tutorial that really helped me grasp the fundamental concepts and get a sense of the power of Axiis. Thanks so much -- I can't wait to dig in further! One small thing: the tickmarks aren't showing up for me, even when I compile the final version you provided.
Superb tutorial, really got me going in AXIIS and ina very fast way.Thank you Tom.
For some reason i am unsure off, the expression:
y="{hLayout.currentReference.height-vScale.valueToLayout(hLayout.currentValue)}"
was not working for me. I figure you can just subtract the height of the current rectangle from the Layout Height and it worked. something like:
Layout Height - Rect Height
in as3 its like this:
y = "{ hLayout.height - hLayout.currentReference.height}"
Hope this can help someone that bumps into this.
tapping foot, smoking cigarette, awaiting the advanced tutorial ... use with csv.
When I downloaded the zip file, the XML was not well-formed. This won't work with Websphere which needs well-formed XML. I'm trying to use the HClusterStackExample. You have the NestedColumnExample but then it doesn't have aggregate functions. Do you have an example that uses both nested XML and aggregate functions?
@Tate, we are planning on releasing our next version at Adobe MAX, and as such have been busy working on the framework so I am hoping to get back to tutorials after MAX.
@Lynn,
Which XML is malformed? The data? We are also including more robust aggregation functions in the upcoming release of Axiis. Currently you need to have your data in a typical relationship format to perform client side aggregations. But you can also use any of the Flex OLAP classes to do that and just pass the final result to the Layout.
Is it possible to use HTTPService that has XML in it for the data source? It is easier for us to do this but I have not found a way to cast the resulting ResultEvent into a String to be used by the Axiis DataSet.
Fixed my HTTPService problem. I was wondering how you change the fontSize for the name attribute of the XML for the HClusterColumnExample?