'use strict'; var Registry = require('../../registry'); var Lib = require('../../lib'); var Axes = require('../../plots/cartesian/axes'); var alignPeriod = require('../../plots/cartesian/align_period'); var histogram2dCalc = require('../histogram2d/calc'); var colorscaleCalc = require('../../components/colorscale/calc'); var convertColumnData = require('./convert_column_xyz'); var clean2dArray = require('./clean_2d_array'); var interp2d = require('./interp2d'); var findEmpties = require('./find_empties'); var makeBoundArray = require('./make_bound_array'); var BADNUM = require('../../constants/numerical').BADNUM; module.exports = function calc(gd, trace) { // prepare the raw data // run makeCalcdata on x and y even for heatmaps, in case of category mappings var xa = Axes.getFromId(gd, trace.xaxis || 'x'); var ya = Axes.getFromId(gd, trace.yaxis || 'y'); var isContour = Registry.traceIs(trace, 'contour'); var isHist = Registry.traceIs(trace, 'histogram'); var isGL2D = Registry.traceIs(trace, 'gl2d'); var zsmooth = isContour ? 'best' : trace.zsmooth; var x, x0, dx, origX; var y, y0, dy, origY; var z, i, binned; // cancel minimum tick spacings (only applies to bars and boxes) xa._minDtick = 0; ya._minDtick = 0; if(isHist) { binned = histogram2dCalc(gd, trace); origX = binned.orig_x; x = binned.x; x0 = binned.x0; dx = binned.dx; origY = binned.orig_y; y = binned.y; y0 = binned.y0; dy = binned.dy; z = binned.z; } else { var zIn = trace.z; if(Lib.isArray1D(zIn)) { convertColumnData(trace, xa, ya, 'x', 'y', ['z']); x = trace._x; y = trace._y; zIn = trace._z; } else { origX = trace.x ? xa.makeCalcdata(trace, 'x') : []; origY = trace.y ? ya.makeCalcdata(trace, 'y') : []; x = alignPeriod(trace, xa, 'x', origX).vals; y = alignPeriod(trace, ya, 'y', origY).vals; trace._x = x; trace._y = y; } x0 = trace.x0; dx = trace.dx; y0 = trace.y0; dy = trace.dy; z = clean2dArray(zIn, trace, xa, ya); } if(xa.rangebreaks || ya.rangebreaks) { z = dropZonBreaks(x, y, z); if(!isHist) { x = skipBreaks(x); y = skipBreaks(y); trace._x = x; trace._y = y; } } if(!isHist && (isContour || trace.connectgaps)) { trace._emptypoints = findEmpties(z); interp2d(z, trace._emptypoints); } function noZsmooth(msg) { zsmooth = trace._input.zsmooth = trace.zsmooth = false; Lib.warn('cannot use zsmooth: "fast": ' + msg); } function scaleIsLinear(s) { if(s.length > 1) { var avgdx = (s[s.length - 1] - s[0]) / (s.length - 1); var maxErrX = Math.abs(avgdx / 100); for(i = 0; i < s.length - 1; i++) { if(Math.abs(s[i + 1] - s[i] - avgdx) > maxErrX) { return false; } } } return true; } // Check whether all brick are uniform trace._islinear = false; if(xa.type === 'log' || ya.type === 'log') { if(zsmooth === 'fast') { noZsmooth('log axis found'); } } else if(!scaleIsLinear(x)) { if(zsmooth === 'fast') noZsmooth('x scale is not linear'); } else if(!scaleIsLinear(y)) { if(zsmooth === 'fast') noZsmooth('y scale is not linear'); } else { trace._islinear = true; } // create arrays of brick boundaries, to be used by autorange and heatmap.plot var xlen = Lib.maxRowLength(z); var xIn = trace.xtype === 'scaled' ? '' : x; var xArray = makeBoundArray(trace, xIn, x0, dx, xlen, xa); var yIn = trace.ytype === 'scaled' ? '' : y; var yArray = makeBoundArray(trace, yIn, y0, dy, z.length, ya); // handled in gl2d convert step if(!isGL2D) { trace._extremes[xa._id] = Axes.findExtremes(xa, xArray); trace._extremes[ya._id] = Axes.findExtremes(ya, yArray); } var cd0 = { x: xArray, y: yArray, z: z, text: trace._text || trace.text, hovertext: trace._hovertext || trace.hovertext }; if(trace.xperiodalignment && origX) { cd0.orig_x = origX; } if(trace.yperiodalignment && origY) { cd0.orig_y = origY; } if(xIn && xIn.length === xArray.length - 1) cd0.xCenter = xIn; if(yIn && yIn.length === yArray.length - 1) cd0.yCenter = yIn; if(isHist) { cd0.xRanges = binned.xRanges; cd0.yRanges = binned.yRanges; cd0.pts = binned.pts; } if(!isContour) { colorscaleCalc(gd, trace, {vals: z, cLetter: 'z'}); } if(isContour && trace.contours && trace.contours.coloring === 'heatmap') { var dummyTrace = { type: trace.type === 'contour' ? 'heatmap' : 'histogram2d', xcalendar: trace.xcalendar, ycalendar: trace.ycalendar }; cd0.xfill = makeBoundArray(dummyTrace, xIn, x0, dx, xlen, xa); cd0.yfill = makeBoundArray(dummyTrace, yIn, y0, dy, z.length, ya); } return [cd0]; }; function skipBreaks(a) { var b = []; var len = a.length; for(var i = 0; i < len; i++) { var v = a[i]; if(v !== BADNUM) b.push(v); } return b; } function dropZonBreaks(x, y, z) { var newZ = []; var k = -1; for(var i = 0; i < z.length; i++) { if(y[i] === BADNUM) continue; k++; newZ[k] = []; for(var j = 0; j < z[i].length; j++) { if(x[j] === BADNUM) continue; newZ[k].push(z[i][j]); } } return newZ; }