blacklight_heatmaps 1.3.1 → 1.4.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.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/app/assets/javascripts/blacklight_heatmaps/default.esm.js +2000 -0
- data/app/assets/javascripts/blacklight_heatmaps/default.esm.js.map +1 -0
- data/app/assets/javascripts/blacklight_heatmaps/default.js +2006 -8
- data/app/assets/javascripts/blacklight_heatmaps/default.js.map +1 -0
- data/app/{assets/javascripts/blacklight_heatmaps → javascript}/basemaps.js +4 -2
- data/app/javascript/blacklight_heatmaps.js +42 -0
- data/app/javascript/icons.js +5 -0
- data/app/javascript/viewers/index.js +76 -0
- data/app/javascript/viewers/show.js +24 -0
- data/lib/blacklight_heatmaps/version.rb +1 -1
- data/lib/generators/blacklight_heatmaps/install_generator.rb +2 -0
- data/spec/examples.txt +31 -0
- data/spec/features/configurable_basemap_spec.rb +1 -2
- data/spec/features/index_page_map_spec.rb +1 -1
- data/spec/features/show_page_map_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -2
- data/vendor/assets/javascripts/geostats.js +511 -284
- data/vendor/assets/javascripts/leaflet_solr_heatmap.js +6 -4
- metadata +13 -9
- data/app/assets/javascripts/blacklight_heatmaps/blacklight_heatmaps.js +0 -18
- data/app/assets/javascripts/blacklight_heatmaps/icons.js +0 -3
- data/app/assets/javascripts/blacklight_heatmaps/viewers/index.js +0 -91
- data/app/assets/javascripts/blacklight_heatmaps/viewers/show.js +0 -39
- data/app/assets/javascripts/index.js +0 -8
@@ -1,7 +1,7 @@
|
|
1
1
|
/**
|
2
|
-
* geostats() is a tiny and standalone javascript library for classification
|
2
|
+
* geostats() is a tiny and standalone javascript library for classification
|
3
3
|
* Project page - https://github.com/simogeo/geostats
|
4
|
-
* Copyright (c) 2011 Simon Georget, http://www.
|
4
|
+
* Copyright (c) 2011 Simon Georget, http://www.intermezzo-coop.eu
|
5
5
|
* Licensed under the MIT license
|
6
6
|
*/
|
7
7
|
|
@@ -85,13 +85,13 @@ var geostats = function(a) {
|
|
85
85
|
this.is_uniqueValues = false;
|
86
86
|
this.debug = false;
|
87
87
|
this.silent = false;
|
88
|
-
|
88
|
+
|
89
89
|
this.bounds = Array();
|
90
90
|
this.ranges = Array();
|
91
91
|
this.inner_ranges = null;
|
92
92
|
this.colors = Array();
|
93
93
|
this.counter = Array();
|
94
|
-
|
94
|
+
|
95
95
|
// statistics information
|
96
96
|
this.stat_sorted = null;
|
97
97
|
this.stat_mean = null;
|
@@ -104,62 +104,62 @@ var geostats = function(a) {
|
|
104
104
|
this.stat_stddev = null;
|
105
105
|
this.stat_cov = null;
|
106
106
|
|
107
|
-
|
107
|
+
|
108
108
|
/**
|
109
109
|
* logging method
|
110
110
|
*/
|
111
111
|
this.log = function(msg, force) {
|
112
|
-
|
112
|
+
|
113
113
|
if(this.debug == true || force != null)
|
114
114
|
console.log(this.objectID + "(object id) :: " + msg);
|
115
|
-
|
115
|
+
|
116
116
|
};
|
117
|
-
|
117
|
+
|
118
118
|
/**
|
119
119
|
* Set bounds
|
120
120
|
*/
|
121
121
|
this.setBounds = function(a) {
|
122
|
-
|
122
|
+
|
123
123
|
this.log('Setting bounds (' + a.length + ') : ' + a.join());
|
124
|
-
|
124
|
+
|
125
125
|
this.bounds = Array() // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
|
126
|
-
|
126
|
+
|
127
127
|
this.bounds = a;
|
128
128
|
//this.bounds = this.decimalFormat(a);
|
129
|
-
|
129
|
+
|
130
130
|
};
|
131
|
-
|
131
|
+
|
132
132
|
/**
|
133
133
|
* Set a new serie
|
134
134
|
*/
|
135
135
|
this.setSerie = function(a) {
|
136
|
-
|
136
|
+
|
137
137
|
this.log('Setting serie (' + a.length + ') : ' + a.join());
|
138
|
-
|
138
|
+
|
139
139
|
this.serie = Array() // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
|
140
140
|
this.serie = a;
|
141
|
-
|
141
|
+
|
142
142
|
//reset statistics after changing serie
|
143
143
|
this.resetStatistics();
|
144
|
-
|
144
|
+
|
145
145
|
this.setPrecision();
|
146
|
-
|
146
|
+
|
147
147
|
};
|
148
|
-
|
148
|
+
|
149
149
|
/**
|
150
150
|
* Set colors
|
151
151
|
*/
|
152
152
|
this.setColors = function(colors) {
|
153
|
-
|
153
|
+
|
154
154
|
this.log('Setting color ramp (' + colors.length + ') : ' + colors.join());
|
155
|
-
|
155
|
+
|
156
156
|
this.colors = colors;
|
157
|
-
|
157
|
+
|
158
158
|
};
|
159
|
-
|
159
|
+
|
160
160
|
/**
|
161
161
|
* Get feature count
|
162
|
-
* With bounds array(0, 0.75, 1.5, 2.25, 3);
|
162
|
+
* With bounds array(0, 0.75, 1.5, 2.25, 3);
|
163
163
|
* should populate this.counter with 5 keys
|
164
164
|
* and increment counters for each key
|
165
165
|
*/
|
@@ -167,19 +167,25 @@ var geostats = function(a) {
|
|
167
167
|
|
168
168
|
if (this._nodata())
|
169
169
|
return;
|
170
|
-
|
170
|
+
|
171
171
|
|
172
172
|
var tmp = this.sorted();
|
173
|
-
|
173
|
+
|
174
174
|
this.counter = new Array();
|
175
|
-
|
175
|
+
|
176
176
|
// we init counter with 0 value
|
177
|
-
|
178
|
-
|
177
|
+
if(this.is_uniqueValues == true) {
|
178
|
+
for (var i = 0; i < this.bounds.length; i++) {
|
179
|
+
this.counter[i]= 0;
|
180
|
+
}
|
181
|
+
} else {
|
182
|
+
for (var i = 0; i < this.bounds.length -1; i++) {
|
183
|
+
this.counter[i]= 0;
|
184
|
+
}
|
179
185
|
}
|
180
|
-
|
181
|
-
for(j=0; j < tmp.length; j++) {
|
182
|
-
|
186
|
+
|
187
|
+
for (var j=0; j < tmp.length; j++) {
|
188
|
+
|
183
189
|
// get current class for value to increment the counter
|
184
190
|
var cclass = this.getClass(tmp[j]);
|
185
191
|
this.counter[cclass]++;
|
@@ -187,239 +193,262 @@ var geostats = function(a) {
|
|
187
193
|
}
|
188
194
|
|
189
195
|
};
|
190
|
-
|
196
|
+
|
191
197
|
/**
|
192
198
|
* Set decimal precision according to user input
|
193
199
|
* or automatcally determined according
|
194
200
|
* to the given serie.
|
195
201
|
*/
|
196
202
|
this.setPrecision = function(decimals) {
|
197
|
-
|
203
|
+
|
198
204
|
// only when called from user
|
199
205
|
if(typeof decimals !== "undefined") {
|
200
206
|
this.precisionflag = 'manual';
|
201
207
|
this.precision = decimals;
|
202
208
|
}
|
203
|
-
|
209
|
+
|
204
210
|
// we calculate the maximal decimal length on given serie
|
205
211
|
if(this.precisionflag == 'auto') {
|
206
|
-
|
212
|
+
|
207
213
|
for (var i = 0; i < this.serie.length; i++) {
|
208
|
-
|
214
|
+
|
209
215
|
// check if the given value is a number and a float
|
210
216
|
if (!isNaN((this.serie[i]+"")) && (this.serie[i]+"").toString().indexOf('.') != -1) {
|
211
217
|
var precision = (this.serie[i] + "").split(".")[1].length;
|
212
218
|
} else {
|
213
219
|
var precision = 0;
|
214
220
|
}
|
215
|
-
|
221
|
+
|
216
222
|
if(precision > this.precision) {
|
217
223
|
this.precision = precision;
|
218
224
|
}
|
219
|
-
|
225
|
+
|
220
226
|
}
|
221
|
-
|
227
|
+
|
228
|
+
}
|
229
|
+
if(this.precision > 20) {
|
230
|
+
// prevent "Uncaught RangeError: toFixed() digits argument must be between 0 and 20" bug. See https://github.com/simogeo/geostats/issues/34
|
231
|
+
this.log('this.precision value (' + this.precision + ') is greater than max value. Automatic set-up to 20 to prevent "Uncaught RangeError: toFixed()" when calling decimalFormat() method.');
|
232
|
+
this.precision = 20;
|
222
233
|
}
|
223
234
|
|
224
235
|
this.log('Calling setPrecision(). Mode : ' + this.precisionflag + ' - Decimals : '+ this.precision);
|
225
|
-
|
236
|
+
|
226
237
|
this.serie = this.decimalFormat(this.serie);
|
227
|
-
|
238
|
+
|
228
239
|
};
|
229
|
-
|
240
|
+
|
230
241
|
/**
|
231
242
|
* Format array numbers regarding to precision
|
232
243
|
*/
|
233
244
|
this.decimalFormat = function(a) {
|
234
|
-
|
245
|
+
|
235
246
|
var b = new Array();
|
236
|
-
|
247
|
+
|
237
248
|
for (var i = 0; i < a.length; i++) {
|
238
249
|
// check if the given value is a number
|
239
250
|
if (isNumber(a[i])) {
|
240
|
-
b[i] = parseFloat(a[i].toFixed(this.precision));
|
251
|
+
b[i] = parseFloat(parseFloat(a[i]).toFixed(this.precision));
|
241
252
|
} else {
|
242
253
|
b[i] = a[i];
|
243
254
|
}
|
244
255
|
}
|
245
|
-
|
256
|
+
|
246
257
|
return b;
|
247
258
|
}
|
248
|
-
|
259
|
+
|
249
260
|
/**
|
250
261
|
* Transform a bounds array to a range array the following array : array(0,
|
251
262
|
* 0.75, 1.5, 2.25, 3); becomes : array('0-0.75', '0.75-1.5', '1.5-2.25',
|
252
263
|
* '2.25-3');
|
253
264
|
*/
|
254
265
|
this.setRanges = function() {
|
255
|
-
|
266
|
+
|
256
267
|
this.ranges = Array(); // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
|
257
|
-
|
258
|
-
for (i = 0; i < (this.bounds.length - 1); i++) {
|
268
|
+
|
269
|
+
for (var i = 0; i < (this.bounds.length - 1); i++) {
|
259
270
|
this.ranges[i] = this.bounds[i] + this.separator + this.bounds[i + 1];
|
260
271
|
}
|
261
272
|
};
|
262
273
|
|
263
274
|
/** return min value */
|
264
|
-
this.min = function() {
|
265
|
-
|
275
|
+
this.min = function(exclude = []) {
|
276
|
+
|
266
277
|
if (this._nodata())
|
267
278
|
return;
|
268
|
-
|
269
|
-
this.stat_min =
|
270
|
-
|
279
|
+
|
280
|
+
if(!exclude.includes(this.serie[0])) this.stat_min = this.serie[0];
|
281
|
+
else this.stat_min = 999999999999;
|
282
|
+
|
283
|
+
|
284
|
+
for (var i = 0; i < this.pop(); i++) {
|
285
|
+
if (this.serie[i] < this.stat_min && !exclude.includes(this.serie[i])) {
|
286
|
+
this.stat_min = this.serie[i];
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
271
290
|
return this.stat_min;
|
272
291
|
};
|
273
292
|
|
274
293
|
/** return max value */
|
275
|
-
this.max = function() {
|
276
|
-
|
277
|
-
|
278
|
-
|
294
|
+
this.max = function(exclude = []) {
|
295
|
+
|
296
|
+
if (this._nodata())
|
297
|
+
return;
|
298
|
+
|
299
|
+
if(!exclude.includes(this.serie[0])) this.stat_max = this.serie[0];
|
300
|
+
else this.stat_max = -999999999999;
|
301
|
+
|
302
|
+
for (var i = 0; i < this.pop(); i++) {
|
303
|
+
if (this.serie[i] > this.stat_max && !exclude.includes(this.serie[i])) {
|
304
|
+
this.stat_max = this.serie[i];
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
279
308
|
return this.stat_max;
|
280
309
|
};
|
281
310
|
|
282
311
|
/** return sum value */
|
283
312
|
this.sum = function() {
|
284
|
-
|
313
|
+
|
285
314
|
if (this._nodata())
|
286
315
|
return;
|
287
|
-
|
316
|
+
|
288
317
|
if (this.stat_sum == null) {
|
289
|
-
|
318
|
+
|
290
319
|
this.stat_sum = 0;
|
291
|
-
for (i = 0; i < this.pop(); i++) {
|
320
|
+
for (var i = 0; i < this.pop(); i++) {
|
292
321
|
this.stat_sum += parseFloat(this.serie[i]);
|
293
322
|
}
|
294
|
-
|
323
|
+
|
295
324
|
}
|
296
|
-
|
325
|
+
|
297
326
|
return this.stat_sum;
|
298
327
|
};
|
299
328
|
|
300
329
|
/** return population number */
|
301
330
|
this.pop = function() {
|
302
|
-
|
331
|
+
|
303
332
|
if (this._nodata())
|
304
333
|
return;
|
305
|
-
|
334
|
+
|
306
335
|
if (this.stat_pop == null) {
|
307
|
-
|
336
|
+
|
308
337
|
this.stat_pop = this.serie.length;
|
309
|
-
|
338
|
+
|
310
339
|
}
|
311
|
-
|
340
|
+
|
312
341
|
return this.stat_pop;
|
313
342
|
};
|
314
343
|
|
315
344
|
/** return mean value */
|
316
345
|
this.mean = function() {
|
317
|
-
|
346
|
+
|
318
347
|
if (this._nodata())
|
319
348
|
return;
|
320
349
|
|
321
350
|
if (this.stat_mean == null) {
|
322
|
-
|
351
|
+
|
323
352
|
this.stat_mean = parseFloat(this.sum() / this.pop());
|
324
|
-
|
353
|
+
|
325
354
|
}
|
326
|
-
|
355
|
+
|
327
356
|
return this.stat_mean;
|
328
357
|
};
|
329
358
|
|
330
359
|
/** return median value */
|
331
360
|
this.median = function() {
|
332
|
-
|
361
|
+
|
333
362
|
if (this._nodata())
|
334
363
|
return;
|
335
|
-
|
364
|
+
|
336
365
|
if (this.stat_median == null) {
|
337
|
-
|
366
|
+
|
338
367
|
this.stat_median = 0;
|
339
368
|
var tmp = this.sorted();
|
340
|
-
|
369
|
+
|
341
370
|
// serie pop is odd
|
342
371
|
if (tmp.length % 2) {
|
343
372
|
this.stat_median = parseFloat(tmp[(Math.ceil(tmp.length / 2) - 1)]);
|
344
|
-
|
373
|
+
|
345
374
|
// serie pop is even
|
346
375
|
} else {
|
347
376
|
this.stat_median = ( parseFloat(tmp[((tmp.length / 2) - 1)]) + parseFloat(tmp[(tmp.length / 2)]) ) / 2;
|
348
377
|
}
|
349
|
-
|
378
|
+
|
350
379
|
}
|
351
|
-
|
380
|
+
|
352
381
|
return this.stat_median;
|
353
382
|
};
|
354
383
|
|
355
384
|
/** return variance value */
|
356
385
|
this.variance = function() {
|
357
|
-
|
358
|
-
round = (typeof round === "undefined") ? true : false;
|
359
|
-
|
386
|
+
|
387
|
+
var round = (typeof round === "undefined") ? true : false;
|
388
|
+
|
360
389
|
if (this._nodata())
|
361
390
|
return;
|
362
|
-
|
391
|
+
|
363
392
|
if (this.stat_variance == null) {
|
364
393
|
|
365
|
-
var tmp = 0;
|
394
|
+
var tmp = 0, serie_mean = this.mean();
|
366
395
|
for (var i = 0; i < this.pop(); i++) {
|
367
|
-
tmp += Math.pow( (this.serie[i] -
|
396
|
+
tmp += Math.pow( (this.serie[i] - serie_mean), 2 );
|
368
397
|
}
|
369
398
|
|
370
|
-
this.stat_variance = tmp /
|
371
|
-
|
399
|
+
this.stat_variance = tmp / this.pop();
|
400
|
+
|
372
401
|
if(round == true) {
|
373
402
|
this.stat_variance = Math.round(this.stat_variance * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
|
374
403
|
}
|
375
|
-
|
404
|
+
|
376
405
|
}
|
377
|
-
|
406
|
+
|
378
407
|
return this.stat_variance;
|
379
408
|
};
|
380
|
-
|
409
|
+
|
381
410
|
/** return standard deviation value */
|
382
411
|
this.stddev = function(round) {
|
383
|
-
|
384
|
-
round = (typeof round === "undefined") ? true : false;
|
385
|
-
|
412
|
+
|
413
|
+
var round = (typeof round === "undefined") ? true : false;
|
414
|
+
|
386
415
|
if (this._nodata())
|
387
416
|
return;
|
388
|
-
|
417
|
+
|
389
418
|
if (this.stat_stddev == null) {
|
390
|
-
|
419
|
+
|
391
420
|
this.stat_stddev = Math.sqrt(this.variance());
|
392
|
-
|
421
|
+
|
393
422
|
if(round == true) {
|
394
423
|
this.stat_stddev = Math.round(this.stat_stddev * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
|
395
424
|
}
|
396
|
-
|
425
|
+
|
397
426
|
}
|
398
|
-
|
427
|
+
|
399
428
|
return this.stat_stddev;
|
400
429
|
};
|
401
|
-
|
430
|
+
|
402
431
|
/** coefficient of variation - measure of dispersion */
|
403
432
|
this.cov = function(round) {
|
404
|
-
|
405
|
-
round = (typeof round === "undefined") ? true : false;
|
406
|
-
|
433
|
+
|
434
|
+
var round = (typeof round === "undefined") ? true : false;
|
435
|
+
|
407
436
|
if (this._nodata())
|
408
437
|
return;
|
409
|
-
|
438
|
+
|
410
439
|
if (this.stat_cov == null) {
|
411
|
-
|
440
|
+
|
412
441
|
this.stat_cov = this.stddev() / this.mean();
|
413
|
-
|
442
|
+
|
414
443
|
if(round == true) {
|
415
444
|
this.stat_cov = Math.round(this.stat_cov * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
|
416
445
|
}
|
417
|
-
|
446
|
+
|
418
447
|
}
|
419
|
-
|
448
|
+
|
420
449
|
return this.stat_cov;
|
421
450
|
};
|
422
|
-
|
451
|
+
|
423
452
|
/** reset all attributes after setting a new serie */
|
424
453
|
this.resetStatistics = function() {
|
425
454
|
this.stat_sorted = null;
|
@@ -433,34 +462,63 @@ var geostats = function(a) {
|
|
433
462
|
this.stat_stddev = null;
|
434
463
|
this.stat_cov = null;
|
435
464
|
}
|
436
|
-
|
465
|
+
|
437
466
|
/** data test */
|
438
467
|
this._nodata = function() {
|
439
468
|
if (this.serie.length == 0) {
|
440
|
-
|
469
|
+
|
441
470
|
if(this.silent) this.log("[silent mode] Error. You should first enter a serie!", true);
|
442
|
-
else
|
471
|
+
else throw new TypeError("Error. You should first enter a serie!");
|
443
472
|
return 1;
|
444
473
|
} else
|
445
474
|
return 0;
|
446
|
-
|
475
|
+
|
476
|
+
};
|
477
|
+
|
478
|
+
/** data test */
|
479
|
+
this._classificationCheck = function(nbClass) {
|
480
|
+
|
481
|
+
if(nbClass >= this.pop()) {
|
482
|
+
var errnum ='Error. ' + nbClass + ' classes are defined for only ' + this.pop() + ' values in serie ! For the current serie, no more than ' + (this.pop() - 1 ) + ' classes can be defined.';
|
483
|
+
|
484
|
+
if(this.silent) this.log(errnum, true);
|
485
|
+
else {
|
486
|
+
alert(errnum);
|
487
|
+
throw new TypeError(errnum);
|
488
|
+
}
|
489
|
+
|
490
|
+
}
|
491
|
+
|
447
492
|
};
|
448
|
-
|
493
|
+
|
494
|
+
/** ensure nbClass is an integer */
|
495
|
+
this._nbClassInt = function(nbClass) {
|
496
|
+
|
497
|
+
var nbclassTmp = parseInt(nbClass, 10);
|
498
|
+
if (isNaN(nbclassTmp)) {
|
499
|
+
if(this.silent) this.log("[silent mode] '" + nbclassTmp + "' is not a valid integer. Enable to set class number.", true);
|
500
|
+
else throw new TypeError("'" + nbclassTmp + "' is not a valid integer. Enable to set class number.");
|
501
|
+
} else {
|
502
|
+
return nbclassTmp;
|
503
|
+
}
|
504
|
+
|
505
|
+
};
|
506
|
+
|
449
507
|
/** check if the serie contains negative value */
|
450
508
|
this._hasNegativeValue = function() {
|
451
|
-
|
452
|
-
for (i = 0; i < this.serie.length; i++) {
|
509
|
+
|
510
|
+
for (var i = 0; i < this.serie.length; i++) {
|
453
511
|
if(this.serie[i] < 0)
|
454
512
|
return true;
|
455
513
|
}
|
456
514
|
|
457
515
|
return false;
|
458
516
|
};
|
459
|
-
|
517
|
+
|
460
518
|
/** check if the serie contains zero value */
|
461
519
|
this._hasZeroValue = function() {
|
462
|
-
|
463
|
-
for (i = 0; i < this.serie.length; i++) {
|
520
|
+
|
521
|
+
for (var i = 0; i < this.serie.length; i++) {
|
464
522
|
if(parseFloat(this.serie[i]) === 0)
|
465
523
|
return true;
|
466
524
|
}
|
@@ -470,9 +528,9 @@ var geostats = function(a) {
|
|
470
528
|
|
471
529
|
/** return sorted values (as array) */
|
472
530
|
this.sorted = function() {
|
473
|
-
|
531
|
+
|
474
532
|
if (this.stat_sorted == null) {
|
475
|
-
|
533
|
+
|
476
534
|
if(this.is_uniqueValues == false) {
|
477
535
|
this.stat_sorted = this.serie.sort(function(a, b) {
|
478
536
|
return a - b;
|
@@ -486,33 +544,33 @@ var geostats = function(a) {
|
|
486
544
|
})
|
487
545
|
}
|
488
546
|
}
|
489
|
-
|
547
|
+
|
490
548
|
return this.stat_sorted;
|
491
|
-
|
549
|
+
|
492
550
|
};
|
493
551
|
|
494
552
|
/** return all info */
|
495
553
|
this.info = function() {
|
496
|
-
|
554
|
+
|
497
555
|
if (this._nodata())
|
498
556
|
return;
|
499
|
-
|
557
|
+
|
500
558
|
var content = '';
|
501
559
|
content += _t('Population') + ' : ' + this.pop() + ' - [' + _t('Min')
|
502
560
|
+ ' : ' + this.min() + ' | ' + _t('Max') + ' : ' + this.max()
|
503
561
|
+ ']' + "\n";
|
504
562
|
content += _t('Mean') + ' : ' + this.mean() + ' - ' + _t('Median') + ' : ' + this.median() + "\n";
|
505
|
-
content += _t('Variance') + ' : ' + this.variance() + ' - ' + _t('Standard deviation') + ' : ' + this.stddev()
|
563
|
+
content += _t('Variance') + ' : ' + this.variance() + ' - ' + _t('Standard deviation') + ' : ' + this.stddev()
|
506
564
|
+ ' - ' + _t('Coefficient of variation') + ' : ' + this.cov() + "\n";
|
507
565
|
|
508
566
|
return content;
|
509
567
|
};
|
510
|
-
|
568
|
+
|
511
569
|
/**
|
512
570
|
* Set Manual classification Return an array with bounds : ie array(0,
|
513
571
|
* 0.75, 1.5, 2.25, 3);
|
514
572
|
* Set ranges and prepare data for displaying legend
|
515
|
-
*
|
573
|
+
*
|
516
574
|
*/
|
517
575
|
this.setClassManually = function(array) {
|
518
576
|
|
@@ -521,13 +579,13 @@ var geostats = function(a) {
|
|
521
579
|
|
522
580
|
if(array[0] !== this.min() || array[array.length-1] !== this.max()) {
|
523
581
|
if(this.silent) this.log("[silent mode] " + t('Given bounds may not be correct! please check your input.\nMin value : ' + this.min() + ' / Max value : ' + this.max()), true);
|
524
|
-
else
|
525
|
-
return;
|
582
|
+
else throw new TypeError(_t('Given bounds may not be correct! please check your input.\nMin value : ' + this.min() + ' / Max value : ' + this.max()));
|
583
|
+
return;
|
526
584
|
}
|
527
585
|
|
528
586
|
this.setBounds(array);
|
529
587
|
this.setRanges();
|
530
|
-
|
588
|
+
|
531
589
|
// we specify the classification method
|
532
590
|
this.method = _t('manual classification') + ' (' + (array.length -1) + ' ' + _t('classes') + ')';
|
533
591
|
|
@@ -540,17 +598,19 @@ var geostats = function(a) {
|
|
540
598
|
*/
|
541
599
|
this.getClassEqInterval = function(nbClass, forceMin, forceMax) {
|
542
600
|
|
601
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
602
|
+
|
543
603
|
if (this._nodata())
|
544
604
|
return;
|
545
605
|
|
546
606
|
var tmpMin = (typeof forceMin === "undefined") ? this.min() : forceMin;
|
547
607
|
var tmpMax = (typeof forceMax === "undefined") ? this.max() : forceMax;
|
548
|
-
|
608
|
+
|
549
609
|
var a = Array();
|
550
610
|
var val = tmpMin;
|
551
611
|
var interval = (tmpMax - tmpMin) / nbClass;
|
552
612
|
|
553
|
-
for (i = 0; i <= nbClass; i++) {
|
613
|
+
for (var i = 0; i <= nbClass; i++) {
|
554
614
|
a[i] = val;
|
555
615
|
val += interval;
|
556
616
|
}
|
@@ -560,15 +620,18 @@ var geostats = function(a) {
|
|
560
620
|
|
561
621
|
this.setBounds(a);
|
562
622
|
this.setRanges();
|
563
|
-
|
623
|
+
|
564
624
|
// we specify the classification method
|
565
625
|
this.method = _t('eq. intervals') + ' (' + nbClass + ' ' + _t('classes') + ')';
|
566
626
|
|
567
627
|
return this.bounds;
|
568
628
|
};
|
569
|
-
|
629
|
+
|
570
630
|
|
571
631
|
this.getQuantiles = function(nbClass) {
|
632
|
+
|
633
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
634
|
+
|
572
635
|
var tmp = this.sorted();
|
573
636
|
var quantiles = [];
|
574
637
|
|
@@ -587,9 +650,13 @@ var geostats = function(a) {
|
|
587
650
|
*/
|
588
651
|
this.getClassQuantile = function(nbClass) {
|
589
652
|
|
653
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
654
|
+
|
590
655
|
if (this._nodata())
|
591
656
|
return;
|
592
657
|
|
658
|
+
this._classificationCheck(nbClass); // be sure number of classes is valid
|
659
|
+
|
593
660
|
var tmp = this.sorted();
|
594
661
|
var bounds = this.getQuantiles(nbClass);
|
595
662
|
bounds.unshift(tmp[0]);
|
@@ -606,7 +673,7 @@ var geostats = function(a) {
|
|
606
673
|
return this.bounds;
|
607
674
|
|
608
675
|
};
|
609
|
-
|
676
|
+
|
610
677
|
/**
|
611
678
|
* Standard Deviation classification
|
612
679
|
* Return an array with bounds : ie array(0,
|
@@ -614,180 +681,194 @@ var geostats = function(a) {
|
|
614
681
|
*/
|
615
682
|
this.getClassStdDeviation = function(nbClass, matchBounds) {
|
616
683
|
|
684
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
685
|
+
|
617
686
|
if (this._nodata())
|
618
687
|
return;
|
619
688
|
|
620
689
|
var tmpMax = this.max();
|
621
|
-
|
622
|
-
|
690
|
+
var tmpMin = this.min();
|
691
|
+
var tmpStdDev = this.stddev();
|
692
|
+
var tmpMean = this.mean();
|
693
|
+
|
623
694
|
var a = Array();
|
624
|
-
|
695
|
+
|
625
696
|
// number of classes is odd
|
626
697
|
if(nbClass % 2 == 1) {
|
627
698
|
|
628
699
|
// Euclidean division to get the inferior bound
|
629
700
|
var infBound = Math.floor(nbClass / 2);
|
630
|
-
|
701
|
+
|
631
702
|
var supBound = infBound + 1;
|
632
|
-
|
703
|
+
|
633
704
|
// we set the central bounds
|
634
|
-
a[infBound] =
|
635
|
-
a[supBound] =
|
636
|
-
|
705
|
+
a[infBound] = tmpMean - (tmpStdDev / 2);
|
706
|
+
a[supBound] = tmpMean + (tmpStdDev / 2);
|
707
|
+
|
637
708
|
// Values < to infBound, except first one
|
638
|
-
for (i = infBound - 1; i > 0; i--) {
|
639
|
-
var val = a[i+1] -
|
709
|
+
for (var i = infBound - 1; i > 0; i--) {
|
710
|
+
var val = a[i+1] - tmpStdDev;
|
640
711
|
a[i] = val;
|
641
712
|
}
|
642
|
-
|
713
|
+
|
643
714
|
// Values > to supBound, except last one
|
644
|
-
for (i = supBound + 1; i < nbClass; i++) {
|
645
|
-
var val = a[i-1] +
|
715
|
+
for (var i = supBound + 1; i < nbClass; i++) {
|
716
|
+
var val = a[i-1] + tmpStdDev;
|
646
717
|
a[i] = val;
|
647
718
|
}
|
648
|
-
|
719
|
+
|
649
720
|
// number of classes is even
|
650
721
|
} else {
|
651
|
-
|
722
|
+
|
652
723
|
var meanBound = nbClass / 2;
|
653
|
-
|
724
|
+
|
654
725
|
// we get the mean value
|
655
|
-
a[meanBound] =
|
656
|
-
|
726
|
+
a[meanBound] = tmpMean;
|
727
|
+
|
657
728
|
// Values < to the mean, except first one
|
658
|
-
for (i = meanBound - 1; i > 0; i--) {
|
659
|
-
var val = a[i+1] -
|
729
|
+
for (var i = meanBound - 1; i > 0; i--) {
|
730
|
+
var val = a[i+1] - tmpStdDev;
|
660
731
|
a[i] = val;
|
661
732
|
}
|
662
|
-
|
733
|
+
|
663
734
|
// Values > to the mean, except last one
|
664
|
-
for (i = meanBound + 1; i < nbClass; i++) {
|
665
|
-
var val = a[i-1] +
|
735
|
+
for (var i = meanBound + 1; i < nbClass; i++) {
|
736
|
+
var val = a[i-1] + tmpStdDev;
|
666
737
|
a[i] = val;
|
667
738
|
}
|
668
739
|
}
|
669
|
-
|
670
|
-
|
740
|
+
|
741
|
+
|
671
742
|
// we finally set the first value
|
672
|
-
// do we excatly match min value or not ?
|
673
|
-
a[0] = (typeof matchBounds === "undefined") ? a[1]-
|
674
|
-
|
743
|
+
// do we excatly match min value or not ?
|
744
|
+
a[0] = (typeof matchBounds === "undefined") ? a[1]- tmpStdDev : tmpMin;
|
745
|
+
|
675
746
|
// we finally set the last value
|
676
|
-
// do we excatly match max value or not ?
|
677
|
-
a[nbClass] = (typeof matchBounds === "undefined") ? a[nbClass-1]+
|
747
|
+
// do we excatly match max value or not ?
|
748
|
+
a[nbClass] = (typeof matchBounds === "undefined") ? a[nbClass-1] + tmpStdDev : tmpMax;
|
678
749
|
|
679
750
|
this.setBounds(a);
|
680
751
|
this.setRanges();
|
681
|
-
|
752
|
+
|
682
753
|
// we specify the classification method
|
683
|
-
this.method = _t('std deviation') + ' (' + nbClass + ' ' + _t('classes')+ ')';
|
684
|
-
|
754
|
+
this.method = _t('std deviation') + ' (' + nbClass + ' ' + _t('classes')+ ')';
|
755
|
+
|
685
756
|
return this.bounds;
|
686
757
|
};
|
687
|
-
|
688
|
-
|
758
|
+
|
759
|
+
|
689
760
|
/**
|
690
|
-
* Geometric Progression classification
|
761
|
+
* Geometric Progression classification
|
691
762
|
* http://en.wikipedia.org/wiki/Geometric_progression
|
692
763
|
* Return an array with bounds : ie array(0,
|
693
764
|
* 0.75, 1.5, 2.25, 3);
|
694
765
|
*/
|
695
766
|
this.getClassGeometricProgression = function(nbClass) {
|
696
767
|
|
768
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
769
|
+
|
697
770
|
if (this._nodata())
|
698
771
|
return;
|
699
772
|
|
700
773
|
if(this._hasNegativeValue() || this._hasZeroValue()) {
|
701
774
|
if(this.silent) this.log("[silent mode] " + _t('geometric progression can\'t be applied with a serie containing negative or zero values.'), true);
|
702
|
-
else
|
775
|
+
else throw new TypeError(_t('geometric progression can\'t be applied with a serie containing negative or zero values.'));
|
703
776
|
return;
|
704
777
|
}
|
705
|
-
|
778
|
+
|
706
779
|
var a = Array();
|
707
780
|
var tmpMin = this.min();
|
708
781
|
var tmpMax = this.max();
|
709
|
-
|
782
|
+
|
710
783
|
var logMax = Math.log(tmpMax) / Math.LN10; // max decimal logarithm (or base 10)
|
711
784
|
var logMin = Math.log(tmpMin) / Math.LN10;; // min decimal logarithm (or base 10)
|
712
|
-
|
785
|
+
|
713
786
|
var interval = (logMax - logMin) / nbClass;
|
714
|
-
|
787
|
+
|
715
788
|
// we compute log bounds
|
716
|
-
for (i = 0; i < nbClass; i++) {
|
789
|
+
for (var i = 0; i < nbClass; i++) {
|
717
790
|
if(i == 0) {
|
718
791
|
a[i] = logMin;
|
719
792
|
} else {
|
720
793
|
a[i] = a[i-1] + interval;
|
721
794
|
}
|
722
795
|
}
|
723
|
-
|
796
|
+
|
724
797
|
// we compute antilog
|
725
798
|
a = a.map(function(x) { return Math.pow(10, x); });
|
726
|
-
|
799
|
+
|
727
800
|
// and we finally add max value
|
728
801
|
a.push(this.max());
|
729
|
-
|
802
|
+
|
730
803
|
this.setBounds(a);
|
731
804
|
this.setRanges();
|
732
|
-
|
805
|
+
|
733
806
|
// we specify the classification method
|
734
807
|
this.method = _t('geometric progression') + ' (' + nbClass + ' ' + _t('classes') + ')';
|
735
808
|
|
736
809
|
return this.bounds;
|
737
810
|
};
|
738
|
-
|
811
|
+
|
739
812
|
/**
|
740
|
-
* Arithmetic Progression classification
|
813
|
+
* Arithmetic Progression classification
|
741
814
|
* http://en.wikipedia.org/wiki/Arithmetic_progression
|
742
815
|
* Return an array with bounds : ie array(0,
|
743
816
|
* 0.75, 1.5, 2.25, 3);
|
744
817
|
*/
|
745
818
|
this.getClassArithmeticProgression = function(nbClass) {
|
746
819
|
|
820
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
821
|
+
|
747
822
|
if (this._nodata())
|
748
823
|
return;
|
749
|
-
|
824
|
+
|
750
825
|
var denominator = 0;
|
751
|
-
|
826
|
+
|
752
827
|
// we compute the (french) "Raison"
|
753
|
-
for (i = 1; i <= nbClass; i++) {
|
828
|
+
for (var i = 1; i <= nbClass; i++) {
|
754
829
|
denominator += i;
|
755
830
|
}
|
756
831
|
|
757
832
|
var a = Array();
|
758
833
|
var tmpMin = this.min();
|
759
834
|
var tmpMax = this.max();
|
760
|
-
|
835
|
+
|
761
836
|
var interval = (tmpMax - tmpMin) / denominator;
|
762
837
|
|
763
|
-
for (i = 0; i <= nbClass; i++) {
|
838
|
+
for (var i = 0; i <= nbClass; i++) {
|
764
839
|
if(i == 0) {
|
765
840
|
a[i] = tmpMin;
|
766
|
-
|
841
|
+
} else if(i == nbClass) {
|
842
|
+
a[i] = tmpMax;
|
843
|
+
} else {
|
767
844
|
a[i] = a[i-1] + (i * interval);
|
768
845
|
}
|
769
846
|
}
|
770
847
|
|
771
848
|
this.setBounds(a);
|
772
849
|
this.setRanges();
|
773
|
-
|
850
|
+
|
774
851
|
// we specify the classification method
|
775
852
|
this.method = _t('arithmetic progression') + ' (' + nbClass + ' ' + _t('classes') + ')';
|
776
853
|
|
777
854
|
return this.bounds;
|
778
855
|
};
|
779
|
-
|
856
|
+
|
780
857
|
/**
|
781
858
|
* Credits : Doug Curl (javascript) and Daniel J Lewis (python implementation)
|
782
859
|
* http://www.arcgis.com/home/item.html?id=0b633ff2f40d412995b8be377211c47b
|
783
860
|
* http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
|
784
861
|
*/
|
785
|
-
this.
|
786
|
-
|
862
|
+
this.getClassJenks2 = function(nbClass) {
|
863
|
+
|
864
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
865
|
+
|
787
866
|
if (this._nodata())
|
788
867
|
return;
|
789
|
-
|
790
|
-
|
868
|
+
|
869
|
+
this._classificationCheck(nbClass); // be sure number of classes is valid
|
870
|
+
|
871
|
+
var dataList = this.sorted();
|
791
872
|
|
792
873
|
// now iterate through the datalist:
|
793
874
|
// determine mat1 and mat2
|
@@ -859,7 +940,7 @@ var geostats = function(a) {
|
|
859
940
|
var kclass = []
|
860
941
|
|
861
942
|
// fill the kclass (classification) array with zeros:
|
862
|
-
for (i = 0; i <= nbClass; i++) {
|
943
|
+
for (var i = 0; i <= nbClass; i++) {
|
863
944
|
kclass.push(0);
|
864
945
|
}
|
865
946
|
|
@@ -888,43 +969,186 @@ var geostats = function(a) {
|
|
888
969
|
this.setBounds(kclass);
|
889
970
|
this.setRanges();
|
890
971
|
|
891
|
-
|
972
|
+
|
973
|
+
this.method = _t('Jenks2') + ' (' + nbClass + ' ' + _t('classes') + ')';
|
974
|
+
|
975
|
+
return this.bounds; //array of breaks
|
976
|
+
}
|
977
|
+
|
978
|
+
/**
|
979
|
+
* Credits from simple-statistics library
|
980
|
+
* https://github.com/simple-statistics/simple-statistics
|
981
|
+
* https://gist.githubusercontent.com/tmcw/4969184/raw/cfd9572d00db6bcdc34f07b088738fc3a47846b4/simple_statistics.js
|
982
|
+
*/
|
983
|
+
this.getClassJenks = function(nbClass) {
|
984
|
+
|
985
|
+
var nbClass = this._nbClassInt(nbClass); // ensure nbClass is an integer
|
986
|
+
|
987
|
+
if (this._nodata())
|
988
|
+
return;
|
989
|
+
|
990
|
+
this._classificationCheck(nbClass); // be sure number of classes is valid
|
991
|
+
|
992
|
+
var dataList = this.sorted();
|
993
|
+
|
994
|
+
// Compute the matrices required for Jenks breaks. These matrices
|
995
|
+
// can be used for any classing of data with `classes <= n_classes`
|
996
|
+
var jenksMatrices = function(data, n_classes) {
|
997
|
+
|
998
|
+
// in the original implementation, these matrices are referred to
|
999
|
+
// as `LC` and `OP`
|
1000
|
+
//
|
1001
|
+
// * lower_class_limits (LC): optimal lower class limits
|
1002
|
+
// * variance_combinations (OP): optimal variance combinations for all classes
|
1003
|
+
var lower_class_limits = [],
|
1004
|
+
variance_combinations = [],
|
1005
|
+
// loop counters
|
1006
|
+
i, j,
|
1007
|
+
// the variance, as computed at each step in the calculation
|
1008
|
+
variance = 0;
|
1009
|
+
|
1010
|
+
// Initialize and fill each matrix with zeroes
|
1011
|
+
for (var i = 0; i < data.length + 1; i++) {
|
1012
|
+
var tmp1 = [], tmp2 = [];
|
1013
|
+
for (var j = 0; j < n_classes + 1; j++) {
|
1014
|
+
tmp1.push(0);
|
1015
|
+
tmp2.push(0);
|
1016
|
+
}
|
1017
|
+
lower_class_limits.push(tmp1);
|
1018
|
+
variance_combinations.push(tmp2);
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
for (var i = 1; i < n_classes + 1; i++) {
|
1022
|
+
lower_class_limits[1][i] = 1;
|
1023
|
+
variance_combinations[1][i] = 0;
|
1024
|
+
// in the original implementation, 9999999 is used but
|
1025
|
+
// since Javascript has `Infinity`, we use that.
|
1026
|
+
for (var j = 2; j < data.length + 1; j++) {
|
1027
|
+
variance_combinations[j][i] = Infinity;
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
for (var l = 2; l < data.length + 1; l++) {
|
1032
|
+
|
1033
|
+
// `SZ` originally. this is the sum of the values seen thus
|
1034
|
+
// far when calculating variance.
|
1035
|
+
var sum = 0,
|
1036
|
+
// `ZSQ` originally. the sum of squares of values seen
|
1037
|
+
// thus far
|
1038
|
+
sum_squares = 0,
|
1039
|
+
// `WT` originally. This is the number of
|
1040
|
+
w = 0,
|
1041
|
+
// `IV` originally
|
1042
|
+
i4 = 0;
|
1043
|
+
|
1044
|
+
// in several instances, you could say `Math.pow(x, 2)`
|
1045
|
+
// instead of `x * x`, but this is slower in some browsers
|
1046
|
+
// introduces an unnecessary concept.
|
1047
|
+
for (var m = 1; m < l + 1; m++) {
|
1048
|
+
|
1049
|
+
// `III` originally
|
1050
|
+
var lower_class_limit = l - m + 1,
|
1051
|
+
val = data[lower_class_limit - 1];
|
1052
|
+
|
1053
|
+
// here we're estimating variance for each potential classing
|
1054
|
+
// of the data, for each potential number of classes. `w`
|
1055
|
+
// is the number of data points considered so far.
|
1056
|
+
w++;
|
1057
|
+
|
1058
|
+
// increase the current sum and sum-of-squares
|
1059
|
+
sum += val;
|
1060
|
+
sum_squares += val * val;
|
1061
|
+
|
1062
|
+
// the variance at this point in the sequence is the difference
|
1063
|
+
// between the sum of squares and the total x 2, over the number
|
1064
|
+
// of samples.
|
1065
|
+
variance = sum_squares - (sum * sum) / w;
|
1066
|
+
|
1067
|
+
i4 = lower_class_limit - 1;
|
1068
|
+
|
1069
|
+
if (i4 !== 0) {
|
1070
|
+
for (var j = 2; j < n_classes + 1; j++) {
|
1071
|
+
if (variance_combinations[l][j] >=
|
1072
|
+
(variance + variance_combinations[i4][j - 1])) {
|
1073
|
+
lower_class_limits[l][j] = lower_class_limit;
|
1074
|
+
variance_combinations[l][j] = variance +
|
1075
|
+
variance_combinations[i4][j - 1];
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
}
|
1079
|
+
}
|
1080
|
+
|
1081
|
+
lower_class_limits[l][1] = 1;
|
1082
|
+
variance_combinations[l][1] = variance;
|
1083
|
+
}
|
1084
|
+
|
1085
|
+
return {
|
1086
|
+
lower_class_limits: lower_class_limits,
|
1087
|
+
variance_combinations: variance_combinations
|
1088
|
+
};
|
1089
|
+
};
|
1090
|
+
|
1091
|
+
// get our basic matrices
|
1092
|
+
var matrices = jenksMatrices(dataList, nbClass),
|
1093
|
+
// we only need lower class limits here
|
1094
|
+
lower_class_limits = matrices.lower_class_limits,
|
1095
|
+
k = dataList.length - 1,
|
1096
|
+
kclass = [],
|
1097
|
+
countNum = nbClass;
|
1098
|
+
|
1099
|
+
// the calculation of classes will never include the upper and
|
1100
|
+
// lower bounds, so we need to explicitly set them
|
1101
|
+
kclass[nbClass] = dataList[dataList.length - 1];
|
1102
|
+
kclass[0] = dataList[0];
|
1103
|
+
|
1104
|
+
// the lower_class_limits matrix is used as indexes into itself
|
1105
|
+
// here: the `k` variable is reused in each iteration.
|
1106
|
+
while (countNum > 1) {
|
1107
|
+
kclass[countNum - 1] = dataList[lower_class_limits[k][countNum] - 2];
|
1108
|
+
k = lower_class_limits[k][countNum] - 1;
|
1109
|
+
countNum--;
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
this.setBounds(kclass);
|
1113
|
+
this.setRanges();
|
1114
|
+
|
1115
|
+
|
892
1116
|
this.method = _t('Jenks') + ' (' + nbClass + ' ' + _t('classes') + ')';
|
893
|
-
|
1117
|
+
|
894
1118
|
return this.bounds; //array of breaks
|
895
1119
|
}
|
896
|
-
|
897
|
-
|
1120
|
+
|
1121
|
+
|
898
1122
|
/**
|
899
|
-
*
|
1123
|
+
* Unique classification Return as many entries as unique values : ie array('blue', 'red', yellow')
|
900
1124
|
* 1.5, 2.25, 3);
|
901
1125
|
*/
|
902
1126
|
this.getClassUniqueValues = function() {
|
903
1127
|
|
904
1128
|
if (this._nodata())
|
905
1129
|
return;
|
906
|
-
|
1130
|
+
|
907
1131
|
this.is_uniqueValues = true;
|
908
|
-
|
1132
|
+
|
909
1133
|
var tmp = this.sorted(); // display in alphabetical order
|
910
1134
|
|
911
1135
|
var a = Array();
|
912
1136
|
|
913
|
-
for (i = 0; i < this.pop(); i++) {
|
1137
|
+
for (var i = 0; i < this.pop(); i++) {
|
914
1138
|
if(a.indexOf(tmp[i]) === -1)
|
915
1139
|
a.push(tmp[i]);
|
916
1140
|
}
|
917
|
-
|
1141
|
+
|
918
1142
|
this.bounds = a;
|
919
|
-
|
1143
|
+
|
920
1144
|
// we specify the classification method
|
921
1145
|
this.method = _t('unique values');
|
922
|
-
|
1146
|
+
|
923
1147
|
return a;
|
924
1148
|
|
925
1149
|
};
|
926
|
-
|
927
|
-
|
1150
|
+
|
1151
|
+
|
928
1152
|
/**
|
929
1153
|
* Return the class of a given value.
|
930
1154
|
* For example value : 6
|
@@ -933,12 +1157,14 @@ var geostats = function(a) {
|
|
933
1157
|
*/
|
934
1158
|
this.getClass = function(value) {
|
935
1159
|
|
936
|
-
for(i = 0; i < this.bounds.length; i++) {
|
937
|
-
|
938
|
-
|
1160
|
+
for (var i = 0; i < this.bounds.length; i++) {
|
1161
|
+
|
939
1162
|
if(this.is_uniqueValues == true) {
|
940
|
-
|
1163
|
+
|
1164
|
+
if(value == this.bounds[i]) {
|
1165
|
+
// console.log(value + ' - ' + this.bounds[i] + ' returned value : ' + i);
|
941
1166
|
return i;
|
1167
|
+
}
|
942
1168
|
} else {
|
943
1169
|
// parseFloat() is necessary
|
944
1170
|
if(parseFloat(value) <= this.bounds[i + 1]) {
|
@@ -946,9 +1172,9 @@ var geostats = function(a) {
|
|
946
1172
|
}
|
947
1173
|
}
|
948
1174
|
}
|
949
|
-
|
1175
|
+
|
950
1176
|
return _t("Unable to get value's class.");
|
951
|
-
|
1177
|
+
|
952
1178
|
};
|
953
1179
|
|
954
1180
|
/**
|
@@ -956,120 +1182,120 @@ var geostats = function(a) {
|
|
956
1182
|
* '2.25-3');
|
957
1183
|
*/
|
958
1184
|
this.getRanges = function() {
|
959
|
-
|
1185
|
+
|
960
1186
|
return this.ranges;
|
961
|
-
|
1187
|
+
|
962
1188
|
};
|
963
1189
|
|
964
1190
|
/**
|
965
1191
|
* Returns the number/index of this.ranges that value falls into
|
966
1192
|
*/
|
967
1193
|
this.getRangeNum = function(value) {
|
968
|
-
|
1194
|
+
|
969
1195
|
var bounds, i;
|
970
1196
|
|
971
|
-
for (i = 0; i < this.ranges.length; i++) {
|
1197
|
+
for (var i = 0; i < this.ranges.length; i++) {
|
972
1198
|
bounds = this.ranges[i].split(/ - /);
|
973
1199
|
if (value <= parseFloat(bounds[1])) {
|
974
1200
|
return i;
|
975
1201
|
}
|
976
1202
|
}
|
977
1203
|
}
|
978
|
-
|
1204
|
+
|
979
1205
|
/*
|
980
|
-
* Compute inner ranges based on serie.
|
981
|
-
* Produce discontinous ranges used for legend - return an array similar to :
|
1206
|
+
* Compute inner ranges based on serie.
|
1207
|
+
* Produce discontinous ranges used for legend - return an array similar to :
|
982
1208
|
* array('0.00-0.74', '0.98-1.52', '1.78-2.25', '2.99-3.14');
|
983
1209
|
* If inner ranges already computed, return array values.
|
984
1210
|
*/
|
985
1211
|
this.getInnerRanges = function() {
|
986
|
-
|
1212
|
+
|
987
1213
|
// if already computed, we return the result
|
988
1214
|
if(this.inner_ranges != null)
|
989
1215
|
return this.inner_ranges;
|
990
1216
|
|
991
|
-
|
1217
|
+
|
992
1218
|
var a = new Array();
|
993
1219
|
var tmp = this.sorted();
|
994
|
-
|
1220
|
+
|
995
1221
|
var cnt = 1; // bounds array counter
|
996
|
-
|
997
|
-
for (i = 0; i < tmp.length; i++) {
|
998
|
-
|
1222
|
+
|
1223
|
+
for (var i = 0; i < tmp.length; i++) {
|
1224
|
+
|
999
1225
|
if(i == 0) var range_firstvalue = tmp[i]; // we init first range value
|
1000
|
-
|
1226
|
+
|
1001
1227
|
if(parseFloat(tmp[i]) > parseFloat(this.bounds[cnt])) {
|
1002
|
-
|
1228
|
+
|
1003
1229
|
a[cnt - 1] = '' + range_firstvalue + this.separator + tmp[i-1];
|
1004
|
-
|
1230
|
+
|
1005
1231
|
var range_firstvalue = tmp[i];
|
1006
|
-
|
1232
|
+
|
1007
1233
|
cnt++;
|
1008
1234
|
|
1009
1235
|
}
|
1010
|
-
|
1236
|
+
|
1011
1237
|
// we reach the last range, we finally complete manually
|
1012
1238
|
// and return the array
|
1013
1239
|
if(cnt == (this.bounds.length - 1)) {
|
1014
1240
|
// we set the last value
|
1015
1241
|
a[cnt - 1] = '' + range_firstvalue + this.separator + tmp[tmp.length-1];
|
1016
|
-
|
1242
|
+
|
1017
1243
|
this.inner_ranges = a;
|
1018
1244
|
return this.inner_ranges;
|
1019
1245
|
}
|
1020
|
-
|
1246
|
+
|
1021
1247
|
|
1022
1248
|
}
|
1023
|
-
|
1249
|
+
|
1024
1250
|
};
|
1025
|
-
|
1251
|
+
|
1026
1252
|
this.getSortedlist = function() {
|
1027
|
-
|
1253
|
+
|
1028
1254
|
return this.sorted().join(', ');
|
1029
|
-
|
1255
|
+
|
1030
1256
|
};
|
1031
|
-
|
1257
|
+
|
1032
1258
|
/**
|
1033
1259
|
* Return an html legend
|
1034
1260
|
* colors : specify an array of color (hexadecimal values)
|
1035
1261
|
* legend : specify a text input for the legend. By default, just displays 'legend'
|
1036
1262
|
* counter : if not null, display counter value
|
1037
1263
|
* callback : if not null, callback function applied on legend boundaries
|
1038
|
-
* mode : null, 'default', 'distinct', 'discontinuous' :
|
1264
|
+
* mode : null, 'default', 'distinct', 'discontinuous' :
|
1039
1265
|
* - if mode is null, will display legend as 'default mode'
|
1040
1266
|
* - 'default' : displays ranges like in ranges array (continuous values), sample : 29.26 - 378.80 / 378.80 - 2762.25 / 2762.25 - 6884.84
|
1041
|
-
* - 'distinct' : Add + 1 according to decimal precision to distinguish classes (discrete values), sample : 29.26 - 378.80 / 378.81 - 2762.25 / 2762.26 - 6884.84
|
1267
|
+
* - 'distinct' : Add + 1 according to decimal precision to distinguish classes (discrete values), sample : 29.26 - 378.80 / 378.81 - 2762.25 / 2762.26 - 6884.84
|
1042
1268
|
* - 'discontinuous' : indicates the range of data actually falling in each class , sample : 29.26 - 225.43 / 852.12 - 2762.20 / 3001.25 - 6884.84 / not implemented yet
|
1043
1269
|
* order : null, 'ASC', 'DESC'
|
1044
1270
|
*/
|
1045
1271
|
this.getHtmlLegend = function(colors, legend, counter, callback, mode, order) {
|
1046
|
-
|
1272
|
+
|
1047
1273
|
var cnt= '';
|
1048
1274
|
var elements = new Array();
|
1049
|
-
|
1275
|
+
|
1050
1276
|
this.doCount(); // we do count, even if not displayed
|
1051
|
-
|
1277
|
+
|
1052
1278
|
if(colors != null) {
|
1053
1279
|
ccolors = colors;
|
1054
1280
|
}
|
1055
1281
|
else {
|
1056
1282
|
ccolors = this.colors;
|
1057
1283
|
}
|
1058
|
-
|
1284
|
+
|
1059
1285
|
if(legend != null) {
|
1060
1286
|
lg = legend;
|
1061
1287
|
}
|
1062
1288
|
else {
|
1063
1289
|
lg = 'Legend';
|
1064
1290
|
}
|
1065
|
-
|
1291
|
+
|
1066
1292
|
if(counter != null) {
|
1067
1293
|
getcounter = true;
|
1068
1294
|
}
|
1069
1295
|
else {
|
1070
1296
|
getcounter = false;
|
1071
1297
|
}
|
1072
|
-
|
1298
|
+
|
1073
1299
|
if(callback != null) {
|
1074
1300
|
fn = callback;
|
1075
1301
|
}
|
@@ -1084,34 +1310,34 @@ var geostats = function(a) {
|
|
1084
1310
|
// check if some classes are not populated / equivalent of in_array function
|
1085
1311
|
if(this.counter.indexOf(0) !== -1) {
|
1086
1312
|
if(this.silent) this.log("[silent mode] " + _t("Geostats cannot apply 'discontinuous' mode to the getHtmlLegend() method because some classes are not populated.\nPlease switch to 'default' or 'distinct' modes. Exit!"), true);
|
1087
|
-
else
|
1313
|
+
else throw new TypeError(_t("Geostats cannot apply 'discontinuous' mode to the getHtmlLegend() method because some classes are not populated.\nPlease switch to 'default' or 'distinct' modes. Exit!"));
|
1088
1314
|
return;
|
1089
1315
|
}
|
1090
1316
|
|
1091
1317
|
}
|
1092
1318
|
if(order !== 'DESC') order = 'ASC';
|
1093
|
-
|
1319
|
+
|
1094
1320
|
if(ccolors.length < this.ranges.length) {
|
1095
1321
|
if(this.silent) this.log("[silent mode] " + _t('The number of colors should fit the number of ranges. Exit!'), true);
|
1096
|
-
else
|
1322
|
+
else throw new TypeError(_t('The number of colors should fit the number of ranges. Exit!'));
|
1097
1323
|
return;
|
1098
1324
|
}
|
1099
|
-
|
1325
|
+
|
1100
1326
|
if(this.is_uniqueValues == false) {
|
1101
|
-
|
1102
|
-
for (i = 0; i < (this.ranges.length); i++) {
|
1327
|
+
|
1328
|
+
for (var i = 0; i < (this.ranges.length); i++) {
|
1103
1329
|
if(getcounter===true) {
|
1104
1330
|
cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
|
1105
1331
|
}
|
1106
1332
|
//console.log("Ranges : " + this.ranges[i]);
|
1107
|
-
|
1108
|
-
// default mode
|
1333
|
+
|
1334
|
+
// default mode
|
1109
1335
|
var tmp = this.ranges[i].split(this.separator);
|
1110
|
-
|
1336
|
+
|
1111
1337
|
var start_value = parseFloat(tmp[0]).toFixed(this.precision);
|
1112
1338
|
var end_value = parseFloat(tmp[1]).toFixed(this.precision);
|
1113
|
-
|
1114
|
-
|
1339
|
+
|
1340
|
+
|
1115
1341
|
// if mode == 'distinct' and we are not working on the first value
|
1116
1342
|
if(mode == 'distinct' && i != 0) {
|
1117
1343
|
|
@@ -1122,34 +1348,34 @@ var geostats = function(a) {
|
|
1122
1348
|
} else {
|
1123
1349
|
|
1124
1350
|
start_value = parseFloat(start_value) + (1 / Math.pow(10,this.precision));
|
1125
|
-
// strangely the formula above return sometimes long decimal values,
|
1351
|
+
// strangely the formula above return sometimes long decimal values,
|
1126
1352
|
// the following instruction fix it
|
1127
1353
|
start_value = parseFloat(start_value).toFixed(this.precision);
|
1128
1354
|
}
|
1129
1355
|
}
|
1130
|
-
|
1356
|
+
|
1131
1357
|
// if mode == 'discontinuous'
|
1132
1358
|
if(mode == 'discontinuous') {
|
1133
|
-
|
1359
|
+
|
1134
1360
|
var tmp = this.inner_ranges[i].split(this.separator);
|
1135
1361
|
// console.log("Ranges : " + this.inner_ranges[i]);
|
1136
|
-
|
1362
|
+
|
1137
1363
|
var start_value = parseFloat(tmp[0]).toFixed(this.precision);
|
1138
1364
|
var end_value = parseFloat(tmp[1]).toFixed(this.precision);
|
1139
|
-
|
1365
|
+
|
1140
1366
|
}
|
1141
|
-
|
1367
|
+
|
1142
1368
|
// we apply callback function
|
1143
1369
|
var el = fn(start_value) + this.legendSeparator + fn(end_value);
|
1144
|
-
|
1370
|
+
|
1145
1371
|
var block = '<div><div class="geostats-legend-block" style="background-color:' + ccolors[i] + '"></div> ' + el + cnt + '</div>';
|
1146
1372
|
elements.push(block);
|
1147
1373
|
}
|
1148
|
-
|
1374
|
+
|
1149
1375
|
} else {
|
1150
|
-
|
1376
|
+
|
1151
1377
|
// only if classification is done on unique values
|
1152
|
-
for (i = 0; i < (this.bounds.length); i++) {
|
1378
|
+
for (var i = 0; i < (this.bounds.length); i++) {
|
1153
1379
|
if(getcounter===true) {
|
1154
1380
|
cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
|
1155
1381
|
}
|
@@ -1158,31 +1384,31 @@ var geostats = function(a) {
|
|
1158
1384
|
|
1159
1385
|
elements.push(block);
|
1160
1386
|
}
|
1161
|
-
|
1387
|
+
|
1162
1388
|
}
|
1163
|
-
|
1389
|
+
|
1164
1390
|
// do we reverse the return legend ?
|
1165
|
-
if(order === 'DESC') elements.reverse();
|
1166
|
-
|
1391
|
+
if(order === 'DESC') elements.reverse();
|
1392
|
+
|
1167
1393
|
// finally we create HTML and return it
|
1168
1394
|
var content = '<div class="geostats-legend"><div class="geostats-legend-title">' + _t(lg) + '</div>';
|
1169
|
-
for (i = 0; i < (elements.length); i++) {
|
1395
|
+
for (var i = 0; i < (elements.length); i++) {
|
1170
1396
|
content += elements[i];
|
1171
1397
|
}
|
1172
1398
|
content += '</div>';
|
1173
|
-
|
1399
|
+
|
1174
1400
|
return content;
|
1175
1401
|
};
|
1176
1402
|
|
1177
|
-
|
1178
|
-
|
1403
|
+
|
1404
|
+
|
1179
1405
|
// object constructor
|
1180
1406
|
// At the end of script. If not setPrecision() method is not known
|
1181
|
-
|
1407
|
+
|
1182
1408
|
// we create an object identifier for debugging
|
1183
1409
|
this.objectID = new Date().getUTCMilliseconds();
|
1184
1410
|
this.log('Creating new geostats object');
|
1185
|
-
|
1411
|
+
|
1186
1412
|
if(typeof a !== 'undefined' && a.length > 0) {
|
1187
1413
|
this.serie = a;
|
1188
1414
|
this.setPrecision();
|
@@ -1191,9 +1417,10 @@ var geostats = function(a) {
|
|
1191
1417
|
this.serie = Array();
|
1192
1418
|
|
1193
1419
|
};
|
1194
|
-
|
1420
|
+
|
1195
1421
|
// creating aliases on classification function for backward compatibility
|
1196
1422
|
this.getJenks = this.getClassJenks;
|
1423
|
+
this.getJenks2 = this.getClassJenks2;
|
1197
1424
|
this.getGeometricProgression = this.getClassGeometricProgression;
|
1198
1425
|
this.getEqInterval = this.getClassEqInterval;
|
1199
1426
|
this.getQuantile = this.getClassQuantile;
|
@@ -1205,4 +1432,4 @@ var geostats = function(a) {
|
|
1205
1432
|
|
1206
1433
|
|
1207
1434
|
return geostats;
|
1208
|
-
});
|
1435
|
+
});
|