SChartAxisTypeDiscontinuousDateTime not working?


#1

Hey guys,

Is there a trick to get the discontinous dateTime xAxis to work properly?

Even though I did set it for my charts, the xAxis still shows gaps for weekends and such. There’s no difference to a regular DateTime xAxis.

Regards,

Max


#2

Hi Max,

You need to add the exluded periods yourself. Take a look at the addExcludedTimePeriod: and addExcludedRepeatedTimePeriod: methods on SChartDiscontinuousDateTimeAxis. Our TimeSeriesChart sample that comes packaged with the framework shows an example of their use.

Jan


#3

Hi Jan,

Thanks for your quick response! 

I’ve just looked at the example which shows how to implement this for weekends, but how would you handle bank holidays?

It seems overly complicated to go through the data and exclude all the dates manually before rendering the chart for the first time, especially with regards to a single chart with series that all have different timelines (i.e historical timelines from stocks being listed on different stock exchanges), which would mean that I’d have to create like a master timeline from which I could draw the dates that don’t have a corresponding data set.

Is that the way to go, or am I missing something obvious here?


#4

Hi Maximilian,

Currently the chart / date-time API doesn’t provide utility methods such as -excludeBankHolidays, however this is certainly something we can look at adding. Regarding excluding all the dates, the chart should drop any dates inside the exclusion-periods, which should mean you don’t have to alter your data at all :slight_smile:

Hope this helps,

Rob


#5

Thanks Rob. That does indeed work beautifully.

I did, however, find a nasty bug with the DiscontinousDateTimeAxis and manual zooming  using [chartAxis setZoom]. Please check the following code (this is more or less pseudo code, so please don’t mind any spelling mistakes);

    ShinobiChart *mainChart = [[ShinobiChartalloc] initWithFrame:frame];
 
     SChartNumberAxis *yAxis = [[SChartNumberAxisalloc] init];
     SChartDiscontinuousDateTimeAxis *xAxis = [[SChartDiscontinuousDateTimeAxisalloc] init];
    
     // a time period that defines the weekends
     SChartRepeatedTimePeriod* weekends = [[SChartRepeatedTimePeriodalloc] initWithStart:[selfdateFromString:@"02-01-2010"]
                                                                               andLength:[SChartDateFrequency dateFrequencyWithDay:2]
                                                                            andFrequency:[SChartDateFrequency dateFrequencyWithWeek:1]];
 
     [xAxis addExcludedRepeatedTimePeriod:weekends];
    mainChart.xAxis = xAxis;
     mainChart.yAxis = yAxis;

The following code goes into a pinch gesture recognizer;

[chartAxis setZoom:value fromPosition:&dateInterval withAnimation:NOandBounceLimits:YES];

The bug seems to be related with the excludedRepeatedTimePeriods. In case I comment our that like ([xAxis addExcludedRepeatedTimePeriod:weekends];),the zooming works as expected. In case I leave it in, it is seriously flawed, i.e. the chart doesn’t zoom around the given position any more. I’ve tested this with the exact same values for “dateInterval” for both cases.

Please let me know if you need a demo project for this in order to replicate the error. The code I’ve presented here should suffice, though. 

Since we’re on it, are you guys looking into the issue with “andBounceLimits” not working? The bug is still very much present.


#6

Hi Maximillian,

Sorry it’s taken a while to get back to you. I created a sample project and managed to replicate your issue.

Unfortunately our axis zoom API is in need of a refactor, and the bounce limits should probably not be available as part of our public API.

You are probably better off setting the axis range directly on the charts you’d like to ‘zoom’.  This would involve using the method below available on SChartAxis:

(BOOL)setRangeWithMinimum:(id)minimum andMaximum:(id)maximum withAnimation:(BOOL)animation

I hope the above is of some help and I’ll raise this issue as something we’ll try and resolve. Please get back to us if the above doesn’t help.

Kind regards,

Sam


#7

Thanks for your response Sam and sorry for the late response.

Unfortunately I can’t use the setRange method. We’ve got several in a UIScrollView where the scrollview acts as a global touch handler. Forwarding touches wouldn’t work with the current implementation of ShinobiCharts, which is why we need to manually set the zoom and pan using setZoom and andByValue.

Both methods still include the bug that the chart won’t bounce back, a bug that has been present for more than a year now.


#8

Ah, I understand - this is certainly something we’ll look at fixing very soon.

The problem is due to the Discontinuous axis not taking into account skipped dates. Fortunately there is a workaround you can use for the time being which involves subclassing the axis and manually calculating the skips yourself. E.g. in your subclass, override setZoom:fromPosition: (e.t.c) like this:

-(BOOL)setZoom:(double)z fromPosition:(double *)position withAnimation:(BOOL)animation andBounceLimits:(BOOL)bounceLimits {
    
    double fixedPosition = *position;
    double timeToSkip = 0;
    
    for(SChartTimePeriod *excluded in self.excludedTimePeriods) {
        double start = [excluded.periodStart timeIntervalSinceDate:self.anchorPoint];
        double length = excluded.periodLength.toSeconds;
        if(start > *position) {
            break;
        }
        
        if(start + length > *position) {
            timeToSkip += fixedPosition - start;
            break;
        } else {
            timeToSkip += length;
        }
    }
    
    for(SChartRepeatedTimePeriod *excluded in self.excludedRepeatedTimePeriods) {
        
        NSDate *anchorDate = [NSDate dateWithTimeIntervalSince1970:[self.anchorPoint doubleValue]];
        NSDate *endDate = [NSDate dateWithTimeIntervalSince1970:[self.dataRange.maximum doubleValue]];

        
        double currentPosition = [excluded.periodStart timeIntervalSinceDate:anchorDate];
        double length = excluded.periodLength.toSeconds;
        double freq = excluded.frequency.toSeconds;
        double end = [endDate timeIntervalSinceDate:anchorDate];
        
        while (currentPosition < end) {
            if(currentPosition + length > end) {
                timeToSkip += end - currentPosition;
                break;
            } else {
                timeToSkip += length;
            }
            currentPosition += freq;
        }
    }
    
    fixedPosition -= timeToSkip;
    
    return [super setZoom:z fromPosition:&fixedPosition withAnimation:animation andBounceLimits:bounceLimits];
}

I hope that’s of some help. I’ll get someone to update this forum post when we have fixed the problem and the workaround is no longer needed.


#9

Thanks a lot Sam! I’ll look into your proposed workaround as soon as possible.