title: Core Plot: Show yearly labels on the x-axis for daily values
body: <p>For the plot values in my Core Plot chart I am displaying <code>NSDate</code> based values on the <code>x</code>-axis.
  The values encompass many years and are plotted on a daily basis.</p>
  <p>I would like to display labels on the <code>x</code>-axis for each year or month, but not for each day. This is why I can't use the labeling method shown in the Core Plot example app <code>DatePlot</code>.</p>
  <p>Currently I am creating the labels manually (as shown in the following code snippet). Unfortunately, this solution leads to the issue shown in the screen shot below (the label for the year 2001 is too close to 2002).</p>
  <pre><code>[sortedArray enumerateObjectsUsingBlock:  
     ^(Price *priceItem, NSUInteger idx, BOOL *stop) {
          
  NSDateComponents *yearComponents = 
     [gregorian components:NSYearCalendarUnit 
     fromDate:price.dateTime];
  NSDateComponents *monthComponents =
     [gregorian components:NSMonthCalendarUnit 
     fromDate:price.dateTime];       
  NSInteger year = [yearComponents year];
  NSInteger month = [monthComponents month];
  if (month != previousMonth) {
     [minorTickLocations addObject:
     [NSDecimalNumber numberWithUnsignedInteger:idx]];
     previousMonth = month;
  }
  if (year != previousYear) {
     CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] 
     initWithText: [NSString stringWithFormat:@&quot;%u&quot;, year]
     textStyle: axisTitleTextStyle];
     newLabel.tickLocation = CPTDecimalFromUnsignedInteger(idx);
     newLabel.offset = x.labelOffset + x.majorTickLength / 2.0;
     [xAxisLabels addObject:newLabel];
     [majorTickLocations addObject:
         [NSDecimalNumber numberWithUnsignedInteger:idx]];
     previousYear = year;
     }
  }];
  </code></pre>
  <p><img src="https://i.stack.imgur.com/ixU8K.png" alt="enter image description here" /></p>
  <p>I am wondering if there is a better way to code this using standard Core Plot methods.</p>
  <p>It would be great if the date formatter behaviour could be used to show only years (<code>YYYY</code>), month and years (<code>MMM-YYYY</code>) or only months (<code>MMM</code>).</p>
  <h2>Edit</h2>
  <p>As Eric recommended in his post, I am converting my dates to fractions of year in order to be able to use <code>CPTDateFormatter</code>. This is how I set up the chart (Initially, I just want to plot a tick per calendar year):</p>
  <pre><code>x.labelingPolicy = CPTAxisLabelingPolicyFixedInterval;
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  [dateFormatter setDateFormat:@&quot;yyyy&quot;];
  CPTCalendarFormatter *calendarFormatter = [[CPTCalendarFormatter alloc]
     initWithDateFormatter:dateFormatter];
  calendarFormatter.referenceDate = [sortedPrices[0] 
     valueForKey:@&quot;dateTime&quot;];
  calendarFormatter.referenceCalendarUnit = NSYearCalendarUnit;
  x.labelFormatter = calendarFormatter;
  </code></pre>
  <p>This is how I convert my initial integer based index to a &quot;fraction-of-year&quot; based index:</p>
  <pre><code>- (NSArray*)indexArrayOfDatesArray:(NSArray*)dates
  {
  NSCalendar *gregorian = [[NSCalendar alloc] 
     initWithCalendarIdentifier:NSGregorianCalendar];
  NSDate *startDate = [sortedCommonSharePrices[0] valueForKey:@&quot;dateTime&quot;];
  NSDateComponents *yearComponents = [gregorian components: NSYearCalendarUnit
     fromDate:startDate];
  NSUInteger startYear = yearComponents.year;
  NSMutableArray *array = [NSMutableArray arrayWithCapacity:dates.count];
  [dates enumerateObjectsUsingBlock:^(NSDate *date, NSUInteger idx, BOOL *stop) {
     NSDateComponents *yearComponents = [gregorian 
          components:NSYearCalendarUnit fromDate:date];
     NSInteger years = [yearComponents year];
     NSUInteger numberOfDaysSinceStartOfYear =
          [gregorian ordinalityOfUnit:NSDayCalendarUnit
           inUnit:NSYearCalendarUnit forDate:date];
     
     NSUInteger totalNumberOfDaysInYear = 365;
          
     double fractionOfYear = (double)numberOfDaysSinceStartOfYear /
        (double)totalNumberOfDaysInYear + (double)years - (double)startYear;
          
     [array addObject:[NSNumber numberWithDouble:fractionOfYear]];
  }];    
  return array;
  }
  </code></pre>
  <p>This seems to work ok, but seems to be a lot of code (any thoughts on improving the code ?).</p>
  <h2>Question</h2>
  <p>When zooming and panning (using <code>plotSpace:willChangePlotRangeTo</code>) I want to set the x-axis labels to the new date range (based on the number of days in the new plot range. However, I get an incorrect number of ticks and wrong labels (please refer to the screenshot below).</p>
  <p>How would I need to set the labeling parameters to get the labeling right?</p>
  <p>Thank you for help!</p>
  <p>Code snippet from <code>plotSpace:willChangePlotRangeTo</code>:</p>
  <pre><code>NSDateComponents *components = [gregorian components:NSDayCalendarUnit 
     fromDate:newStartDate toDate:newEndDate options:0];
  NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  CPTCalendarFormatter *calendarFormatter = 
     [[CPTCalendarFormatter alloc] initWithDateFormatter:dateFormatter];
  calendarFormatter.referenceDate = [sortedPrices[0] valueForKey:@&quot;dateTime&quot;];
                       
  if (components.day &lt; 365) {
     dateFormatter.dateFormat = @&quot;ddd-MMM-yyyy&quot;;
     calendarFormatter.referenceCalendarUnit = NSDayCalendarUnit;
  } else if (components.day &lt; 365 * 2) {
     dateFormatter.dateFormat = @&quot;MMM yyyy&quot;;
     calendarFormatter.referenceCalendarUnit = NSYearCalendarUnit;
  } else if (components.day &lt; 365 * 4) {
     dateFormatter.dateFormat = @&quot;qqq yyyy&quot;;
     calendarFormatter.referenceCalendarUnit = NSYearCalendarUnit;
  } else {
     dateFormatter.dateFormat = @&quot;yyyy&quot;;
     calendarFormatter.referenceCalendarUnit = NSYearCalendarUnit;
  }
  CPTXYAxis *x = axisSet.xAxis;
  x.preferredNumberOfMajorTicks = 10;
  x.majorIntervalLength = CPTDecimalFromDouble(0.1);
  x.minorTicksPerInterval = 1;
  x.labelFormatter = calendarFormatter;
  </code></pre>
  <p><img src="https://i.stack.imgur.com/HiV98.png" alt="Wrong ticks and labels" /></p>