From 6c21a1eecde1ace03d15040609ed0836ace86fb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Tue, 26 Nov 2024 11:36:42 +0100 Subject: [PATCH] support UintArray data, add more tests --- src/contours.js | 11 +++-- test/output/matrixContours.svg | 29 +++++++++++ test/output/matrixContours1.svg | 29 +++++++++++ test/output/matrixContours2.svg | 20 ++++++++ test/output/matrixContours3.svg | 23 +++++++++ test/output/matrixContours4Holes.svg | 25 ++++++++++ test/snapshots/index.js | 73 ++++++++++++++++++---------- 7 files changed, 180 insertions(+), 30 deletions(-) create mode 100644 test/output/matrixContours.svg create mode 100644 test/output/matrixContours1.svg create mode 100644 test/output/matrixContours2.svg create mode 100644 test/output/matrixContours3.svg create mode 100644 test/output/matrixContours4Holes.svg diff --git a/src/contours.js b/src/contours.js index 88b7171..dfe3580 100644 --- a/src/contours.js +++ b/src/contours.js @@ -59,11 +59,12 @@ export default function() { const v = value == null ? NaN : +value; if (isNaN(v)) throw new Error(`invalid value: ${value}`); - // Don’t round the corners by clamping values on the edge. - const bottom = values.slice(0, dx); - const top = values.slice(-dx); - const left = Array.from({length: dy}, (_, i) => values[i * dx]); - const right = Array.from({length: dy}, (_, i) => values[i * dx + dx - 1]); + // Don’t round the corners by clamping values on the edge. Note: to blur, we + // need to ensure that the values are valid numbers. + const bottom = Array.from(values.slice(0, dx), valid); + const top = Array.from(values.slice(-dx), valid); + const left = Array.from({length: dy}, (_, i) => valid(values[i * dx])); + const right = Array.from({length: dy}, (_, i) => valid(values[i * dx + dx - 1])); blur(bottom, blurEdges); blur(top, blurEdges); blur(left, blurEdges); diff --git a/test/output/matrixContours.svg b/test/output/matrixContours.svg new file mode 100644 index 0000000..f900e1e --- /dev/null +++ b/test/output/matrixContours.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/output/matrixContours1.svg b/test/output/matrixContours1.svg new file mode 100644 index 0000000..f900e1e --- /dev/null +++ b/test/output/matrixContours1.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/output/matrixContours2.svg b/test/output/matrixContours2.svg new file mode 100644 index 0000000..79a9bd9 --- /dev/null +++ b/test/output/matrixContours2.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/output/matrixContours3.svg b/test/output/matrixContours3.svg new file mode 100644 index 0000000..a86f09e --- /dev/null +++ b/test/output/matrixContours3.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/output/matrixContours4Holes.svg b/test/output/matrixContours4Holes.svg new file mode 100644 index 0000000..0954799 --- /dev/null +++ b/test/output/matrixContours4Holes.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/snapshots/index.js b/test/snapshots/index.js index ea0de69..6ded72c 100644 --- a/test/snapshots/index.js +++ b/test/snapshots/index.js @@ -82,14 +82,12 @@ export async function faithfulContour() { `; } -export async function volcanoContours() { - const data = await json("data/volcano.json"); +function svgContours(data, {width = 500, smooth = true} = {}) { const n = data.width; const m = data.height; - const width = 928; const height = Math.round(m / n * width); const path = geoPath().projection(geoIdentity().scale(width / n)); - const color = scaleSequential(interpolateTurbo).domain(extent(data.values)).nice(); + const color = scaleSequential(interpolateTurbo).domain(extent(data.values, d => isFinite(d) ? d : NaN)).nice(); const svg = create("svg") .attr("width", width) .attr("height", height) @@ -100,30 +98,55 @@ export async function volcanoContours() { .selectAll() .data(color.ticks(20)) .join("path") - .attr("d", d => path(contours().size([n, m]).contour(data.values, d))) + .attr("d", d => path(contours().smooth(smooth).size([n, m]).contour(data.values, d))) .attr("fill", color); return svg.node(); } +export async function volcanoContours() { + return svgContours(await json("data/volcano.json"), {width: 928}); +} + export async function volcanoContoursRugged() { - const data = await json("data/volcano.json"); - const n = data.width; - const m = data.height; - const width = 928; - const height = Math.round(m / n * width); - const path = geoPath().projection(geoIdentity().scale(width / n)); - const color = scaleSequential(interpolateTurbo).domain(extent(data.values)).nice(); - const svg = create("svg") - .attr("width", width) - .attr("height", height) - .attr("viewBox", [0, 0, width, height]) - .attr("style", "max-width: 100%; height: auto;"); - svg.append("g") - .attr("stroke", "black") - .selectAll() - .data(color.ticks(20)) - .join("path") - .attr("d", d => path(contours().smooth(false).size([n, m]).contour(data.values, d))) - .attr("fill", color); - return svg.node(); + return svgContours(await json("data/volcano.json"), {width: 928, smooth: false}); +} + +export function matrixContours1() { + const n = 16; + const data = {values: new Uint32Array(n * n), width: n, height: n}; + for (let i = 0; i < n; ++i) + for (let j = 0; j < n; ++j) + data.values[i + n * j] = i * j; + return svgContours(data); +} + +export function matrixContours2() { + const n = 16; + const data = {values: new Float32Array(n * n), width: n, height: n}; + for (let i = 0; i < n; ++i) + for (let j = 0; j < n; ++j) + data.values[i + n * j] = i + j; + return svgContours(data); +} + +export function matrixContours3() { + const n = 200; + const data = {values: new Float32Array(n * n), width: n, height: n}; + for (let i = 0; i < n; ++i) + for (let j = 0; j < n; ++j) + data.values[i + n * j] = Math.sin(2 * i / n + 2 * (j / n)**2); + return svgContours(data); +} + + +export function matrixContours4Holes() { + const n = 200; + const data = {values: new Float32Array(n * n), width: n, height: n}; + for (let i = 0; i < n; ++i) + for (let j = 0; j < n; ++j) + data.values[i + n * j] = Math.cos(2 * i / n + 2 * (j / n)**2); + data.values[1256] = NaN; + data.values[6900] = -Infinity; + data.values[18700] = +Infinity; + return svgContours(data); }