Scrolling and zooming chart with CategoryAxis

Title of this post is a little bit misleading because it is not possible to use ChartScroller directly with CategoryAxis. This is because ChartScroller relays on axis minimum/maximum properties which are not present in CategoryAxis. Luckily it is possible to simulate CategoryAxis behavior with LinearAxis which is supported by ChartScroller. I will describe how to do it in this post.

Simple scenario

The simplest and quite common scenario is having one data provider containing objects with single property determining category and further properties determining values of the series. Such data provider may look something like this (code copied from Flex API examples):

[Bindable]
public var dp: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 },
    { Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
    { Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);

In such case we have to do three things to simulate CategoryAxis behavior with LinearAxis:

  • Declare only yField property of series (not xField).
  • Create label function converting data provider index to category name.
  • Declare LinearAxis using created label function with interval property set to 1.

Label function may look like this (If xField of series is not specified Flex passes item index as labelValue so all we have to do is find correct item and return category value):

public function categoryLabelFunction(labelValue:Object, 
                        previousValue:Object, axis:IAxis):String
{
    var index:int = int(labelValue);
    
    if (index >= 0 && index < dp.length)
        return dp[index].Month;
    return "";
}

As you can see chart MXML code is only slightly modified compared to code using standard CategoryAxis:

<mx:ColumnChart id="columnChart" width="100%" height="100%" 
    gutterLeft="50" gutterRight="40" dataProvider="{dp}">
    <mx:series>
        <!-- Note that xField is not specified -->
        <mx:ColumnSeries yField="Profit" />
        <mx:ColumnSeries yField="Expenses" />
        <mx:ColumnSeries yField="Amount" />
    </mx:series>
    <mx:horizontalAxis>
        <!-- LinearAxis simulating CategoryAxis -->
        <mx:LinearAxis interval="1"
            labelFunction="categoryLabelFunction" />
    </mx:horizontalAxis>
</mx:ColumnChart>

View source is enabled, you can download zipped sources from here.

More complex scenario

In some cases you may need to use xField series properties. For example you may be using separate data providers of different length for different series. In such case additional parse function have to be created to convert category name to numeric value which can be placed along LinearAxis. You can find full example of such scenario here.

View source is enabled, you can download zipped sources from here.

Share on Google+Share on FacebookShare on LinkedInPin on PinterestTweet about this on Twitter

25 thoughts on “Scrolling and zooming chart with CategoryAxis”

  1. It should work without any problems.
    Notice that changing dataProvider will not reset axis minimum/maximum values so if you want a to have axis minimum/maximum values adjusted to data (so that all data are visible) you may have to set them to NaN after dataProvider is changed.

  2. Good afternoon Friend, His/her work was very good… I don’t only know like you would do to put the showDataTips = “true” and to bring the category of each column. Could he/she become trained?

  3. Hey Iwo,
    great work … I am using dataprovider from backend, bt the vertical axis for me shows from 0 to 100 (inspite of me having data greater than 100) … do i have to set some property for the same ..
    Thanks,
    cheers,

  4. Hi Nimesh,
    0/100 is the default minimum/maximum of linear axis. I can’t tell you why this values are preserved without having a look at your code, but I can give you a workaround: Set the vertical axis minimum/maximum values to NaN after dataProvider is changed, this should cause axis range to be adjusted to data.

  5. Hi Omer,
    I tested it on the example above, by changing ColumnChart to LineChart and ColumnSeries to LineSeries, and it works.
    Only horizontal axis looks different, but previous look can be restored by setting horizontalAxisStyleName="blockNumericAxis" on LineChart or by creating axis renderer with styleName="blockNumericAxis".

  6. Can any one let me know how to prevent the X-axis scrolling if there is no data further or earlier than first node?
    Because it is continue to scrolling even if there is no data?

    Thanks in Advance.

  7. For now there is no such feature. In my project we quite often scroll beyond the data and than fetch remaining data. It would be possible to define global minimum/maximum which will block further scrolling but I don’t have time to do it… I’ve just changed the job and moved and I’m really busy…

  8. hi, you wrote nice code it helps me a lot. but i find a small problem. Replace dataprovider to the following and find some undesired results.
    [Bindable]
    public var dp:ArrayCollection = new ArrayCollection
    ([{ Month: “Jan”, Profit: 2000} ]);

    you will find that loop goes on some 100 times(100 traces) and chart includes only 1 thin line on left hand side corner.

  9. Hi,

    I’ve tried your code on a LineChart, and it works amazingly. I’ve modified the labelFunction and parseFunction for the horizontal axis in order to get a DD/MM dateformat. Unfortunately, I got a disturbing issue : when I ZoomOut too much, the order of my dates is inversed (from right to left) whereas the Graph stays the same… What sould I do?

    Thank you in advance

  10. Hi,
    I observed that when you scroll too much the line chart is compressed and the category labels skip I mean they are displayed at intervals.How can I avoid this?

    Thanks and help will be appreciated

  11. Hey , pretty cool!

    But there is a problem. If you have millions value and don’t want to show everything when you zoom in and out, i mean how could we filter out values, so it doesn’t get heavy to pan or zoom?

    I know there is an algorithm call Douglas_Peucker for simplify lines that can be used. But don’t know how to implement it or where..
    How can we me make an function like google stockschart where it depends on the period you chose ?

    Sorry my bad french

    /Thanks

  12. Now how can it been modified so that the bars doesn’t disappear when you pan at some direction like its doing now? where in the code is preventing it to be draw all the data, even if its outside the visible area?

    Thanks!

  13. Hi,
    I would like to know whether i could dynamically change the dataprovider elements.
    i.e instead of – return dp[index].Month;
    how can i access the Month dynamically?

  14. Hi,
    I would like to know whether i could dynamically change the dataprovider elements.
    i.e instead of – return dp[index].Month;
    how can i change the Month dynamically?

  15. Hi Iwo.

    You Example works fine, great work, i’m noobie en flex, so, when you do the categoryLabelFunction to use linear axis like a Category axis, if i change the id of array Data provider to my var that take data from RemoteObj Mysql DB, the application Run but don’t finish to charge, don’t see nothing, mi remote connection run fine, because i can populate a Data grid.

    my data provider:

    private var datos:ArrayCollection;

    [Bindable]
    private var datos2:Array;

    private function onInit():void
    {
    miServicio.test_chart.send();
    }

    private function onResult():void
    {
    datos= miServicio.test_chart.lastResult;
    datos2=datos.source;
    dGrid.selectedIndex=0;
    }

    Your Function with my dataprovider Var:

    public function categoryLabelFunction(labelValue:Object, previousValue:Object, axis:IAxis):String
    {
    var index:int = int(labelValue);

    if (index >= 0 && index < datos2.length)

    return datos2[index].fechacompra;
    return "";
    }

    fechacompra is my category axis row, i tried with "datos" and "datos2" no errors, but the application doesn't run.

    Thank you for your time

  16. Hi, Iwo!
    Thanks for great solution.
    Could you please hint what is the best way to implement datetimeaxis horizontal scrolling within disabled date ranges ?

  17. Beautiful Iwo!

    Works a charm!

    I changed the component a little bit so that the user can click to zoom and ctrl+click to zoom out. I shall mail you the changes (though it’s not much).

    Thanks again.

  18. Hi, Iwo
    I have a problem with graph zooming. I found that the categoryAxis labels that span several lines will not be rendered completeyly sometimes I zoom the graphs. From example, my labels are composed of ‘region,’ ‘category’ and ‘year’, they are supposed to be shown in 3 lines virtically. But sometimes when I resize the graph, the ‘year’ is missing.
    I thinks this is caused by the internal optimization of flex. I am wondering that if there is any way to force the labels to be displayed completely ? Thanks!

  19. I have tried your code and enabled only vertical zooming and scrolling.
    What I have noticed is when I zoom vertically and if a column value goes beyond the max of Y axis value, it disappears. Is there a way to show that column.
    Please suggest.

    Thanks

Leave a Reply

Your email address will not be published. Required fields are marked *