提高大量数据的highcharts性能

Om3*_*3ga 10 javascript jquery highcharts

我想获得更多的数据.示例数据如下

1850/01   -0.845   -0.922   -0.748   -1.038   -0.652   -1.379   -0.311   -1.053   -0.636   -1.418   -0.272
1850/02   -0.043   -0.113    0.047   -0.244    0.159   -0.613    0.528   -0.260    0.177   -0.653    0.569
1850/03   -0.698   -0.794   -0.633   -0.891   -0.506   -1.123   -0.274   -0.910   -0.495   -1.174   -0.229
……….
2016/12    0.795    0.746    0.828    0.756    0.834    0.586    1.005    0.731    0.848    0.575    1.010
2017/01    1.025    0.977    1.067    0.983    1.068    0.786    1.265    0.963    1.084    0.778    1.271
2017/02    1.151    1.098    1.198    1.112    1.191    0.957    1.346    1.089    1.208    0.946    1.352
Run Code Online (Sandbox Code Playgroud)

从1850年到2017年以及每月开始.我正在处理这个数据集,以便在像这样的Highcharts中使用它

$.each(lines, function(index, row) {
  var cells = row.split(','),
  series = {
    type: 'line',
    data:[]
  };

  $.each(cells, function(itemNo, item) {
    if (itemNo == 0) {
      series.name = item;
    } else {
      series.data.push(parseFloat(item));
    }
  });

  data.push(series);
});
Run Code Online (Sandbox Code Playgroud)

我以下面的方式使用它

chart = $('#container').highcharts({
  chart: {
    polar: true
  },
  series: data
});
Run Code Online (Sandbox Code Playgroud)

这确实有效,但它真的很慢.如何改进/增强其性能,以便我可以快速加载highcharts而不冻结浏览器?

更新 这是我的xAxis

xAxis: {
        tickInterval: 1,
        min: 0,
        max: 12,
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    },
Run Code Online (Sandbox Code Playgroud)

更新2

yAxis: {
        min: -1,
        max: 2.2,
        endOnTick: false,
        title: {
            text: 'Temperature (°C)'
        },
        plotLines: [{
            value: 2,
            width: 1,
            label: {
                text: '2°C',
                align: 'right',
                y: 2
            },
            color: 'red'
        }, {
            value: 1.5,
            width: 1,
            label: {
                text: '1.5°C',
                align: 'right',
                y: 30
            },
            color: 'red'
        }],
    },
Run Code Online (Sandbox Code Playgroud)

Bal*_*zar 8

鉴于您显示的数据不是每月更新一次,我觉得为每个视图生成图表对您的客户来说是一个很大的资源浪费.

实际上,您可以很容易地生成图表,而无需更改您现在正在执行的任何操作,而是提取生成的SVG并将其简单地提供给访问者.

为此,您只需使用getSVGHighCharts方法,它将以字符串形式返回SVG.

我真的不知道你是否想要某种程序来自动更新图表,但你可以使用cron作业来达到这个目的.请记住,即使使用最初的更新数据方法,您也必须做一些事情.


关于你的脚本,首先要注意的是你正在使用$.each,与性能相比,这在性能方面相当糟糕.正如这个jsPerf所证明的,我得到了3,649 Op/s,$.each而for循环可以让你达到202,755 Op/s疯狂的速度!既然你也做了双循环,那就差别了^2.

但同样,由于数据不经常更新,脚本的这一部分可以完全删除并转换为与函数输出相对应的JSON,HighCharts可以直接加载,跳过CSV的整个处理和转换.


如果不要求使用HighCharts,则可以使用react-vis,它是围绕数据可视化的React组件的集合.它是作为SVG顶部的api构建的.

我做了一个演示,您可以使用与您相同的数据在CodePen结账,以绘制自1850年以来的月度温度.

const {
  HorizontalGridLines,
  XAxis,
  XYPlot,
  YAxis,
  LineMarkSeries,
} = reactVis

const color = d3.scaleLinear()
  .domain([1850, 2017])
  .range(['yellow', 'red'])

const Chart = () => (
  <XYPlot width={window.innerWidth - 100} height={window.innerHeight - 100}>
    <XAxis title='Month' />
    <YAxis title='Temperature' />
    <HorizontalGridLines />
    {Object.keys(data).map(key => (
      <LineMarkSeries color={color(key)} data={data[key]} key={key} />
    ))}
  </XYPlot>
)

ReactDOM.render(<Chart />, document.querySelector('#root'))
Run Code Online (Sandbox Code Playgroud)

我也使用d3scaleLinear方法来查看多年来的变化,因为我认为这将是一个有趣的信息,但它可以根据您的需要进行更改.

情节

它正在使用SVG,但我们也正在通过deck.gl的中介与webgl集成,这将允许更多的优化获得,仍然没有准备好,我不确定你真的需要那么多,但值得注意.

免责声明:我目前在优步工作,制作了deck.gl和react-vis.


cjg*_*cjg 7

我认为这个问题需要结合其他人提出的解决方案.这些包括:

  1. 压缩数据:如果我理解正确,那么您有167年的数据和每年12个月.这些中的每一个都是一系列,总共> 2000系列.我不确定这会创建一个可解释的图表,但我也可能误解了您的数据的性质以及您计划如何绘制它.
  2. 使用Highcharts的boost.js模块:Highcharts通常将其图形呈现为SVG.我对boost.js模块的理解是,它会导致图表的某些部分在HTML5画布元素上呈现.对于大量数据点,HTML5画布比SVG快得多.在这里看一个实证比较:SVG vs canvas:如何选择
  3. 设置图表选项以最小化资源需求:我认为您遇到的减速不太可能是由于您的数据处理.相反,我认为这几乎肯定是由于Highcharts所需的渲染时间以及监视所有图表元素上的事件所需的浏览器资源.默认情况下,例如,Highcharts图允许您将鼠标"悬停"在数据点上以突出显示它们,并且它们显示工具提示,其中包含有关数据点的信息.如果您有一个包含数千个数据点的图,那么这需要您的浏览器在图表对象上处理数千个鼠标事件.关闭此图表功能应该可以提高性能.在下面的演示中,我使用鼠标关闭了工具提示和数据点突出显示.我也关闭了传奇,以提高图表的可见性.
  4. 您可以按块处理和更新数据:从长远来看,这实际上比您一次性渲染块需要更多的时间,因为Highcharts每次添加新系列时都必须重绘图表.但是,它可能会带来更好的用户体验,因为页面会显得更具响应性.下面的演示使用了这种方法.它允许您设置每个块处理的数据行数(linesPerChunk)以及一个块完成处理和您希望开始处理下一个块(timeBetweenChunks)之间的时间延迟.理想情况下,timeBetweenChunks将设置为Highcharts渲染和显示最后一个块所需的时间,以便计算机在处理数据和渲染数据之间交替,两者之间没有非生产性的间隙.理想情况下,可以自适应地设置它,以便它在计算机/用户/浏览器等之间是最佳的,但我不知道如何做到这一点; 任何想法都会受到欢迎.所以目前它只是设置为一个恒定的100毫秒.使用2000行数据,每行数据100行,以及块之间100毫秒,整个过程需要大约2秒才能加载.关键功能是plotMoreData().处理块,并添加新的系列的图表后,它的延迟自称timeBetweenChunks使用window.setTimeout(plotMoreData, timeBetweenChunks).然后它重绘图表.当plotMoreData下次调用时,它会处理下一个块,依此类推.它在处理并显示所有数据时停止,并且还更新状态消息.

编辑:似乎Highcharts boost模块不适用于极坐标图,这是一个已知问题.此处描述了一个修复:Polar Scatter使用Boost模块.我能够通过修改boost.src.js(从Highcharts Github存储库构建如下:

在〜第1380行,我换了:

if (!settings.useGPUTranslations) {
    inst.skipTranslation = true;
    x = xAxis.toPixels(x, true);
    y = yAxis.toPixels(y, true);
}
Run Code Online (Sandbox Code Playgroud)

有:

if (!settings.useGPUTranslations) {
    inst.skipTranslation = true;
    // Default (non-Polar) calculation
    if( !series.chart.polar ) {
        x = xAxis.toPixels(x, true);
        y = yAxis.toPixels(y, true);
    }
    // Handle Polar chart coordinate conversion
    else {
        var polarPoint = {
            plotX: xAxis.translate( x, 0, 0, 0, 1, series.options.pointPlacement, series.type === 'flags' ),
            plotY: yAxis.translate( y, 0, 1, 0, 1 )
        };

        series.toXY( polarPoint );
        x = Math.round( polarPoint.plotX );
        y = Math.round( polarPoint.plotY );
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效.请参阅此处的演示:JSFiddle Polar Highcharts Boost Demo