Savings

See also: https://calculang-talk-belfastjs.pages.dev/apps/savings

Savings

Code
viewof duration_in = Inputs.range([0,15],{step:1,value:5,label:'duration_in'})
viewof interest_rate_in = Inputs.range([0,0.1],{step:0.005,value:0.02,label:'interest_rate_in'})
viewof one_off_payment_in = Inputs.range([0,10000],{step:100,value:0,label:'one_off_payment_in'})
viewof annual_payment_in = Inputs.range([0,10000],{step:100,value:1000,label:'annual_payment_in'})
Code
input_cursors = [{duration_in,interest_rate_in,one_off_payment_in,annual_payment_in}];

viewof grid = embed(
  calcuvizspec({
    models: [main],
    input_cursors,
    mark: 'text',
    encodings: {
      x: {name: 'year_in', type: 'nominal', domain: _.range(-1,duration_in+0+.1)},
      text: {name: 'value', type: 'quantitative', format:',.2f'},
      y: {name: 'formula', type:'nominal', domain: formulae_not_inputs},
      color: {name: 'formula', type:'nominal', domain: formulae_not_inputs, legend: false},
    },
    width: 500, height:100
}))
calculang formulae ๐Ÿช„

highlight or click a number in visual to see itโ€™s calculang formula below:

and the values used:





















tofix: log gets appended on dupe mousemoves, use signal listeners instead?

navigation?

Code
viewof year_in = Inputs.range([-1,7],{step:1,value:5,label:'year_in'})

nodes = main_fondued.__tracer.nodes().filter(d => d.type == 'function' && d.name != 'get')
nodes2 = main_fondued.__tracer.nodes().filter(d => (d.type == 'function' || d.type == 'callsite') && d.name != 'get') // for mapping to callsites

invocs = { return main_fondued.__tracer.logDelta(main_fondued.__tracer.trackLogs({ ids: nodes.map(d => d.id)}), 200000 ) ; year_in }
invocs2 = { return main_fondued.__tracer.logDelta(main_fondued.__tracer.trackLogs({ ids: nodes2.map(d => d.id)}), 200000 ) ; year_in }

// where fonuded model is called
// TODO why doesn't this update with param changes?
main_fondued[formula_select]({/*...input_cursors[0]*/duration_in,interest_rate_in,one_off_payment_in,annual_payment_in, year_in})
Code
relationships = [...invocs.filter(d => d.parents).map(d => ({d, parent:invocs.filter(e => e.invocationId==d.parents[0].invocationId)[0]})),
                 ...invocs.filter(d => !d.parents).map(d => ({d, parent:'no parent'}))]

relationships2 = relationships.map(d => ({...d.d, year_in: d.d.arguments[0].value.ownProperties.year_in ? d.d.arguments[0].value.ownProperties.year_in.value : undefined, parent_formula: d.parent.formula, parent_year_in:d.parent.arguments ? d.parent.arguments[0].value.ownProperties.year_in.value : undefined, parent_value: d.parent != 'no parent' ? d.parent.returnValue.value : undefined, parent:d.parent}))

relationships3 = _.uniqBy(relationships2, d => d.parent_formula+d.parent_year_in+d.formula+d.arguments)

WORKINGS_NEW3 = relationships3.filter(d => d.parent != 'no parent').filter(d => d.parent.type='callsite').filter(d => d.parent.formula == formula_select && d.parent.arguments[0].value.ownProperties.year_in.value == year_in)

w3 = WORKINGS_NEW3.map(d => d.returnValue.value)





Appendix

Code
import { calcuvizspec } from "@declann/little-calcu-helpers"
embed = require('vega-embed');

viewof entrypoint = Inputs.select(['models/savings/savings.cul.js'], {label:'entrypoint'})

entrypoint_no_cul_js = entrypoint.slice(0,-7)

main = require(`../../${entrypoint_no_cul_js}.js`);

main_fondued = require(`../../${entrypoint_no_cul_js}-nomemo_esm/dist/cul_scope_0-babeled-fondued.bundle.js`);

introspection_fetch = await fetch(`../../${entrypoint_no_cul_js}.introspection.json`)

introspection = introspection_fetch.json({typed:true})

introspection_nomemo_fetch = await fetch(`../../${entrypoint_no_cul_js}-nomemo.introspection.json`)

introspection_nomemo = introspection_nomemo_fetch.json({typed:true})

inputs = Object.values(introspection.cul_functions).filter(d => d.reason == 'input definition').map(d => d.name).sort()

formulae = Object.values(introspection.cul_functions).filter(d => d.reason == 'definition').map(d => d.name)

// formulae excluding pure inputs
formulae_not_inputs = Object.values(introspection.cul_functions).filter(d => d.reason == 'definition' && inputs.indexOf(d.name+'_in') == -1).map(d => d.name)
|