ascii-grid
Advanced tools
| const calcStats = require("calc-stats"); | ||
| const parseAsciiGridMeta = require("./parse-ascii-grid-meta"); | ||
| const iterAsciiGridPoint = require("./iter-ascii-grid-point"); | ||
| function calcAsciiGridStats({ | ||
| assume_clean = true, | ||
| debug_level = 0, | ||
| data, | ||
| max_read_length = Infinity, | ||
| start_of_data_byte, | ||
| start_column = 0, | ||
| end_column, // index of last column (using zero-based index) | ||
| start_row = 0, | ||
| end_row, // index of last row (using zero-based index) | ||
| meta, | ||
| calcHistogram = true, | ||
| calcMax = true, | ||
| calcMean = true, | ||
| calcMedian = true, | ||
| calcMin = true, | ||
| calcMode = true, | ||
| calcModes = true, | ||
| calcSum = true | ||
| }) { | ||
| if (!meta) meta = parseAsciiGridMeta({ data, debug: debug_level >= 1, max_read_length }); | ||
| const { nodata_value } = meta; | ||
| const iterObj = iterAsciiGridPoint({ | ||
| assume_clean, | ||
| data, | ||
| start_of_data_byte, | ||
| start_column, | ||
| end_column, | ||
| start_row, | ||
| end_row, | ||
| meta | ||
| }); | ||
| const iterNum = { | ||
| next: () => { | ||
| let obj; | ||
| // iterate until we reach the end or get a valid value | ||
| while ((obj = iterObj.next())) { | ||
| const { done, value } = obj; | ||
| if (done) return { done }; | ||
| const { num } = value; | ||
| if (num !== nodata_value) return { done, value: num }; | ||
| } | ||
| } | ||
| }; | ||
| const stats = calcStats(iterNum, { | ||
| calcHistogram, | ||
| calcMax, | ||
| calcMean, | ||
| calcMedian, | ||
| calcMin, | ||
| calcMode, | ||
| calcModes, | ||
| calcSum | ||
| }); | ||
| return stats; | ||
| } | ||
| module.exports = calcAsciiGridStats; |
| const iterAsciiGridPoint = require("./iter-ascii-grid-point"); | ||
| module.exports = ({ | ||
| assume_clean = true, | ||
| debug_level = 0, | ||
| data, | ||
| max_read_length = Infinity, | ||
| start_of_data_byte, | ||
| start_column = 0, | ||
| end_column, // index of last column (using zero-based index) | ||
| start_row = 0, | ||
| end_row, // index of last row (using zero-based index) | ||
| meta, | ||
| callback | ||
| }) => { | ||
| if (debug_level >= 1) console.time("[asci-grid/for-each-point] took"); | ||
| const iter = iterAsciiGridPoint({ | ||
| assume_clean, | ||
| debug_level, | ||
| data, | ||
| max_read_length, | ||
| start_of_data_byte, | ||
| start_column, | ||
| end_column, | ||
| start_row, | ||
| end_row, | ||
| meta | ||
| }); | ||
| let obj; | ||
| while (((obj = iter.next()), obj.done === false)) { | ||
| callback(obj.value); | ||
| } | ||
| if (debug_level >= 1) console.timeEnd("[asci-grid] parse-ascii-grid-data took"); | ||
| }; |
| const getByte = require("get-byte"); | ||
| const parseAsciiGridMetaData = require("./parse-ascii-grid-meta"); | ||
| const NEWLINE_CHARCODE = "\n".charCodeAt(0); | ||
| const SPACE_CHARCODE = " ".charCodeAt(0); | ||
| const MINUS_CHARCODE = "-".charCodeAt(0); | ||
| const ZERO_CHARCODE = "0".charCodeAt(0); | ||
| const NINE_CHARCODE = "9".charCodeAt(0); | ||
| const DOT_CHARCODE = ".".charCodeAt(0); | ||
| const NULL_CHARCODE = 0; | ||
| /* | ||
| Notes: .asc files can end with a newline, null byte, or number | ||
| */ | ||
| module.exports = ({ | ||
| assume_clean = true, | ||
| debug_level = 0, | ||
| data, | ||
| max_read_length = Infinity, | ||
| start_of_data_byte, | ||
| start_column = 0, | ||
| end_column, // index of last column (using zero-based index) | ||
| start_row = 0, | ||
| end_row, // index of last row (using zero-based index) | ||
| meta, | ||
| callback | ||
| }) => { | ||
| if (debug_level >= 1) console.time("[asci-grid/for-each-point] took"); | ||
| let numstr = ""; | ||
| if (end_column < start_column) throw new Error("[ascii-grid/for-each-point] end_column must be greater than or equal to start_column"); | ||
| if (end_row < start_row) throw new Error("[ascii-grid/for-each-point] end_row must be greater than or equal to start_row"); | ||
| const read_length = Math.min(data.length, max_read_length); | ||
| if (debug_level >= 1) console.log("[ascii-grid/for-each-point] read_length:", read_length); | ||
| if (!meta) meta = parseAsciiGridMetaData({ data }); | ||
| if (debug_level >= 1) console.log("[ascii-grid/for-each-point] meta:", meta); | ||
| if (!end_row) end_row = meta.nrows - 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/for-each-point] end_row:", end_row); | ||
| if (!end_column) end_column = meta.ncols - 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/for-each-point] end_column:", end_column); | ||
| let i = start_of_data_byte !== undefined ? start_of_data_byte : meta.last_metadata_byte + 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/for-each-point] i:", i); | ||
| // index of current row | ||
| let r = 0; | ||
| // index of current column | ||
| let c = 0; | ||
| // previous character | ||
| let prev; | ||
| return { | ||
| next: () => { | ||
| let ret; | ||
| while (i <= read_length) { | ||
| // add phantom null byte to end, because of the processing algo | ||
| const byte = i === read_length ? NULL_CHARCODE : getByte(data, i); | ||
| if (debug_level >= 2) console.log("[ascii-grid/for-each-point] i, byte:", [i, String.fromCharCode(byte)]); | ||
| if (byte === SPACE_CHARCODE || byte === NEWLINE_CHARCODE || byte === NULL_CHARCODE) { | ||
| if (prev === SPACE_CHARCODE || prev === NEWLINE_CHARCODE || prev === NULL_CHARCODE) { | ||
| // don't do anything because have reached weird edge case | ||
| // where file has two white space characters in a row | ||
| // for example, a new line + space before the start of the next row's data | ||
| prev = byte; | ||
| i++; | ||
| continue; | ||
| } | ||
| if (numstr !== "" && c >= start_column && c <= end_column) { | ||
| const num = parseFloat(numstr); | ||
| if (r >= start_row && r <= end_row) { | ||
| ret = { | ||
| value: { c, r, num }, | ||
| done: false | ||
| }; | ||
| } | ||
| } else { | ||
| if (debug_level >= 2) console.log("[ascii-grid/for-each-point] skipping value at [", r, "][", c, "]"); | ||
| } | ||
| numstr = ""; | ||
| // reached end of the row | ||
| if (c == meta.ncols - 1) { | ||
| r++; | ||
| c = 0; | ||
| } else { | ||
| c++; | ||
| } | ||
| } else if ( | ||
| assume_clean || | ||
| byte === MINUS_CHARCODE || | ||
| byte === ZERO_CHARCODE || | ||
| byte === NINE_CHARCODE || | ||
| byte === DOT_CHARCODE || | ||
| (byte > ZERO_CHARCODE && byte < NINE_CHARCODE) | ||
| ) { | ||
| numstr += String.fromCharCode(byte); | ||
| } else if (debug_level >= 2) { | ||
| console.error("[ascii-grid/for-each-point]: unknown byte", [byte]); | ||
| } | ||
| prev = byte; | ||
| i++; | ||
| if (ret) return ret; | ||
| } | ||
| return { | ||
| value: undefined, | ||
| done: true | ||
| }; | ||
| } | ||
| }; | ||
| }; |
+6
-2
| { | ||
| "name": "ascii-grid", | ||
| "version": "1.1.0", | ||
| "version": "1.2.0", | ||
| "description": "Identify and Read an ARC/INFO ASCII Grid", | ||
@@ -10,3 +10,6 @@ "main": "src/index.js", | ||
| "src/parse-ascii-grid-data.js", | ||
| "src/parse-ascii-grid-meta.js" | ||
| "src/parse-ascii-grid-meta.js", | ||
| "src/calc-ascii-grid-stats.js", | ||
| "src/for-each-ascii-grid-point.js", | ||
| "src/iter-ascii-grid-point.js" | ||
| ], | ||
@@ -46,4 +49,5 @@ "scripts": { | ||
| "dependencies": { | ||
| "calc-stats": "^0.0.2", | ||
| "get-byte": "0.0.0" | ||
| } | ||
| } |
+47
-0
@@ -118,1 +118,48 @@ # ascii-grid: beta | ||
| ``` | ||
| ## Streaming Grid Points | ||
| If you don't want to save a large array of all the grid points, | ||
| but rather iterate over the points with a callback, see below: | ||
| ```javascript | ||
| const forEachAsciiGridPoint = require("ascii-grid/for-each-ascii-grid-point"); | ||
| forEachAsciiGridPoint({ | ||
| data: buffer, | ||
| callback: ({ c, r, num }) => { | ||
| console.log("row index is", r); | ||
| console.log("column index is", c); | ||
| console.log("value is", num); | ||
| } | ||
| }); | ||
| ``` | ||
| ## Calculating Statistics | ||
| You can calculate statistics for the ASCII grid. Calculations are made by iterating | ||
| over the grid points in a memory-aware way, avoiding loading the whole grid into memory. | ||
| It uses [calc-stats](https://github.com/DanielJDufour/calc-stats) for the calculations. | ||
| ```javascript | ||
| const calcAsciiGridStats = require("ascii-grid/calc-ascii-grid-stats"); | ||
| const stats = calcAsciiGridStats({ data: buffer }); | ||
| /* | ||
| stats is | ||
| { | ||
| median: 24.926056, | ||
| min: -275.890015, | ||
| max: 351.943481, | ||
| sum: 304535462.0868404, | ||
| mean: 13.685328213781924, | ||
| modes: [6.894897], | ||
| mode: 6.894897, | ||
| histogram: { | ||
| "23.1291283": { | ||
| n: 23.1291283, // the actual value in numerical format | ||
| ct: 82 // number of times that n appears | ||
| }, | ||
| . | ||
| . | ||
| . | ||
| } | ||
| } | ||
| */ | ||
| ``` |
+7
-1
| const isAsciiGrid = require("./is-ascii-grid"); | ||
| const parseAsciiGridData = require("./parse-ascii-grid-data"); | ||
| const parseAsciiGridMetaData = require("./parse-ascii-grid-meta"); | ||
| const calcAsciiGridStats = require("./calc-ascii-grid-stats"); | ||
| const iterAsciiGridPoint = require("./iter-ascii-grid-point"); | ||
| const forEachAsciiGridPoint = require("./for-each-ascii-grid-point"); | ||
@@ -8,3 +11,6 @@ module.exports = { | ||
| parseAsciiGridData, | ||
| parseAsciiGridMetaData | ||
| parseAsciiGridMetaData, | ||
| calcAsciiGridStats, | ||
| iterAsciiGridPoint, | ||
| forEachAsciiGridPoint | ||
| }; |
| const getByte = require("get-byte"); | ||
| const parseAsciiGridMetaData = require("./parse-ascii-grid-meta"); | ||
| const forEachAsciiGridPoint = require("./for-each-ascii-grid-point"); | ||
@@ -30,94 +31,43 @@ const NEWLINE_CHARCODE = "\n".charCodeAt(0); | ||
| if (debug_level >= 1) console.time("[asci-grid] parse-ascii-grid-data took"); | ||
| const result = {}; | ||
| const table = []; | ||
| const values = []; | ||
| let row = []; | ||
| let numstr = ""; | ||
| let previous_row_index; | ||
| let i = 0; | ||
| if (end_column < start_column) throw new Error("[ascii-grid/parse-ascii-grid-data] end_column must be greater than or equal to start_column"); | ||
| if (end_row < start_row) throw new Error("[ascii-grid/parse-ascii-grid-data] end_row must be greater than or equal to start_row"); | ||
| const read_length = Math.min(data.length, max_read_length); | ||
| if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] read_length:", read_length); | ||
| if (!meta) meta = parseAsciiGridMetaData({ data }); | ||
| if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] meta:", meta); | ||
| if (!end_row) end_row = meta.nrows - 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] end_row:", end_row); | ||
| if (!end_column) end_column = meta.ncols - 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] end_column:", end_column); | ||
| let i = start_of_data_byte !== undefined ? start_of_data_byte : meta.last_metadata_byte + 1; | ||
| if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] i:", i); | ||
| // index of current row | ||
| let r = 0; | ||
| // index of current column | ||
| let c = 0; | ||
| // previous character | ||
| let prev; | ||
| while (i <= read_length) { | ||
| // add phantom null byte to end, because of the processing algo | ||
| const byte = i === read_length ? NULL_CHARCODE : getByte(data, i); | ||
| if (debug_level >= 2) console.log("[ascii-grid/parse-ascii-grid-data] i, byte:", [i, String.fromCharCode(byte)]); | ||
| if (byte === SPACE_CHARCODE || byte === NEWLINE_CHARCODE || byte === NULL_CHARCODE) { | ||
| if (prev === SPACE_CHARCODE || prev === NEWLINE_CHARCODE || prev === NULL_CHARCODE) { | ||
| // don't do anything because have reached weird edge case | ||
| // where file has two white space characters in a row | ||
| // for example, a new line + space before the start of the next row's data | ||
| prev = byte; | ||
| i++; | ||
| continue; | ||
| } | ||
| if (numstr !== "" && c >= start_column && c <= end_column) { | ||
| const num = parseFloat(numstr); | ||
| if (flat) { | ||
| if (r >= start_row && r <= end_row) { | ||
| table.push(num); | ||
| forEachAsciiGridPoint({ | ||
| assume_clean, | ||
| debug_level, | ||
| data, | ||
| max_read_length, | ||
| start_of_data_byte, | ||
| start_column, | ||
| end_column, | ||
| start_row, | ||
| end_row, | ||
| meta, | ||
| callback: flat | ||
| ? ({ num }) => values.push(num) | ||
| : ({ r, num }) => { | ||
| if (i === 0) { | ||
| row.push(num); | ||
| } else if (r !== previous_row_index) { | ||
| values.push(row); | ||
| row = [num]; | ||
| } else { | ||
| row.push(num); | ||
| } | ||
| } else { | ||
| row.push(num); | ||
| } | ||
| } else { | ||
| if (debug_level >= 2) console.log("[ascii-grid/parse-ascii-grid-data] skipping value at [", r, "][", c, "]"); | ||
| } | ||
| numstr = ""; | ||
| // reached end of the row | ||
| if (c == meta.ncols - 1) { | ||
| if (!flat && r >= start_row && r <= end_row) { | ||
| table.push(row); | ||
| i++; | ||
| previous_row_index = r; | ||
| } | ||
| r++; | ||
| c = 0; | ||
| row = []; | ||
| } else { | ||
| c++; | ||
| } | ||
| } else if ( | ||
| assume_clean || | ||
| byte === MINUS_CHARCODE || | ||
| byte === ZERO_CHARCODE || | ||
| byte === NINE_CHARCODE || | ||
| byte === DOT_CHARCODE || | ||
| (byte > ZERO_CHARCODE && byte < NINE_CHARCODE) | ||
| ) { | ||
| numstr += String.fromCharCode(byte); | ||
| } else if (debug_level >= 2) { | ||
| console.error("[ascii-grid/parse-ascii-grid-data]: unknown byte", [byte]); | ||
| } | ||
| }); | ||
| prev = byte; | ||
| i++; | ||
| // make sure don't forget about the last row | ||
| if (!flat && Array.isArray(row) && row.length > 0) { | ||
| values.push(row); | ||
| } | ||
| result.values = table; | ||
| result.values = values; | ||
@@ -124,0 +74,0 @@ if (debug_level >= 1) console.log("[ascii-grid/parse-ascii-grid-data] finishing"); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
23684
31.95%10
42.86%344
91.11%165
39.83%2
100%1
Infinity%+ Added
+ Added
+ Added