imerss-bioinfo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +156 -0
  2. package/build.js +196 -0
  3. package/docs/css/imerss-viz-all.css +1227 -0
  4. package/docs/css/imerss-viz-wp-overrides.css +70 -0
  5. package/docs/css/pepiowelh.css +76 -0
  6. package/docs/css/xetthecum-external.css +47 -0
  7. package/docs/css/xetthecum-shared.css +80 -0
  8. package/docs/css/xetthecum.css +526 -0
  9. package/docs/js/imerss-viz-all.js +58 -0
  10. package/docs/js/imerss-viz-all.js.map +1 -0
  11. package/docs/js/jquery.js +10881 -0
  12. package/index.html +81 -0
  13. package/index.js +7 -0
  14. package/indexWithJustMap.html +92 -0
  15. package/indexWithMap.html +79 -0
  16. package/indexWithMapHoweSound.html +91 -0
  17. package/indexWithMapPepiowelh.html +119 -0
  18. package/indexWithMapValdes.html +90 -0
  19. package/indexWithMapXetthecum.html +90 -0
  20. package/package.json +50 -0
  21. package/src/WoRMS/taxonAPI.js +13 -0
  22. package/src/arphify.js +662 -0
  23. package/src/assignNames.js +103 -0
  24. package/src/auxBuild/restoreJQuery.js +1 -0
  25. package/src/buildSource/Comprehensive Lists.html +42 -0
  26. package/src/buildSource/Data Paper Part I Visualisation.html +50 -0
  27. package/src/buildSource/Galiano Life List.html +43 -0
  28. package/src/buildSource/Metchosin/index.html +22 -0
  29. package/src/buildSource/Pe'pi'ow'elh.html +72 -0
  30. package/src/buildSource/Squamish Life List.html +48 -0
  31. package/src/buildSource/Valdes Island Biodiversity.html +64 -0
  32. package/src/buildSource/Xetthecum.html +40 -0
  33. package/src/buildSource/dataPaperSunburstAndMap.html +30 -0
  34. package/src/buildSource/index.html +224 -0
  35. package/src/client/css/imerss-viz-wp-overrides.css +70 -0
  36. package/src/client/css/imerss-viz.css +531 -0
  37. package/src/client/css/pepiowelh.css +76 -0
  38. package/src/client/css/xetthecum-external.css +47 -0
  39. package/src/client/css/xetthecum-shared.css +80 -0
  40. package/src/client/css/xetthecum.css +526 -0
  41. package/src/client/html/imerss-viz-map-only.html +75 -0
  42. package/src/client/html/imerss-viz-map-pepi.html +77 -0
  43. package/src/client/html/imerss-viz-map-xetthecum.html +90 -0
  44. package/src/client/html/imerss-viz-map.html +75 -0
  45. package/src/client/html/imerss-viz.html +58 -0
  46. package/src/client/html/importing Xetthecum patterns.txt +10 -0
  47. package/src/client/html/xetthecum-patterns.html +27 -0
  48. package/src/client/img/Animalia_2.svg +1 -0
  49. package/src/client/img/Animalia_Annelida.svg +655 -0
  50. package/src/client/img/Animalia_Chaetognatha.svg +72 -0
  51. package/src/client/img/Animalia_Cnidaria.svg +173 -0
  52. package/src/client/img/Animalia_Ctenophora.svg +298 -0
  53. package/src/client/img/Animalia_Nemertea.svg +54 -0
  54. package/src/client/img/Animalia_Phoronida.svg +271 -0
  55. package/src/client/img/Animalia_Platyhelminthes.svg +58 -0
  56. package/src/client/img/Animalia_Porifera.svg +220 -0
  57. package/src/client/img/Animalia_Sipuncula.svg +155 -0
  58. package/src/client/img/Arachnoidiscus_schmidtii_web_1-2-scaled.webp +0 -0
  59. package/src/client/img/Arrow-down.svg +11 -0
  60. package/src/client/img/Arrow-up.svg +6 -0
  61. package/src/client/img/Chromista.svg +1 -0
  62. package/src/client/img/Pepiowelh/BlackNoWe2-wb-bb.png +0 -0
  63. package/src/client/img/Pepiowelh/BlackNoWe2-wb.png +0 -0
  64. package/src/client/img/Pepiowelh/BlackNoWe2.png +0 -0
  65. package/src/client/img/Pepiowelh/Ecocultural Mapping Banner.svg +1 -0
  66. package/src/client/img/Plankton.jpg +0 -0
  67. package/src/client/img/Plantae.svg +1 -0
  68. package/src/client/img/Plantae_2.svg +1 -0
  69. package/src/client/img/Protista.svg +1 -0
  70. package/src/client/img/Valdes/Valdes Island Conservancy.jpg +0 -0
  71. package/src/client/img/Xetthecum/Agricultural.jpg +0 -0
  72. package/src/client/img/Xetthecum/Anthropogenic_banner.jpg +0 -0
  73. package/src/client/img/Xetthecum/Broad_Leaf.jpg +0 -0
  74. package/src/client/img/Xetthecum/Caves.jpg +0 -0
  75. package/src/client/img/Xetthecum/Coastal_Bluffs.jpg +0 -0
  76. package/src/client/img/Xetthecum/Conifer_Pole_Sapling.jpg +0 -0
  77. package/src/client/img/Xetthecum/Developed.jpg +0 -0
  78. package/src/client/img/Xetthecum/Dock.jpg +0 -0
  79. package/src/client/img/Xetthecum/Eelgrass.jpg +0 -0
  80. package/src/client/img/Xetthecum/Forests_banner.jpg +0 -0
  81. package/src/client/img/Xetthecum/Freshwater_banner.jpg +0 -0
  82. package/src/client/img/Xetthecum/Greig_Creek.jpg +0 -0
  83. package/src/client/img/Xetthecum/Intertidal.jpg +0 -0
  84. package/src/client/img/Xetthecum/Laughlin_Lake.jpg +0 -0
  85. package/src/client/img/Xetthecum/Marine_banner.jpg +0 -0
  86. package/src/client/img/Xetthecum/Mature_Conifer_Forest.jpg +0 -0
  87. package/src/client/img/Xetthecum/Porlier_Pass_Road.jpg +0 -0
  88. package/src/client/img/Xetthecum/Riparian.jpg +0 -0
  89. package/src/client/img/Xetthecum/Rural.jpg +0 -0
  90. package/src/client/img/Xetthecum/Subtidal.jpg +0 -0
  91. package/src/client/img/Xetthecum/Wetland.jpg +0 -0
  92. package/src/client/img/Xetthecum/Woodland.jpg +0 -0
  93. package/src/client/img/Xetthecum/Woodland_banner.jpg +0 -0
  94. package/src/client/img/Xetthecum/Xetthecum.jpg +0 -0
  95. package/src/client/img/Xetthecum/Young_Conifer_Forest.jpg +0 -0
  96. package/src/client/img/Xetthecum/Young_Mixed_Forest.jpg +0 -0
  97. package/src/client/img/Xetthecum/food.svg +38 -0
  98. package/src/client/img/Xetthecum/indicator.svg +52 -0
  99. package/src/client/img/Xetthecum/material.svg +186 -0
  100. package/src/client/img/Xetthecum/medicinal.svg +62 -0
  101. package/src/client/img/Xetthecum/missing-value.svg +3 -0
  102. package/src/client/img/Xetthecum/spiritual.svg +13 -0
  103. package/src/client/img/Xetthecum/trade.svg +74 -0
  104. package/src/client/img/audio.svg +5 -0
  105. package/src/client/img/external-link.svg +3 -0
  106. package/src/client/img/selected-eye.svg +4 -0
  107. package/src/client/img/selected-tick.svg +3 -0
  108. package/src/client/img/thumbs/BCLeps.jpg +0 -0
  109. package/src/client/img/thumbs/Checklist.jpg +0 -0
  110. package/src/client/img/thumbs/Data-Paper-Figma.jpg +0 -0
  111. package/src/client/img/thumbs/Galiano-Data-Paper.jpg +0 -0
  112. package/src/client/img/thumbs/Galiano.jpg +0 -0
  113. package/src/client/img/thumbs/Maxwell.jpg +0 -0
  114. package/src/client/img/thumbs/Squamish.jpg +0 -0
  115. package/src/client/img/thumbs/Valdes.jpg +0 -0
  116. package/src/client/img/thumbs/Xetthecum.jpg +0 -0
  117. package/src/client/img/up-arrow.svg +4 -0
  118. package/src/client/js/autocomplete.js +53 -0
  119. package/src/client/js/checklist.js +179 -0
  120. package/src/client/js/colour.js +139 -0
  121. package/src/client/js/datasetControls.js +212 -0
  122. package/src/client/js/imerss-viz.js +1397 -0
  123. package/src/client/js/leafletMap.js +357 -0
  124. package/src/client/js/leafletMapWithGrid.js +337 -0
  125. package/src/client/js/leafletMapWithRegions.js +381 -0
  126. package/src/client/js/renderSVG.js +108 -0
  127. package/src/client/js/tabs.js +53 -0
  128. package/src/client/js/xetthecum.js +106 -0
  129. package/src/client/json/emptyPhyloMap.json +1 -0
  130. package/src/client/json/kingdomPhyloMap.json +17 -0
  131. package/src/client/json/phyloMap.json +58 -0
  132. package/src/compare.js +97 -0
  133. package/src/compilecsv.js +47 -0
  134. package/src/dataProcessing/LZ4.js +27 -0
  135. package/src/dataProcessing/coordinatePatch.js +151 -0
  136. package/src/dataProcessing/readCSV.js +107 -0
  137. package/src/dataProcessing/readCSVwithMap.js +90 -0
  138. package/src/dataProcessing/readCSVwithoutMap.js +25 -0
  139. package/src/dataProcessing/readJSON.js +23 -0
  140. package/src/dataProcessing/sqlite.js +174 -0
  141. package/src/dataProcessing/summarise.js +122 -0
  142. package/src/dataProcessing/taxonScrape.js +14 -0
  143. package/src/dataProcessing/worker.js +31 -0
  144. package/src/dataProcessing/writeCSV.js +34 -0
  145. package/src/dataProcessing/writeJSON.js +15 -0
  146. package/src/dbtaxa.js +96 -0
  147. package/src/deAuthorise.js +48 -0
  148. package/src/deqgis.js +148 -0
  149. package/src/expressions/expr.js +65 -0
  150. package/src/expressions/jsep.js +925 -0
  151. package/src/filterFirst.js +51 -0
  152. package/src/geom/geoJSON.js +121 -0
  153. package/src/iNaturalist/examples/api.inaturalist.org-v1-taxa!q=Acmispon americanus americanus.json +200 -0
  154. package/src/iNaturalist/examples/api.inaturalist.org-v1-taxa!q=Flabellina japonica.json +61 -0
  155. package/src/iNaturalist/examples/www.inaturalist.org-taxa-877359.json +132 -0
  156. package/src/iNaturalist/iNatUrls.js +17 -0
  157. package/src/iNaturalist/obsAPI.js +150 -0
  158. package/src/iNaturalist/taxonAPI.js +460 -0
  159. package/src/inatObs.js +120 -0
  160. package/src/inattify.js +123 -0
  161. package/src/intersect.js +80 -0
  162. package/src/intersectFilter.js +48 -0
  163. package/src/landlocked.js +137 -0
  164. package/src/lib/jquery.binarytransport.js +51 -0
  165. package/src/lib/lz4-commentary.txt +9 -0
  166. package/src/lib/lz4.js +73 -0
  167. package/src/lib/point-in-polygon.js +36 -0
  168. package/src/lz4.js +40 -0
  169. package/src/marmalise.js +333 -0
  170. package/src/materialise.js +68 -0
  171. package/src/reintegrate.js +71 -0
  172. package/src/taxonomise.js +615 -0
  173. package/src/unscrewGBIF.js +44 -0
  174. package/src/utils/dataSource.js +173 -0
  175. package/src/utils/settleStructure.js +62 -0
  176. package/src/utils/utils.js +92 -0
  177. package/src/viz/plethify.js +39 -0
  178. package/src/wormify.js +154 -0
  179. package/src/xetthecum/xetthecumFilters.js +126 -0
  180. package/test/testDataSource.js +182 -0
  181. package/test/testiNatObsSource.js +38 -0
  182. package/test/testiNatSource.js +50 -0
@@ -0,0 +1,173 @@
1
+ /* eslint-env node */
2
+
3
+ "use strict";
4
+
5
+ const fluid = require("infusion");
6
+
7
+ fluid.defaults("fluid.dataSource.noencoding", {
8
+ components: {
9
+ encoding: {
10
+ type: "fluid.dataSource.encoding.none"
11
+ }
12
+ }
13
+ });
14
+
15
+ // Patch this from Kettle DataSource to interpret iNat errors which have
16
+ fluid.extractHtmlError = function (received) {
17
+ const preMatches = /<pre>(.*)<\/pre>/gm.exec(received);
18
+ if (preMatches) {
19
+ return preMatches[1];
20
+ }
21
+ const titleMatches = /<title>(.*)<\/title>/gm.exec(received);
22
+ return titleMatches ? titleMatches[1] : received;
23
+ };
24
+
25
+ fluid.defaults("fluid.dataSource.retrying", {
26
+ gradeNames: "fluid.dataSource",
27
+ retryInterval: 1000,
28
+ retries: 3,
29
+ invokers: {
30
+ get: {
31
+ funcName: "fluid.dataSource.retrying.get",
32
+ args: ["{that}", "{arguments}.0", "{arguments}.1"] // directModel, directOptions
33
+ }
34
+ }
35
+ });
36
+
37
+ fluid.promise.delay = function (delay) {
38
+ const togo = fluid.promise();
39
+ setTimeout(togo.resolve, delay);
40
+ return togo;
41
+ };
42
+
43
+ fluid.dataSource.retrying.get = async function (that, directModel, directOptions) {
44
+ const underlyingGet = function () {
45
+ return fluid.dataSource.get(that, directModel, directOptions);
46
+ };
47
+ let err = null;
48
+ for (let i = 0; i < that.options.retries; ++i) {
49
+ try {
50
+ const payload = await underlyingGet();
51
+ return payload;
52
+ } catch (e) {
53
+ fluid.log("Got exception ", e.message , " from dataSource, retry " + (i + 1) + "/" + that.options.retries);
54
+ err = e;
55
+ await fluid.promise.delay(that.options.retryInterval);
56
+ }
57
+ }
58
+ throw err;
59
+ };
60
+
61
+ fluid.setLogging(true);
62
+
63
+ // A rate limited dataSource that will guarantee not to make more than 1 call every <rateLimit> ms to the underlying
64
+ // dataSource
65
+
66
+ // Neither throttle nor debounce seem appropriate for this - https://underscorejs.org/#throttle - since they do
67
+ // not guarantee one for one invocation of target source
68
+
69
+ fluid.defaults("fluid.dataSource.rateLimiter", {
70
+ gradeNames: "fluid.component",
71
+ // minimum time in ms between calls
72
+ rateLimit: 1000,
73
+ members: {
74
+ pending: null,
75
+ lastFired: 0,
76
+ queue: []
77
+ },
78
+ invokers: {
79
+ requestStart: "fluid.dataSource.rateLimiter.requestStart({that}, {arguments}.0)",
80
+ requestEnd: "fluid.dataSource.rateLimiter.requestEnd({that}, {arguments}.0)",
81
+ next: "fluid.dataSource.rateLimiter.next({that})"
82
+ }
83
+ });
84
+
85
+ fluid.dataSource.rateLimiter.next = function (that) {
86
+ const now = Date.now();
87
+ const resolve = function (toResolve) {
88
+ that.lastFired = now;
89
+ toResolve.resolve(toResolve.payload);
90
+ };
91
+
92
+ const uncess = that.lastFired + that.options.rateLimit - now;
93
+ // console.log("rateLimit: " + that.options.rateLimit + " uncess " + uncess);
94
+ if (!that.pending && that.queue.length > 0) {
95
+ if (uncess > 0) {
96
+ that.pending = setTimeout(function () {
97
+ that.pending = null;
98
+ that.next();
99
+ }, uncess);
100
+ } else {
101
+ const top = that.queue.shift();
102
+ resolve(top);
103
+ }
104
+ }
105
+ };
106
+
107
+ fluid.dataSource.rateLimiter.requestStart = function (that, payload) {
108
+ const togo = fluid.promise();
109
+ togo.payload = payload;
110
+ that.queue.push(togo);
111
+ that.next();
112
+ return togo;
113
+ };
114
+
115
+ fluid.dataSource.rateLimiter.requestEnd = function (that, payload) {
116
+ // fluid.log("requestEnd");
117
+ that.next();
118
+ return payload;
119
+ };
120
+
121
+ fluid.defaults("fluid.dataSource.withRateLimiter", {
122
+ gradeNames: "fluid.dataSource.rateLimiter",
123
+ listeners: {
124
+ "onRead.rateLimitBefore": {
125
+ priority: "before:impl",
126
+ func: "{that}.requestStart"
127
+ },
128
+ "onRead.rateLimitAfter": {
129
+ priority: "after:impl",
130
+ func: "{that}.requestEnd"
131
+ }
132
+ }
133
+ });
134
+
135
+ fluid.defaults("fluid.inMemoryCachedSource", {
136
+ gradeNames: ["fluid.dataSource", "fluid.dataSource.noencoding", "fluid.dataSource.writable"],
137
+ members: {
138
+ cache: {}
139
+ },
140
+ listeners: {
141
+ "onRead.impl": {
142
+ func: "fluid.inMemoryCachedSource.read",
143
+ args: ["{that}", "{arguments}.0", "{arguments}.1"]
144
+ },
145
+ "onWrite.impl": {
146
+ func: "fluid.inMemoryCachedSource.write",
147
+ args: ["{that}", "{arguments}.0", "{arguments}.1"]
148
+ }
149
+ }
150
+ });
151
+
152
+ fluid.inMemoryCachedSource.toCacheKey = function (directModel) {
153
+ if (fluid.isPrimitive(directModel)) {
154
+ return directModel.toString();
155
+ } else {
156
+ let togo = "";
157
+ for (const key in directModel) {
158
+ togo += key + "|" + directModel[key] + "|";
159
+ }
160
+ return togo;
161
+ }
162
+ };
163
+
164
+ fluid.inMemoryCachedSource.read = function (that, payload, options) {
165
+ const key = fluid.inMemoryCachedSource.toCacheKey(options.directModel);
166
+ return that.cache[key];
167
+ };
168
+
169
+ fluid.inMemoryCachedSource.write = function (that, payload, options) {
170
+ const key = fluid.inMemoryCachedSource.toCacheKey(options.directModel);
171
+ that.cache[key] = payload;
172
+ return payload;
173
+ };
@@ -0,0 +1,62 @@
1
+ /* eslint-env node */
2
+
3
+ "use strict";
4
+
5
+ var fluid = require("infusion");
6
+ var hortis = fluid.registerNamespace("hortis");
7
+
8
+ hortis.settleStructure = function (structure) {
9
+ if (fluid.isPromise(structure)) {
10
+ return structure;
11
+ }
12
+ var settleRec = {
13
+ // This flag is an awkward consequence of our choice to allow synchronous promise resolution
14
+ inSync: true, // Are we still in synchronous scanning - necessary to avoid double resolution on hitting unresolved === 0 on initial scan
15
+ unresolved: 0,
16
+ depth: 0,
17
+ promise: fluid.promise(),
18
+ structure: structure,
19
+ resolve: function () {
20
+ settleRec.promise.resolve(structure);
21
+ }
22
+ };
23
+ hortis.settleStructureRecurse(structure, settleRec);
24
+ settleRec.inSync = false;
25
+ if (settleRec.unresolved === 0) { // Case of 0 asynchronous promises found
26
+ settleRec.resolve();
27
+ }
28
+ return settleRec.promise;
29
+ };
30
+
31
+ hortis.settleStructureRecurse = function (structure, settleRec) {
32
+ ++settleRec.depth;
33
+ if (settleRec.depth > fluid.strategyRecursionBailout) {
34
+ fluid.fail("Recursion exceeded for value " + JSON.stringify(structure) + " overall structure " + JSON.stringify(settleRec.structure, null, 2));
35
+ }
36
+ if (fluid.isPlainObject(structure)) {
37
+ fluid.each(structure, function (value, key) {
38
+ if (fluid.isPromise(value)) {
39
+ hortis.settleStructurePush(settleRec, structure, value, key);
40
+ } else {
41
+ hortis.settleStructureRecurse(value, settleRec);
42
+ }
43
+ });
44
+ }
45
+ --settleRec.depth;
46
+ };
47
+
48
+ hortis.settleStructurePush = function (settleRec, holder, promise, key) {
49
+ ++settleRec.unresolved;
50
+ promise.then(function (value) {
51
+ holder[key] = value;
52
+ --settleRec.unresolved;
53
+ if (settleRec.unresolved === 0 && !settleRec.inSync) {
54
+ settleRec.resolve();
55
+ }
56
+ }, function (err) {
57
+ if (!settleRec.promise.disposition) {
58
+ settleRec.promise.reject(hortis.upgradeError(err, " while resolving promise with key " + key));
59
+ }
60
+ });
61
+ };
62
+
@@ -0,0 +1,92 @@
1
+ /* eslint-env node */
2
+
3
+ "use strict";
4
+
5
+ const fluid = require("infusion");
6
+
7
+ const hortis = fluid.registerNamespace("hortis");
8
+
9
+ hortis.capitalize = function (string) {
10
+ return string.charAt(0).toUpperCase() + string.slice(1);
11
+ };
12
+
13
+ hortis.pluralise = function (number, noun) {
14
+ return number + " " + noun + (number === 1 ? "" : "s");
15
+ };
16
+
17
+ // Helpful answer: https://stackoverflow.com/a/35759874
18
+ hortis.parseFloat = function (str) {
19
+ return isNaN(str) ? NaN : parseFloat(str);
20
+ };
21
+
22
+ // https://stackoverflow.com/a/24457420
23
+ hortis.isInteger = function isNumeric(value) {
24
+ return /^-?\d+$/.test(value);
25
+ };
26
+
27
+ /** Upgrades a promise rejection payload (or Error) by suffixing an additional "while" reason into its "message" field
28
+ * @param {Object|Error} originError - A rejection payload. This should (at least) have the member `isError: true` set, as well as a String `message` holding a rejection reason.
29
+ * @param {String} whileMsg - A message describing the activity which led to this error
30
+ * @return {Object} The rejected payload formed by shallow cloning the supplied argument (if it is not an `Error`) and suffixing its `message` member
31
+ */
32
+ hortis.upgradeError = function (originError, whileMsg) {
33
+ const error = originError instanceof Error ? originError : fluid.extend({}, originError);
34
+ error.message = originError.message + whileMsg;
35
+ return error;
36
+ };
37
+
38
+ hortis.roundDecimals = function (text, places) {
39
+ const parsed = hortis.parseFloat(text);
40
+ if (!isNaN(parsed)) {
41
+ return +parsed.toFixed(places);
42
+ } else {
43
+ return text;
44
+ }
45
+ };
46
+
47
+ hortis.stringTemplateRegex = /\${([^\}]*)}/g;
48
+
49
+ // Template values with a ${key} syntax using a straightforward regex strategy and optional warning for missing values
50
+ hortis.stringTemplate = function (template, vars, warnFunc) {
51
+ const replacer = function (all, match) {
52
+ const segs = match.split(".");
53
+ const fetched = fluid.getImmediate(vars, segs);
54
+ if (warnFunc && fetched === undefined) {
55
+ warnFunc(match);
56
+ }
57
+ return fetched || "";
58
+ };
59
+ return template.replace(hortis.stringTemplateRegex, replacer);
60
+ };
61
+
62
+ // Template values with a %key syntax and optional warning for missing values
63
+ fluid.stringTemplateWarn = function (template, values, warnFunc) {
64
+ let keys = Object.keys(values);
65
+ keys = keys.sort(fluid.compareStringLength());
66
+ for (let i = 0; i < keys.length; ++i) {
67
+ const key = keys[i];
68
+ const templatePlaceholder = "%" + key;
69
+ const replacementValue = values[key];
70
+ if (warnFunc && replacementValue === undefined) {
71
+ warnFunc(key);
72
+ }
73
+ template = template.replaceAll(templatePlaceholder, replacementValue);
74
+ }
75
+ return template;
76
+ };
77
+
78
+ hortis.findDuplicates = function (array) {
79
+ return array.filter(function (item, index) {
80
+ return array.indexOf(item) !== index;
81
+ });
82
+ };
83
+
84
+ // Taken from https://stackoverflow.com/a/64909887
85
+ hortis.asyncMap = async function (arr, fn) {
86
+ const result = [];
87
+ for (let idx = 0; idx < arr.length; ++idx) {
88
+ const cur = arr[idx];
89
+ result.push(await fn(cur, idx, arr));
90
+ }
91
+ return result;
92
+ };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ // This gets injected into the Leaflet app autogenerated by QGIS2web
3
+
4
+ var hortis = fluid ? fluid.registerNamespace("hortis") : {};
5
+
6
+ hortis.plethLevels = {
7
+ 0: "#f7fcfd",
8
+ 5: "#e5f5f9",
9
+ 10: "#ccece6",
10
+ 20: "#99d8c9",
11
+ 50: "#66c2a4",
12
+ 100: "#41ae76",
13
+ 200: "#238b45",
14
+ 500: "#005824"
15
+ };
16
+
17
+ hortis.revKeys = Object.keys(hortis.plethLevels).reverse().map(function (stringKey) {
18
+ return Number(stringKey);
19
+ });
20
+
21
+ hortis.getColor = function (count) {
22
+ for (var i = 0; i < hortis.revKeys.length; ++i) {
23
+ var key = hortis.revKeys[i];
24
+ if (count > key) {
25
+ return hortis.plethLevels[key];
26
+ }
27
+ }
28
+ };
29
+
30
+ hortis.plethStyle = function (feature) {
31
+ return {
32
+ fillColor: hortis.getColor(feature.properties.speciesCount),
33
+ weight: 1,
34
+ opacity: 1,
35
+ color: "black",
36
+ //dashArray: '3',
37
+ fillOpacity: 0.7
38
+ };
39
+ };
package/src/wormify.js ADDED
@@ -0,0 +1,154 @@
1
+ /* eslint-env node */
2
+
3
+ "use strict";
4
+
5
+ var fluid = require("infusion");
6
+ var fs = require("fs");
7
+ var kettle = require("kettle");
8
+ var minimist = require("minimist");
9
+
10
+ require("./utils/utils.js");
11
+ require("./utils/settleStructure.js");
12
+ require("./dataProcessing/readJSON.js");
13
+ require("./dataProcessing/readCSV.js");
14
+ require("./dataProcessing/readCSVwithMap.js");
15
+ require("./dataProcessing/writeCSV.js");
16
+ require("./dataProcessing/taxonScrape.js");
17
+
18
+ require("./WoRMS/taxonAPI.js");
19
+
20
+ fluid.setLogging(true);
21
+
22
+ var hortis = fluid.registerNamespace("hortis");
23
+ var taxonAPIFileBase = "data/WoRMS/taxonAPI";
24
+
25
+ var source = kettle.dataSource.URL({
26
+ url: "https://www.marinespecies.org/rest/AphiaRecordsByName/%name?like=false&marine_only=false&offset=1",
27
+ termMap: {
28
+ name: "%name"
29
+ }
30
+ });
31
+
32
+ var parsedArgs = minimist(process.argv.slice(2));
33
+
34
+ var mapFile = parsedArgs.map || "data/dataPaper-I-in/dataPaper-out-map.json";
35
+ var map = hortis.readJSONSync(mapFile);
36
+
37
+ var file = parsedArgs._[0] || "data/dataPaper-I-in/reintegrated.csv";
38
+ var outFile = "reintegrated-WoRMS.csv";
39
+
40
+ var resultsPromise = hortis.csvReaderWithMap({
41
+ inputFile: file,
42
+ mapColumns: map.columns
43
+ }).completionPromise;
44
+
45
+ var outMapColumns = fluid.copy(map.columns);
46
+
47
+ delete outMapColumns.authority;
48
+ outMapColumns.authority = "Authority";
49
+ outMapColumns.WoRMSAuthority = "WoRMS Authority";
50
+ outMapColumns.mismatch = "Authority mismatch";
51
+ outMapColumns.accepted = "WoRMS Accepted";
52
+
53
+ resultsPromise.then(function (results) {
54
+ var rows = results.rows;
55
+ console.log("Got " + rows.length + " rows");
56
+
57
+ var queue = fluid.transform(rows, function (row) {
58
+ return {name: row.iNaturalistTaxonName};
59
+ });
60
+ var cachePromise = hortis.queueFetchWork(queue);
61
+ cachePromise.then(function (cache) {
62
+ var newRows = rows.map(function (oneRow) {
63
+ var newRow = fluid.copy(oneRow);
64
+ var entry = cache[oneRow.iNaturalistTaxonName];
65
+ newRow.WoRMSAuthority = entry ? (entry.authority ? entry.authority : entry.message) : "Internal error";
66
+ var authority = newRow.subtaxonAuthority || newRow.authority;
67
+ newRow.mismatch = newRow.WoRMSAuthority === authority ? "" : "x";
68
+ newRow.accepted = entry && entry.status;
69
+ return newRow;
70
+ });
71
+ hortis.writeCSV(outFile, outMapColumns, newRows, fluid.promise());
72
+ });
73
+ });
74
+
75
+ // Values of "status" field in decreasing order of desirability
76
+ hortis.WoRMSstatus = ["accepted", "unaccepted", "deleted"];
77
+
78
+ hortis.WoRMSstatusIndex = function (status) {
79
+ var index = hortis.WoRMSstatus.indexOf(status);
80
+ return index === -1 ? hortis.WoRMSstatus.length : index;
81
+ };
82
+
83
+ hortis.findBestWoRMSDoc = function (docs) {
84
+ var byIndex = [];
85
+ fluid.each(docs, function (doc) {
86
+ var index = hortis.WoRMSstatusIndex(doc.status);
87
+ fluid.pushArray(byIndex, index, doc);
88
+ });
89
+ return byIndex.find(function (slot) {
90
+ return slot && slot.length > 0;
91
+ });
92
+ };
93
+
94
+ hortis.queueFetchWork = function (queue) {
95
+ var that = {
96
+ queue: queue,
97
+ cache: {},
98
+ skipCount: 0,
99
+ fetched: [],
100
+ completion: fluid.promise()
101
+ };
102
+ var oneWork = function () {
103
+ if (that.queue.length) {
104
+ var head = that.queue.shift();
105
+ var name = head.name;
106
+ var filename = hortis.WoRMSTaxa.filenameFromTaxonName(taxonAPIFileBase, name);
107
+ var doc;
108
+ if (that.cache[name] || fs.existsSync(filename)) {
109
+ // hortis.noteSkip(that, "File " + filename + " exists, skipping");
110
+ doc = that.cache[filename];
111
+ if (!doc) {
112
+ doc = hortis.readJSONSync(filename);
113
+ that.cache[name] = doc;
114
+ }
115
+ // hortis.enqueueAncestry(doc, that.queue);
116
+ fluid.invokeLater(oneWork);
117
+ } else {
118
+ doc = source.get(head).then(function (docs) {
119
+ that.fetched.push(head);
120
+ var sortedDocs = hortis.findBestWoRMSDoc(docs);
121
+ if (!sortedDocs || sortedDocs.length === 0) {
122
+ console.log("Received no results for name " + head.name);
123
+ that.cache[name] = {
124
+ isError: true,
125
+ message: "Document not found"
126
+ };
127
+ } else {
128
+ if (sortedDocs.length > 1) {
129
+ console.log("Warning: received " + sortedDocs.length + " equally good results for name " + head.name);
130
+ }
131
+ // hortis.enqueueAncestry(doc, that.queue);
132
+ hortis.writeTaxonDoc(filename, sortedDocs[0]);
133
+ that.cache[name] = sortedDocs[0];
134
+ }
135
+ // that.completion.resolve(that.cache);
136
+ nextWork();
137
+ }, function (err) {
138
+ console.log("Received ERROR for name " + head.name, err);
139
+ that.cache[name] = {
140
+ isError: true,
141
+ message: err
142
+ };
143
+ });
144
+ }
145
+ } else {
146
+ that.completion.resolve(that.cache);
147
+ }
148
+ };
149
+ var nextWork = function () {
150
+ setTimeout(oneWork, 1000);
151
+ };
152
+ nextWork();
153
+ return that.completion;
154
+ };
@@ -0,0 +1,126 @@
1
+ /* eslint-env node */
2
+
3
+ "use strict";
4
+
5
+ var fluid = require("infusion");
6
+ var hortis = fluid.registerNamespace("hortis");
7
+
8
+ require("../dataProcessing/writeCSV.js");
9
+
10
+ fluid.registerNamespace("hortis.xetthecum");
11
+
12
+ hortis.xetthecum.names = [{
13
+ field: "hulqThom",
14
+ auth: "(Thom, 2011)"
15
+ }, {
16
+ field: "hulqTurner1",
17
+ auth: "(Turner, 2014)"
18
+ }, {
19
+ field: "hulqTurner2",
20
+ auth: "(Turner, 2014)"
21
+ }];
22
+
23
+ hortis.xetthecum.valueOutMap = {
24
+ columns: {
25
+ "foodValue": "Food Value",
26
+ "medicinalValue": "Medicinal Value",
27
+ "spiritualValue": "Spiritual Value",
28
+ "materialValue": "Material Value",
29
+ "tradeValue": "Trade Value",
30
+ "indicatorValue": "Indicator Value"
31
+ }
32
+ };
33
+
34
+ hortis.xetthecum.extraOutMap = {
35
+ columns: {
36
+ "hulqName": "Hulquminum Name",
37
+ "hulqAuth": "Hulquminum Authority"
38
+ }
39
+ };
40
+
41
+ hortis.xetthecum.mediaOutMap = {
42
+ columns: {
43
+ "audioLink": "Audio Link"
44
+ }
45
+ };
46
+
47
+ hortis.xetthecum.chooseName = function (target, hulqRow) {
48
+ var bestRec = hortis.xetthecum.names.find(function (rec) {
49
+ return !!hulqRow[rec.field];
50
+ });
51
+ if (bestRec) {
52
+ target.hulqName = hulqRow[bestRec.field];
53
+ target.hulqAuth = bestRec.auth;
54
+ return true;
55
+ } else {
56
+ return false;
57
+ }
58
+ };
59
+
60
+ hortis.xetthecum.summariseUnseen = function (byTaxon, usedTaxa, message) {
61
+ var unseen = [];
62
+ fluid.each(byTaxon, function (value, key) {
63
+ if (!usedTaxa[key]) {
64
+ unseen.push(key);
65
+ }
66
+ });
67
+ console.log("The following ", unseen.length, " taxa with " + message + " were not observed:\n" + unseen.join("\n"));
68
+ };
69
+
70
+ hortis.xetthecum.assignHulqNames = function (resolved, patch) {
71
+ var byTaxon = {};
72
+ var usedTaxa = {};
73
+ var withoutHulq = [];
74
+ var hits = 0;
75
+ var valueFields = Object.keys(hortis.xetthecum.valueOutMap.columns);
76
+ patch.patchData.rows.forEach(function (row) {
77
+ byTaxon[row.scientificName] = row;
78
+ });
79
+ resolved.summarisedRows.forEach(function (row) {
80
+ var taxon = row.iNaturalistTaxonName;
81
+ var hulqRow = byTaxon[taxon];
82
+ if (!hulqRow) {
83
+ withoutHulq.push({
84
+ taxon: taxon,
85
+ found: "no record"
86
+ });
87
+ } else {
88
+ usedTaxa[taxon] = true;
89
+ var transfer = fluid.filterKeys(hulqRow, valueFields);
90
+ var foundName = hortis.xetthecum.chooseName(transfer, hulqRow);
91
+ if (foundName) {
92
+ ++hits;
93
+ } else {
94
+ withoutHulq.push({
95
+ taxon: taxon,
96
+ found: "no name"
97
+ });
98
+ }
99
+ fluid.extend(row, transfer);
100
+ }
101
+ });
102
+ console.log("Matched " + hits + " taxa with Hul'qumi'num names");
103
+
104
+ hortis.xetthecum.summariseUnseen(byTaxon, usedTaxa, "Hul'qumi'num name records");
105
+ hortis.writeCSV("hulq-mismatches.csv", ["taxon", "found"], withoutHulq, fluid.promise());
106
+ resolved.combinedOutMap = hortis.combineMaps([resolved.combinedOutMap, hortis.xetthecum.valueOutMap, hortis.xetthecum.extraOutMap]);
107
+ };
108
+
109
+ hortis.xetthecum.assignHulqMedia = function (resolved, patch) {
110
+ var byTaxon = {};
111
+ var usedTaxa = {};
112
+ patch.patchData.rows.forEach(function (row) {
113
+ var sanitized = hortis.sanitizeSpeciesName(row.scientificName);
114
+ byTaxon[sanitized] = row;
115
+ });
116
+ resolved.summarisedRows.forEach(function (row) {
117
+ var taxon = row.iNaturalistTaxonName;
118
+ var hulqRow = byTaxon[taxon];
119
+ if (hulqRow) {
120
+ usedTaxa[taxon] = true;
121
+ row.audioLink = hulqRow.audioLink;
122
+ }
123
+ });
124
+ resolved.combinedOutMap = hortis.combineMaps([resolved.combinedOutMap, hortis.xetthecum.mediaOutMap]);
125
+ hortis.xetthecum.summariseUnseen(byTaxon, usedTaxa, "Hul'qumi'num media data");
126
+ };