Stacking charts

When you use multiple data series in the AreaChart, BarChart, and ColumnChart controls, you can control how Flex displays the series using the type property of the controls. The following table describes the values that the type property supports:

Property

Description

clustered

Chart elements for each series are grouped by category. This is the default value for BarChart and ColumnChart controls.

overlaid

Chart elements for each series are rendered on top of each other, with the element corresponding to the last series on top. This is the default value for AreaChart controls.

stacked

Chart elements for each series are stacked on top of each other. Each element represents the cumulative value of the elements beneath it.

100%

Chart elements are stacked on top of each other, adding up to 100%. Each chart element represents the percentage that the value contributes to the sum of the values for that category.

The following example creates an AreaChart control that has four data series, stacked on top of each other:

<?xml version="1.0"?>
<!-- charts/AreaStacked.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    creationComplete="srv.send()"
    height="600">
    
    <fx:Declarations>
        <!-- View source of the following page to see the structure of the data that Flex uses in this example. -->
        <mx:HTTPService id="srv" url="http://aspexamples.adobe.com/chart_examples/expenses-xml.aspx"/>
        <!-- To see data in an HTML table, go to http://aspexamples.adobe.com/chart_examples/expenses.aspx -->  
    </fx:Declarations>

    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

  <s:Panel title="Stacked AreaChart">
        <s:layout>
            <s:VerticalLayout/>
        </s:layout>
     <mx:AreaChart id="myChart"
        dataProvider="{srv.lastResult.data.result}" 
        showDataTips="true" 
        type="stacked">
        <mx:horizontalAxis>
           <mx:CategoryAxis categoryField="Month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:AreaSeries yField="profit" displayName="Profit"/>
           <mx:AreaSeries yField="expenses" displayName="Expenses"/>
           <mx:AreaSeries yField="amount" displayName="Amount"/>
        </mx:series>
     </mx:AreaChart>
     <mx:Legend dataProvider="{myChart}"/>
  </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

The following example shows a stacked AreaChart control:

A stacked AreaChart control.

With an overlay, the last series appears on top, and can obscure the data series below it unless you use the alpha property of the fill to make it transparent. For more information, see Using fills with chart controls.

If you set the type property to 100%, the control draws each series stacked on top of each other, adding up to 100% of the area. Each column represents the percentage that the value contributes to the sum of the values for that category, as the following example shows:

An AreaChart control in which each series is stacked on top of each other, adding up to 100% of the area.

You can use the ColumnSet, BarSet, and AreaSet classes to combine groups of chart series, and thereby use different types of series within the same chart. The following example uses BarSet classes to combine clustered and stacked BarSeries in a single chart. The example shows how to do this in MXML and ActionScript:

<?xml version="1.0"?>
<!-- charts/UsingBarSets.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    creationComplete="initApp()"
    height="1050" width="600">

    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

  <fx:Script><![CDATA[
     import mx.charts.Legend;
     import mx.charts.BarChart;
     import mx.charts.series.BarSet;
     import mx.charts.series.BarSeries;
     import mx.collections.ArrayCollection;

     [Bindable]
     private var yearlyData:ArrayCollection = new ArrayCollection([
        {month:"January", revenue:120, costs:45,
            overhead:102, oneTime:23},
        {month:"February", revenue:108, costs:42,
            overhead:87, oneTime:47},
        {month:"March", revenue:150, costs:82,
            overhead:32, oneTime:21},
        {month:"April", revenue:170, costs:44,
            overhead:68},
        {month:"May", revenue:250, costs:57,
            overhead:77, oneTime:17},
        {month:"June", revenue:200, costs:33,
            overhead:51, oneTime:30},
        {month:"July", revenue:145, costs:80,
            overhead:62, oneTime:18},
        {month:"August", revenue:166, costs:87,
            overhead:48},
        {month:"September", revenue:103, costs:56,
            overhead:42},
        {month:"October", revenue:140, costs:91,
            overhead:45, oneTime:60},
        {month:"November", revenue:100, costs:42,
            overhead:33, oneTime:67},
        {month:"December", revenue:182, costs:56,
            overhead:25, oneTime:48},
        {month:"May", revenue:120, costs:57,
            overhead:30}
     ]);

     private function initApp():void {
        var c:BarChart = new BarChart();
        c.dataProvider = yearlyData;
        c.showDataTips = true;

        var vAxis:CategoryAxis = new CategoryAxis();
        vAxis.categoryField = "month";
        c.verticalAxis = vAxis;

        var mySeries:Array = new Array();

        var outerSet:BarSet = new BarSet();
        outerSet.type = "clustered";
        var series1:BarSeries = new BarSeries();
        series1.xField = "revenue";
        series1.displayName = "Revenue";
        outerSet.series = [series1];

        var innerSet:BarSet = new BarSet();
        innerSet.type = "stacked";
        var series2:BarSeries = new BarSeries();
        var series3:BarSeries = new BarSeries();
        series2.xField = "costs";
        series2.displayName = "Recurring Costs";
        series3.xField = "oneTime";
        series3.displayName = "One-Time Costs";
        innerSet.series = [series2, series3];

        c.series = [outerSet, innerSet];

        var l:Legend = new Legend();
        l.dataProvider = c;

        panel2.addElement(c);
        panel2.addElement(l);
     }
  ]]></fx:Script>

  <s:Panel title="Mixed Sets Chart Created in MXML" id="panel1">
     <s:layout>
         <s:HorizontalLayout/>
     </s:layout>
     <mx:BarChart id="myChart" 
        dataProvider="{yearlyData}" showDataTips="true">
        <mx:verticalAxis>
            <mx:CategoryAxis categoryField="month"/>
        </mx:verticalAxis>
        <mx:series>
            <mx:BarSet type="clustered">
                <mx:BarSeries xField="revenue" 
                    displayName="Revenue"/>
                <mx:BarSet type="stacked">
                    <mx:BarSeries 
                        xField="costs" 
                        displayName="Recurring Costs"/>
                    <mx:BarSeries 
                        xField="oneTime" 
                        displayName="One-Time Costs"/>
                </mx:BarSet>
            </mx:BarSet>
        </mx:series>
     </mx:BarChart>
     <mx:Legend dataProvider="{myChart}"/>
  </s:Panel>
  <s:Panel title="Mixed Sets Chart Created in ActionScript" id="panel2">
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>  
  </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

The resulting chart shows two clustered series; one is a standalone series, and the other is a stacked series, as the following example shows:

Two clustered series; one is a standalone series, and the other is a stacked series.

Normally, the values in stacked series are additive, which means that they are all added to one another to create an ever larger data item (column or bar or area). When one or more values is negative, the rendering of the data items can be unpredictable because adding a negative value would normally take away from the data item. You can also use the allowNegativeForStacked property of the AreaSet, BarSet, and ColumnSet classes to let a stacked series include data with negative values, and thereby render negative data items that are properly stacked.

The following example stacks the Profit and Expenses fields, in which some of the values are negative.

<?xml version="1.0"?>
<!-- charts/StackedNegative.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    height="600">

  <fx:Script><![CDATA[
     import mx.collections.ArrayCollection;
     [Bindable]
     public var expenses:ArrayCollection = new ArrayCollection([
        {Month:"Jan", Profit:-2000, Expenses:-1500},
        {Month:"Feb", Profit:1000, Expenses:-200},
        {Month:"Mar", Profit:1500, Expenses:-500}
     ]);
  ]]></fx:Script>

    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

  <s:Panel title="Column Chart">
     <s:layout>
         <s:HorizontalLayout/>
     </s:layout>
     <mx:ColumnChart id="myChart" 
        dataProvider="{expenses}" 
        showDataTips="true">
        <mx:horizontalAxis>
           <mx:CategoryAxis 
                dataProvider="{expenses}" 
                categoryField="Month"/>
        </mx:horizontalAxis>
        <mx:series>
            <mx:ColumnSet type="stacked" 
                allowNegativeForStacked="true">
                <mx:series>
                    <mx:ColumnSeries 
                        xField="Month" 
                        yField="Profit" 
                        displayName="Profit"/>
                    <mx:ColumnSeries 
                        xField="Month" 
                        yField="Expenses" 
                        displayName="Expenses"/>
                </mx:series>
            </mx:ColumnSet>           
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below:

The resulting chart shows three months of data, with all expenses and some income data rendering in negative values:

A ColumnChart control in which some columns render in negative values.

You can create cascading or waterfall column charts by using the ColumnChart control. One way to do this is to create an invisible series and to use that to set the variable height of the other columns, creating the waterfall effect. The following is an example of a waterfall chart:

A waterfall or cascading column chart.

The following code creates this chart:

<?xml version="1.0"?>
<!-- charts/WaterfallStacked.mxml -->
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:mx="library://ns.adobe.com/flex/mx" 
    xmlns:s="library://ns.adobe.com/flex/spark"
    height="600">
  
  <fx:Script><![CDATA[
     import mx.collections.ArrayCollection;
     [Bindable]
     public var expenses:ArrayCollection = new ArrayCollection([
        {Month:"2005", top:25, middle:20, bottom:17, Invisible:0},
        {Month:"Jan", top:14, middle:12, bottom:10, Invisible:62},
        {Month:"Feb", top:8, middle:6, bottom:4, Invisible:98},
        {Month:"Mar", top:6, middle:5, bottom:5, Invisible:116},
        {Month:"Apr", top:5, middle:4, bottom:4, Invisible:132},
        {Month:"May", top:5, middle:3, bottom:5, Invisible:140},
        {Month:"Jun", top:4, middle:3, bottom:2, Invisible:155},
        {Month:"2006", top:68, middle:57, bottom:39, Invisible:0}
     ]);
  ]]></fx:Script>
  
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>

  <s:Panel title="Stacked Waterfall">
     <s:layout>
         <s:HorizontalLayout/>
     </s:layout>
     <mx:ColumnChart id="myChart"
        dataProvider="{expenses}"
        columnWidthRatio=".9"
        showDataTips="true"
        type="stacked">
        <mx:horizontalAxis>
           <mx:CategoryAxis
                dataProvider="{expenses}"
                categoryField="Month"/>
        </mx:horizontalAxis>
        <mx:series>
           <mx:ColumnSeries yField="Invisible">
                <mx:fill>
                    <!--Set alpha to 0 to hide invisible column.-->
                    <mx:SolidColor color="0xFFFFFF" alpha="0"/>
                </mx:fill>
           </mx:ColumnSeries>
           <mx:ColumnSeries yField="bottom" displayName="Profit"/>
           <mx:ColumnSeries yField="middle" displayName="Expenses"/>
           <mx:ColumnSeries yField="top" displayName="Profit"/>
        </mx:series>
     </mx:ColumnChart>
     <mx:Legend dataProvider="{myChart}"/>
  </s:Panel>
</s:Application>

The executing SWF file for the previous example is shown below: