From 899828adeb68bad5bf528bc3319ab2a66a2e5553 Mon Sep 17 00:00:00 2001 From: William Carroll Date: Fri, 6 Jan 2023 10:16:56 -0800 Subject: feat(wpcarro/ynab): Proof-of-concept viz for finances After experimenting with existing "data engineering solutions" like datasette, periscope, I think rolling my own dataviz for this project might be easiest (surprisingly). **Wish List:** - Benthos job to dump my financial transactions into a SQL table. - Scatter plot of expenses (or just transactions generally). - Support filtering the data using "Simple Select" query language. - Stacked histogram of income/expenses with a line overlaying the "idealized" savings. Change-Id: Iec2948641dba8c4c6d5ad19a0e1ea142b81198af Reviewed-on: https://cl.tvl.fyi/c/depot/+/7784 Tested-by: BuildkiteCI Reviewed-by: wpcarro --- users/wpcarro/ynabsql/dataviz/index.css | 1 + users/wpcarro/ynabsql/dataviz/index.html | 12 ++++++ users/wpcarro/ynabsql/dataviz/index.js | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 users/wpcarro/ynabsql/dataviz/index.css create mode 100644 users/wpcarro/ynabsql/dataviz/index.html create mode 100644 users/wpcarro/ynabsql/dataviz/index.js (limited to 'users') diff --git a/users/wpcarro/ynabsql/dataviz/index.css b/users/wpcarro/ynabsql/dataviz/index.css new file mode 100644 index 000000000000..82130daf4867 --- /dev/null +++ b/users/wpcarro/ynabsql/dataviz/index.css @@ -0,0 +1 @@ +/* testing */ diff --git a/users/wpcarro/ynabsql/dataviz/index.html b/users/wpcarro/ynabsql/dataviz/index.html new file mode 100644 index 000000000000..00f35a7807dd --- /dev/null +++ b/users/wpcarro/ynabsql/dataviz/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/users/wpcarro/ynabsql/dataviz/index.js b/users/wpcarro/ynabsql/dataviz/index.js new file mode 100644 index 000000000000..cc58591d7ff8 --- /dev/null +++ b/users/wpcarro/ynabsql/dataviz/index.js @@ -0,0 +1,72 @@ +const colors = { + red: 'rgb(255, 99, 132)', + orange: 'rgb(255, 159, 64)', + yellow: 'rgb(255, 205, 86)', + green: 'rgb(75, 192, 192)', + blue: 'rgb(54, 162, 235)', + purple: 'rgb(153, 102, 255)', + grey: 'rgb(201, 203, 207)' +}; + +function randomExpense() { + // 10/1000 expenses are O(1,000) + // 100/2000 expenses are O(100) + // 1,000/2000 expenses are O(10) + // 10,000/2000 expenses are O(1) + const r = Math.random(); + + if (r <= 0.02) { + return Math.floor(Math.random() * 5000); + } else if (r <= 0.1) { + return Math.floor(Math.random() * 1000); + } else if (r <= 0.5) { + return Math.floor(Math.random() * 100); + } else { + return Math.floor(Math.random() * 10); + } +} + +// Browser starts to choke around 10,000 data points. +function generateData() { + return Array(2000).fill(0).map(x => ({ + // select a random day [0, 365] + x: Math.floor(Math.random() * 365), + // select a random USD amount in the range [1, 5,000] + y: randomExpense(), + // TODO(wpcarro): Attach transaction to `metadata` key. + metadata: { foo: 'bar' }, + })); +} + +//////////////////////////////////////////////////////////////////////////////// +// Main +//////////////////////////////////////////////////////////////////////////////// + +const mount = document.getElementById('mount'); + +new Chart(mount, { + type: 'scatter', + data: { + datasets: [ + { + label: 'Expenses', + data: generateData(), + backgroundColor: colors.red, + } + ], + }, + options: { + plugins: { + tooltip: { + callbacks: { + title: function (x) { + return `$${x[0].raw.y}`; + }, + label: function (x) { + return JSON.stringify(x.raw.metadata); + }, + }, + }, + }, + }, +}) -- cgit 1.4.1