Merge branch 'master' of https://github.com/danvk/dygraphs
authorJeremy Brewer <jeremy.d.brewer@gmail.com>
Fri, 7 Jan 2011 17:14:30 +0000 (12:14 -0500)
committerJeremy Brewer <jeremy.d.brewer@gmail.com>
Fri, 7 Jan 2011 17:14:30 +0000 (12:14 -0500)
Conflicts:
dygraph.js
tests/significant-figures.html

1  2 
dygraph.js
tests/dygraph-many-points-benchmark.html
tests/number-format.html

diff --cc dygraph.js
@@@ -73,6 -73,6 +73,46 @@@ Dygraph.toString = function() 
    return this.__repr__();
  };
  
++/**
++ * Number formatting function which mimicks the behavior of %g in printf, i.e.
++ * either exponential or fixed format (without trailing 0s) is used depending on
++ * the length of the generated string.  The advantage of this format is that
++ * there is a predictable upper bound on the resulting string length and
++ * significant figures are not dropped.
++ *
++ * NOTE: JavaScript's native toPrecision() is NOT a drop-in replacement for %g.
++ * It creates strings which are too long for absolute values between 10^-4 and
++ * 10^-6.  See tests/number-format.html for examples.
++ *
++ * @param {Number} x The number to format
++ * @param {Number} opt_precision The precision to use, default 2.
++ * @return {String} A string formatted like %g in printf.  The max generated
++ *                  string length should be precision +
++ */
++Dygraph.defaultFormat = function(x, opt_precision) {
++  // Avoid invalid precision values; [1, 21] is the valid range.
++  var p = Math.min(Math.max(1, opt_precision || 2), 21);
++
++  // This is deceptively simple.  The actual algorithm comes from:
++  //
++  // Max allowed length = p + 4
++  // where 4 comes from 'e+n' and '.'.
++  //
++  // Length of fixed format = 2 + y + p
++  // where 2 comes from '0.' and y = # of leading zeroes.
++  //
++  // Equating the two and solving for y yields y = 2, or 0.00xxxx which is
++  // 1.0e-3.
++  //
++  // Since the behavior of toPrecision() is identical for larger numbers, we
++  // don't have to worry about the other bound.
++  //
++  // Finally, the argument for toExponential() is the number of trailing digits,
++  // so we take off 1 for the value before the '.'.
++  return (Math.abs(x) < 1.0e-3 && x != 0.0) ?
++      x.toExponential(p - 1) : x.toPrecision(p);
++};
++
  // Various default values
  Dygraph.DEFAULT_ROLL_PERIOD = 1;
  Dygraph.DEFAULT_WIDTH = 480;
@@@ -96,9 -96,7 +136,7 @@@ Dygraph.DEFAULT_ATTRS = 
    labelsKMG2: false,
    showLabelsOnHighlight: true,
  
-   yValueFormatter: function(x, opt_numDigits) {
-     return x.toPrecision(Math.min(21, Math.max(1, opt_numDigits || 2)));
-   },
 -  yValueFormatter: function(x) { return Dygraph.round_(x, 2); },
++  yValueFormatter: Dygraph.defaultFormat,
  
    strokeWidth: 1.0,
  
@@@ -2352,10 -2305,10 +2405,12 @@@ Dygraph.prototype.computeYAxisRanges_ 
          Dygraph.numericTicks(axis.computedValueRange[0],
                               axis.computedValueRange[1],
                               this, axis, tick_values);
 +      axis.ticks = ret.ticks;
 +      this.numYDigits_ = ret.numDigits;
      }
    }
+   return [this.axes_, this.seriesToAxisMap_];
  };
   
  /**
index 0000000,0000000..3abdeb1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,55 @@@
++<html>
++  <head>
++    <title>Benchmarking for Plots with Many Points</title>
++    <!--[if IE]>
++    <script type="text/javascript" src="../excanvas.js"></script>
++    <![endif]-->
++    <script type="text/javascript" src="../strftime/strftime-min.js"></script>
++    <script type="text/javascript" src="../rgbcolor/rgbcolor.js"></script>
++    <script type="text/javascript" src="../dygraph-canvas.js"></script>
++    <script type="text/javascript" src="../dygraph.js"></script>
++  </head>
++  <body>
++    <p>Plot which can be easily generated with different numbers of points for
++       benchmarking/profiling and improving performance of dygraphs.</p>    
++    <p>Number of points:
++       <input type="text" id="num_points_input" size="20"
++              onchange="updatePlot();"></p>
++    <p>Roll period (in points):
++      <input type="text" id="roll_period_input" size="20"
++              onchange="updatePlot();"></p>
++    <br>
++    <br>
++    <div id="plot"></div>
++
++    <script type="text/javascript">
++      var plot;
++
++      updatePlot = function() {
++        var plotDiv = document.getElementById('plot');
++        plotDiv.innerHTML = 'Redrawing...';
++        var numPoints =
++            parseInt(document.getElementById('num_points_input').value);
++        var data = [];
++        var xmin = 0.0;
++        var xmax = 2.0 * Math.PI;
++        var delta = (xmax - xmin) / (numPoints - 1);
++
++        for (var i = 0; i < numPoints; ++i) {
++          var x = xmin + delta * i;
++          var y = Math.sin(x);
++          data[i] = [x, y];
++        }
++
++        var rollPeriod = parseInt(
++            document.getElementById('roll_period_input').value);
++        var opts = {labels: ['x', 'sin(x)'], rollPeriod: rollPeriod};
++        plot = new Dygraph(plotDiv, data, opts);
++      };
++
++      document.getElementById('num_points_input').value = '100';
++      document.getElementById('roll_period_input').value = '1';
++      updatePlot();
++    </script>
++  </body>
++</html>
index 0000000,0000000..e17a15c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,87 @@@
++<html>
++  <head>
++    <title>Test of number formatting</title>
++    <!--[if IE]>
++    <script type="text/javascript" src="../excanvas.js"></script>
++    <![endif]-->
++    <script type="text/javascript" src="../strftime/strftime-min.js"></script>
++    <script type="text/javascript" src="../rgbcolor/rgbcolor.js"></script>
++    <script type="text/javascript" src="../dygraph-canvas.js"></script>
++    <script type="text/javascript" src="../dygraph.js"></script>
++  </head>
++  <body>
++    <p>The default formatting mimicks printf with %.<i>p</i>g where <i>p</i> is
++       the precision to use.  It turns out that JavaScript's toPrecision()
++       method is almost but not exactly equal to %g; they differ for values
++       with small absolute values (10^-1 to 10^-5 or so), with toPrecision()
++       yielding strings that are longer than they should be (i.e. using fixed
++       point where %g would use exponential).</p>
++
++    <p>This test is intended to check that our formatting works properly for a
++       variety of precisions.</p>
++
++    <p>Precision to use (1 to 21):
++      <input type="text" id="p_input" size="20" onchange="updateTable();"></p>
++    <br>
++    <br>
++    <div id="content" style="font-family:'Courier New',monospace"></div>
++
++    <script type="text/javascript">
++      // Helper functions for generating an HTML table for holding the test
++      // results.
++      createRow = function(columnType, columns) {
++        var row = document.createElement('tr');
++        for (var i = 0; i  < columns.length; i ++) {
++          var th = document.createElement(columnType);
++          var text = document.createTextNode(columns[i]);
++          th.appendChild(text);
++          row.appendChild(th);
++        };
++        return row;
++      };
++
++      createHeaderRow = function(columns) {
++        return createRow('th', columns);
++      };
++
++      createDataRow = function(columns) {
++        return createRow('td', columns);
++      };
++
++      createTable = function(headerColumns, dataColumnsList) {
++        var table = document.createElement('table');
++        table.appendChild(createHeaderRow(headerColumns));
++        for (var i = 0; i < dataColumnsList.length; i++) {
++          table.appendChild(createDataRow(dataColumnsList[i]));
++        }
++        return table;
++      };
++
++      updateTable = function() {
++        var headers = ['Dygraph.defaultFormat()', 'toPrecision()',
++                       'Dygraph.defaultFormat()', 'toPrecision()'];
++        var numbers = [];
++        var p = parseInt(document.getElementById('p_input').value);
++
++        for (var i = -10; i <= 10; i++) {
++          var n = Math.pow(10, i);
++          numbers.push([Dygraph.defaultFormat(n, p),
++                        n.toPrecision(p),
++                        Dygraph.defaultFormat(Math.PI * n, p),
++                        (Math.PI * n).toPrecision(p)]);
++        }
++
++        // Check exact values of 0.
++        numbers.push([Dygraph.defaultFormat(0.0, p),
++                      0.0.toPrecision(p)]);
++
++        var elem = document.getElementById('content');
++        elem.innerHTML = '';
++        elem.appendChild(createTable(headers, numbers));
++      };
++
++      document.getElementById('p_input').value = '4';
++      updateTable();
++    </script>
++  </body>
++</html>