Frage

I'm using Flex for charting time series data. the data range is from 2002 to 2009, however the data is not available for some periods of time (i.e from 4/2004 to 8/2005). The following lines show the tags I'm using for the chart:

<mx:Canvas id="cp" backgroundColor="#ffffff" fontFamily="Verdana" fontSize="12" color="#093A89" fontWeight="bold" width="100%" height="100%" alpha="1" creationComplete="init()">
<mx:LineChart id="cChart"  showDataTips="true" paddingRight="40" paddingLeft="30" width="100%" height="85%">
    <mx:verticalAxis>
        <mx:LinearAxis id="linearAxis" baseAtZero="false" title="{parameterLabel}" minorInterval="0.5" interval="1.0"/>
    </mx:verticalAxis>
    <mx:verticalAxisRenderers>
        <mx:AxisRenderer axis="{linearAxis}" fontSize="10">
            <mx:axisStroke>
                <mx:SolidColorStroke weight="6" color="#BBCCDD" alpha="1" caps="square"/>
            </mx:axisStroke>                    
        </mx:AxisRenderer>
    </mx:verticalAxisRenderers>
    <mx:horizontalAxis>
        <mx:DateTimeAxis id="ca" minimum="{sDate}" maximum="{eDate}" title="Date" dataUnits="days" dataInterval="1" labelUnits="days"/> 
    </mx:horizontalAxis>
    <mx:horizontalAxisRenderers>
        <mx:AxisRenderer axis="{ca}" canDropLabels="true" fontSize="10" labelRotation="45">         
            <mx:axisStroke>
                <mx:SolidColorStroke weight="6" color="#BBCCDD" alpha="1" caps="square"/>
            </mx:axisStroke>                    
        </mx:AxisRenderer>              
    </mx:horizontalAxisRenderers>
    <mx:series>
        <mx:LineSeries id="l1" visible="false"/>
    </mx:series>
</mx:LineChart>
<mx:Legend id="mylgn" horizontalCenter="0" bottom="32"/>
<s:Label id="lblChart1" text="{dataType} {parameterLabel} at {streamLabel}" horizontalCenter="0" bottom="20"/>
<s:Label id="lblChart2" text="{optionalText}" horizontalCenter="0" bottom="5"/>

The following image illustrates the chart created by the above code: enter image description here

As you can see there are gaps for the intervals with no data. Is there any way to remove/cut the intervals with no data? What is the best practice for this type of data?

Any thoughts or recommendation would be much appreciated

War es hilfreich?

Lösung

This is accomplished via an adapter to your dataProvider.

To show a horizontal line between missing samples, you must add an additional sample to your data provider with value equal to the last sample.

If you had time series data of:

timestamp    value
4/2004       3
8/2005       23

You would add an additional sample immediately before 8/2005 equal to the previous value of 3.

timestamp    value
4/2004       3
7/2005       3 <-- insert sample
8/2005       23

Instead of interpolating between values 3 and 23, a flat horizontal line is displayed.

Sample data model

package
{
    public class TrendData
    {
        public var timestamp:Date;
        public var value:Number;
    }
}

Static adapter utility

package
{
    import mx.collections.ArrayList;

    public class TimeSeriesDataAdapter
    {

        public static function interpolate(data:ArrayList):ArrayList
        {
            var set:ArrayList = new ArrayList();
            var timespan:Number;

            // add first sample:
            set.addItem(data[0]);

            for (var i:uint = 1; i < data.length; i++)
            {
                // measure timestamp between current sample and last sample
                timespan = TrendData(data[i]).timestamp.time - TrendData(data[i-1]).timestamp.time;

                // if the timespan is greater than desired range (1-day), add a sample
                if(timespan >= 86400000)
                {
                    var trendData:TrendData = new TrendData();

                    // set timestamp just before sample
                    trendData.timestamp = new Date(TrendData(data[i]).timestamp.time - 1);

                    // set value to previous value
                    trendData.value = TrendData(data[i-1]).value;

                    set.addItem(trendData);
                }

                set.addItem(data[i]);
            }

            return set;
        }

    }
}

Data Visualization implementation

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx">

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayList;

            [Bindable]
            [ArrayElementType("TrendData")]
            public var data:ArrayList
        ]]>
    </fx:Script>

    <mx:LineChart dataProvider="{TimeSeriesDataAdapter.interpolate(data)}" />

</s:Application>

Andere Tipps

I used Jason's answer to fix the gap issue in my charts. However to make the code suitable for my application, I applied the following changes. 1- I replaced ArryList to ArrayCollection 2- I didn't use the TrendData class 3- Since my date filed is string, I had to convert it to date first 4- I considered 7 days or more as a gap 5- I had to sort my ArrayCollection before creating the excessive points.

The following shows my version of the TimeSeriesDataAdapter.interpolate function:

 public static function interpolate(data:ArrayCollection):ArrayCollection
 {
      var set:ArrayCollection = new ArrayCollection();
      var timespan:Number;
      var oneDayTime:Number = 86400000; // 1000*60*60*24 = 1 day
      for (var j:uint = 1; j < data.length; j++)
      {
           // measure timestamp between current sample and last sample
           data[j].formattedDate  = DateField.stringToDate(data[j].Date,"MM/DD/YYYY");
           data[j].time  = data[j].formattedDate.time;
      }
      var dataSortField:SortField = new SortField(); 
      dataSortField.name = "time"; 
      var numericDataSort:Sort = new Sort(); 
      numericDataSort.fields = [dataSortField]; 
      data.sort = numericDataSort; 
      data.refresh(); 
      // add first sample:
      set.addItem(data[0]);
      for (var i:uint = 1; i < data.length; i++)
      {
           // measure timestamp between current sample and last sample
           timespan = data[i].time - data[i-1].time;
           // if the timespan is greater than desired range (7-days), add a sample
           if(timespan >= oneDayTime*7) 
           {
                var trendData:Object = new Object();
                var timestamp:Date = new Date();
                trendData = data[i-1];
                // set timestamp just before sample
                timestamp.time = data[i].time - 1;
                trendData.Date = DateField.dateToString(timestamp,"MM/DD/YYYY");
                set.addItem(trendData);
           }
           set.addItem(data[i]);
      }
      return set;
 }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top