majorTickFrequency with SChartCategoryAxis (does nothing)


#1

When drawing a chart, I often need to use an SChartCategoryAxis even when the x-axis “seem” like they should be time sequences. Data sources don’t always store time sequences as DateTime objects, for example fiscal calendars, sequences of fiscal weeks, and so on that you might *think* should be DateTime but actually are not.

This fits fine with SChartCategoryAxis, except that when labeling the Major Ticks, SChartCateogryAxis pays no attention to whether the labels will overlap, and the result with more than a handful of “categories” is that the labels are printed on top of each other and the entire axis is unreadable.

Overall these types of charts would be fine if labels could be printed at intervals…but the documentation says labels are printed on every tick mark. Sure enough setting majorTickFrequency has no effect.

First, please change this! majorTickFrequency can make a lot of sense in this situation, and having it unimplemented is so unfortunate. 

Second, is there any way to work around this limitation?  I have tried to “force” some of these scenarios into an SDateTimeAxis to regain some control over axis labeling, but it just doesn’t fit well at all, and using a CategoryAxis really is the “right” fit if more control over axis labeling were possible. 

Thanks,

Rob


#2

For now, the best solution is to use sChart:alterTickMark:beforeAddingToAxis: on SChartDelegate. Any tick labels you don’t want to appear, simply set the incoming “tickMark.tickLabel” to nil.

We do plan to address this in future, but for now this should work around the problem.


#3

Thanks, tkelly.  

OK, I have added that protocol and method, and I can turn off the labels using the nil set.

What I haven’t been able to determine is how I can know which tick is being passed into this method for an SChartCategoryAxis.  I don’t see a property like “tickIndex”, and the .value property is always 0.0.  Really what I would need for this to work is to know whether the mod of a tickIndex property is zero, then display the ticklabel, otherwise don’t display it.  How do accomplish that?

Thanks,

Rob


#4

Oh, and to clarify, the code I would want to use (if there were a tickIndex property) would be:

if ( tickMark.tickIndex % 3 != 0) tickMark.tickLabel = nil;


#5

Hmm… that is unfortunate. We will definitely review that!

In the meantime, the following should fix the issue for you until we properly implement this;

-(void)sChart:(ShinobiChart *)chart alterTickMark:(SChartTickMark *)tickMark beforeAddingToAxis:(SChartAxis *)axis
{
    // Don't apply to y-axis
    if (axis != chart.xAxis)
        return;
    
    // Make majorTickFrequency = 3
    if ([tickMark.tickLabel.text intValue] % 3 != 0)
        tickMark.tickLabel = nil;
}

#6

No, that won’t work.  Your fix assumes the labels are { “1”, “2”, “3”, … }.   The actual labels are whatever the data source decides they are.  Maybe they are {“FY2013 P1”, “FY2013 P2”, … }.  Needing to parse the label text means creating every chart becomes much more tedious, and the solution will have a TON of brittle code baked into it (e.g. if the data source changes it’s label format slightly, or is localized for different countries, the app breaks).


#7

tkelly,

Well for now I worked-around this by:

  1. Creating a dictionary of labels that should be displayed in the chart data source, adding to the dictionary every “n-th” label as the data is read into the data source

  2. Implementing the following method:

    • (void)sChart:(ShinobiChart *)chart alterTickMark:(SChartTickMark *)tickMark beforeAddingToAxis:(SChartAxis *)axis
      {
      if (axis.isXAxis)
      {
      if (![_chartDataSource shouldDisplayLabel:tickMark.tickLabel.text])
      tickMark.tickLabel = nil;
      }
      }

This works and avoids embedding logic to parse and understand label text in the iOS app, but I still consider clumbsy.  By comparison, on the Windows 8 platform I’m using Telerik’s charts…with their category axis, this is a simple setting (LabelInterval):

<telerikChart:CategoricalAxis LabelStyle="{StaticResource ChartLabelStyle}" LabelFitMode="Rotate" LabelInterval="2" LabelFormat="{}{0:MM-dd}" />

#8

For the record, I agree with robkerr on this one.  I had to write a bit of code to acheive this, and while it is possible with the tools provided, not what I would expect when buying a framework.

My implementation:

// don't show labels for every individual point...instead display only a few evenly spaced apart
// this is a workaround until Shinobi fixes majorTickFrequency for SChartCategoryAxis
- (void)sChart:(ShinobiChart *)chart alterTickMark:(SChartTickMark *)tickMark beforeAddingToAxis:(SChartAxis *)axis
{
    if (axis.isXAxis){
        if (![self shouldDisplayLabel:tickMark.tickLabel.text]){
            tickMark.tickLabel.text = @"";
            tickMark.tickEnabled = NO;
        }
    }
}

// helper method for the hack mentioned above
- (BOOL)shouldDisplayLabel:(NSString*)labelText
{
    long numberOfPoints = [balances count];
    for (int i = 0; i < numberOfPoints; i++)
    {
        NSDictionary *pointDict = balances[i];
        if ([(NSString*)pointDict[@"date"] isEqualToString:labelText]){
            return (i % TICK_FREQUENCY == 0);
        }
    }
    return NO;
}

#9

Hi,
I would like to know if this is still relevant because it is almost 2 years from last post.

Is there still no other way to alter frequency of the Tick in SChartCategoryAxis?


#10

Hi Marko,

Unfortunately this is still something we are yet to implement. I’ll bring it up in our next planning meeting so we can discuss a timeframe for adding this feature.

Please accept our apologies,

Sam


#11

As a possible workaround, you could try using a number axis where the x-value represents the index of the data in your array. On this axis you could supply a custom tick label formatter that accepts the x-value and then returns the string you desire to display on your x-axis.

As the number axis allows you to define a custom tick frequency, you should then be able to define the tick frequency you desire.

If you could supply a little more information about your data and the chart you’re looking to achieve, I’d be happy to provide a more in-depth solution.