From 3c2e115bc2b277cca6fe6c186b0a57b0793f3343 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 13 Oct 2016 13:45:32 +0200 Subject: [PATCH 1/7] Retain double float resolution of position data --- package.json | 2 +- src/lib/float32_truncate.js | 27 +++++++++++++++++++-------- src/traces/scattergl/convert.js | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 6008e4cef06..54d8b5e3781 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "gl-plot2d": "^1.1.9", "gl-plot3d": "^1.5.1", "gl-pointcloud2d": "^1.0.0", - "gl-scatter2d": "^1.0.5", + "gl-scatter2d": "monfera/gl-scatter2d#64-bit", "gl-scatter2d-fancy": "^1.1.1", "gl-scatter3d": "^1.0.4", "gl-select-box": "^1.0.1", diff --git a/src/lib/float32_truncate.js b/src/lib/float32_truncate.js index 8d8f758f337..015c5b698f9 100644 --- a/src/lib/float32_truncate.js +++ b/src/lib/float32_truncate.js @@ -8,14 +8,25 @@ 'use strict'; +function truncateFloat32(arrayIn, len) { + var arrayOut = new Float32Array(len); + for(var i = 0; i < len; i++) arrayOut[i] = arrayIn[i]; + return arrayOut; +} + +function truncateFloat64(arrayIn, len) { + var arrayOut = new Float64Array(len); + for(var i = 0; i < len; i++) arrayOut[i] = arrayIn[i]; + return arrayOut; +} + /** - * Truncate a Float32Array to some length. A wrapper to support environments - * (e.g. node-webkit) that do not implement Float32Array.prototype.slice + * Truncate a typed array to some length. + * For some reason, ES2015 Float32Array.prototype.slice takes + * 2x as long, therefore we aren't checking for its existence */ -module.exports = function truncate(float32ArrayIn, len) { - // for some reason, ES2015 Float32Array.prototype.slice takes 2x as long... - // therefore we aren't checking for its existence - var float32ArrayOut = new Float32Array(len); - for(var i = 0; i < len; i++) float32ArrayOut[i] = float32ArrayIn[i]; - return float32ArrayOut; +module.exports = function truncate(arrayIn, len) { + if(arrayIn instanceof Float32Array) return truncateFloat32(arrayIn, len); + if(arrayIn instanceof Float64Array) return truncateFloat64(arrayIn, len); + throw new Error('This array type is not yet supported by `truncate`.'); }; diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 339d32679d2..6ccd570727b 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -291,7 +291,7 @@ proto.updateFast = function(options) { var len = x.length, idToIndex = new Array(len), - positions = new Float32Array(2 * len), + positions = new Float64Array(2 * len), bounds = this.bounds, pId = 0, ptr = 0; From b46c096ecf20933802a7dc95d7a57056a77823ab Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Thu, 20 Oct 2016 18:53:20 +0200 Subject: [PATCH 2/7] high precision fancy scattergl - don't lose precision in convert --- package.json | 2 +- src/traces/scattergl/convert.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 54d8b5e3781..85593b4d278 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "gl-plot3d": "^1.5.1", "gl-pointcloud2d": "^1.0.0", "gl-scatter2d": "monfera/gl-scatter2d#64-bit", - "gl-scatter2d-fancy": "^1.1.1", + "gl-scatter2d-fancy": "monfera/gl-scatter2d#64-bit", "gl-scatter3d": "^1.0.4", "gl-select-box": "^1.0.1", "gl-shader": "4.2.0", diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 6ccd570727b..1f85ebdca60 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -389,7 +389,7 @@ proto.updateFancy = function(options) { var len = x.length, idToIndex = new Array(len), - positions = new Float32Array(2 * len), + positions = new Float64Array(2 * len), errorsX = new Float32Array(4 * len), errorsY = new Float32Array(4 * len), pId = 0, From d0774f47c5b67aac019f017aa900e981c38abba0 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 21 Oct 2016 20:13:14 +0200 Subject: [PATCH 3/7] high precision fancy scattergl for gl-line2d too - don't lose precision in convert --- package.json | 4 ++-- src/traces/scattergl/convert.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 85593b4d278..80969edc9bf 100644 --- a/package.json +++ b/package.json @@ -59,10 +59,10 @@ "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", "gl-contour2d": "^1.1.2", - "gl-error2d": "^1.0.0", + "gl-error2d": "monfera/gl-line2d#64-bit", "gl-error3d": "^1.0.0", "gl-heatmap2d": "^1.0.2", - "gl-line2d": "^1.3.0", + "gl-line2d": "monfera/gl-line2d#64-bit", "gl-line3d": "^1.1.0", "gl-mat4": "^1.1.2", "gl-mesh3d": "^1.2.0", diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 1f85ebdca60..430a2f87a9a 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -51,7 +51,7 @@ function LineWithMarkers(scene, uid) { this.hasLines = false; this.lineOptions = { - positions: new Float32Array(0), + positions: new Float64Array(0), color: [0, 0, 0, 1], width: 1, fill: [false, false, false, false], @@ -357,13 +357,13 @@ proto.updateFast = function(options) { this.scatter.update(this.scatterOptions); } else { - this.scatterOptions.positions = new Float32Array(0); + this.scatterOptions.positions = new Float64Array(0); this.scatterOptions.glyphs = []; this.scatter.update(this.scatterOptions); } // turn off fancy scatter plot - this.scatterOptions.positions = new Float32Array(0); + this.scatterOptions.positions = new Float64Array(0); this.scatterOptions.glyphs = []; this.fancyScatter.update(this.scatterOptions); @@ -506,7 +506,7 @@ proto.updateLines = function(options, positions) { var p = 0; var x = this.xData; var y = this.yData; - linePositions = new Float32Array(2 * x.length); + linePositions = new Float64Array(2 * x.length); for(i = 0; i < x.length; ++i) { linePositions[p++] = x[i]; @@ -542,7 +542,7 @@ proto.updateLines = function(options, positions) { this.lineOptions.fillColor = [fillColor, fillColor, fillColor, fillColor]; } else { - this.lineOptions.positions = new Float32Array(0); + this.lineOptions.positions = new Float64Array(0); } this.line.update(this.lineOptions); From c9ec8ed2ff0dd64fa4a05d889c975f38919efca4 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 21 Oct 2016 20:24:34 +0200 Subject: [PATCH 4/7] PR feedback: generalized file name --- src/lib/{float32_truncate.js => typed_array_truncate.js} | 0 src/traces/scattergl/convert.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lib/{float32_truncate.js => typed_array_truncate.js} (100%) diff --git a/src/lib/float32_truncate.js b/src/lib/typed_array_truncate.js similarity index 100% rename from src/lib/float32_truncate.js rename to src/lib/typed_array_truncate.js diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index 430a2f87a9a..f69eb4e570d 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -20,7 +20,7 @@ var Axes = require('../../plots/cartesian/axes'); var autoType = require('../../plots/cartesian/axis_autotype'); var ErrorBars = require('../../components/errorbars'); var str2RGBArray = require('../../lib/str2rgbarray'); -var truncate = require('../../lib/float32_truncate'); +var truncate = require('../../lib/typed_array_truncate'); var formatColor = require('../../lib/gl_format_color'); var subTypes = require('../scatter/subtypes'); var makeBubbleSizeFn = require('../scatter/make_bubble_size_func'); From 4096769670a50e6b8dd1d927ad8569228e4a88b1 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 21 Oct 2016 20:39:27 +0200 Subject: [PATCH 5/7] eliminating last remnants of Float32Array in scattergl/convert --- package.json | 4 ++-- src/traces/scattergl/convert.js | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 80969edc9bf..230597438dd 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", "gl-contour2d": "^1.1.2", - "gl-error2d": "monfera/gl-line2d#64-bit", + "gl-error2d": "monfera/gl-error2d#64-bit", "gl-error3d": "^1.0.0", "gl-heatmap2d": "^1.0.2", "gl-line2d": "monfera/gl-line2d#64-bit", @@ -70,7 +70,7 @@ "gl-plot3d": "^1.5.1", "gl-pointcloud2d": "^1.0.0", "gl-scatter2d": "monfera/gl-scatter2d#64-bit", - "gl-scatter2d-fancy": "monfera/gl-scatter2d#64-bit", + "gl-scatter2d-fancy": "monfera/gl-scatter2d-fancy#64-bit", "gl-scatter3d": "^1.0.4", "gl-select-box": "^1.0.1", "gl-shader": "4.2.0", diff --git a/src/traces/scattergl/convert.js b/src/traces/scattergl/convert.js index f69eb4e570d..1b4c361897d 100644 --- a/src/traces/scattergl/convert.js +++ b/src/traces/scattergl/convert.js @@ -67,8 +67,8 @@ function LineWithMarkers(scene, uid) { this.hasErrorX = false; this.errorXOptions = { - positions: new Float32Array(0), - errors: new Float32Array(0), + positions: new Float64Array(0), + errors: new Float64Array(0), lineWidth: 1, capSize: 0, color: [0, 0, 0, 1] @@ -78,8 +78,8 @@ function LineWithMarkers(scene, uid) { this.hasErrorY = false; this.errorYOptions = { - positions: new Float32Array(0), - errors: new Float32Array(0), + positions: new Float64Array(0), + errors: new Float64Array(0), lineWidth: 1, capSize: 0, color: [0, 0, 0, 1] @@ -89,7 +89,7 @@ function LineWithMarkers(scene, uid) { this.hasMarkers = false; this.scatterOptions = { - positions: new Float32Array(0), + positions: new Float64Array(0), sizes: [], colors: [], glyphs: [], @@ -390,8 +390,8 @@ proto.updateFancy = function(options) { var len = x.length, idToIndex = new Array(len), positions = new Float64Array(2 * len), - errorsX = new Float32Array(4 * len), - errorsY = new Float32Array(4 * len), + errorsX = new Float64Array(4 * len), + errorsY = new Float64Array(4 * len), pId = 0, ptr = 0, ptrX = 0, @@ -482,13 +482,13 @@ proto.updateFancy = function(options) { this.fancyScatter.update(this.scatterOptions); } else { - this.scatterOptions.positions = new Float32Array(0); + this.scatterOptions.positions = new Float64Array(0); this.scatterOptions.glyphs = []; this.fancyScatter.update(this.scatterOptions); } // turn off fast scatter plot - this.scatterOptions.positions = new Float32Array(0); + this.scatterOptions.positions = new Float64Array(0); this.scatterOptions.glyphs = []; this.scatter.update(this.scatterOptions); @@ -565,7 +565,7 @@ proto.updateError = function(axLetter, options, positions, errors) { errorObjOptions.color = convertColor(errorOptions.color, 1, 1); } else { - errorObjOptions.positions = new Float32Array(0); + errorObjOptions.positions = new Float64Array(0); } errorObj.update(errorObjOptions); @@ -588,7 +588,7 @@ proto.expandAxesFast = function(bounds, markerSize) { } }; -// not quite on-par with 'scatter' (scatter fill in several other expand options), +// not quite on-par with 'scatter' (scatter fill in several other expand options) // but close enough for now proto.expandAxesFancy = function(x, y, ppad) { var scene = this.scene, From 70ff88e53486222f447ff7e7d678fe3923dd7fe6 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Tue, 25 Oct 2016 21:30:01 +0200 Subject: [PATCH 6/7] bumped to the published (recently refactored) webgl renderer dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 230597438dd..9e5edc65757 100644 --- a/package.json +++ b/package.json @@ -59,18 +59,18 @@ "es6-promise": "^3.0.2", "fast-isnumeric": "^1.1.1", "gl-contour2d": "^1.1.2", - "gl-error2d": "monfera/gl-error2d#64-bit", + "gl-error2d": "^1.2.0", "gl-error3d": "^1.0.0", "gl-heatmap2d": "^1.0.2", - "gl-line2d": "monfera/gl-line2d#64-bit", + "gl-line2d": "^1.4.0", "gl-line3d": "^1.1.0", "gl-mat4": "^1.1.2", "gl-mesh3d": "^1.2.0", "gl-plot2d": "^1.1.9", "gl-plot3d": "^1.5.1", "gl-pointcloud2d": "^1.0.0", - "gl-scatter2d": "monfera/gl-scatter2d#64-bit", - "gl-scatter2d-fancy": "monfera/gl-scatter2d-fancy#64-bit", + "gl-scatter2d": "^1.2.0", + "gl-scatter2d-fancy": "^1.2.0", "gl-scatter3d": "^1.0.4", "gl-select-box": "^1.0.1", "gl-shader": "4.2.0", From d528fa73ff5f25b74aa10f427160113447c6f299 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Tue, 25 Oct 2016 23:12:46 +0200 Subject: [PATCH 7/7] revamp test case for high precision; separate fancy vs not case --- test/image/baselines/gl2d_date_axes.png | Bin 20443 -> 21308 bytes test/image/mocks/gl2d_date_axes.json | 64 +++++++++++++++++++++--- 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/test/image/baselines/gl2d_date_axes.png b/test/image/baselines/gl2d_date_axes.png index 49d27930719b17fc840a9437409d3d5ed3734263..22f47afcb013f1b1e0c9d8e32b14df69b5228c84 100644 GIT binary patch literal 21308 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

O@ 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 VKp&Y7-ij%3_*aYln7wC0{}-$|-sAuP literal 20443 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