Typescript Notebook Example
Contents
Typescript Notebook Example¶
This book uses typescript-jupyter-kernel to execute Typescript code, which gives us both the advantages of Node.js and Browser all under Jupyter.
Accessing the Filesystem¶
For example we can load some csv data from the local filesystem using fs
and parse the data using d3-dsv which for convenience has been integrated into the Typescript kernel and is accessible as jupyter.data
:
import { readFileSync } from 'fs';
const { csvParse } = jupyter.data;
const rawData = readFileSync('./data.csv').toString('utf-8');
const parsedData = csvParse(rawData);
jupyter.out(parsedData);
[ { Country: 'Luxembourg', 'Hourly Minimum Wage in USD (2015)': '11.9', 'Hourly Minimum Wage in USD (2016)': '11.8', 'Hourly Minimum Wage in USD (2017)': '12.1', 'Hourly Minimum Wage in USD (2018)': '12', 'Hourly Minimum Wage in USD (2019)': '12.2', 'Hourly Minimum Wage in USD (2020)': '12.4' }, { Country: 'Australia', 'Hourly Minimum Wage in USD (2015)': '11.6', 'Hourly Minimum Wage in USD (2016)': '11.8', 'Hourly Minimum Wage in USD (2017)': '11.9', 'Hourly Minimum Wage in USD (2018)': '12', 'Hourly Minimum Wage in USD (2019)': '12.2', 'Hourly Minimum Wage in USD (2020)': '12.4' }, { Country: 'France', 'Hourly Minimum Wage in USD (2015)': '12', 'Hourly Minimum Wage in USD (2016)': '12.1', 'Hourly Minimum Wage in USD (2017)': '12.1', 'Hourly Minimum Wage in USD (2018)': '12', 'Hourly Minimum Wage in USD (2019)': '12.1', 'Hourly Minimum Wage in USD (2020)': '12.1' }, { Country: 'Germany', 'Hourly Minimum Wage in USD (2015)': '11.3', 'Hourly Minimum Wage in USD (2016)': '11.3', 'Hourly Minimum Wage in USD (2017)': '11.6', 'Hourly Minimum Wage in USD (2018)': '11.4', 'Hourly Minimum Wage in USD (2019)': '11.7', 'Hourly Minimum Wage in USD (2020)': '11.8' }, { Country: 'New Zealand', 'Hourly Minimum Wage in USD (2015)': '9.8', 'Hourly Minimum Wage in USD (2016)': '10.1', 'Hourly Minimum Wage in USD (2017)': '10.2', 'Hourly Minimum Wage in USD (2018)': '10.4', 'Hourly Minimum Wage in USD (2019)': '11', 'Hourly Minimum Wage in USD (2020)': '11.6' }, columns: [ 'Country', 'Hourly Minimum Wage in USD (2015)', 'Hourly Minimum Wage in USD (2016)', 'Hourly Minimum Wage in USD (2017)', 'Hourly Minimum Wage in USD (2018)', 'Hourly Minimum Wage in USD (2019)', 'Hourly Minimum Wage in USD (2020)' ] ]
Rendering Data to HTML¶
We can take the previous code and use jupyter.dom
(which is simply a JSDOM instance) to construct and render an HTML table:
import { readFileSync } from 'fs';
const {
data: {
csvParseRows
},
dom: {
window: {
document
}
},
renderDom,
} = jupyter;
const rawData = readFileSync('./data.csv').toString('utf-8');
const [
columnHeaders,
...rows
] = csvParseRows(rawData);
const table = document.createElement('table');
const tableHeader = document.createElement('thead');
const tableHeaderRow = document.createElement('tr');
const tableBody = document.createElement('tbody');
columnHeaders.forEach(
(h) => {
const columnHeader = document.createElement('th');
columnHeader.innerHTML = h;
tableHeaderRow.appendChild(columnHeader);
}
);
tableHeader.appendChild(tableHeaderRow);
rows.forEach(
(r) => {
const rowElement = document.createElement('tr');
r.forEach(
(d) => {
const dataElement = document.createElement('td');
dataElement.innerHTML = d;
rowElement.appendChild(dataElement);
}
);
tableBody.appendChild(rowElement);
}
);
table.appendChild(tableHeader);
table.appendChild(tableBody);
document.body.appendChild(table);
renderDom();
Country | Hourly Minimum Wage in USD (2015) | Hourly Minimum Wage in USD (2016) | Hourly Minimum Wage in USD (2017) | Hourly Minimum Wage in USD (2018) | Hourly Minimum Wage in USD (2019) | Hourly Minimum Wage in USD (2020) |
---|---|---|---|---|---|---|
Luxembourg | 11.9 | 11.8 | 12.1 | 12 | 12.2 | 12.4 |
Australia | 11.6 | 11.8 | 11.9 | 12 | 12.2 | 12.4 |
France | 12 | 12.1 | 12.1 | 12 | 12.1 | 12.1 |
Germany | 11.3 | 11.3 | 11.6 | 11.4 | 11.7 | 11.8 |
New Zealand | 9.8 | 10.1 | 10.2 | 10.4 | 11 | 11.6 |
Visualizing Data¶
It should be noted that destructuring the document
out of jupyter
on the previous example was done strictly for demonstrational purposes, as window
, navigator
, and document
are exposed as global variables.
In the following example we can take advantage of the aforementioned fact in order to render a chart using echarts (which was added to this book’s package.json
as a dependency) since echarts expects the document
object to be available globally:
import { readFileSync } from 'fs';
import * as echarts from 'echarts';
// Get the HTML body
const { body } = document;
// Add an <h2> heading to the body
// NOTE: using Unicode Identity for the emoji since emojis in code
// can break the communication between Jupyter and the kernel
body.appendChild(document.createElement('h2'));
body.querySelector('h2').innerHTML = 'Top 5 Countries with Highest Minimum Hourly Wage \xF0\x9F\x8C\x8E';
// Load a CSV file from the local filesystem
const csvString = readFileSync('./data.csv').toString('utf-8');
// Use a local js browser library to parse CSV data
const { csvParseRows } = jupyter.data;
const [
csvHeaders,
...csvDataRows
] = csvParseRows(csvString);
csvHeaders.shift(); // Remove unnecesary "Country" header
const countries = csvDataRows.map((r) => r[0]); // Extract country from each row
// Map rows into series compatible with ECharts
const series = csvDataRows.map(
([name, ...values]) => (
{
name,
type: 'line',
data: values.map((i) => parseFloat(i))
}
)
);
// Create a container div for a chart
const chartContainer = document.createElement('div');
chartContainer.style = 'width: 800px; height: 600px; margin-top: 20px;';
Object.defineProperty(chartContainer, 'clientWidth', {value: 800});
Object.defineProperty(chartContainer, 'clientHeight', {value: 600});
// Initialize an echarts instance using the chart container div
var myChart = echarts.init(
chartContainer,
null,
{
renderer: 'svg',
},
);
const chartOptions = {
legend: {
data: countries
},
grid: {
left: '80px',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: true,
data: csvHeaders,
axisLabel: {
interval: 0,
rotate: 45 // If the label names are too long you can manage this by rotating the label.
},
axisLine: {
lineStyle: {
color: '#14ab3c'
}
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed'
}
}
},
yAxis: {
type: 'value',
min: 8,
max: 14,
axisLine: {
lineStyle: {
color: '#14ab3c',
type: 'solid'
}
}
},
series
};
// Load the CSV data into a bar chart
myChart.setOption(chartOptions);
// Append the chart container div to the body
body.appendChild(chartContainer);
jupyter.renderDom();