smartdown-gallery
Version:
Example Smartdown documents and associated resources that demonstrate various Smartdown features and serve as raw material for other Smartdown demos.
539 lines (402 loc) • 15.1 kB
Markdown
### `stdlib` Experiments
[stdlib](https://stdlib.io) is a Javascript library supporting both NodeJS and web browsers. Quoting the authors:
> 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.
The 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 namesspaced 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.
The source for this example can be viewed and transiently edited at [Smartdown Stdlib Example](https://smartdown.site/?url=lib/gallery/Stdlib.md)
#### CDF Experiments
Trying to plot the CDF for various $\sigma$ and $\mu$ versions of the normal distribution.
Based upon the Stdlib examples:
- https://stdlib.io/develop/docs/api/@stdlib/math/base/dists/normal/cdf
- https://stdlib.io/develop/docs/api/@stdlib/plot/ctor/
```stdlib/playable/autoplay
const thisDiv = this.div;
var toHTML = Stdlib.vdomToHtml;
var randn = stdlib.random.base.boxMuller;
var Plot = stdlib.plot;
var cdf = stdlib.stats.base.dists.normal.cdf;
var x = new Float64Array( 100 );
var y1 = new Float64Array( x.length );
var y2 = new Float64Array( x.length );
var y3 = new Float64Array( x.length );
var y4 = new Float64Array( x.length );
for (var i = 0; i < x.length; i++) {
x[ i ] = (((i + 1) * 1.0) - x.length / 2) / 25.0;
y1[ i ] = cdf(x[i], 0, 1);
y2[ i ] = cdf(x[i], 0, 0.5);
y3[ i ] = cdf(x[i], 0, 0.2);
y4[ i ] = cdf(x[i], 0, 0.1);
}
var h = new Plot(
[x, x, x, x],
[y1, y2, y3, y4],
{
yMin: -0.1,
yMax: 1.1,
'description': 'Plotting the CDF of the Normal Distribution',
'title': 'CDF of the Normal Distribution for various σ',
'labels': [
'σ = 1',
'σ = 0.5',
'σ = 0.2',
'σ = 0.1'
],
lineWidth: 5,
width: 450,
paddingLeft: 30,
paddingRight: 50,
});
thisDiv.innerHTML = Stdlib.vdomToHtml( h.render() );
```
---
### Incremental Classification
From the example in the documentation at [incrBinaryClassification](https://stdlib.io/docs/api/latest/@stdlib/ml/incr/binary-classification).
I honestly don't understand this example (yet), I've just transliterated it to Smartdown.
```javascript /stdlib/playable/autoplay
// var normal = require( '@stdlib/random/base/normal' );
// var binomial = require( '@stdlib/random/base/binomial' );
// var array = require( '@stdlib/ndarray/array' );
// var exp = require( '@stdlib/math/base/special/exp' );
// var incrBinaryClassification = require( '@stdlib/ml/incr/binary-classification' );
const binomial = stdlib.random.base.binomial;
const normal = stdlib.random.base.normal;
const array = stdlib.ndarray.array;
const exp = stdlib.math.base.special.exp;
const incrBinaryClassification = stdlib.ml.incr.incrBinaryClassification;
// Create a new accumulator:
const acc = incrBinaryClassification( 2, {
'intercept': true,
'lambda': 1.0e-3,
'loss': 'log'
});
// Incrementally update the classification model...
var phat;
var x;
var i;
for ( i = 0; i < 10000; i++ ) {
x = array( [ normal( 0.0, 1.0 ), normal( 0.0, 1.0 ) ] );
phat = 1.0 / ( 1.0+exp( -( ( 3.0*x.get(0) ) - ( 2.0*x.get(1) ) + 1.0 ) ) );
acc( x, ( binomial( 1, phat ) ) ? 1.0 : -1.0 );
}
// Retrieve model coefficients:
var coefs = acc();
console.log( 'Feature coefficients: %d, %d', coefs.get( 0 ), coefs.get( 1 ) );
console.log( 'Intercept: %d', coefs.get( 2 ) );
// Format model coefficients:
const markdownCoefficientsOutput =
`
### Model Coefficients
|Coefficient|Value|
|:---:|---:|
|coefs.get( 0 )|${coefs.get( 0 )}|
|coefs.get( 1 )|${coefs.get( 1 )}|
|coefs.get( 2 )|${coefs.get( 2 )}|
`;
smartdown.setVariable('MarkdownCoefficientsOutput', markdownCoefficientsOutput);
// Predict new observations...
x = array( [ [ 0.9, 0.1 ], [ 0.1, 0.9 ], [ 0.9, 0.9 ] ] );
const xPrediction = acc.predict( x );
console.log( 'x = [%d, %d]; label = %d', x.get( 0, 0 ), x.get( 0, 1 ), xPrediction.get( 0 ) );
console.log( 'x = [%d, %d]; label = %d', x.get( 1, 0 ), x.get( 1, 1 ), xPrediction.get( 1 ) );
console.log( 'x = [%d, %d]; label = %d', x.get( 2, 0 ), x.get( 2, 1 ), xPrediction.get( 2 ) );
const probabilityPrediction = acc.predict( x, 'probability' );
console.log( 'x = [%d, %d]; P(y=1|x) = %d', x.get( 0, 0 ), x.get( 0, 1 ), probabilityPrediction.get( 0 ) );
console.log( 'x = [%d, %d]; P(y=1|x) = %d', x.get( 1, 0 ), x.get( 1, 1 ), probabilityPrediction.get( 1 ) );
console.log( 'x = [%d, %d]; P(y=1|x) = %d', x.get( 2, 0 ), x.get( 2, 1 ), probabilityPrediction.get( 2 ) );
const linearPrediction = acc.predict( x, 'linear' );
console.log( 'x = [%d, %d]; lp = %d', x.get( 0, 0 ), x.get( 0, 1 ), linearPrediction.get( 0 ) );
console.log( 'x = [%d, %d]; lp = %d', x.get( 1, 0 ), x.get( 1, 1 ), linearPrediction.get( 1 ) );
console.log( 'x = [%d, %d]; lp = %d', x.get( 2, 0 ), x.get( 2, 1 ), linearPrediction.get( 2 ) );
var markdownXOutput =
`
### \`x\` prediction
|x|Prediction|
|:---:|---:|
|\`x.get( 0, 0 ), x.get( 0, 1 )\`|${xPrediction.get( 0 )}|
|\`x.get( 1, 0 ), x.get( 1, 1 )\`|${xPrediction.get( 1 )}|
|\`x.get( 2, 0 ), x.get( 2, 1 )\`|${xPrediction.get( 2 )}|
`;
var markdownProbabilityOutput =
`
### \`probability\` prediction
|x|Prediction|
|:---:|---:|
|\`x.get( 0, 0 ), x.get( 0, 1 )\`|${probabilityPrediction.get( 0 )}|
|\`x.get( 1, 0 ), x.get( 1, 1 )\`|${probabilityPrediction.get( 1 )}|
|\`x.get( 2, 0 ), x.get( 2, 1 )\`|${probabilityPrediction.get( 2 )}|
`;
var markdownLinearOutput =
`
### \`linear\` prediction
|x|Prediction|
|:---:|---:|
|\`x.get( 0, 0 ), x.get( 0, 1 )\`|${linearPrediction.get( 0 )}|
|\`x.get( 1, 0 ), x.get( 1, 1 )\`|${linearPrediction.get( 1 )}|
|\`x.get( 2, 0 ), x.get( 2, 1 )\`|${linearPrediction.get( 2 )}|
`;
smartdown.setVariable('MarkdownXOutput', markdownXOutput);
smartdown.setVariable('MarkdownProbabilityOutput', markdownProbabilityOutput);
smartdown.setVariable('MarkdownLinearOutput', markdownLinearOutput);
```
[](:!MarkdownCoefficientsOutput|markdown)
[](:!MarkdownXOutput|markdown)
[](:!MarkdownProbabilityOutput|markdown)
[](:!MarkdownLinearOutput|markdown)
---
#### Unicode Sparklines
From https://stdlib.io/develop/docs/api/@stdlib/plot/sparklines/unicode/column
For 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.
##### The Generated Plot
[](:!SparklinePlot)
##### The `stdlib.plot.sparklines.unicode.column` script
```javascript/playable
//smartdown.import=stdlib
var randu = stdlib.random.base.randu;
var columnChart = stdlib.plot.sparklines.unicode.UnicodeColumnChartSparkline;
var chart;
var data;
var id;
var i;
// Generate some random data...
data = new Float64Array( 30 );
for ( i = 0; i < data.length; i++ ) {
data[ i ] = randu() * 100.0;
}
// Create a new column chart:
chart = columnChart();
// Set the chart data:
chart.data = data;
// Configure the chart to support streaming data:
chart.window = data.length;
chart.yMin = 0.0;
chart.yMax = 100.0;
// Update the terminal chart with new data every second:
id = setInterval( update, 1000 );
// After some time, stop updating and close:
setTimeout( stop, 20000 );
function update() {
// Update the chart with new data:
chart.push( randu() * 100.0 );
var rendered = chart.render();
smartdown.setVariable('SparklinePlot', rendered);
}
function stop() {
clearInterval( id );
}
```
---
#### Plots
Adapted from https://stdlib.io/develop/docs/api/@stdlib/plot/ctor
This 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`).
```javascript/playable
//smartdown.import=stdlib
const thisDiv = this.div;
var toHTML = Stdlib.vdomToHtml;
var randn = stdlib.random.base.boxMuller;
var Plot = stdlib.plot;
var now;
var x;
var y;
var i;
// Create some data...
now = ( new Date() ).getTime();
x = new Float64Array( 100 );
y = new Float64Array( x.length );
for ( i = 0; i < x.length; i++ ) {
x[ i ] = now + (i * 360000);
y[ i ] = 50.0 + (10.0 * randn());
}
// Create a new plot:
var h = new Plot( [x], [y], {
'width': 500,
'height': 500,
'xScale': 'time',
'xTickFormat': '%H:%M'
});
// Render as a virtual DOM tree:
var vtree = h.render();
// console.log( JSON.stringify( vtree ) );
smartdown.setVariable('treeJSON', vtree);
// Transform the virtual DOM tree to HTML:
var html = toHTML( vtree );
// console.log( html );
thisDiv.innerHTML = html;
```
##### The generated virtual DOM Tree
[](:!treeJSON|json)
---
#### NLP (Natural Language Processing)
Derived from this example https://stdlib.io/docs/api/v0.0.90/@stdlib/nlp/lda, the following playable will utilize the [SOTU State of the Union Dataset](https://stdlib.io/docs/api/v0.0.90/@stdlib/datasets/sotu) to perform a simple clustering of the speech texts into three main *themes*.
This example also uses the [English Stop Words Dataset](https://stdlib.io/docs/api/v0.0.90/@stdlib/datasets/stopwords-en).
##### Smartdown outputs
The following smartdown cells will be populated with values generated by the `stdlib` script below. They are initially empty or undefined.
###### Stopwords
[](:!stopwords)
###### State of the Union Texts (first 100 characters)
[](:!speechTexts)
###### Average $\theta$ per topic
[](:!yearsMD|markdown)
###### Top words associated with each topic
[](:!topicMD|markdown)
###### The playable `stdlib` example.
```javascript/playable
//smartdown.import=stdlib
var that = this;
// Hack to keep the progress bar up while everything happens in
// this long-running script. Better would be a smartdown.setProgress()
// method that would not leak the implementation details.
//
var saveProgress = this.progress; // Oh, the hack
this.progress = null;
Stdlib.loadSOTU(function() {
var roundn = stdlib.math.base.special.roundn;
var stopwords = Stdlib.datasets['stopwords_en'];
var lda = stdlib.nlp.lda;
var STOPWORDS = stopwords();
var terms;
var model;
var str;
var i;
smartdown.setVariable('stopwords', STOPWORDS);
function getText(e) {
function remove(word) {
var RE = new RegExp('\\b' + word + '\\b', 'gi');
str = str.replace(RE, '');
}
str = e.text.toLowerCase();
STOPWORDS.forEach(remove);
return str;
}
var startYear = 1930;
var endYear = 2020;
var speechTexts = null;
var speeches = Stdlib.datasets['sotu-data']();
speechTexts = speeches.reduce(
function (
accumulator,
speech,
currentIndex,
array) {
if (speech.year >= startYear && speech.year <= endYear) {
accumulator.push(getText(speech));
}
return accumulator;
},
[]);
var trimmedTexts = speeches.map(function(speech, index, array) {
return speech.year + ': ' + speech.text.slice(0, 100);
});
smartdown.setVariable('speechTexts', trimmedTexts);
model = lda(speechTexts, 3);
// model.fit(1000, 100, 10);
model.fit(100, 50, 10);
// Safari (at least on my machine) will timeout and Chrome will give a warning
// if we try to execute too many iterations, so I'm using smaller parameters than would
// be used in a non-browser context. Perhaps Service Workers would alleviate this?
//
var yearsMD = '|Year|Topic 1 Average $\\theta$|Topic 2 Average $\\theta$|Topic 3 Average $\\theta$|\n|:---|---:|---:|---:|\n';
for (i = 0; i < speechTexts.length; i++) {
var year = (startYear + i);
var theta0 = roundn(model.avgTheta.get(i, 0), -3);
var theta1 = roundn(model.avgTheta.get(i, 1), -3);
var theta2 = roundn(model.avgTheta.get(i, 2), -3);
str = 'Year: ' + year + '\t';
str += 'Topic 1: ' + theta0 + '\t';
str += 'Topic 2: ' + theta1 + '\t';
str += 'Topic 3: ' + theta2;
yearsMD += `|${year}|${theta0}|${theta1}|${theta2}|\n`;
}
yearsMD += '\n';
smartdown.setVariable('yearsMD', yearsMD);
var topicMD = '|Topic|Words Most Associated with Topic|\n|:---|:---|\n';
var trim = stdlib.string.trim;
var removePunctuation = stdlib.string.removePunctuation;
for (var whichTopic = 0; whichTopic < 3; ++whichTopic) {
terms = model.getTerms(whichTopic, 20);
var topicString = `|Topic ${whichTopic}||\n`;
for (i = 0; i < terms.length; i++) {
terms[i] = terms[i].word;
const stripped = trim(removePunctuation(terms[i]));
if (stripped !== '' && stripped !== '-') {
topicString += `||${terms[i]}|\n`;
}
}
var termsString = terms.join(', ');
topicMD += topicString;
}
smartdown.setVariable('topicMD', topicMD);
saveProgress.style.display = 'none';
});
```
---
#### Use Graphviz to display `stdlib` functions
This 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`.
[More Graphviz examples](:@Graphviz)
[](:!plot|code)
[](:!plot|graphviz)
```javascript /playable
//smartdown.import=stdlib
var index = 1;
function generateTree(rootIndex, rootfIndex, rootName, root) {
var source =
`
"node${rootIndex}" [
shape = "record"
label = "`;
if (!root) {
return '';
}
var keys = Object.keys(root);
var fIndex = 0;
var subroot = [];
keys.forEach(function(k) {
++fIndex;
++index;
var v = root[k];
var line = ` "${rootName}" -> "${k}";\n`;
line = `<f${fIndex}> ${k}|`;
source += line;
if (typeof v === 'object') {
subroot.push({
v: v,
k: k,
index: index,
fIndex: fIndex
});
}
});
source = source.slice(0, source.length - 1);
source += '"\n];';
subroot.forEach(function(subroot) {
if (subroot.v) {
source += generateTree(subroot.index, subroot.fIndex, subroot.k, subroot.v);
source += `\n"node${rootIndex}":f${subroot.fIndex} -> "node${subroot.index}":f0;\n`;
}
});
return source;
}
var tree = generateTree(1, 0, 'stdlib', stdlib.math);
var plot =
`
digraph G {
rankdir = "LR"
ranksep = 1.5
ratio="compact"
node [
fontsize = "10"
margin = "0"
shape = "rectangle"
];
edge [
];
"node0" [
label = "<f0> math"
shape = "record"
];
${tree}
"node0":f0 -> "node1":f1
}
`;
smartdown.setVariable('plot', plot);
```
---
[Back to Home](:@Home)