diff --git a/manager_for_ynab/sankey/__init__.py b/manager_for_ynab/sankey/__init__.py index 38b9106..7f3b79f 100644 --- a/manager_for_ynab/sankey/__init__.py +++ b/manager_for_ynab/sankey/__init__.py @@ -31,13 +31,19 @@ _LABEL_FORMATTER = "function(params) { return params.data.label; }" _TOOLTIP_FORMATTER = """ function(params) { + const amount = Number(params.data.amount).toLocaleString(undefined, { style: 'currency', currency: 'USD' }); + if (params.dataType === 'edge') { const source = params.data.source_label; const target = params.data.target_label; - const amount = Number(params.data.amount).toLocaleString(undefined, { style: 'currency', currency: 'USD' }); return `${source} → ${target}: ${amount}`; } + + if (params.data.amount != null) { + return `${params.data.label}: ${amount}`; + } + return params.data.label; } """ @@ -351,6 +357,15 @@ def sorted_categories(group: SankeyNode) -> list[SankeyNode]: def build_echarts_html(data: SankeyData, *, start: date, end: date) -> str: min_link_value = max(float(value) for value in data.values) * _MIN_LINK_VALUE_RATIO + + amounts: dict[int, Decimal] = defaultdict(Decimal) + for source, target, value in zip( + data.sources, data.targets, data.values, strict=True + ): + amounts[target] += value + if amounts[source] == 0: + amounts[source] = value + return ( charts.Sankey( init_opts=options.InitOpts(width="100%", height=f"{_MIN_FIGURE_HEIGHT}px") @@ -358,8 +373,10 @@ def build_echarts_html(data: SankeyData, *, start: date, end: date) -> str: .add( "", nodes=[ - {"name": key, "label": label} - for key, label in zip(data.keys, data.labels, strict=True) + {"name": key, "label": label, "amount": float(amounts[i])} + for i, (key, label) in enumerate( + zip(data.keys, data.labels, strict=True) + ) ], links=[ { diff --git a/tests/sankey/test.py b/tests/sankey/test.py index f04945f..056f092 100644 --- a/tests/sankey/test.py +++ b/tests/sankey/test.py @@ -400,6 +400,26 @@ def test_build_echarts_html_uses_node_keys_and_labels(): assert "params.data.target_label" in html assert "params.data.amount" in html assert "currency: 'USD'" in html + assert ( + '"name": "income:Employer",\n "label": "Employer",\n "amount": 500.0' + in html + ) + assert ( + '"name": "ready_to_assign",\n "label": "Ready to Assign",\n "amount": 500.0' + in html + ) + assert ( + '"name": "income",\n "label": "Income",\n "amount": 500.0' + in html + ) + assert ( + '"name": "category_group:taxes-group",\n "label": "Taxes",\n "amount": 120.0' + in html + ) + assert ( + '"name": "category:taxes-category",\n "label": "Taxes",\n "amount": 120.0' + in html + ) assert "height:1000px" in html assert "layoutIterations" in html