The chart controls have a dataProvider property that defines the data for the chart. The data provider creates a level of abstraction between Flex components and the data that you use to populate them. You can populate multiple charts from the same data provider, switch data providers for a chart at run time, and modify the data provider so that changes are reflected by all charts using the data provider.
To use the data from a data provider in your chart control, you map the xField and yField properties of the chart series to the fields in the data provider. The xField property defines the data for the horizontal axis, and the yField property defines the data for the vertical axis.
For example, assume your data provider has the following structure:
{Month: "Feb", Profit: 1000, Expenses: 200, Amount: 60}
You can use the Profit and Expenses fields and ignore the Month field by mapping the xField property of the series object to one field and the yField property of the series object to another field, as the following example shows:
<mx:PlotSeries xField="Profit" yField="Expenses"/>
The result is that each data point is the intersection of the Profit and Expenses fields from the data provider.
To place the data points into a meaningful grouping, you can choose a separate property of the data provider as the categoryField. In this case, to sort each data point by month, you map the Month field to the categoryField property of the horizontal axis:
<mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month"/> </mx:horizontalAxis>
In some cases, depending on the type of chart and the type of data you are representing, you use either the xField property or the yField property to define the data series. In a ColumnChart control, for example, the yField property defines the height of the column. You do not have to specify an xField property. To get an axis label for each column, you specify a categoryField property for the horizontalAxis.
The data provider can contain complex objects, or objects within objects. For example, a data provider object can have the following structure:
{month: "Aug", close: {High:45.87,Low:12.2}, open:25.19}
In this case, you cannot simply refer to the field of the data provider by using a categoryField, xField, or similar flat naming convention. Rather, you use the dataFunction of the series or axis to drill down into the data provider. For more information on working with complex data, see Structure of chart data.
When you use chart data, keep the following in mind:
<mx:ColumnSeries dataProvider="{[1,2,3,4,5]}"/>
For a complete list of the fields that each data series can use, see the data series entry in Adobe Flex Language Reference. For more information on data providers, see Data provider controls.
You can supply data to a data provider in the following ways:
There are some limitations on the structure of the chart data, and how to reference chart data if it is constructed with complex objects. For more information, see Structure of chart data.
For more information on data providers, see Using Data Providers and Collections.
Using a static Array of objects for the data provider is the simplest approach. You typically create an Array of objects, as the following example shows:
<?xml version="1.0"?> <!-- charts/ArrayOfObjectsDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var expenses:Array = [ {Month:"January",Profit:2000,Expenses:1500,Amount:450}, {Month:"February",Profit:1000,Expenses:200,Amount:600}, {Month:"March",Profit:1500,Expenses:500,Amount:300}, {Month:"April",Profit:500,Expenses:300,Amount:500}, {Month:"May",Profit:1000,Expenses:450,Amount:250}, {Month:"June",Profit:2000,Expenses:500,Amount:700} ]; ]]></mx:Script> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can also use MXML to define the content of an Array, as the following example shows:
<?xml version="1.0"?> <!-- charts/ArrayOfMXMLObjectsDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Array id="expenses"> <mx:Object Month="January" Profit="2000" Expenses="1500" Amount="450" /> <mx:Object Month="February" Profit="1000" Expenses="200" Amount="600" /> <mx:Object Month="March" Profit="1500" Expenses="500" Amount="300" /> <mx:Object Month="April" Profit="500" Expenses="300" Amount="500" /> <mx:Object Month="May" Profit="1000" Expenses="450" Amount="250" /> <mx:Object Month="June" Profit="2000" Expenses="500" Amount="700" /> </mx:Array> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can also define objects in MXML with a more verbose syntax, as the following example shows:
<?xml version="1.0"?> <!-- charts/ArrayOfVerboseMXMLObjects.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Array id="expenses"> <mx:Object> <mx:Month>January</mx:Month> <mx:Profit>2000</mx:Profit> <mx:Expenses>1500</mx:Expenses> <mx:Amount>450</mx:Amount> </mx:Object> <mx:Object> <mx:Month>February</mx:Month> <mx:Profit>1000</mx:Profit> <mx:Expenses>200</mx:Expenses> <mx:Amount>600</mx:Amount> </mx:Object> <mx:Object> <mx:Month>March</mx:Month> <mx:Profit>1500</mx:Profit> <mx:Expenses>500</mx:Expenses> <mx:Amount>300</mx:Amount> </mx:Object> <mx:Object> <mx:Month>April</mx:Month> <mx:Profit>500</mx:Profit> <mx:Expenses>300</mx:Expenses> <mx:Amount>300</mx:Amount> </mx:Object> <mx:Object> <mx:Month>May</mx:Month> <mx:Profit>1000</mx:Profit> <mx:Expenses>450</mx:Expenses> <mx:Amount>250</mx:Amount> </mx:Object> <mx:Object> <mx:Month>June</mx:Month> <mx:Profit>2000</mx:Profit> <mx:Expenses>500</mx:Expenses> <mx:Amount>700</mx:Amount> </mx:Object> </mx:Array> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
A disadvantage of using a simple Array as a chart's data provider is that you can use only the methods of the Array class to manipulate the data. In addition, when you use an Array as a data provider, the data in it must be static. Even if you make the Array bindable, when data in an Array changes, the chart does not reflect those changes. For more robust data manipulation and data binding, you can use a collection for the chart data provider, as described in Using collections as data providers.
Collections are a more robust data provider mechanism than Arrays. They provide operations that include the insertion and deletion of objects as well as sorting and filtering. Collections also support change notification. An ArrayCollection object provides an easy way to expose an Array as an ICollectionView or IList interface.
As with Arrays, you can use MXML to define the contents of a collection, as the following example shows:
<?xml version="1.0"?> <!-- charts/ArrayCollectionOfMXMLObjectsDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:ArrayCollection id="expenses"> <mx:Object Month="January" Profit="2000" Expenses="1500" Amount="450" /> <mx:Object Month="February" Profit="1000" Expenses="200" Amount="600" /> <mx:Object Month="March" Profit="1500" Expenses="500" Amount="300" /> <mx:Object Month="April" Profit="500" Expenses="300" Amount="500" /> <mx:Object Month="May" Profit="1000" Expenses="450" Amount="250" /> <mx:Object Month="June" Profit="2000" Expenses="500" Amount="700" /> </mx:ArrayCollection> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
Or you can define an object in MXML usig child tags rather than attributes:
<?xml version="1.0"?> <!-- charts/ArrayCollectionOfVerboseMXMLObjects.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:ArrayCollection id="expenses"> <mx:Object> <mx:Month>January</mx:Month> <mx:Profit>2000</mx:Profit> <mx:Expenses>1500</mx:Expenses> <mx:Amount>450</mx:Amount> </mx:Object> <mx:Object> <mx:Month>February</mx:Month> <mx:Profit>1000</mx:Profit> <mx:Expenses>200</mx:Expenses> <mx:Amount>600</mx:Amount> </mx:Object> <mx:Object> <mx:Month>March</mx:Month> <mx:Profit>1500</mx:Profit> <mx:Expenses>500</mx:Expenses> <mx:Amount>300</mx:Amount> </mx:Object> <mx:Object> <mx:Month>April</mx:Month> <mx:Profit>500</mx:Profit> <mx:Expenses>300</mx:Expenses> <mx:Amount>300</mx:Amount> </mx:Object> <mx:Object> <mx:Month>May</mx:Month> <mx:Profit>1000</mx:Profit> <mx:Expenses>450</mx:Expenses> <mx:Amount>250</mx:Amount> </mx:Object> <mx:Object> <mx:Month>June</mx:Month> <mx:Profit>2000</mx:Profit> <mx:Expenses>500</mx:Expenses> <mx:Amount>700</mx:Amount> </mx:Object> </mx:ArrayCollection> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can create an ArrayCollection object in ActionScript. If you define an ArrayCollection in this way, ensure that you import the mx.collections.ArrayCollection class, as the following example shows:
<?xml version="1.0"?> <!-- charts/ArrayCollectionOfObjects.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var expenses:ArrayCollection = new ArrayCollection([ {Month:"January", Profit:2000, Expenses:1500, Amount:450}, {Month:"February", Profit:1000, Expenses:200, Amount:600}, {Month:"March", Profit:1500, Expenses:500, Amount:300}, {Month:"April", Profit:500, Expenses:300, Amount:500}, {Month:"May", Profit:1000, Expenses:450, Amount:250}, {Month:"June", Profit:2000, Expenses:500, Amount:700} ]); ]]></mx:Script> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expenses}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expenses}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
If your data is in an Array, you can pass the Array to the ArrayCollection's constructor to convert it to an ArrayCollection. The following example creates an Array, and then converts it to an ArrayCollection:
<?xml version="1.0"?> <!-- charts/ArrayConvertedToArrayCollection.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; private var expenses:Array = [ {Month:"January", Profit:2000, Expenses:1500, Amount:450}, {Month:"February", Profit:1000, Expenses:200, Amount:600}, {Month:"March", Profit:1500, Expenses:500, Amount:300}, {Month:"April", Profit:500, Expenses:300, Amount:500}, {Month:"May", Profit:1000, Expenses:450, Amount:250}, {Month:"June", Profit:2000, Expenses:500, Amount:700} ]; [Bindable] public var expensesAC:ArrayCollection = new ArrayCollection(expenses); ]]></mx:Script> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expensesAC}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expensesAC}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
Similarly, you can use an <mx:ArrayCollection> tag to perform the conversion:
<?xml version="1.0"?> <!-- charts/ArrayConvertedToArrayCollectionMXML.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] private var expenses:Array = [ {Month:"January", Profit:2000, Expenses:1500, Amount:450}, {Month:"February", Profit:1000, Expenses:200, Amount:600}, {Month:"March", Profit:1500, Expenses:500, Amount:300}, {Month:"April", Profit:500, Expenses:300, Amount:500}, {Month:"May", Profit:1000, Expenses:450, Amount:250}, {Month:"June", Profit:2000, Expenses:500, Amount:700} ]; ]]></mx:Script> <mx:ArrayCollection id="expensesAC" source="{expenses}"/> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{expensesAC}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{expensesAC}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Month" yField="Profit" displayName="Profit" /> <mx:ColumnSeries xField="Month" yField="Expenses" displayName="Expenses" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
The data in ArrayCollections can be bound to the chart's data provider so that the data can be updated in real-time. The following example creates an object with elapsed time and total memory usage every second. It then pushes that new object onto an ArrayCollection that is used as the data provider for a line chart. As a result, the chart itself updates every second showing memory usage of Adobe® Flash® Player or Adobe® AIR™ over time.
<?xml version="1.0"?> <!-- charts/RealTimeArrayCollection.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize= "initTimer()"> <mx:Script><![CDATA[ import flash.utils.Timer; import flash.events.TimerEvent; import mx.collections.ArrayCollection; [Bindable] public var memoryUsage:ArrayCollection = new ArrayCollection(); public function initTimer():void { // The first parameter in the Timer constructor // is the interval, in milliseconds. // The second parameter is how many times to run (0 is // infinity). var myTimer:Timer = new Timer(1000, 0); // Add the listener for the timer event. myTimer.addEventListener("timer", timerHandler); myTimer.start(); } public function timerHandler(event:TimerEvent):void { var o:Object = new Object(); // Get the number of milliseconds since Flash Player or AIR started. o.time = getTimer(); // Get the total memory Flash Player or AIR is using. o.memory = flash.system.System.totalMemory; trace(o.time + ":" + o.memory); // Add new object to the ArrayCollection, which is bound // to the chart's data provider. memoryUsage.addItem(o); } ]]></mx:Script> <mx:LineChart id="chart" dataProvider="{memoryUsage}" showDataTips="true"> <mx:horizontalAxis> <mx:LinearAxis/> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis minimum="5000000"/> </mx:verticalAxis> <mx:series> <mx:LineSeries yField="memory"/> </mx:series> </mx:LineChart> </mx:Application>The executing SWF file for the previous example is shown below:
Data collections can be paged, which means that data is sent to the client in chunks as the application requests it. But Flex charting controls display all of the data all of the time, by default. As a result, when you use data collections with charts, you should disable the paging features or use non-paged views of the data collection for chart data. For more information on using collections, see Using Data Providers and Collections.
You can define data provider data in a structured file. The following example shows the contents of the data.xml file:
<data> <result month="Jan-04"> <apple>81768</apple> <orange>60310</orange> <banana>43357</banana> </result> <result month="Feb-04"> <apple>81156</apple> <orange>58883</orange> <banana>49280</banana> </result> </data>
You can load the file directly as a source of a Model, as the following example shows:
<?xml version="1.0"?> <!-- charts/XMLFileDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Model id="results" source="../assets/data.xml"/> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{results.result}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis categoryField="month"/> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="banana" displayName="Banana"/> <mx:LineSeries yField="apple" displayName="Apple"/> <mx:LineSeries yField="orange" displayName="Orange"/> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can use more complex XML to define the data provider's data. For example, an XML-based data provider can have nested tags. In that case, however, you must use a dataFunction to define the fields that the chart uses. For more information, see Structure of chart data.
To use an ArrayCollection as the chart's data provider, you convert the Model to an ArrayCollection, as the following example shows:
<?xml version="1.0"?> <!-- charts/XMLFileToArrayCollectionDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"> <mx:Script> import mx.utils.ArrayUtil; </mx:Script> <mx:Model id="results" source="../assets/data.xml"/> <mx:ArrayCollection id="myAC" source="{ArrayUtil.toArray(results.result)}" /> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{myAC}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis categoryField="month"/> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="banana" displayName="Banana"/> <mx:LineSeries yField="apple" displayName="Apple"/> <mx:LineSeries yField="orange" displayName="Orange"/> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can also define the XML file as a URL for an HTTPService component, and then bind the HTTPService result directly to the chart's data provider, as the following example shows:
<?xml version="1.0"?> <!-- charts/HTTPServiceDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" creationComplete="srv.send()"> <mx:HTTPService id="srv" url="../assets/data.xml"/> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{srv.lastResult.data.result}" showDataTips="true" > <mx:horizontalAxis> <mx:CategoryAxis categoryField="month"/> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/> <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/> <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
To use an ArrayCollection, you convert the HTTPService result to an ArrayCollection, as the following example shows:
<?xml version="1.0"?> <!-- charts/HTTPServiceToArrayCollectionDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="srv.send()"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] public var myData:ArrayCollection; ]]></mx:Script> <mx:HTTPService id="srv" url="assets/data.xml" useProxy="false" result="myData=ArrayCollection(srv.lastResult.data.result)" /> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{myData}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis categoryField="month"/> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/> <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/> <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
You can also set the result format of the HTTPService to E4X, and then use it as a source for an XMLListCollection object, as the following example shows:
<?xml version="1.0"?> <!-- charts/HTTPServiceToXMLListCollection.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="srv.send()"> <mx:Script><![CDATA[ import mx.utils.ArrayUtil; ]]></mx:Script> <mx:HTTPService id="srv" url="assets/data.xml" resultFormat="e4x" /> <mx:XMLListCollection id="myAC" source="{srv.lastResult.result}" /> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{myAC}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis categoryField="month"/> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="apple" displayName="Apple" name="Apple"/> <mx:LineSeries yField="orange" displayName="Orange" name="Orange"/> <mx:LineSeries yField="banana" displayName="Banana" name="Banana"/> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
A useful way to create data for use in sample charts is to generate random data. The following example generates test data for use with the chart controls:
<?xml version="1.0"?> <!-- charts/RandomDataGeneration.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initApp()"> <mx:Script><![CDATA[ import mx.collections.*; // Define data provider array for the chart data. [Bindable] public var dataSet:ArrayCollection; // Define the number of elements in the array. public var dsLength:Number = 10; public function initApp():void { // Initialize data provider array. dataSet = new ArrayCollection(genData()); } public function genData():Array { var result:Array = []; for (var i:int=0;i<dsLength;i++) { var localVals:Object = { valueA:Math.random()*100, valueB:Math.random()*100, valueX:Math.random()*100, valueY:Math.random()*100 }; // Push new object onto the data array. result.push(localVals); } return result; } ]]></mx:Script> <mx:Panel title="Plot Chart"> <mx:PlotChart id="myChart" dataProvider="{dataSet}" showDataTips="true"> <mx:series> <mx:PlotSeries xField="valueX" yField="valueY" displayName="Series 1" /> <mx:PlotSeries xField="valueA" yField="valueB" displayName="Series 2" /> </mx:series> </mx:PlotChart> <mx:Legend id="l1" dataProvider="{myChart}"/> </mx:Panel> </mx:Application>The executing SWF file for the previous example is shown below:
In most cases, the data that is used as the chart's data provider is made up of scalar values. For example, objects contain a single set of fields:
{month: "Aug", close: 45.87, open:25.19},
Or XML data contains a single set of child tags in a flat structure:
<stock> <month>Aug</month> <close>45.87</close> <open>25.19</open> </stock>
In these cases, you assign the data provider's fields to items in the chart by using the xField and yField for the series, or the categoryField for the axis; for example:
<mx:ColumnSeries yField="close"/> <mx:CategoryAxis categoryField="month"/>
However, the structure of the chart data can be made up of more complex objects, such as objects within objects or XML with nested child tags. For example, you can embed an object within an object:
{month: "Aug", close: {High:45.87,Low:12.2}, open:25.19}
Or use nested tags in an XML object:
<stock> <date> <month>Aug</month> </date> <price> <close>45.87</close> <open>25.19</open> </price> </stock>
In these cases, you cannot refer to the target data by using the flat naming such as yField="close". You also cannot use dot notation. For example, yField="values.close" or categoryField="data.month" are not valid. Instead, you must use a dataFunction method to define which ChartItem fields are populated by the data provider.
For the CategoryAxis class, the dataFunction has the following signature:
function_name(axis:AxisBase, item:Object):Object
Where axis is the base class for the current axis, and item is the item in the data provider.
For the Series class, the dataFunction has the following signature:
function_name(series:Series, item:Object, fieldName:String):Object
Where series is a reference to the current series, item is the item in the data provider, and fieldName is the field in the current ChartItem that will be populated.
The following example creates two functions that access complex data for both the axis and the series:
<?xml version="1.0"?> <!-- charts/DataFunctionExample.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%"> <mx:Script><![CDATA[ import mx.charts.chartClasses.AxisBase; import mx.charts.chartClasses.Series; import mx.charts.CategoryAxis; import mx.charts.chartClasses.IAxis; import mx.charts.chartClasses.ChartBase; import mx.charts.chartClasses.CartesianTransform; // This data provider contains complex, nested objects. [Bindable] public var SMITH:Array = [ {month: "Aug", close: {High:45.87,Low:12.2}, open:25.19}, {month: "Sep", close: {High:45.74,Low:10.23}, open:35.29}, {month: "Oct", close: {High:45.77,Low:12.13}, open:45.19}, {month: "Nov", close: {High:46.06,Low:10.45}, open:15.59}, ]; private function dataFunc(series:Series, item:Object, fieldName:String):Object { trace("fieldName: " + fieldName); if(fieldName == "yValue" && series.id=="highClose") return(item.close.High); else if(fieldName == "yValue" && series.id=="lowClose") return(item.close.Low); else if(fieldName == "xValue") return(item.month); else return null; } private function catFunc(axis:AxisBase, item:Object):Object { for (var s:String in item) { trace(s + ":" + item[s]); } return(item.month); } ]]></mx:Script> <mx:ColumnChart id="chart" dataProvider="{SMITH}" showDataTips="true" width="100%" height="100%" > <mx:horizontalAxis> <!-- The dataFunction replaces "categoryField='month'. --> <mx:CategoryAxis id="h1" dataFunction="catFunc"/> </mx:horizontalAxis> <mx:series> <!-- The dataFunction replaces yField value, which cannot drill down into an object (close.High is not valid). --> <mx:ColumnSeries id="highClose" displayName="Close (High)" dataFunction="dataFunc" /> <!-- The dataFunction replaces yField value, which cannot drill down into an object (close.Low is not valid). --> <mx:ColumnSeries id="lowClose" displayName="Close (Low)" dataFunction="dataFunc" /> </mx:series> </mx:ColumnChart> </mx:Application>The executing SWF file for the previous example is shown below:
Using ActionScript, you can change a charting control's data at run time by using a variety of methods.
You can change a chart or a series data provider. The following example binds the data provider to a local variable. It then toggles the chart's data provider using that local variable when the user clicks the button.
<?xml version="1.0"?> <!-- charts/ChangeDataProvider.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] public var expenses:ArrayCollection = new ArrayCollection([ {Month:"Jan", Profit:2000, Expenses:1500, Amount:450}, {Month:"Feb", Profit:1000, Expenses:200, Amount:600}, {Month:"Mar", Profit:1500, Expenses:500, Amount:300} ]); [Bindable] public var expenses2:ArrayCollection = new ArrayCollection([ {Month:"Jan", Profit:2400, Expenses:1509, Amount:950}, {Month:"Feb", Profit:3000, Expenses:2200, Amount:400}, {Month:"Mar", Profit:3500, Expenses:1200, Amount:200} ]); [Bindable] public var dp:ArrayCollection = expenses; public function changeDataProvider():void { if (dp==expenses) { dp = expenses2; } else { dp = expenses; } } ]]></mx:Script> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{dp}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{dp}" categoryField="Month" /> </mx:horizontalAxis> <mx:series> <mx:LineSeries yField="Profit" displayName="Profit" /> <mx:LineSeries yField="Expenses" displayName="Expenses" /> <mx:LineSeries yField="Amount" displayName="Amount" /> </mx:series> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> <mx:Button id="b1" label="Change Data Provider" click="changeDataProvider()" /> </mx:Application>The executing SWF file for the previous example is shown below:
You can add or remove a data point from a series. The following example adds an item to the existing data provider when the user clicks the button:
<?xml version="1.0"?> <!-- charts/AddDataItem.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] public var dpac:ArrayCollection = new ArrayCollection([ {A:2000}, {A:3000}, {A:4000}, {A:4000}, {A:3000}, {A:2000}, {A:6000} ]); public function addDataItem():void { var o:Object = {"A":2000}; dpac.addItem(o); } private function removeItem():void { var i:int = dpac.length; if (i > 0) { dpac.removeItemAt(i - 1); } } ]]></mx:Script> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" showDataTips="true" height="400" width="600" dataProvider="{dpac}" > <mx:series> <mx:ColumnSeries yField="A" displayName="Series 1"/> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> <mx:HBox> <mx:Button label="Add Data Item" click="addDataItem();"/> <mx:Button label="Remove Data Item" click="removeItem();"/> </mx:HBox> </mx:Application>The executing SWF file for the previous example is shown below:
You can also change the fields of a series to change chart data at run time. You do this by changing the value of the data provider field (such as xField or yField) on the series object. To get a reference to the series, you use the series' id property or the chart control's series index. The following example toggles the data series when the user clicks on the Change Series button:
<?xml version="1.0"?> <!-- charts/ToggleSeries.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize= "initApp();"> <mx:Script><![CDATA[ [Bindable] public var dataSet:Array; public var myStates:Array = ["Wisconsin","Ohio","Arizona","Penn"]; public var curSeries:String; public function initApp():void { var newData:Array = []; for(var i:int=0;i<myStates.length;i++) { newData[i] = { Apples: Math.floor(Math.random()*150), Oranges: Math.floor(Math.random()*150), myState: myStates[i] } } dataSet = newData; curSeries = "apples"; } public function changeData():void { var series:Object = myChart.series[0]; if (curSeries == "apples") { curSeries="oranges"; series.yField = "Oranges"; series.displayName = "Oranges"; series.setStyle("fill",0xFF9933); } else { curSeries="apples"; series.yField = "Apples"; series.displayName = "Apples"; series.setStyle("fill",0xFF0000); } } ]]></mx:Script> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{dataSet}" showDataTips="true" > <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{dataSet}" categoryField="myState" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries yField="Apples" displayName="Apples" > <mx:fill> <mx:SolidColor color="0xFF0000"/> </mx:fill> </mx:ColumnSeries> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> <mx:Button id="b1" label="Toggle Series" click="changeData()" /> </mx:Application>The executing SWF file for the previous example is shown below:
You can take advantage of data binding to make your chart reflect data changes in real time. The following example uses a Timer to define the intervals at which it checks for new data. Because the chart's data provider is bound to an ArrayCollection, whenever a new data point is added to the collection, the chart is automatically updated.
<?xml version="1.0"?> <!-- charts/WatchingCollections.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize="initData();"> <mx:Script><![CDATA[ import mx.collections.ArrayCollection; [Bindable] public var dataSet:ArrayCollection; [Bindable] public var revenue:Number = 100; private var t:Timer; private function initData():void { dataSet = new ArrayCollection(); t = new Timer(500); } private function startApp():void { t.addEventListener(TimerEvent.TIMER, addData); t.start(); } private function addData(e:Event):void { /* Add a maximum of 100 data points before user has to click the Start button again. */ if (dataSet.length > 100) { stopApp(); } dataSet.addItem( { revenue: revenue } ); revenue += Math.random() * 10 - 5; } private function stopApp():void { t.stop(); t.removeEventListener(TimerEvent.TIMER, addData); } ]]></mx:Script> <mx:SeriesInterpolate id="interp" elementOffset="0" duration="300" minimumElementDuration="0" /> <mx:Panel title="Line Chart"> <mx:LineChart id="myChart" dataProvider="{dataSet}"> <mx:series> <mx:LineSeries yField="revenue" showDataEffect="{interp}" displayName="Revenue" /> </mx:series> <mx:horizontalAxis> <mx:LinearAxis autoAdjust="false"/> </mx:horizontalAxis> </mx:LineChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> <mx:HBox> <mx:Button id="b1" label="Start" click="startApp()"/> <mx:Button id="b2" label="Stop" click="stopApp()"/> </mx:HBox> </mx:Application>The executing SWF file for the previous example is shown below:
You can also use system values to update charts at run time. The following example tracks the value of the totalMemory property in a LineChart control in real time:
<?xml version="1.0"?> <!-- charts/MemoryGraph.mxml --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" initialize= "initTimer()"> <mx:Script><![CDATA[ import flash.utils.Timer; import flash.events.TimerEvent; import mx.collections.ArrayCollection; [Bindable] public var memoryUsage:ArrayCollection = new ArrayCollection(); public function initTimer():void { // The first parameter in the Timer constructor // is the interval, in milliseconds. The second // parameter is how many times to run (0 is // infinity). var myTimer:Timer = new Timer(1000, 0); // Add the listener for the timer event. myTimer.addEventListener("timer", timerHandler); myTimer.start(); } public function timerHandler(event:TimerEvent):void { var o:Object = new Object(); // Get the number of milliseconds since Flash // Player started. o.time = getTimer(); // Get the total memory Flash Player is using. o.memory = flash.system.System.totalMemory; // Add new object to the ArrayCollection, which // is bound to the chart's data provider. memoryUsage.addItem(o); } ]]></mx:Script> <mx:LineChart id="chart" dataProvider="{memoryUsage}" showDataTips="true" > <mx:horizontalAxis> <mx:LinearAxis/> </mx:horizontalAxis> <mx:verticalAxis> <mx:LinearAxis minimum="5000000"/> </mx:verticalAxis> <mx:series> <mx:Array> <mx:LineSeries yField="memory"/> </mx:Array> </mx:series> </mx:LineChart> </mx:Application>The executing SWF file for the previous example is shown below:
Hello,
Not very clear on how this works. Some assistance in documentation towards explaining this should be great:
<mx:Month>May</mx:Month>
<mx:Profit>1000</mx:Profit>
<mx:Expenses>450</mx:Expenses>
<mx:Amount>250</mx:Amount>
The tags Profit, Expenses etc are not defined as tags in the standard MXML Namespace. But the code compiles fine and does not through exception.
These are properties of the Object tag that contains them. Objects are dynamic, so you can add whatever properties you want to them. If you look at the example right above the one you're commenting on, you can see it has pretty much the identical code without using the mx namespace.
For the HTTPServiceToXMLListCollection example, you need to change the categoryField from "month" to "@month". This is required to access the properties properly with XML.
matt horn
flex docs
Hey All,
Very well explained doc.
I just wanted to know as to how can we include a scroll bar in the line chart wit the x axis.
Assume that My line chart has lots of data and it becomes messy to view the same, if there would be a scrollbar it would be real great.
Thanks,
Nimesh
Nimesh Sharma,
I'm sorry, I don't know the answer to your question. In general, you will get faster and better responses to questions like this by posting them to the Adobe Flex Forums or the Flexcoders Yahoo group. These sites receive much more traffic than single pages in the Flex online documentation.
Best regards,
Randy Nielsen
Flex Documentation Manager
Adobe Systems Incorporated
How does one use a web service to populate the data of a column chart?
Mike Marcavage,
You would use mx:WebService in a way similar to the mx:HTTPService example, about halfway down the page.
ref:http://livedocs.adobe.com/flex/3/html/charts_intro_8.html