genLabels method

List<String> genLabels (double left, double right, { bool tightStyle: true, int nticks: 5, int scale })

Generates nice axis labels for a graph and return them as a list of Strings. From https://github.com/alexreisner/smart_chart/blob/master/lib/smart_chart/vendor/nice_numbers.rb

Takes graph left, right (data range from min to max), and an options map:

nticks - number of ticks (target, won't be hit exactly) scale - number of digits to the right of the decimal point in labels; null to have the algorithm choose the best value (=default) tightStyle - (default=true), tight means min and max labels are min and max data values, loose means min label is less than min data value and max label is greater than max data value

This is an implementation of Paul Heckbert's "Nice Numbers for Graph Labels" algorithm, as described in the Graphics Gems book: http://books.google.com/books?id=fvA7zLEFWZgC&pg=PA61&lpg=PA61#v=onepage

See also http://www.justintalbot.com/research/axis-labeling/ for an improved algorithm which considers font sizes etc.

Implementation

static List<String> genLabels(double left, double right,
    {bool tightStyle = true, int nticks = 5, int scale}) {
  double min = left, max = right;
  if (left > right) // also works for this case
  {
    min = right;
    max = left;
  }

  // find min, max, and interval
  double range = nicenum(max - min, false);
  double d = nicenum(range / (nticks - 1), true); //  tick mark spacing
  double graphmin = (min / d).floor() * d; // graph range min
  double graphmax = (max / d).ceil() * d; //  graph range max

  // define # of fractional digits to show
  int nfrac = scale;
  if (nfrac == null) {
    double log10d = math.log(d) / math.ln10;
    nfrac = math.max(-log10d.floor(), 0);
  }

  // generate label positions
  List<String> marks = [];
  for (double x = graphmin; x < graphmax + 0.5 * d; x += d) {
    marks.add("${x.toStringAsFixed(nfrac)}");
  }

  // tighten up ends if necessary
  if (tightStyle) {
    marks[0] = min.toStringAsFixed(nfrac);
    marks[marks.length - 1] = max.toStringAsFixed(nfrac);
  }

//  if(left > right)
//  {
//    marks = List.from(marks.reversed);
//  }

  return marks;
}