1

我必须使用 Google 的折线图在折线图中显示大约 20 条线。这些线可能会重叠。向数据添加噪声以使所有线条都可见的最佳方法是什么。

在此处输入图像描述和 的值是相同的cat1,但我希望从图像中可以明显看出它们非常接近 - 所以我的想法是线条不应该重叠,但应该有点分开。用户不能假设所有值都重叠,因为对于某些事件,比如说 D,这些值可能会丢失。cat2cat3

4

1 回答 1

5

鉴于此图表:

重叠线

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['x', '#1', '#2', '#3'],
    ['A', 1, 1, 1],
    ['B', 2, 2, 2],
    ['C', 3, 3, 3],
    ['D', 4, 4, 4],
    ['E', 5, 5, 5],
    ['F', 6, 6, 6],
    ['G', 7, 7, 7],
    ['H', 8, 8, 8],
    ['I', 9, 9, 9],
  ]);

  // Create and draw the visualization.
  new google.visualization.LineChart(document.getElementById('visualization')).
      draw(data, {width: 500, height: 400,
                  vAxis: {maxValue: 10}}
          );
}

一种方法是为每个系列添加一致的 +/-:

固定抖动

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['x', '#1', '#2', '#3'],
    ['A', 1, 1, 1],
    ['B', 2, 2, 2],
    ['C', 3, 3, 3],
    ['D', 4, 4, 4],
    ['E', 5, 5, 5],
    ['F', 6, 6, 6],
    ['G', 7, 7, 7],
    ['H', 8, 8, 8],
    ['I', 9, 9, 9],
  ]);

  for (var i = 1;i < data.getNumberOfColumns();i++) {
    // Algorithm to add +/- 0.1 for each series
    var dither = Math.round((i - 1)/2)/5;
    if ( (i - 1) % 2 == 0 ) {
      dither = dither * -1;
    }
    for (var j = 0;j < data.getNumberOfRows();j++){
      // Add dither to series to display differently, but keep same data for tooltip
      data.setCell(j, i, data.getValue(j, i) + dither, data.getValue(j, i) + '', undefined)
    }
  }

  // Create and draw the visualization.
  new google.visualization.LineChart(document.getElementById('visualization')).
    draw(data, {width: 500, height: 400,
                vAxis: {maxValue: 10}}
        );
}

这种方法的问题是,如果您的坐标轴或数据的值发生显着变化,您将无法看到间隙(因为屏幕的分辨率不够大)。为了解决这个问题,我们需要手动设置轴的最小/最大值,以便能够提出适当的因素。例如,从这个答案中,我们可以采用以下算法来确定近似于谷歌自动为我们设置的最小和最大轴值:

// Take the Max/Min of all data values in all graphs
var totalMax = 345;
var totalMin = -123;

// Figure out the largest number (positive or negative)
var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));

// Round to an exponent of 10 appropriate for the biggest number
var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
var roundingDec = Math.pow(10,roundingExp);

// Round your max and min to the nearest exponent of 10
var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
var newMin = Math.floor(totalMin/roundingDec)*roundingDec;

// Determine the range of your values
var range = newMax - newMin;

// Define the number of gridlines (default 5)
var gridlines = 5;

// Determine an appropriate gap between gridlines
var interval = range / (gridlines - 1);

// Round that interval up to the exponent of 10
var newInterval = Math.ceil(interval/roundingDec)*roundingDec;

// Re-round your max and min to the new interval
var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
var finalMin = Math.floor(totalMin/newInterval)*newInterval;

我们可以将所有这些加在一起,如果所有值都增加 10 倍,它甚至会起作用(这不适用于硬编码版本):

动态抖动

function drawVisualization() {
  // Create and populate the data table.
  var data = google.visualization.arrayToDataTable([
    ['x', '#1', '#2', '#3'],
    ['A', 10, 10, 10],
    ['B', 20, 20, 20],
    ['C', 30, 30, 30],
    ['D', 40, 40, 40],
    ['E', 50, 50, 50],
    ['F', 60, 60, 60],
    ['G', 70, 70, 70],
    ['H', 80, 80, 80],
    ['I', 90, 90, 90],
  ]);

  // Get max and min values for the data table

  var totalMin = data.getValue(0,1);
  var totalMax = data.getValue(0,1);

  for (var i = 1;i < data.getNumberOfColumns();i++) {
    for (var j = 0;j < data.getNumberOfRows();j++){
      if ( data.getValue(j, i) < totalMin ) {
        totalMin = data.getValue(j, i);
      }          
      if ( data.getValue(j, i) > totalMax ) {
        totalMax = data.getValue(j, i);
      }
    }
  }

  // Calculate grid line axes and min/max settings

  // Figure out the largest number (positive or negative)
  var biggestNumber = Math.max(Math.abs(totalMax),Math.abs(totalMin));

  // Round to an exponent of 10 appropriate for the biggest number
  var roundingExp = Math.floor(Math.log(biggestNumber) / Math.LN10);
  var roundingDec = Math.pow(10,roundingExp);

  // Round your max and min to the nearest exponent of 10
  var newMax = Math.ceil(totalMax/roundingDec)*roundingDec;
  var newMin = Math.floor(totalMin/roundingDec)*roundingDec;

  // Determine the range of your values
  var range = newMax - newMin;

  // Define the number of gridlines (default 5)
  var gridlines = 5;

  // Determine an appropriate gap between gridlines
  var interval = range / (gridlines - 1);

  // Round that interval up to the exponent of 10
  var newInterval = Math.ceil(interval/roundingDec)*roundingDec;

  // Re-round your max and min to the new interval
  var finalMax = Math.ceil(totalMax/newInterval)*newInterval;
  var finalMin = Math.floor(totalMin/newInterval)*newInterval;

  // Calculate Dither

  for (var i = 1;i < data.getNumberOfColumns();i++) {
    // Algorithm to add +/- 0.1 for each series
    var dither = Math.round((i - 1)/2)/(10/newInterval);
    if ( (i - 1) % 2 == 0 ) {
      dither = dither * -1;
    }
    for (var j = 0;j < data.getNumberOfRows();j++){
      // Add dither to series to display differently, but keep same data for tooltip
      data.setCell(j, i, data.getValue(j, i) + dither, data.getValue(j, i) + '', undefined)
        }
        }

        // Create and draw the visualization.
        new google.visualization.LineChart(document.getElementById('visualization')).
        draw(data, {width: 500, height: 400,
        vAxis: {minValue: finalMin, maxValue: finalMax}}
        );
    }
于 2013-09-30T00:47:00.027 回答