cbbcloud
cbbcloud

Reputation: 479

Dynamically fetch data for plot range in core plot iOS

I am writing an application that records some data for an extended period of time (up to several hours) and displays the data in a graph/plot. I am storing my recorded values using core data and using core plot to display them in a scatter plot. My Core data entity looks like this:

MyEntity

My core plot graph is a scatter plot that displays the "someValue" values on the y axis and the "timeStamp" values on the x axis.

The screenshot shows what the core plot looks like.

My core plot graph with "someValue" on the y-axis and "timeStamp" on the x-axis.

The problem is I have a lot of values (values are being added to the core data data base every second for a couple of hours). I don't want to fetch all of my Core Data entities and load them into memory to be displayed in core plot at once. Instead, I'd rather only fetch the entities that lie within the visible plot range from my core data store and then display them using core plot. I would store the fetched results in an NSArray or something similar and would use the NSArray in my CPTPlotDataSource methods to populate the plot. My NSArray would always get overwritten when the range changes so that only the visible data points are kept in memory.

What I thought was I would use the

- (CPTPlotRange *)plotSpace:(CPTPlotSpace *)space
  willChangePlotRangeTo:(CPTPlotRange *)newRange
          forCoordinate:(CPTCoordinate)coordinate

method of the CPTPlotSpaceDelegate, and fetch the relevant entities from core data using the timeStamp as a predicate. However, I couldn't figure out how to do that. Is there a way to access the timeStamp values given the plot's current range? I thought about trying to access my x-axis labels since they display the current time and fetching from my data store using that but I couldn't figure out how. Is this even the right way to go about this? Any help is appreciated.

Upvotes: 1

Views: 503

Answers (1)

cbbcloud
cbbcloud

Reputation: 479

Ok I managed to figure it out :). Here is my solution, in case anyone else stumbles across this problem:

I realised that the only way to fetch my visible date range is to extract the date values from the axis labels. I then used those date values to perform the query on my core data model. I did this using the CPTAxisDelegate method shouldUpdateAxisLabelsAtLocations. That delegate method gets called every time the range changes in any way (through panning/zooming). Here is what I did:

-(BOOL)axis:(CPTAxis *)axis shouldUpdateAxisLabelsAtLocations:(NSSet *)locations{
    //Extract the NSDate values from the axis labels
    NSFormatter *formatter = axis.labelFormatter;
    NSMutableArray *rangeDates = [[NSMutableArray alloc]init];
    for ( NSDecimalNumber *tickLocation in locations ) {
        NSString *labelString       = [formatter stringForObjectValue:tickLocation];

       //Generate an NSDate object from the label
       NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
       [dateFormatter setDateFormat:@"HH:mm:ss"];
       NSDate *date = [dateFormatter dateFromString:labelString];
       [rangeDates addObject:date];
    }

    //Sort dates in ascending order (old to new) since they aren't sorted in the tickLocation array
    [rangeDates sortUsingSelector:@selector(compare:)];
    NSDate *startDate = rangeDates[0];
    NSDate *endDate = rangeDates[rangeDates.count-1]; 

    //Modify dates as needed and perform core data query using start and end dates
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"timestamp >= %@ AND timestamp <= %@", startDate, endDate];
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:self.managedObjectContext]];
    [request setPredicate:predicate];
    NSError *error = nil;
    NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
}

Using this method, I was able to fetch only the records in my core data store that would currently be visible in the plot. I hope this helps anyone that's come across a serious issue.

Upvotes: 0

Related Questions