node-red-contrib-prib-functions 0.21.0 → 0.23.2

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.
package/README.md CHANGED
@@ -30,6 +30,8 @@ being outside 3 standard deviations from mean. This can be changed to median and
30
30
  A set of data analysis functions that can be run over an array of data
31
31
 
32
32
  Single value metrics:
33
+ * autocorrelation
34
+ * Autocovariance
33
35
  * Average/Mean
34
36
  * Maximum
35
37
  * Median
@@ -109,53 +111,104 @@ Messages generates a message for each row or record.
109
111
 
110
112
  Transformations:
111
113
 
112
- * Array to CSV
113
- * Array to HTML
114
- * Array to ISO8385
115
- * Array to Messages
116
- * Array to xlsx / xlsx object (excel uses [xlsx][7])
114
+ * Array to
115
+ * CSV
116
+ * HTML
117
+ * ISO8385
118
+ * Messages
119
+ * xlsx / xlsx object (excel uses [xlsx][7])
117
120
  * AVRO to JSON (uses [avsc][6])
118
- * Buffer to comprossed
121
+ * Buffer to compressed
119
122
  * Confluence to JSON
120
- * Compressed to Buffer
121
- * Compressed to String
122
- * COmpressed to JSON
123
- * CSV to Array
124
- * CSV to HTML
125
- * CSV to Messages
126
- * CSVWithHeader to Array
127
- * CSVWithHeader to HTML
128
- * CSVWithHeader to JSON
123
+ * Compressed to
124
+ * Buffer
125
+ * String
126
+ * JSON
127
+ * CSV to
128
+ * Array
129
+ * HTML
130
+ * Messages
131
+ * CSVWithHeader to
132
+ * Array
133
+ * HTML
134
+ * JSON
135
+ * Date to
136
+ * is between
137
+ * ISO string
138
+ * locale string
139
+ * range limit
129
140
  * ISO8385 to Array
130
141
  * ISO8385 to JSON
131
- * JSON to Array
132
- * JSON to Confluence
133
- * JSON to CSV
134
- * JSON to AVRO (uses [avsc][6])
135
- * JSON to ISO8385
136
- * JSON to Messages
137
- * JSON to String
138
- * JSON to xlsx / xlsx object (excel uses [xlsx][7])
139
- * JSON to XML (uses [fast-xml-parser][4])
140
- * String to JSON
141
- * path to Basename
142
- * path to Dirname
143
- * path to Extname
144
- * path to Format
145
- * path to Is Absolute
146
- * path to Join
147
- * path to Parse
148
- * path to Normalize
149
- * path to Resolve
142
+ * JSON to
143
+ * Array
144
+ * Confluence
145
+ * CSV
146
+ * AVRO (uses [avsc][6])
147
+ * ISO8385
148
+ * Messages
149
+ * String
150
+ * xlsx / xlsx object (excel uses [xlsx][7])
151
+ * XML (uses [fast-xml-parser][4])
152
+ * Number
153
+ * is between
154
+ * range limit
155
+ * path
156
+ * Basename
157
+ * Dirname
158
+ * Extname
159
+ * Format
160
+ * Is Absolute
161
+ * Join
162
+ * Parse
163
+ * Normalize
164
+ * Resolve
150
165
  * snappy compress (uses [snappy][5], must install separately)
151
166
  * snappy uncompress (uses [snappy][5], must install separately)
167
+ * String to
168
+ * Append
169
+ * Array By Delimiter
170
+ * At
171
+ * Camelize
172
+ * Capitalize
173
+ * Compressed
174
+ * Char At
175
+ * Char Code At"
176
+ * Code Point At
177
+ * Concat
178
+ * Date
179
+ * Delimiter On Case
180
+ * _ to space
181
+ * _ to space Capitilize
182
+ * Drop square bracket prefix
183
+ * Ends With
184
+ * Float
185
+ * Get Word
186
+ * Integer
187
+ * is Between
188
+ * Lower Case
189
+ * Number
190
+ * Prepend
191
+ * JSON
192
+ * Range Limit
193
+ * Split
194
+ * Starts With
195
+ * Timestamp
196
+ * Title
197
+ * Title Grammatical
198
+ * Trim
199
+ * Trim End
200
+ * Trim Start
201
+ * Upper Case
202
+ * Xml String Encode
203
+
204
+
152
205
  * xlsx / xlsx object to array/JSON (excel uses [xlsx][7])
153
206
  * XML to JSON (uses [fast-xml-parser][4])
154
207
 
155
208
  Note, snappy needs to be installed separately as can have issues with auto install as build binaries.
156
209
 
157
210
  With xlsx object one can use the function in [xlsx][7] against the object in functions node.
158
-
211
+ "
159
212
  Example AVRO with schema
160
213
 
161
214
  ![Transform AVRO](documentation/transformArvo.jpg "Transform AVRO example")
@@ -300,6 +353,9 @@ Test/example flow in test/generalTest.json
300
353
  ------------------------------------------------------------
301
354
 
302
355
  # Version
356
+ 0.23.0 Removes bug in test, more translation
357
+
358
+ 0.22.0 Add autocovariance + autocorealationship to real time data analystics, improves test
303
359
 
304
360
  0.21.0 Add lag/seasonal to real time data analystics
305
361
 
@@ -0,0 +1,13 @@
1
+ const arrayTypesForEach=require("./arrayTypesForEach.js")
2
+ require("./arraySum.js")
3
+
4
+ arrayTypesForEach(object=>{
5
+ if(object.prototype.average==null)
6
+ Object.defineProperty(object.prototype, "average", {
7
+ value(i=0,end=this.length-1) {
8
+ return this.sum(i,end)/this.length;
9
+ },
10
+ writable: true,
11
+ configurable: true
12
+ });
13
+ })
@@ -1,3 +1,4 @@
1
+ /*
1
2
  [Array,Float32Array,Float64Array].forEach(object=>{
2
3
  if(object.prototype.sum==null)
3
4
  Object.defineProperty(object.prototype, "sum", {
@@ -8,4 +9,17 @@
8
9
  writable: true,
9
10
  configurable: true
10
11
  });
12
+ })
13
+ */
14
+ const arrayTypesForEach=require("./arrayTypesForEach.js")
15
+ arrayTypesForEach(object=>{
16
+ if(object.prototype.sum==null)
17
+ Object.defineProperty(object.prototype, "sum", {
18
+ value(i=0,end=this.length-1,sum=0) {
19
+ for(;i<=end;i++) sum+=this[i];
20
+ return sum;
21
+ },
22
+ writable: true,
23
+ configurable: true
24
+ });
11
25
  })
@@ -0,0 +1,5 @@
1
+ const typedArrays= {Array:Array,Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,
2
+ Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,
3
+ Float64Array:Float64Array,BigInt64Array:BigInt64Array,BigUint64Array:BigUint64Array}
4
+
5
+ module.exports=(call)=>Object.keys(typedArrays).map(t=>typedArrays[t]).forEach(type=>call(type))
@@ -0,0 +1,29 @@
1
+
2
+ require("./arrayAverage.js");
3
+ const arrayTypesForEach=require("./arrayTypesForEach.js")
4
+ arrayTypesForEach(object=>{
5
+ if(object.prototype.autocovariance==null)
6
+ Object.defineProperty(object.prototype, "autocovariance", {
7
+ value(lag,avg=this.average()) {
8
+ let autoCov = 0
9
+ const vectorSize=this.length
10
+ const vectorSizeLagged=vectorSize-lag
11
+ for(let i=0; i<vectorSizeLagged; i++) {
12
+ autoCov += ((this[i+lag])-avg)*(this[i]-avg)
13
+ }
14
+ return (1/(vectorSize-1))*autoCov
15
+ },
16
+ writable: true,
17
+ configurable: true
18
+ })
19
+ })
20
+ arrayTypesForEach(object=>{
21
+ if(object.prototype.autocorrelation==null)
22
+ Object.defineProperty(object.prototype, "autocorrelation", {
23
+ value(lag,avg=this.average()) {
24
+ return this.autocovariance(lag, avg) / this.autocovariance(0, avg)
25
+ },
26
+ writable: true,
27
+ configurable: true
28
+ })
29
+ })
@@ -47,7 +47,7 @@
47
47
  }
48
48
  });
49
49
  $("#node-input-action").change(function() {
50
- if(["differenceSeasonal","differenceSeasonalSecondOrder","realtime","realtimePredict"].includes( $(this).val() )) {
50
+ if(["autocovariance","autocorrelation","differenceSeasonal","differenceSeasonalSecondOrder","realtime","realtimePredict"].includes( $(this).val() )) {
51
51
  $(".form-row-http-in-lag").show();
52
52
  } else {
53
53
  $(".form-row-http-in-lag").hide();
@@ -158,6 +158,8 @@
158
158
  <div class="form-row">
159
159
  <label for="node-input-action"><i class="fa fa-list-ul"></i> Method</label>
160
160
  <select id="node-input-action" placeholder="action">
161
+ <option value="autocovariance">Autocovariance</option>
162
+ <option value="autocorrelation">Autocorrelation</option>
161
163
  <option value="avg">Average</option>
162
164
  <option value="covariance">Covariance</option>
163
165
  <option value="corelationship">Corelationship</option>
@@ -1,6 +1,7 @@
1
1
  const logger = new (require("node-red-contrib-logger"))("Data Analysis");
2
2
  logger.sendInfo("Copyright 2020 Jaroslav Peter Prib");
3
3
 
4
+ require("./autocorrelation.js");
4
5
  require("./arrayLast");
5
6
  require("./arrayDifference")
6
7
  require("./arrayDifferenceSeasonal")
@@ -129,6 +130,8 @@ function getColumns(node) {
129
130
  }
130
131
  }
131
132
  functions={
133
+ autocovariance:(d,term,node)=>d.autocovariance(node.lag),
134
+ autocorrelation:(d,term,node)=>d.autocorrelation(node.lag),
132
135
  avg:(d)=>functions.sum(d)/d.length,
133
136
  arrayMax:(d)=>{ // not tested
134
137
  let max=[],indices
Binary file
package/lib/common.js ADDED
@@ -0,0 +1,128 @@
1
+ const error=(node,message,shortMessage,logger)=>{
2
+ if(logger && logger.active) logger.send({label:"error",node:node.id,error:error,shortMessage});
3
+ node.error(message);
4
+ node.status({fill:"red",shape:"ring",text:shortMessage});
5
+ }
6
+ const evalFunction(id,mapping,logger)=>{
7
+ logger&&logger.sendInfo({label:"evalFunction",id:id,mapping:mapping})
8
+ try{
9
+ return eval(mapping);
10
+ } catch(ex) {
11
+ logger.sendError({label:"evalFunction error",id:id,mapping:mapping,error:ex.message})
12
+ throw Error(id+" "+ex.message);
13
+ }
14
+ }
15
+ const evalInFunction=(node,propertyName)=>{
16
+ try{
17
+ const nodeContext = node.context();
18
+ const flow = nodeContext.flow;
19
+ const global = nodeContext.global;
20
+ const property=node[propertyName];
21
+ if(property==null) throw Error("no value for "+propertyName);
22
+ const propertyType=propertyName+"-type";
23
+ if(! (propertyType in node)) return evalFunction(propertyName,"()=>node."+property)
24
+ switch (node[propertyType]){
25
+ case "num":
26
+ case "json":
27
+ return evalFunction(propertyName,"()=>"+property);
28
+ case "node":
29
+ return evalFunction(propertyName,"()=>nodeContext.get("+property+")");
30
+ case "flow":
31
+ if(flow) throw Error("context store may be memoryonly so flow doesn't work")
32
+ return evalFunction(propertyName,"()=>flow.get("+property+")");
33
+ case "global":
34
+ return evalFunction(propertyName,"()=>global.get("+property+")");
35
+ case "env":
36
+ return evalFunction(propertyName,"()=>env.get("+property+")");
37
+ case "msg":
38
+ return evalFunction(propertyName,"(msg)=>msg."+property);
39
+ default:
40
+ logger.sendInfo({label:"setData unknown type",action:node.action,propertyType:propertyType,type:node[propertyType]});
41
+ throw Error("unknown type "+node[propertyType])
42
+ }
43
+ } catch(ex) {
44
+ logger.sendError({label:"setup",error:ex.message,stack:ex.stack});
45
+ throw Error(property+" "+ex.message);
46
+ }
47
+ }
48
+
49
+ const argsArray=(node,msg)=>{
50
+ const args=[];
51
+ node.argFunction.forEach(callFunction=> {
52
+ const result=callFunction(msg);
53
+ args.push(result);
54
+ });
55
+ return args;
56
+ }
57
+ const setArgsFunction=(node)=>{
58
+ node.argFunction=[];
59
+ node.args.forEach(property=>{
60
+ try{
61
+ node.argFunction.push(evalInFunction(node,property).bind(this));
62
+ } catch(ex) {
63
+ throw Error("args "+property+" "+ex.message)
64
+ }
65
+ })
66
+ }
67
+
68
+
69
+ const setTargetFunction=(node)=>{
70
+ if(node.target) throw Error("target is null")
71
+ if(node.hasOwnProperty("target-type")) {
72
+ node.setData=evalFunction("target","data=>data)")
73
+ return
74
+ }
75
+ const nodeContext = node.context()
76
+ const type=node["target-type"]
77
+ switch(type){
78
+ case "node":
79
+ node.setData=evalFunction("target","data=>nodeContext.set("+node.target+",data)")
80
+ break
81
+ case "flow":
82
+ if(nodeContext.flow) throw Error("context store may be memory only so flow doesn't work")
83
+ node.setData=evalFunction("target","data=>nodeContext.flow.set("+node.target+",data)")
84
+ break
85
+ case "global":
86
+ node.setData=evalFunction("target","data=>nodeContext.global.set("+node.target+",data)")
87
+ break
88
+ case "msg":
89
+ node.setData=evalFunction("target","(data,msg)=>{msg."+node.target+"=data;}")
90
+ break
91
+ default:
92
+ throw Error("setData unknown type "+type)
93
+ }
94
+ }
95
+
96
+ const baseProcess=(msg,call=sourceMatrix[node.action])=>{
97
+ const value=node.getSource(msg);
98
+ if(value==null) throw Error("source data not found");
99
+ const valueObject=(value instanceof Matrix?value:new Matrix(value));
100
+ return call.apply(valueObject,argsArray(node,msg));
101
+ }
102
+ const baseProcessAndSet=(msg)=>{
103
+ const result=baseProcess(msg);
104
+ node.setData.apply(node,[result,msg]);
105
+ }
106
+ function createProcess(msg){
107
+ const sourceMatrix=new Matrix({rowsMax:node.rows,columns:node.columns,dataType:node.dataType});
108
+ if(!(node.initialState in sourceMatrix)) throw Error("Invalid initial state "+node.initialState);
109
+ sourceMatrix[node.initialState]()
110
+ node.setData.apply(node,[sourceMatrix,msg]);
111
+ }
112
+ function defineProcess(msg){
113
+ const sourceMatrix=new Matrix({rows:node.rows,columns:node.columns,dataType:node.dataType});
114
+ node.setData.apply(node,[sourceMatrix,msg]);
115
+ }
116
+ function defineEmptyProcess(msg){
117
+ if(logger.active) logger.sendInfo({label:"define",arg:{rowsMax:node.row,columns:node.column}});
118
+ const sourceMatrix=new Matrix({rowsMax:node.rows,columns:node.columns});
119
+ node.setData.apply(node,[sourceMatrix,msg]);
120
+ }
121
+ function createSize(msg){
122
+ const sourceMatrix=new Matrix({rows:node.size,columns:node.size});
123
+ node.setData.apply(node,[sourceMatrix[node.action](),msg]);
124
+ }
125
+ function createDummy(msg){
126
+ const sourceMatrix=new Matrix(1,1);
127
+ node.setData.apply(node,[sourceMatrix[node.action].apply(sourceMatrix,argsArray(node,msg)),msg]);
128
+ }