UNPKG

12.8 kBMarkdownView Raw
1
2## `stdlib` Experiments
3
4[stdlib](https://stdlib.io) is a Javascript library supporting both NodeJS and web browsers. Quoting the authors:
5
6> Stdlib is a standard library for JavaScript and Node.js, with an emphasis on numeric computing. The library provides a collection of robust, high performance libraries for mathematics, statistics, streams, utilities, and more.
7
8The examples below are adapted from various `stdlib` documentation examples, although many uses of `console.log()` have been replaced with writing to Smartdown variables and having these variables rendered via Smartdown cells. The other minor change needed to use `stdlib` within Smartdown is to replace usage of `require('@stdlib/foo/bar')` with a reference to Smartdown's bundled version `Stdlib.foo.bar`. This is currently necessary because `stdlib` is being bundled (via Webpack) with Smartdown. Eventually, this will be replaced with a more dynamic mechanism.
9
10The source for this example can be viewed and transiently edited at [Smartdown Stdlib Example](https://smartdown.site/?url=lib/gallery/Stdlib.md)
11
12
13### CDF Experiments
14
15Trying to plot the CDF for various $\sigma$ and $\mu$ versions of the normal distribution.
16
17Based upon the Stdlib examples:
18
19- https://stdlib.io/develop/docs/api/@stdlib/math/base/dists/normal/cdf
20- https://stdlib.io/develop/docs/api/@stdlib/plot/ctor/
21
22
23```javascript/playable
24const thisDiv = this.div;
25
26var toHTML = Stdlib.vdomToHtml;
27var randn = Stdlib.random.base.boxMuller;
28var plot = Stdlib.plot.ctor;
29var cdf = Stdlib.math.base.dists.normal.cdf;
30
31
32var x = new Float64Array( 100 );
33var y1 = new Float64Array( x.length );
34var y2 = new Float64Array( x.length );
35var y3 = new Float64Array( x.length );
36var y4 = new Float64Array( x.length );
37for (var i = 0; i < x.length; i++) {
38 x[ i ] = (((i + 1) * 1.0) - x.length / 2) / 25.0;
39 y1[ i ] = cdf(x[i], 0, 1);
40 y2[ i ] = cdf(x[i], 0, 0.5);
41 y3[ i ] = cdf(x[i], 0, 0.2);
42 y4[ i ] = cdf(x[i], 0, 0.1);
43}
44
45var h = plot( [x, x, x, x], [y1, y2, y3, y4], {
46 yMin: -0.1,
47 yMax: 1.1,
48 'description': 'Plotting the CDF of the Normal Distribution',
49 'title': 'CDF of the Normal Distribution for various σ',
50 'labels': [
51 'σ = 1',
52 'σ = 0.5',
53 'σ = 0.2',
54 'σ = 0.1'
55 ],
56 lineWidth: 5
57});
58
59thisDiv.innerHTML = Stdlib.vdomToHtml( h.render() );
60
61```
62
63---
64
65### Machine Learning
66
67From this example: https://stdlib.io/develop/docs/api/@stdlib/ml/online-binary-classification
68
69I honestly don't understand this example (yet), I've just transliterated it to Smartdown.
70
71```javascript/playable
72var binomial = Stdlib.random.base.binomial;
73var normal = Stdlib.random.base.normal;
74var exp = Stdlib.math.base.special.exp;
75var onlineBinaryClassification = Stdlib.ml.onlineBinaryClassification;
76
77var phat;
78var lp;
79var x1;
80var x2;
81var y;
82var i;
83
84// Create model:
85var model = onlineBinaryClassification({
86 'lambda': 1e-3,
87 'loss': 'log',
88 'intercept': true
89});
90
91// Update model as data comes in...
92for ( i = 0; i < 10000; i++ ) {
93 x1 = normal( 0.0, 1.0 );
94 x2 = normal( 0.0, 1.0 );
95 lp = (3.0 * x1) - (2.0 * x2) + 1.0;
96 phat = 1.0 / ( 1.0 + exp( -lp ) );
97 y = binomial( 1, phat ) ? 1.0 : -1.0;
98 model.update( [ x1, x2 ], y );
99}
100
101// Extract model coefficients:
102var markdownCoefficients =
103`
104### Model Coefficients
105
106$$
107${model.coefs}
108$$
109`;
110
111// Predict new observations:
112// console.log( 'Pr(Y=1)_hat = %d; x1 = %d; x2 = %d', model.predict( [0.9, 0.1], 'probability' ), 0.9, 0.1 );
113// console.log( 'y_hat = %d; x1 = %d; x2 = %d', model.predict( [0.1, 0.9], 'link' ), 0.1, 0.9 );
114// console.log( 'y_hat = %d; x1 = %d; x2 = %d', model.predict( [0.9, 0.9], 'link' ), 0.9, 0.9 );
115
116const p1 = 0.9;
117const p2 = 0.1;
118const predictionProbability = model.predict( [p1, p2], 'probability' );
119const predictionLink12 = model.predict( [p1, p2], 'link' );
120const predictionLink22 = model.predict( [p1, p2], 'link' );
121
122var markdownOutput =
123`
124### Output
125
126|Expression|Value|$x_1$|$x_2$|
127|:---:|---:|---:|---:|
128|$\\hat{P_r(Y=1)}$|${predictionProbability}|${x1}|${x2}|
129|$\\hat{y}$|${predictionLink12}|${x1}|${x2}|
130|$\\hat{y}$|${predictionLink22}|${x2}|${x2}|
131`;
132
133smartdown.setVariable('MarkdownCoefficients', markdownCoefficients);
134smartdown.setVariable('MarkdownOutput', markdownOutput);
135```
136
137[](:!MarkdownCoefficients|markdown)
138[](:!MarkdownOutput|markdown)
139
140---
141
142### Unicode Sparklines
143
144From https://stdlib.io/develop/docs/api/@stdlib/plot/sparklines/unicode/column
145
146For this example, we modify the use of `console.log()` to instead place the Unicode sparkline into a Smartdown variable, where it will be rendered automatically as it is updated.
147
148#### The Generated Plot
149[](:!SparklinePlot)
150
151
152#### The `Stdlib.plot.sparklines.unicode.column` script
153
154```javascript/playable
155var randu = Stdlib.random.base.randu;
156var columnChart = Stdlib.plot.sparklines.unicode.column;
157
158var chart;
159var data;
160var id;
161var i;
162
163// Generate some random data...
164data = new Float64Array( 30 );
165for ( i = 0; i < data.length; i++ ) {
166 data[ i ] = randu() * 100.0;
167}
168
169// Create a new column chart:
170chart = columnChart();
171
172// Set the chart data:
173chart.data = data;
174
175// Configure the chart to support streaming data:
176chart.window = data.length;
177chart.yMin = 0.0;
178chart.yMax = 100.0;
179
180// Update the terminal chart with new data every second:
181id = setInterval( update, 1000 );
182
183// After some time, stop updating and close:
184setTimeout( stop, 20000 );
185
186function update() {
187 // Update the chart with new data:
188 chart.push( randu() * 100.0 );
189
190 var rendered = chart.render();
191 smartdown.setVariable('SparklinePlot', rendered);
192}
193
194function stop() {
195 clearInterval( id );
196}
197```
198
199---
200
201### Plots
202
203Adapted from https://stdlib.io/develop/docs/api/@stdlib/plot/ctor
204
205This example generates a plot as *virtual DOM*, which is then converted to HTML prior to rendering within the Smartdown-created playable's div (`this.div`).
206
207
208```javascript/playable
209const thisDiv = this.div;
210
211var toHTML = Stdlib.vdomToHtml;
212var randn = Stdlib.random.base.boxMuller;
213var plot = Stdlib.plot.ctor;
214
215var now;
216var x;
217var y;
218var i;
219
220// Create some data...
221now = ( new Date() ).getTime();
222x = new Float64Array( 100 );
223y = new Float64Array( x.length );
224for ( i = 0; i < x.length; i++ ) {
225 x[ i ] = now + (i * 360000);
226 y[ i ] = 50.0 + (10.0 * randn());
227}
228
229// Create a new plot:
230var h = plot( [x], [y], {
231 'width': 500,
232 'height': 500,
233 'xScale': 'time',
234 'xTickFormat': '%H:%M'
235});
236
237// Render as a virtual DOM tree:
238var vtree = h.render();
239// console.log( JSON.stringify( vtree ) );
240smartdown.setVariable('treeJSON', vtree);
241
242// Transform the virtual DOM tree to HTML:
243var html = toHTML( vtree );
244// console.log( html );
245thisDiv.innerHTML = html;
246
247```
248
249##### The generated virtual DOM Tree
250
251[](:!treeJSON|json)
252
253
254---
255
256### NLP (Natural Language Processing)
257
258Derived from this example https://stdlib.io/develop/docs/api/@stdlib/nlp/lda
259
260This version of Smartdown includes a subset (1930-2010) of the full 1790-2016 [SOTU State of the Union Dataset](https://stdlib.io/develop/docs/api/@stdlib/datasets/sotu), because the data is currently being bundled with the rest of Smartdown, and is quite large. In the future, the `stdlib` datasets will be optionally and dynamically loadable, which will reduce the default Smartdown bundle size and enable a much richer set of data to be used.
261
262This example also uses the [English Stop Words Dataset](https://stdlib.io/develop/docs/api/@stdlib/datasets/stopwords-en).
263
264
265#### Smartdown outputs
266
267The following smartdown cells will be populated with values generated by the `stdlib` script below. They are initially empty or undefined.
268
269##### Stopwords
270[](:!stopwords)
271
272##### State of the Union Texts (first 100 characters)
273[](:!speechTexts)
274
275##### Average $\theta$ per topic
276[](:!yearsMD|markdown)
277
278##### Top words associated with each topic
279[](:!topicMD|markdown)
280
281
282##### The playable `stdlib` example.
283
284```javascript/playable
285var that = this;
286
287// Hack to keep the progress bar up while everything happens in
288// this long-running script. Better would be a smartdown.setProgress()
289// method that would not leak the implementation details.
290//
291var saveProgress = this.progress; // Oh, the hack
292this.progress = null;
293
294Stdlib.loadSOTU(function() {
295 var roundn = Stdlib.math.base.special.roundn;
296 var stopwords = Stdlib.datasets['stopwords-en'];
297 var lda = Stdlib.nlp.lda;
298
299 var STOPWORDS = stopwords();
300 var terms;
301 var model;
302 var str;
303 var i;
304
305 smartdown.setVariable('stopwords', STOPWORDS);
306
307 function getText(e) {
308 function remove(word) {
309 var RE = new RegExp('\\b' + word + '\\b', 'gi');
310 str = str.replace(RE, '');
311 }
312
313 str = e.text.toLowerCase();
314 STOPWORDS.forEach(remove);
315 return str;
316 }
317
318 var startYear = 1930;
319 var endYear = 2010;
320
321 var speechTexts = null;
322 var speeches = Stdlib.datasets['sotu-data'];
323
324 speechTexts = speeches.reduce(
325 function (
326 accumulator,
327 speech,
328 currentIndex,
329 array) {
330 if (speech.year >= startYear && speech.year <= endYear) {
331 accumulator.push(getText(speech));
332 }
333 return accumulator;
334 },
335 []);
336
337 var trimmedTexts = speeches.map(function(speech, index, array) {
338 return speech.text.slice(0, 100);
339 });
340 smartdown.setVariable('speechTexts', trimmedTexts);
341
342 model = lda(speechTexts, 3);
343
344 // model.fit(1000, 100, 10);
345 model.fit(100, 50, 10);
346
347 // Safari (at least on my machine) will timeout and Chrome will give a warning
348 // if we try to execute too many iterations, so I'm using smaller parameters than would
349 // be used in a non-browser context. Perhaps Service Workers would alleviate this?
350 //
351
352 var yearsMD = '|Year|Topic 1 Average $\\theta$|Topic 2 Average $\\theta$|Topic 3 Average $\\theta$|\n|:---|---:|---:|---:|\n';
353 for (i = 0; i <= 80; i++) {
354 var year = (startYear + i);
355 var theta0 = roundn(model.avgTheta.get(i, 0), -3);
356 var theta1 = roundn(model.avgTheta.get(i, 1), -3);
357 var theta2 = roundn(model.avgTheta.get(i, 2), -3);
358
359 str = 'Year: ' + year + '\t';
360 str += 'Topic 1: ' + theta0 + '\t';
361 str += 'Topic 2: ' + theta1 + '\t';
362 str += 'Topic 3: ' + theta2;
363 yearsMD += `|${year}|${theta0}|${theta1}|${theta2}|\n`;
364 }
365 yearsMD += '\n';
366
367 smartdown.setVariable('yearsMD', yearsMD);
368
369 var topicMD = '|Topic|Words Most Associated with Topic|\n|:---|:---|\n';
370 var trim = Stdlib.string.trim;
371 var removePunctuation = Stdlib.string.removePunctuation;
372
373 for (var whichTopic = 0; whichTopic < 3; ++whichTopic) {
374 terms = model.getTerms(whichTopic, 20);
375 var topicString = `|Topic ${whichTopic}||\n`;
376
377 for (i = 0; i < terms.length; i++) {
378 terms[i] = terms[i].word;
379 const stripped = trim(removePunctuation(terms[i]));
380 if (stripped !== '' && stripped !== '-') {
381 topicString += `||${terms[i]}|\n`;
382 }
383 }
384
385 var termsString = terms.join(', ');
386
387 topicMD += topicString;
388 }
389
390 smartdown.setVariable('topicMD', topicMD);
391
392 saveProgress.style.display = 'none';
393});
394```
395
396---
397
398### Use Graphviz to display `stdlib` functions
399
400This is a *very quick hack* to demonstrate the synergy between Smartdown's playables, variables, and cells. It uses Graphviz to display the heirarchical structure of the `stdlib` namespace. For this example, we are only displaying the heirarchy under `stdlib.math`.
401
402[More Graphviz examples](:@Graphviz)
403
404[](:!plot|code)
405[](:!plot|graphviz)
406
407```javascript/playable
408
409var index = 1;
410
411function generateTree(rootIndex, rootfIndex, rootName, root) {
412 var source =
413`
414"node${rootIndex}" [
415 shape = "record"
416 label = "`;
417 var keys = Object.keys(root);
418 var fIndex = 0;
419 var subroot = [];
420
421 keys.forEach(function(k) {
422 ++fIndex;
423 ++index;
424 var v = root[k];
425 var line = ` "${rootName}" -> "${k}";\n`;
426 line = `<f${fIndex}> ${k}|`;
427 source += line;
428
429 if (typeof v === 'object') {
430 subroot.push({
431 v: v,
432 k: k,
433 index: index,
434 fIndex: fIndex
435 });
436 }
437 });
438 source = source.slice(0, source.length - 1);
439 source += '"\n];';
440
441 subroot.forEach(function(subroot) {
442 source += generateTree(subroot.index, subroot.fIndex, subroot.k, subroot.v);
443 source += `\n"node${rootIndex}":f${subroot.fIndex} -> "node${subroot.index}":f0;\n`;
444 });
445
446 return source;
447}
448
449var tree = generateTree(1, 0, 'stdlib', Stdlib.math);
450var plot =
451`
452digraph G {
453 rankdir = "LR"
454 ranksep = 1.5
455 ratio="compact"
456 node [
457 fontsize = "10"
458 margin = "0"
459 shape = "rectangle"
460 ];
461 edge [
462 ];
463 "node0" [
464 label = "<f0> math"
465 shape = "record"
466 ];
467 ${tree}
468 "node0":f0 -> "node1":f1
469}
470`;
471smartdown.setVariable('plot', plot);
472```
473
474---
475
476
477[Back to Home](:@Home)
478