From 7dc3d6c3fb59a3ea100a40c767f57fb624235f03 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 16:06:39 +0000
Subject: [PATCH 1/7] Initial plan
From 1669e8f66968c736601dc287528ef1fb2d5a1d56 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 16:11:29 +0000
Subject: [PATCH 2/7] Add advanced bank statement example with deep financial
insights
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
.../json/bank-statement-advanced.idoc.json | 905 ++++++++++++++++++
1 file changed, 905 insertions(+)
create mode 100644 packages/web-deploy/json/bank-statement-advanced.idoc.json
diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json
new file mode 100644
index 00000000..3f9bac7a
--- /dev/null
+++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json
@@ -0,0 +1,905 @@
+{
+ "$schema": "../../../docs/schema/idoc_v1.json",
+ "title": "Advanced Personal Financial Dashboard",
+ "style": {
+ "css": [
+ "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }",
+ "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'trends spending budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }",
+ ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }",
+ "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }",
+ "#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }",
+ "#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }",
+ "#insights { grid-area: insights; min-width: 0; overflow: hidden; }",
+ "#trends { grid-area: trends; min-width: 0; overflow: hidden; }",
+ "#spending { grid-area: spending; min-width: 0; overflow: hidden; }",
+ "#budget { grid-area: budget; min-width: 0; overflow: hidden; }",
+ "#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }",
+ "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }",
+ "#categories { grid-area: categories; min-width: 0; overflow: hidden; }",
+ "#transactions { grid-area: transactions; min-width: 0; overflow: hidden; }",
+ "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }",
+ "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }",
+ "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }",
+ ".tabulator { max-width: 100%; overflow: auto; }",
+ ".tabulator .tabulator-table { min-width: fit-content; }",
+ ".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }",
+ ".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }",
+ ".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }",
+ ".positive { color: #38a169; }",
+ ".negative { color: #e53e3e; }",
+ ".warning { color: #d69e2e; }",
+ ".slider-container { margin: 15px 0; }",
+ ".slider-label { font-weight: 500; color: #2d3748; margin-bottom: 8px; display: block; }",
+ "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights trends' 'spending budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }",
+ "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'trends' 'spending' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }"
+ ]
+ },
+ "dataLoaders": [
+ {
+ "dataSourceName": "transactions",
+ "type": "inline",
+ "format": "csv",
+ "content": [
+ "date,description,category,amount,type,merchant",
+ "2024-01-02,Salary Deposit,Income,3500.00,income,Employer",
+ "2024-01-03,Rent Payment,Housing,-1200.00,expense,Property Management Co",
+ "2024-01-04,Grocery Store,Food,-85.50,expense,Whole Foods",
+ "2024-01-05,Gas Station,Transportation,-45.00,expense,Shell",
+ "2024-01-06,Coffee Shop,Food,-12.75,expense,Starbucks",
+ "2024-01-08,Electric Bill,Utilities,-89.99,expense,ConEd",
+ "2024-01-10,Movie Tickets,Entertainment,-28.00,expense,AMC Theaters",
+ "2024-01-12,Pharmacy,Healthcare,-25.99,expense,CVS Pharmacy",
+ "2024-01-14,Online Shopping,Shopping,-67.89,expense,Amazon",
+ "2024-01-15,Freelance Project,Income,850.00,income,Client ABC",
+ "2024-01-16,Restaurant,Food,-42.50,expense,Local Bistro",
+ "2024-01-18,Internet Bill,Utilities,-59.99,expense,Comcast",
+ "2024-01-20,Gym Membership,Health,-29.99,expense,Planet Fitness",
+ "2024-01-22,Grocery Store,Food,-92.34,expense,Whole Foods",
+ "2024-01-24,Car Insurance,Transportation,-125.00,expense,Geico",
+ "2024-01-25,Clothing Store,Shopping,-89.99,expense,H&M",
+ "2024-01-26,Savings Transfer,Savings,-500.00,transfer,Savings Account",
+ "2024-01-28,Gas Station,Transportation,-38.75,expense,Shell",
+ "2024-01-30,Phone Bill,Utilities,-45.00,expense,Verizon",
+ "2024-02-01,Coffee Shop,Food,-8.50,expense,Starbucks",
+ "2024-02-03,Subscription,Entertainment,-15.99,expense,Netflix",
+ "2024-02-05,Grocery Store,Food,-78.25,expense,Trader Joes",
+ "2024-02-07,Restaurant,Food,-65.00,expense,Local Bistro",
+ "2024-02-10,Gas Station,Transportation,-42.30,expense,Exxon",
+ "2024-02-12,Online Shopping,Shopping,-125.50,expense,Amazon",
+ "2024-02-14,Date Night,Entertainment,-95.00,expense,Fine Dining",
+ "2024-02-16,Freelance Project,Income,750.00,income,Client XYZ",
+ "2024-02-18,Pharmacy,Healthcare,-18.75,expense,Walgreens",
+ "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe",
+ "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods",
+ "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target",
+ "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell"
+ ]
+ },
+ {
+ "dataSourceName": "categoryBudgets",
+ "type": "inline",
+ "format": "csv",
+ "content": [
+ "category,budgetAmount,color",
+ "Housing,1200,#667eea",
+ "Food,400,#764ba2",
+ "Transportation,300,#f093fb",
+ "Utilities,250,#4ecdc4",
+ "Entertainment,200,#45b7d1",
+ "Healthcare,150,#96ceb4",
+ "Shopping,200,#feca57",
+ "Health,50,#ff9ff3",
+ "Savings,600,#54a0ff"
+ ]
+ }
+ ],
+ "variables": [
+ {
+ "variableId": "selectedTimeframe",
+ "type": "string",
+ "initialValue": "All Time"
+ },
+ {
+ "variableId": "totalIncome",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'income'"
+ },
+ {
+ "type": "aggregate",
+ "ops": ["sum"],
+ "fields": ["amount"],
+ "as": ["total"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "totalExpenses",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "aggregate",
+ "ops": ["sum"],
+ "fields": ["amount"],
+ "as": ["total"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "totalSavings",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'transfer' && datum.category === 'Savings'"
+ },
+ {
+ "type": "aggregate",
+ "ops": ["sum"],
+ "fields": ["amount"],
+ "as": ["total"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "currentBalance",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "aggregate",
+ "ops": ["sum"],
+ "fields": ["amount"],
+ "as": ["total"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "expensesByCategory",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["category"],
+ "ops": ["sum", "count"],
+ "fields": ["absAmount", "absAmount"],
+ "as": ["totalAmount", "transactionCount"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "budgetComparison",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["expensesByCategory", "categoryBudgets"],
+ "dataFrameTransformations": [
+ {
+ "type": "lookup",
+ "from": "categoryBudgets",
+ "key": "category",
+ "fields": ["budgetAmount", "color"],
+ "as": ["budget", "color"]
+ },
+ {
+ "type": "formula",
+ "expr": "datum.totalAmount - datum.budget",
+ "as": "variance"
+ },
+ {
+ "type": "formula",
+ "expr": "datum.totalAmount / datum.budget",
+ "as": "percentOfBudget"
+ },
+ {
+ "type": "formula",
+ "expr": "datum.budget - datum.totalAmount",
+ "as": "remaining"
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "topMerchants",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["merchant"],
+ "ops": ["sum", "count"],
+ "fields": ["absAmount", "absAmount"],
+ "as": ["totalSpent", "visitCount"]
+ },
+ {
+ "type": "window",
+ "ops": ["rank"],
+ "fields": [null],
+ "as": ["rank"],
+ "sort": [{"field": "totalSpent", "order": "descending"}]
+ },
+ {
+ "type": "filter",
+ "expr": "datum.rank <= 10"
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "dailySpending",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "formula",
+ "expr": "datetime(datum.date)",
+ "as": "dateTime"
+ },
+ {
+ "type": "formula",
+ "expr": "day(datum.dateTime)",
+ "as": "dayOfWeek"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["date"],
+ "ops": ["sum"],
+ "fields": ["absAmount"],
+ "as": ["dailyTotal"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "weeklySpending",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "formula",
+ "expr": "datetime(datum.date)",
+ "as": "dateTime"
+ },
+ {
+ "type": "formula",
+ "expr": "week(datum.dateTime)",
+ "as": "weekOfYear"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["weekOfYear"],
+ "ops": ["sum"],
+ "fields": ["absAmount"],
+ "as": ["weeklyTotal"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "spendingByDayOfWeek",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "formula",
+ "expr": "datetime(datum.date)",
+ "as": "dateTime"
+ },
+ {
+ "type": "formula",
+ "expr": "day(datum.dateTime)",
+ "as": "dayOfWeek"
+ },
+ {
+ "type": "formula",
+ "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'",
+ "as": "dayName"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["dayOfWeek", "dayName"],
+ "ops": ["sum", "count"],
+ "fields": ["absAmount", "absAmount"],
+ "as": ["totalSpent", "transactionCount"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "formattedIncome",
+ "type": "string",
+ "initialValue": "$0.00",
+ "calculation": {
+ "vegaExpression": "'$' + format(length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 0, ',.2f')"
+ }
+ },
+ {
+ "variableId": "formattedExpenses",
+ "type": "string",
+ "initialValue": "$0.00",
+ "calculation": {
+ "vegaExpression": "'$' + format(abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0), ',.2f')"
+ }
+ },
+ {
+ "variableId": "formattedBalance",
+ "type": "string",
+ "initialValue": "$0.00",
+ "calculation": {
+ "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')"
+ }
+ },
+ {
+ "variableId": "formattedSavings",
+ "type": "string",
+ "initialValue": "$0.00",
+ "calculation": {
+ "vegaExpression": "'$' + format(abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0), ',.2f')"
+ }
+ },
+ {
+ "variableId": "savingsRate",
+ "type": "string",
+ "initialValue": "0%",
+ "calculation": {
+ "vegaExpression": "format((abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0) / (length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 1)) * 100, '.1f') + '%'"
+ }
+ },
+ {
+ "variableId": "avgDailySpending",
+ "type": "string",
+ "initialValue": "$0.00",
+ "calculation": {
+ "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')"
+ }
+ }
+ ],
+ "groups": [
+ {
+ "groupId": "header",
+ "elements": [
+ "# 💰 Advanced Personal Financial Dashboard",
+ "**Deep insights into your spending habits and financial patterns**"
+ ]
+ },
+ {
+ "groupId": "summary",
+ "elements": [
+ "### 📊 Financial Overview",
+ "",
+ "**Total Income:** {{formattedIncome}}",
+ "**Total Expenses:** {{formattedExpenses}}",
+ "**Current Balance:** {{formattedBalance}}",
+ "**Total Savings:** {{formattedSavings}}",
+ "",
+ "#### Quick Stats",
+ {
+ "type": "tabulator",
+ "dataSourceName": "expensesByCategory",
+ "editable": false,
+ "cssClass": "compact-table",
+ "tabulatorOptions": {
+ "layout": "fitColumns",
+ "headerSort": false,
+ "initialSort": [
+ {"column": "totalAmount", "dir": "desc"}
+ ],
+ "columns": [
+ {
+ "title": "Category",
+ "field": "category",
+ "sorter": "string"
+ },
+ {
+ "title": "Total",
+ "field": "totalAmount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Transactions",
+ "field": "transactionCount",
+ "sorter": "number"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "groupId": "metrics",
+ "elements": [
+ "### 🎯 Key Metrics",
+ "",
+ "
",
+ "
{{savingsRate}}
",
+ "
Savings Rate
",
+ "
",
+ "",
+ "",
+ "
{{avgDailySpending}}
",
+ "
Avg Daily Spending
",
+ "
",
+ "",
+ "#### Financial Health",
+ "- **Expense Ratio:** High spending in Food and Housing",
+ "- **Saving Behavior:** Regular savings transfers detected",
+ "- **Income Diversity:** Salary + Freelance income"
+ ]
+ },
+ {
+ "groupId": "insights",
+ "elements": [
+ "### 🔍 Smart Insights",
+ "",
+ "**Top Spending Categories:**",
+ "1. Housing ({{formattedExpenses}} of expenses)",
+ "2. Food & Dining (frequent purchases)",
+ "3. Transportation (regular fuel costs)",
+ "",
+ "**Spending Patterns:**",
+ "- Most active merchant: Starbucks (frequent coffee purchases)",
+ "- Grocery shopping: Mostly Whole Foods",
+ "- Regular bills: Utilities paid on time",
+ "",
+ "**Recommendations:**",
+ "- Consider bulk coffee purchases to reduce café visits",
+ "- Monitor entertainment spending trends",
+ "- Great job on consistent savings!"
+ ]
+ },
+ {
+ "groupId": "trends",
+ "elements": [
+ "### 📈 Spending Trends",
+ {
+ "type": "chart",
+ "chartKey": "dailySpendingTrend"
+ }
+ ]
+ },
+ {
+ "groupId": "spending",
+ "elements": [
+ "### 🥧 Category Breakdown",
+ {
+ "type": "chart",
+ "chartKey": "expensesPieChart"
+ }
+ ]
+ },
+ {
+ "groupId": "budget",
+ "elements": [
+ "### 🎯 Budget vs Actual",
+ {
+ "type": "tabulator",
+ "dataSourceName": "budgetComparison",
+ "editable": false,
+ "tabulatorOptions": {
+ "layout": "fitColumns",
+ "columns": [
+ {
+ "title": "Category",
+ "field": "category",
+ "sorter": "string"
+ },
+ {
+ "title": "Budget",
+ "field": "budget",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Actual",
+ "field": "totalAmount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Variance",
+ "field": "variance",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "% of Budget",
+ "field": "percentOfBudget",
+ "formatter": "progress",
+ "formatterParams": {
+ "min": 0,
+ "max": 2,
+ "color": ["green", "orange", "red"],
+ "legend": true
+ },
+ "sorter": "number"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "groupId": "merchants",
+ "elements": [
+ "### 🏪 Top Merchants",
+ {
+ "type": "tabulator",
+ "dataSourceName": "topMerchants",
+ "editable": false,
+ "tabulatorOptions": {
+ "layout": "fitColumns",
+ "columns": [
+ {
+ "title": "Merchant",
+ "field": "merchant",
+ "sorter": "string"
+ },
+ {
+ "title": "Total Spent",
+ "field": "totalSpent",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Visits",
+ "field": "visitCount",
+ "sorter": "number"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "groupId": "patterns",
+ "elements": [
+ "### 📅 Day of Week Patterns",
+ {
+ "type": "chart",
+ "chartKey": "dayOfWeekSpending"
+ }
+ ]
+ },
+ {
+ "groupId": "categories",
+ "elements": [
+ "### 📊 Category Deep Dive",
+ {
+ "type": "chart",
+ "chartKey": "budgetComparisonChart"
+ }
+ ]
+ },
+ {
+ "groupId": "transactions",
+ "elements": [
+ "### 📋 Transaction History",
+ "**Edit transactions below to update your analysis**",
+ {
+ "type": "tabulator",
+ "variableId": "editableTransactions",
+ "dataSourceName": "transactions",
+ "editable": true,
+ "tabulatorOptions": {
+ "layout": "fitColumns",
+ "maxHeight": "400px",
+ "columns": [
+ {
+ "title": "Date",
+ "field": "date",
+ "sorter": "date",
+ "editor": "date"
+ },
+ {
+ "title": "Description",
+ "field": "description",
+ "editor": "input"
+ },
+ {
+ "title": "Merchant",
+ "field": "merchant",
+ "editor": "input"
+ },
+ {
+ "title": "Category",
+ "field": "category",
+ "editor": "list",
+ "editorParams": {
+ "values": ["Income", "Housing", "Food", "Transportation", "Utilities", "Entertainment", "Healthcare", "Shopping", "Health", "Savings"]
+ }
+ },
+ {
+ "title": "Amount",
+ "field": "amount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "editor": "number",
+ "editorParams": {
+ "step": 0.01
+ }
+ },
+ {
+ "title": "Type",
+ "field": "type",
+ "editor": "list",
+ "editorParams": {
+ "values": ["income", "expense", "transfer"]
+ }
+ }
+ ],
+ "addRowPos": "top"
+ }
+ }
+ ]
+ }
+ ],
+ "resources": {
+ "charts": {
+ "expensesPieChart": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 300,
+ "data": {
+ "name": "expensesByCategory"
+ },
+ "mark": {
+ "type": "arc",
+ "innerRadius": 50,
+ "stroke": "white",
+ "strokeWidth": 2
+ },
+ "encoding": {
+ "theta": {
+ "field": "totalAmount",
+ "type": "quantitative",
+ "title": "Amount Spent"
+ },
+ "color": {
+ "field": "category",
+ "type": "nominal",
+ "sort": {"field": "totalAmount", "order": "descending"},
+ "scale": {
+ "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"]
+ },
+ "legend": {
+ "orient": "right",
+ "title": "Category"
+ }
+ },
+ "tooltip": [
+ {"field": "category", "type": "nominal", "title": "Category"},
+ {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"},
+ {"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
+ ]
+ }
+ },
+ "dailySpendingTrend": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 200,
+ "data": {
+ "name": "dailySpending"
+ },
+ "mark": {
+ "type": "line",
+ "point": true,
+ "strokeWidth": 3
+ },
+ "encoding": {
+ "x": {
+ "field": "date",
+ "type": "temporal",
+ "title": "Date"
+ },
+ "y": {
+ "field": "dailyTotal",
+ "type": "quantitative",
+ "title": "Daily Spending ($)"
+ },
+ "color": {
+ "value": "#667eea"
+ },
+ "tooltip": [
+ {"field": "date", "type": "temporal", "title": "Date"},
+ {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
+ ]
+ }
+ },
+ "dayOfWeekSpending": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 200,
+ "data": {
+ "name": "spendingByDayOfWeek"
+ },
+ "mark": "bar",
+ "encoding": {
+ "x": {
+ "field": "dayName",
+ "type": "ordinal",
+ "title": "Day of Week",
+ "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
+ },
+ "y": {
+ "field": "totalSpent",
+ "type": "quantitative",
+ "title": "Total Spent ($)"
+ },
+ "color": {
+ "field": "totalSpent",
+ "type": "quantitative",
+ "scale": {
+ "range": ["#e8f4f8", "#2e86ab"]
+ },
+ "legend": null
+ },
+ "tooltip": [
+ {"field": "dayName", "type": "nominal", "title": "Day"},
+ {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"},
+ {"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
+ ]
+ }
+ },
+ "budgetComparisonChart": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 300,
+ "data": {
+ "name": "budgetComparison"
+ },
+ "transform": [
+ {
+ "fold": ["budget", "totalAmount"],
+ "as": ["type", "amount"]
+ }
+ ],
+ "mark": "bar",
+ "encoding": {
+ "x": {
+ "field": "category",
+ "type": "nominal",
+ "title": "Category"
+ },
+ "y": {
+ "field": "amount",
+ "type": "quantitative",
+ "title": "Amount ($)"
+ },
+ "color": {
+ "field": "type",
+ "type": "nominal",
+ "scale": {
+ "domain": ["budget", "totalAmount"],
+ "range": ["#a8dadc", "#e63946"]
+ },
+ "legend": {
+ "title": "Type",
+ "labelExpr": "datum.label === 'budget' ? 'Budget' : 'Actual'"
+ }
+ },
+ "xOffset": {
+ "field": "type",
+ "type": "nominal"
+ },
+ "tooltip": [
+ {"field": "category", "type": "nominal", "title": "Category"},
+ {"field": "type", "type": "nominal", "title": "Type"},
+ {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
+ ]
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
From 66dac868d07a3dc6f50022fd164288e25c8d08fe Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 16:17:12 +0000
Subject: [PATCH 3/7] Enhance bank statement with time filtering, spending
heatmap, and smart insights
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
.../json/bank-statement-advanced.idoc.json | 157 ++++++++++++++++--
1 file changed, 143 insertions(+), 14 deletions(-)
diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json
index 3f9bac7a..f00723b1 100644
--- a/packages/web-deploy/json/bank-statement-advanced.idoc.json
+++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json
@@ -72,7 +72,19 @@
"2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe",
"2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods",
"2024-02-25,Clothing Store,Shopping,-145.99,expense,Target",
- "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell"
+ "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell",
+ "2024-03-02,Coffee Shop,Food,-9.75,expense,Starbucks",
+ "2024-03-05,Grocery Store,Food,-112.34,expense,Whole Foods",
+ "2024-03-08,Streaming Service,Entertainment,-12.99,expense,Disney+",
+ "2024-03-10,Phone Bill,Utilities,-45.00,expense,Verizon",
+ "2024-03-12,Restaurant,Food,-78.50,expense,Fine Dining",
+ "2024-03-15,Freelance Project,Income,920.00,income,Client DEF",
+ "2024-03-18,Gas Station,Transportation,-41.25,expense,Exxon",
+ "2024-03-20,Online Shopping,Shopping,-89.99,expense,Amazon",
+ "2024-03-22,Gym Membership,Health,-29.99,expense,Planet Fitness",
+ "2024-03-25,Electric Bill,Utilities,-95.75,expense,ConEd",
+ "2024-03-28,Coffee Shop,Food,-13.50,expense,Local Cafe",
+ "2024-03-30,Savings Transfer,Savings,-600.00,transfer,Savings Account"
]
},
{
@@ -100,12 +112,32 @@
"initialValue": "All Time"
},
{
- "variableId": "totalIncome",
+ "variableId": "filteredTransactions",
"type": "object",
"isArray": true,
"initialValue": [],
"calculation": {
"dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "formula",
+ "expr": "selectedTimeframe === 'January' ? (year(datum.date) === 2024 && month(datum.date) === 0) : selectedTimeframe === 'February' ? (year(datum.date) === 2024 && month(datum.date) === 1) : selectedTimeframe === 'March' ? (year(datum.date) === 2024 && month(datum.date) === 2) : true",
+ "as": "timeMatch"
+ },
+ {
+ "type": "filter",
+ "expr": "datum.timeMatch"
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "totalIncome",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -126,7 +158,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -147,7 +179,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -168,7 +200,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "aggregate",
@@ -185,7 +217,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -245,7 +277,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -283,7 +315,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -320,7 +352,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -357,7 +389,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["editableTransactions"],
+ "dataSourceNames": ["filteredTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -440,6 +472,30 @@
"calculation": {
"vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')"
}
+ },
+ {
+ "variableId": "highestExpenseCategory",
+ "type": "string",
+ "initialValue": "None",
+ "calculation": {
+ "vegaExpression": "length(data('expensesByCategory')) > 0 ? data('expensesByCategory')[0].category : 'None'"
+ }
+ },
+ {
+ "variableId": "totalTransactions",
+ "type": "string",
+ "initialValue": "0",
+ "calculation": {
+ "vegaExpression": "'' + length(data('filteredTransactions'))"
+ }
+ },
+ {
+ "variableId": "expenseTransactions",
+ "type": "string",
+ "initialValue": "0",
+ "calculation": {
+ "vegaExpression": "'' + length(data('filteredTransactions').filter(function(d) { return d.type === 'expense'; }))"
+ }
}
],
"groups": [
@@ -455,6 +511,13 @@
"elements": [
"### 📊 Financial Overview",
"",
+ {
+ "type": "dropdown",
+ "variableId": "selectedTimeframe",
+ "label": "Time Period:",
+ "options": ["All Time", "January", "February", "March"]
+ },
+ "",
"**Total Income:** {{formattedIncome}}",
"**Total Expenses:** {{formattedExpenses}}",
"**Current Balance:** {{formattedBalance}}",
@@ -524,16 +587,21 @@
"elements": [
"### 🔍 Smart Insights",
"",
- "**Top Spending Categories:**",
- "1. Housing ({{formattedExpenses}} of expenses)",
- "2. Food & Dining (frequent purchases)",
- "3. Transportation (regular fuel costs)",
+ "**Spending Summary:**",
+ "- **Total Transactions:** {{totalTransactions}}",
+ "- **Expense Transactions:** {{expenseTransactions}}",
+ "- **Top Category:** {{highestExpenseCategory}}",
"",
"**Spending Patterns:**",
"- Most active merchant: Starbucks (frequent coffee purchases)",
"- Grocery shopping: Mostly Whole Foods",
"- Regular bills: Utilities paid on time",
"",
+ "**Financial Health Alerts:**",
+ "- ⚠️ Food spending is above average",
+ "- ✅ Regular savings pattern detected",
+ "- 💡 Consider consolidating grocery shopping",
+ "",
"**Recommendations:**",
"- Consider bulk coffee purchases to reduce café visits",
"- Monitor entertainment spending trends",
@@ -547,6 +615,12 @@
{
"type": "chart",
"chartKey": "dailySpendingTrend"
+ },
+ "",
+ "#### Daily Spending Heatmap",
+ {
+ "type": "chart",
+ "chartKey": "spendingHeatmap"
}
]
},
@@ -899,6 +973,61 @@
{"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
]
}
+ },
+ "spendingHeatmap": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 250,
+ "data": {
+ "name": "dailySpending"
+ },
+ "transform": [
+ {
+ "formula": "datetime(datum.date)",
+ "as": "dateTime"
+ },
+ {
+ "formula": "day(datum.dateTime)",
+ "as": "dayOfWeek"
+ },
+ {
+ "formula": "date(datum.dateTime)",
+ "as": "dayOfMonth"
+ },
+ {
+ "formula": "month(datum.dateTime)",
+ "as": "monthNumber"
+ }
+ ],
+ "mark": "rect",
+ "encoding": {
+ "x": {
+ "field": "dayOfWeek",
+ "type": "ordinal",
+ "title": "Day of Week",
+ "scale": {
+ "domain": [1, 2, 3, 4, 5, 6, 0]
+ }
+ },
+ "y": {
+ "field": "dayOfMonth",
+ "type": "ordinal",
+ "title": "Day of Month"
+ },
+ "color": {
+ "field": "dailyTotal",
+ "type": "quantitative",
+ "title": "Amount Spent",
+ "scale": {
+ "scheme": "blues",
+ "range": ["#f7fbff", "#08519c"]
+ }
+ },
+ "tooltip": [
+ {"field": "date", "type": "temporal", "title": "Date"},
+ {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
+ ]
+ }
}
}
}
From ecf2feee041e230ec04c2eafaf81ee806f39d1f8 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 16:31:28 +0000
Subject: [PATCH 4/7] Fix bank statement advanced example - remove invalid Vega
expressions and time filtering
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
.../json/bank-statement-advanced.idoc.json | 242 ++----------------
1 file changed, 27 insertions(+), 215 deletions(-)
diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json
index f00723b1..49645898 100644
--- a/packages/web-deploy/json/bank-statement-advanced.idoc.json
+++ b/packages/web-deploy/json/bank-statement-advanced.idoc.json
@@ -1,17 +1,17 @@
{
"$schema": "../../../docs/schema/idoc_v1.json",
- "title": "Advanced Personal Financial Dashboard",
+ "title": "Enhanced Personal Bank Statement",
"style": {
"css": [
"body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }",
- "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'trends spending budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }",
+ "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'chart trends budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }",
".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }",
"#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }",
"#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }",
"#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }",
"#insights { grid-area: insights; min-width: 0; overflow: hidden; }",
+ "#chart { grid-area: chart; min-width: 0; overflow: hidden; }",
"#trends { grid-area: trends; min-width: 0; overflow: hidden; }",
- "#spending { grid-area: spending; min-width: 0; overflow: hidden; }",
"#budget { grid-area: budget; min-width: 0; overflow: hidden; }",
"#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }",
"#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }",
@@ -22,16 +22,14 @@
"h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }",
".tabulator { max-width: 100%; overflow: auto; }",
".tabulator .tabulator-table { min-width: fit-content; }",
+ ".compact-table { font-size: 0.85em; }",
+ ".compact-table .tabulator-header { height: 30px; }",
+ ".compact-table .tabulator-row { height: 28px; }",
".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }",
".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }",
".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }",
- ".positive { color: #38a169; }",
- ".negative { color: #e53e3e; }",
- ".warning { color: #d69e2e; }",
- ".slider-container { margin: 15px 0; }",
- ".slider-label { font-weight: 500; color: #2d3748; margin-bottom: 8px; display: block; }",
- "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights trends' 'spending budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }",
- "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'trends' 'spending' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }"
+ "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights chart' 'trends budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }",
+ "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'chart' 'trends' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }"
]
},
"dataLoaders": [
@@ -72,19 +70,7 @@
"2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe",
"2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods",
"2024-02-25,Clothing Store,Shopping,-145.99,expense,Target",
- "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell",
- "2024-03-02,Coffee Shop,Food,-9.75,expense,Starbucks",
- "2024-03-05,Grocery Store,Food,-112.34,expense,Whole Foods",
- "2024-03-08,Streaming Service,Entertainment,-12.99,expense,Disney+",
- "2024-03-10,Phone Bill,Utilities,-45.00,expense,Verizon",
- "2024-03-12,Restaurant,Food,-78.50,expense,Fine Dining",
- "2024-03-15,Freelance Project,Income,920.00,income,Client DEF",
- "2024-03-18,Gas Station,Transportation,-41.25,expense,Exxon",
- "2024-03-20,Online Shopping,Shopping,-89.99,expense,Amazon",
- "2024-03-22,Gym Membership,Health,-29.99,expense,Planet Fitness",
- "2024-03-25,Electric Bill,Utilities,-95.75,expense,ConEd",
- "2024-03-28,Coffee Shop,Food,-13.50,expense,Local Cafe",
- "2024-03-30,Savings Transfer,Savings,-600.00,transfer,Savings Account"
+ "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell"
]
},
{
@@ -106,38 +92,13 @@
}
],
"variables": [
- {
- "variableId": "selectedTimeframe",
- "type": "string",
- "initialValue": "All Time"
- },
- {
- "variableId": "filteredTransactions",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "formula",
- "expr": "selectedTimeframe === 'January' ? (year(datum.date) === 2024 && month(datum.date) === 0) : selectedTimeframe === 'February' ? (year(datum.date) === 2024 && month(datum.date) === 1) : selectedTimeframe === 'March' ? (year(datum.date) === 2024 && month(datum.date) === 2) : true",
- "as": "timeMatch"
- },
- {
- "type": "filter",
- "expr": "datum.timeMatch"
- }
- ]
- }
- },
{
"variableId": "totalIncome",
"type": "object",
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -158,7 +119,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -179,7 +140,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -200,7 +161,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "aggregate",
@@ -217,7 +178,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -262,11 +223,6 @@
"type": "formula",
"expr": "datum.totalAmount / datum.budget",
"as": "percentOfBudget"
- },
- {
- "type": "formula",
- "expr": "datum.budget - datum.totalAmount",
- "as": "remaining"
}
]
}
@@ -277,7 +233,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -315,7 +271,7 @@
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -326,16 +282,6 @@
"expr": "abs(datum.amount)",
"as": "absAmount"
},
- {
- "type": "formula",
- "expr": "datetime(datum.date)",
- "as": "dateTime"
- },
- {
- "type": "formula",
- "expr": "day(datum.dateTime)",
- "as": "dayOfWeek"
- },
{
"type": "aggregate",
"groupby": ["date"],
@@ -346,50 +292,13 @@
]
}
},
- {
- "variableId": "weeklySpending",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["filteredTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "formula",
- "expr": "abs(datum.amount)",
- "as": "absAmount"
- },
- {
- "type": "formula",
- "expr": "datetime(datum.date)",
- "as": "dateTime"
- },
- {
- "type": "formula",
- "expr": "week(datum.dateTime)",
- "as": "weekOfYear"
- },
- {
- "type": "aggregate",
- "groupby": ["weekOfYear"],
- "ops": ["sum"],
- "fields": ["absAmount"],
- "as": ["weeklyTotal"]
- }
- ]
- }
- },
{
"variableId": "spendingByDayOfWeek",
"type": "object",
"isArray": true,
"initialValue": [],
"calculation": {
- "dataSourceNames": ["filteredTransactions"],
+ "dataSourceNames": ["editableTransactions"],
"dataFrameTransformations": [
{
"type": "filter",
@@ -472,37 +381,13 @@
"calculation": {
"vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')"
}
- },
- {
- "variableId": "highestExpenseCategory",
- "type": "string",
- "initialValue": "None",
- "calculation": {
- "vegaExpression": "length(data('expensesByCategory')) > 0 ? data('expensesByCategory')[0].category : 'None'"
- }
- },
- {
- "variableId": "totalTransactions",
- "type": "string",
- "initialValue": "0",
- "calculation": {
- "vegaExpression": "'' + length(data('filteredTransactions'))"
- }
- },
- {
- "variableId": "expenseTransactions",
- "type": "string",
- "initialValue": "0",
- "calculation": {
- "vegaExpression": "'' + length(data('filteredTransactions').filter(function(d) { return d.type === 'expense'; }))"
- }
}
],
"groups": [
{
"groupId": "header",
"elements": [
- "# 💰 Advanced Personal Financial Dashboard",
+ "# 💰 Enhanced Personal Bank Statement",
"**Deep insights into your spending habits and financial patterns**"
]
},
@@ -511,19 +396,12 @@
"elements": [
"### 📊 Financial Overview",
"",
- {
- "type": "dropdown",
- "variableId": "selectedTimeframe",
- "label": "Time Period:",
- "options": ["All Time", "January", "February", "March"]
- },
- "",
"**Total Income:** {{formattedIncome}}",
"**Total Expenses:** {{formattedExpenses}}",
"**Current Balance:** {{formattedBalance}}",
"**Total Savings:** {{formattedSavings}}",
"",
- "#### Quick Stats",
+ "#### Category Summary",
{
"type": "tabulator",
"dataSourceName": "expensesByCategory",
@@ -587,18 +465,13 @@
"elements": [
"### 🔍 Smart Insights",
"",
- "**Spending Summary:**",
- "- **Total Transactions:** {{totalTransactions}}",
- "- **Expense Transactions:** {{expenseTransactions}}",
- "- **Top Category:** {{highestExpenseCategory}}",
- "",
"**Spending Patterns:**",
"- Most active merchant: Starbucks (frequent coffee purchases)",
"- Grocery shopping: Mostly Whole Foods",
"- Regular bills: Utilities paid on time",
"",
"**Financial Health Alerts:**",
- "- ⚠️ Food spending is above average",
+ "- ⚠️ Food spending may be above budget",
"- ✅ Regular savings pattern detected",
"- 💡 Consider consolidating grocery shopping",
"",
@@ -609,28 +482,22 @@
]
},
{
- "groupId": "trends",
+ "groupId": "chart",
"elements": [
- "### 📈 Spending Trends",
+ "### 🥧 Expense Distribution",
{
"type": "chart",
- "chartKey": "dailySpendingTrend"
- },
- "",
- "#### Daily Spending Heatmap",
- {
- "type": "chart",
- "chartKey": "spendingHeatmap"
+ "chartKey": "expensesPieChart"
}
]
},
{
- "groupId": "spending",
+ "groupId": "trends",
"elements": [
- "### 🥧 Category Breakdown",
+ "### 📈 Daily Spending Trends",
{
"type": "chart",
- "chartKey": "expensesPieChart"
+ "chartKey": "dailySpendingTrend"
}
]
},
@@ -746,7 +613,7 @@
{
"groupId": "categories",
"elements": [
- "### 📊 Category Deep Dive",
+ "### 📊 Budget Comparison Chart",
{
"type": "chart",
"chartKey": "budgetComparisonChart"
@@ -973,61 +840,6 @@
{"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
]
}
- },
- "spendingHeatmap": {
- "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
- "width": "container",
- "height": 250,
- "data": {
- "name": "dailySpending"
- },
- "transform": [
- {
- "formula": "datetime(datum.date)",
- "as": "dateTime"
- },
- {
- "formula": "day(datum.dateTime)",
- "as": "dayOfWeek"
- },
- {
- "formula": "date(datum.dateTime)",
- "as": "dayOfMonth"
- },
- {
- "formula": "month(datum.dateTime)",
- "as": "monthNumber"
- }
- ],
- "mark": "rect",
- "encoding": {
- "x": {
- "field": "dayOfWeek",
- "type": "ordinal",
- "title": "Day of Week",
- "scale": {
- "domain": [1, 2, 3, 4, 5, 6, 0]
- }
- },
- "y": {
- "field": "dayOfMonth",
- "type": "ordinal",
- "title": "Day of Month"
- },
- "color": {
- "field": "dailyTotal",
- "type": "quantitative",
- "title": "Amount Spent",
- "scale": {
- "scheme": "blues",
- "range": ["#f7fbff", "#08519c"]
- }
- },
- "tooltip": [
- {"field": "date", "type": "temporal", "title": "Date"},
- {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
- ]
- }
}
}
}
From 36a1c29c05989999bdb5a57fa1052b0ed4d93ce2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 16:41:58 +0000
Subject: [PATCH 5/7] Add deeper category analysis to bank statement - keep
original structure, add drill-down insights
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
.../json/bank-statement-advanced.idoc.json | 846 ------------------
.../web-deploy/json/bank-statement.idoc.json | 250 +++++-
2 files changed, 248 insertions(+), 848 deletions(-)
delete mode 100644 packages/web-deploy/json/bank-statement-advanced.idoc.json
diff --git a/packages/web-deploy/json/bank-statement-advanced.idoc.json b/packages/web-deploy/json/bank-statement-advanced.idoc.json
deleted file mode 100644
index 49645898..00000000
--- a/packages/web-deploy/json/bank-statement-advanced.idoc.json
+++ /dev/null
@@ -1,846 +0,0 @@
-{
- "$schema": "../../../docs/schema/idoc_v1.json",
- "title": "Enhanced Personal Bank Statement",
- "style": {
- "css": [
- "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }",
- "body { display: grid; grid-template-areas: 'header header header' 'summary metrics insights' 'chart trends budget' 'merchants patterns categories' 'transactions transactions transactions'; grid-template-columns: 1fr 1fr 1fr; gap: 20px; max-width: 1600px; margin: 0 auto; }",
- ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }",
- "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }",
- "#summary { grid-area: summary; text-align: center; min-width: 0; overflow: hidden; }",
- "#metrics { grid-area: metrics; min-width: 0; overflow: hidden; }",
- "#insights { grid-area: insights; min-width: 0; overflow: hidden; }",
- "#chart { grid-area: chart; min-width: 0; overflow: hidden; }",
- "#trends { grid-area: trends; min-width: 0; overflow: hidden; }",
- "#budget { grid-area: budget; min-width: 0; overflow: hidden; }",
- "#merchants { grid-area: merchants; min-width: 0; overflow: hidden; }",
- "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }",
- "#categories { grid-area: categories; min-width: 0; overflow: hidden; }",
- "#transactions { grid-area: transactions; min-width: 0; overflow: hidden; }",
- "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }",
- "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }",
- "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }",
- ".tabulator { max-width: 100%; overflow: auto; }",
- ".tabulator .tabulator-table { min-width: fit-content; }",
- ".compact-table { font-size: 0.85em; }",
- ".compact-table .tabulator-header { height: 30px; }",
- ".compact-table .tabulator-row { height: 28px; }",
- ".metric { text-align: center; margin: 10px 0; padding: 15px; background: #f7fafc; border-radius: 8px; border-left: 4px solid #3182ce; }",
- ".metric .value { font-size: 1.5em; font-weight: bold; color: #2d3748; }",
- ".metric .label { font-size: 0.9em; color: #718096; text-transform: uppercase; letter-spacing: 0.5px; }",
- "@media (max-width: 1200px) { body { grid-template-columns: 1fr 1fr; grid-template-areas: 'header header' 'summary metrics' 'insights chart' 'trends budget' 'merchants patterns' 'categories categories' 'transactions transactions'; } }",
- "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'metrics' 'insights' 'chart' 'trends' 'budget' 'merchants' 'patterns' 'categories' 'transactions'; } }"
- ]
- },
- "dataLoaders": [
- {
- "dataSourceName": "transactions",
- "type": "inline",
- "format": "csv",
- "content": [
- "date,description,category,amount,type,merchant",
- "2024-01-02,Salary Deposit,Income,3500.00,income,Employer",
- "2024-01-03,Rent Payment,Housing,-1200.00,expense,Property Management Co",
- "2024-01-04,Grocery Store,Food,-85.50,expense,Whole Foods",
- "2024-01-05,Gas Station,Transportation,-45.00,expense,Shell",
- "2024-01-06,Coffee Shop,Food,-12.75,expense,Starbucks",
- "2024-01-08,Electric Bill,Utilities,-89.99,expense,ConEd",
- "2024-01-10,Movie Tickets,Entertainment,-28.00,expense,AMC Theaters",
- "2024-01-12,Pharmacy,Healthcare,-25.99,expense,CVS Pharmacy",
- "2024-01-14,Online Shopping,Shopping,-67.89,expense,Amazon",
- "2024-01-15,Freelance Project,Income,850.00,income,Client ABC",
- "2024-01-16,Restaurant,Food,-42.50,expense,Local Bistro",
- "2024-01-18,Internet Bill,Utilities,-59.99,expense,Comcast",
- "2024-01-20,Gym Membership,Health,-29.99,expense,Planet Fitness",
- "2024-01-22,Grocery Store,Food,-92.34,expense,Whole Foods",
- "2024-01-24,Car Insurance,Transportation,-125.00,expense,Geico",
- "2024-01-25,Clothing Store,Shopping,-89.99,expense,H&M",
- "2024-01-26,Savings Transfer,Savings,-500.00,transfer,Savings Account",
- "2024-01-28,Gas Station,Transportation,-38.75,expense,Shell",
- "2024-01-30,Phone Bill,Utilities,-45.00,expense,Verizon",
- "2024-02-01,Coffee Shop,Food,-8.50,expense,Starbucks",
- "2024-02-03,Subscription,Entertainment,-15.99,expense,Netflix",
- "2024-02-05,Grocery Store,Food,-78.25,expense,Trader Joes",
- "2024-02-07,Restaurant,Food,-65.00,expense,Local Bistro",
- "2024-02-10,Gas Station,Transportation,-42.30,expense,Exxon",
- "2024-02-12,Online Shopping,Shopping,-125.50,expense,Amazon",
- "2024-02-14,Date Night,Entertainment,-95.00,expense,Fine Dining",
- "2024-02-16,Freelance Project,Income,750.00,income,Client XYZ",
- "2024-02-18,Pharmacy,Healthcare,-18.75,expense,Walgreens",
- "2024-02-20,Coffee Shop,Food,-11.25,expense,Local Cafe",
- "2024-02-22,Grocery Store,Food,-89.50,expense,Whole Foods",
- "2024-02-25,Clothing Store,Shopping,-145.99,expense,Target",
- "2024-02-28,Gas Station,Transportation,-40.80,expense,Shell"
- ]
- },
- {
- "dataSourceName": "categoryBudgets",
- "type": "inline",
- "format": "csv",
- "content": [
- "category,budgetAmount,color",
- "Housing,1200,#667eea",
- "Food,400,#764ba2",
- "Transportation,300,#f093fb",
- "Utilities,250,#4ecdc4",
- "Entertainment,200,#45b7d1",
- "Healthcare,150,#96ceb4",
- "Shopping,200,#feca57",
- "Health,50,#ff9ff3",
- "Savings,600,#54a0ff"
- ]
- }
- ],
- "variables": [
- {
- "variableId": "totalIncome",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'income'"
- },
- {
- "type": "aggregate",
- "ops": ["sum"],
- "fields": ["amount"],
- "as": ["total"]
- }
- ]
- }
- },
- {
- "variableId": "totalExpenses",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "aggregate",
- "ops": ["sum"],
- "fields": ["amount"],
- "as": ["total"]
- }
- ]
- }
- },
- {
- "variableId": "totalSavings",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'transfer' && datum.category === 'Savings'"
- },
- {
- "type": "aggregate",
- "ops": ["sum"],
- "fields": ["amount"],
- "as": ["total"]
- }
- ]
- }
- },
- {
- "variableId": "currentBalance",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "aggregate",
- "ops": ["sum"],
- "fields": ["amount"],
- "as": ["total"]
- }
- ]
- }
- },
- {
- "variableId": "expensesByCategory",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "formula",
- "expr": "abs(datum.amount)",
- "as": "absAmount"
- },
- {
- "type": "aggregate",
- "groupby": ["category"],
- "ops": ["sum", "count"],
- "fields": ["absAmount", "absAmount"],
- "as": ["totalAmount", "transactionCount"]
- }
- ]
- }
- },
- {
- "variableId": "budgetComparison",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["expensesByCategory", "categoryBudgets"],
- "dataFrameTransformations": [
- {
- "type": "lookup",
- "from": "categoryBudgets",
- "key": "category",
- "fields": ["budgetAmount", "color"],
- "as": ["budget", "color"]
- },
- {
- "type": "formula",
- "expr": "datum.totalAmount - datum.budget",
- "as": "variance"
- },
- {
- "type": "formula",
- "expr": "datum.totalAmount / datum.budget",
- "as": "percentOfBudget"
- }
- ]
- }
- },
- {
- "variableId": "topMerchants",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "formula",
- "expr": "abs(datum.amount)",
- "as": "absAmount"
- },
- {
- "type": "aggregate",
- "groupby": ["merchant"],
- "ops": ["sum", "count"],
- "fields": ["absAmount", "absAmount"],
- "as": ["totalSpent", "visitCount"]
- },
- {
- "type": "window",
- "ops": ["rank"],
- "fields": [null],
- "as": ["rank"],
- "sort": [{"field": "totalSpent", "order": "descending"}]
- },
- {
- "type": "filter",
- "expr": "datum.rank <= 10"
- }
- ]
- }
- },
- {
- "variableId": "dailySpending",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "formula",
- "expr": "abs(datum.amount)",
- "as": "absAmount"
- },
- {
- "type": "aggregate",
- "groupby": ["date"],
- "ops": ["sum"],
- "fields": ["absAmount"],
- "as": ["dailyTotal"]
- }
- ]
- }
- },
- {
- "variableId": "spendingByDayOfWeek",
- "type": "object",
- "isArray": true,
- "initialValue": [],
- "calculation": {
- "dataSourceNames": ["editableTransactions"],
- "dataFrameTransformations": [
- {
- "type": "filter",
- "expr": "datum.type === 'expense'"
- },
- {
- "type": "formula",
- "expr": "abs(datum.amount)",
- "as": "absAmount"
- },
- {
- "type": "formula",
- "expr": "datetime(datum.date)",
- "as": "dateTime"
- },
- {
- "type": "formula",
- "expr": "day(datum.dateTime)",
- "as": "dayOfWeek"
- },
- {
- "type": "formula",
- "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'",
- "as": "dayName"
- },
- {
- "type": "aggregate",
- "groupby": ["dayOfWeek", "dayName"],
- "ops": ["sum", "count"],
- "fields": ["absAmount", "absAmount"],
- "as": ["totalSpent", "transactionCount"]
- }
- ]
- }
- },
- {
- "variableId": "formattedIncome",
- "type": "string",
- "initialValue": "$0.00",
- "calculation": {
- "vegaExpression": "'$' + format(length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 0, ',.2f')"
- }
- },
- {
- "variableId": "formattedExpenses",
- "type": "string",
- "initialValue": "$0.00",
- "calculation": {
- "vegaExpression": "'$' + format(abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0), ',.2f')"
- }
- },
- {
- "variableId": "formattedBalance",
- "type": "string",
- "initialValue": "$0.00",
- "calculation": {
- "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')"
- }
- },
- {
- "variableId": "formattedSavings",
- "type": "string",
- "initialValue": "$0.00",
- "calculation": {
- "vegaExpression": "'$' + format(abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0), ',.2f')"
- }
- },
- {
- "variableId": "savingsRate",
- "type": "string",
- "initialValue": "0%",
- "calculation": {
- "vegaExpression": "format((abs(length(data('totalSavings')) > 0 ? data('totalSavings')[0].total : 0) / (length(data('totalIncome')) > 0 ? data('totalIncome')[0].total : 1)) * 100, '.1f') + '%'"
- }
- },
- {
- "variableId": "avgDailySpending",
- "type": "string",
- "initialValue": "$0.00",
- "calculation": {
- "vegaExpression": "'$' + format((abs(length(data('totalExpenses')) > 0 ? data('totalExpenses')[0].total : 0) / 30), ',.2f')"
- }
- }
- ],
- "groups": [
- {
- "groupId": "header",
- "elements": [
- "# 💰 Enhanced Personal Bank Statement",
- "**Deep insights into your spending habits and financial patterns**"
- ]
- },
- {
- "groupId": "summary",
- "elements": [
- "### 📊 Financial Overview",
- "",
- "**Total Income:** {{formattedIncome}}",
- "**Total Expenses:** {{formattedExpenses}}",
- "**Current Balance:** {{formattedBalance}}",
- "**Total Savings:** {{formattedSavings}}",
- "",
- "#### Category Summary",
- {
- "type": "tabulator",
- "dataSourceName": "expensesByCategory",
- "editable": false,
- "cssClass": "compact-table",
- "tabulatorOptions": {
- "layout": "fitColumns",
- "headerSort": false,
- "initialSort": [
- {"column": "totalAmount", "dir": "desc"}
- ],
- "columns": [
- {
- "title": "Category",
- "field": "category",
- "sorter": "string"
- },
- {
- "title": "Total",
- "field": "totalAmount",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "sorter": "number"
- },
- {
- "title": "Transactions",
- "field": "transactionCount",
- "sorter": "number"
- }
- ]
- }
- }
- ]
- },
- {
- "groupId": "metrics",
- "elements": [
- "### 🎯 Key Metrics",
- "",
- "",
- "
{{savingsRate}}
",
- "
Savings Rate
",
- "
",
- "",
- "",
- "
{{avgDailySpending}}
",
- "
Avg Daily Spending
",
- "
",
- "",
- "#### Financial Health",
- "- **Expense Ratio:** High spending in Food and Housing",
- "- **Saving Behavior:** Regular savings transfers detected",
- "- **Income Diversity:** Salary + Freelance income"
- ]
- },
- {
- "groupId": "insights",
- "elements": [
- "### 🔍 Smart Insights",
- "",
- "**Spending Patterns:**",
- "- Most active merchant: Starbucks (frequent coffee purchases)",
- "- Grocery shopping: Mostly Whole Foods",
- "- Regular bills: Utilities paid on time",
- "",
- "**Financial Health Alerts:**",
- "- ⚠️ Food spending may be above budget",
- "- ✅ Regular savings pattern detected",
- "- 💡 Consider consolidating grocery shopping",
- "",
- "**Recommendations:**",
- "- Consider bulk coffee purchases to reduce café visits",
- "- Monitor entertainment spending trends",
- "- Great job on consistent savings!"
- ]
- },
- {
- "groupId": "chart",
- "elements": [
- "### 🥧 Expense Distribution",
- {
- "type": "chart",
- "chartKey": "expensesPieChart"
- }
- ]
- },
- {
- "groupId": "trends",
- "elements": [
- "### 📈 Daily Spending Trends",
- {
- "type": "chart",
- "chartKey": "dailySpendingTrend"
- }
- ]
- },
- {
- "groupId": "budget",
- "elements": [
- "### 🎯 Budget vs Actual",
- {
- "type": "tabulator",
- "dataSourceName": "budgetComparison",
- "editable": false,
- "tabulatorOptions": {
- "layout": "fitColumns",
- "columns": [
- {
- "title": "Category",
- "field": "category",
- "sorter": "string"
- },
- {
- "title": "Budget",
- "field": "budget",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "sorter": "number"
- },
- {
- "title": "Actual",
- "field": "totalAmount",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "sorter": "number"
- },
- {
- "title": "Variance",
- "field": "variance",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "sorter": "number"
- },
- {
- "title": "% of Budget",
- "field": "percentOfBudget",
- "formatter": "progress",
- "formatterParams": {
- "min": 0,
- "max": 2,
- "color": ["green", "orange", "red"],
- "legend": true
- },
- "sorter": "number"
- }
- ]
- }
- }
- ]
- },
- {
- "groupId": "merchants",
- "elements": [
- "### 🏪 Top Merchants",
- {
- "type": "tabulator",
- "dataSourceName": "topMerchants",
- "editable": false,
- "tabulatorOptions": {
- "layout": "fitColumns",
- "columns": [
- {
- "title": "Merchant",
- "field": "merchant",
- "sorter": "string"
- },
- {
- "title": "Total Spent",
- "field": "totalSpent",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "sorter": "number"
- },
- {
- "title": "Visits",
- "field": "visitCount",
- "sorter": "number"
- }
- ]
- }
- }
- ]
- },
- {
- "groupId": "patterns",
- "elements": [
- "### 📅 Day of Week Patterns",
- {
- "type": "chart",
- "chartKey": "dayOfWeekSpending"
- }
- ]
- },
- {
- "groupId": "categories",
- "elements": [
- "### 📊 Budget Comparison Chart",
- {
- "type": "chart",
- "chartKey": "budgetComparisonChart"
- }
- ]
- },
- {
- "groupId": "transactions",
- "elements": [
- "### 📋 Transaction History",
- "**Edit transactions below to update your analysis**",
- {
- "type": "tabulator",
- "variableId": "editableTransactions",
- "dataSourceName": "transactions",
- "editable": true,
- "tabulatorOptions": {
- "layout": "fitColumns",
- "maxHeight": "400px",
- "columns": [
- {
- "title": "Date",
- "field": "date",
- "sorter": "date",
- "editor": "date"
- },
- {
- "title": "Description",
- "field": "description",
- "editor": "input"
- },
- {
- "title": "Merchant",
- "field": "merchant",
- "editor": "input"
- },
- {
- "title": "Category",
- "field": "category",
- "editor": "list",
- "editorParams": {
- "values": ["Income", "Housing", "Food", "Transportation", "Utilities", "Entertainment", "Healthcare", "Shopping", "Health", "Savings"]
- }
- },
- {
- "title": "Amount",
- "field": "amount",
- "formatter": "money",
- "formatterParams": {
- "symbol": "$",
- "precision": 2
- },
- "editor": "number",
- "editorParams": {
- "step": 0.01
- }
- },
- {
- "title": "Type",
- "field": "type",
- "editor": "list",
- "editorParams": {
- "values": ["income", "expense", "transfer"]
- }
- }
- ],
- "addRowPos": "top"
- }
- }
- ]
- }
- ],
- "resources": {
- "charts": {
- "expensesPieChart": {
- "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
- "width": "container",
- "height": 300,
- "data": {
- "name": "expensesByCategory"
- },
- "mark": {
- "type": "arc",
- "innerRadius": 50,
- "stroke": "white",
- "strokeWidth": 2
- },
- "encoding": {
- "theta": {
- "field": "totalAmount",
- "type": "quantitative",
- "title": "Amount Spent"
- },
- "color": {
- "field": "category",
- "type": "nominal",
- "sort": {"field": "totalAmount", "order": "descending"},
- "scale": {
- "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"]
- },
- "legend": {
- "orient": "right",
- "title": "Category"
- }
- },
- "tooltip": [
- {"field": "category", "type": "nominal", "title": "Category"},
- {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"},
- {"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
- ]
- }
- },
- "dailySpendingTrend": {
- "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
- "width": "container",
- "height": 200,
- "data": {
- "name": "dailySpending"
- },
- "mark": {
- "type": "line",
- "point": true,
- "strokeWidth": 3
- },
- "encoding": {
- "x": {
- "field": "date",
- "type": "temporal",
- "title": "Date"
- },
- "y": {
- "field": "dailyTotal",
- "type": "quantitative",
- "title": "Daily Spending ($)"
- },
- "color": {
- "value": "#667eea"
- },
- "tooltip": [
- {"field": "date", "type": "temporal", "title": "Date"},
- {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
- ]
- }
- },
- "dayOfWeekSpending": {
- "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
- "width": "container",
- "height": 200,
- "data": {
- "name": "spendingByDayOfWeek"
- },
- "mark": "bar",
- "encoding": {
- "x": {
- "field": "dayName",
- "type": "ordinal",
- "title": "Day of Week",
- "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
- },
- "y": {
- "field": "totalSpent",
- "type": "quantitative",
- "title": "Total Spent ($)"
- },
- "color": {
- "field": "totalSpent",
- "type": "quantitative",
- "scale": {
- "range": ["#e8f4f8", "#2e86ab"]
- },
- "legend": null
- },
- "tooltip": [
- {"field": "dayName", "type": "nominal", "title": "Day"},
- {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"},
- {"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
- ]
- }
- },
- "budgetComparisonChart": {
- "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
- "width": "container",
- "height": 300,
- "data": {
- "name": "budgetComparison"
- },
- "transform": [
- {
- "fold": ["budget", "totalAmount"],
- "as": ["type", "amount"]
- }
- ],
- "mark": "bar",
- "encoding": {
- "x": {
- "field": "category",
- "type": "nominal",
- "title": "Category"
- },
- "y": {
- "field": "amount",
- "type": "quantitative",
- "title": "Amount ($)"
- },
- "color": {
- "field": "type",
- "type": "nominal",
- "scale": {
- "domain": ["budget", "totalAmount"],
- "range": ["#a8dadc", "#e63946"]
- },
- "legend": {
- "title": "Type",
- "labelExpr": "datum.label === 'budget' ? 'Budget' : 'Actual'"
- }
- },
- "xOffset": {
- "field": "type",
- "type": "nominal"
- },
- "tooltip": [
- {"field": "category", "type": "nominal", "title": "Category"},
- {"field": "type", "type": "nominal", "title": "Type"},
- {"field": "amount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
- ]
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json
index 3f8d2312..f0c6430c 100644
--- a/packages/web-deploy/json/bank-statement.idoc.json
+++ b/packages/web-deploy/json/bank-statement.idoc.json
@@ -4,12 +4,15 @@
"style": {
"css": [
"body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }",
- "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }",
+ "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }",
".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }",
"#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }",
"#summary { grid-area: summary; text-align: center; min-width: 0; }",
"#chart { grid-area: chart; min-width: 0; }",
"#transactions { grid-area: transactions; min-width: 0; }",
+ "#drilldown { grid-area: drilldown; min-width: 0; overflow: hidden; }",
+ "#trends { grid-area: trends; min-width: 0; overflow: hidden; }",
+ "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }",
"h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }",
"h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }",
"h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }",
@@ -18,7 +21,7 @@
".compact-table { font-size: 0.85em; }",
".compact-table .tabulator-header { height: 30px; }",
".compact-table .tabulator-row { height: 28px; }",
- "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions'; } }"
+ "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'trends' 'patterns'; } }"
]
},
"dataLoaders": [
@@ -160,6 +163,102 @@
"calculation": {
"vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')"
}
+ },
+ {
+ "variableId": "transactionsByCategory",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["category"],
+ "ops": ["sum", "count", "mean", "max"],
+ "fields": ["absAmount", "absAmount", "absAmount", "absAmount"],
+ "as": ["totalAmount", "transactionCount", "avgAmount", "maxAmount"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "dailySpending",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["date"],
+ "ops": ["sum"],
+ "fields": ["absAmount"],
+ "as": ["dailyTotal"]
+ }
+ ]
+ }
+ },
+ {
+ "variableId": "spendingByDayOfWeek",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "formula",
+ "expr": "datetime(datum.date)",
+ "as": "dateTime"
+ },
+ {
+ "type": "formula",
+ "expr": "day(datum.dateTime)",
+ "as": "dayOfWeek"
+ },
+ {
+ "type": "formula",
+ "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'",
+ "as": "dayName"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["dayOfWeek", "dayName"],
+ "ops": ["sum", "count"],
+ "fields": ["absAmount", "absAmount"],
+ "as": ["totalSpent", "transactionCount"]
+ }
+ ]
+ }
}
],
"groups": [
@@ -281,6 +380,86 @@
}
}
]
+ },
+ {
+ "groupId": "drilldown",
+ "elements": [
+ "### 🔍 Category Deep Dive",
+ "**Detailed breakdown of spending patterns by category**",
+ {
+ "type": "tabulator",
+ "dataSourceName": "transactionsByCategory",
+ "editable": false,
+ "tabulatorOptions": {
+ "layout": "fitColumns",
+ "initialSort": [
+ {"column": "totalAmount", "dir": "desc"}
+ ],
+ "columns": [
+ {
+ "title": "Category",
+ "field": "category",
+ "sorter": "string"
+ },
+ {
+ "title": "Total Spent",
+ "field": "totalAmount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Transactions",
+ "field": "transactionCount",
+ "sorter": "number"
+ },
+ {
+ "title": "Avg per Transaction",
+ "field": "avgAmount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ },
+ {
+ "title": "Largest Transaction",
+ "field": "maxAmount",
+ "formatter": "money",
+ "formatterParams": {
+ "symbol": "$",
+ "precision": 2
+ },
+ "sorter": "number"
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "groupId": "trends",
+ "elements": [
+ "### 📈 Spending Trends",
+ {
+ "type": "chart",
+ "chartKey": "dailySpendingTrend"
+ }
+ ]
+ },
+ {
+ "groupId": "patterns",
+ "elements": [
+ "### 📅 Spending Patterns",
+ {
+ "type": "chart",
+ "chartKey": "dayOfWeekSpending"
+ }
+ ]
}
],
"resources": {
@@ -327,6 +506,73 @@
{"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
]
}
+ },
+ "dailySpendingTrend": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 250,
+ "data": {
+ "name": "dailySpending"
+ },
+ "mark": {
+ "type": "line",
+ "point": true,
+ "strokeWidth": 3
+ },
+ "encoding": {
+ "x": {
+ "field": "date",
+ "type": "temporal",
+ "title": "Date"
+ },
+ "y": {
+ "field": "dailyTotal",
+ "type": "quantitative",
+ "title": "Daily Spending ($)"
+ },
+ "color": {
+ "value": "#667eea"
+ },
+ "tooltip": [
+ {"field": "date", "type": "temporal", "title": "Date"},
+ {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
+ ]
+ }
+ },
+ "dayOfWeekSpending": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 250,
+ "data": {
+ "name": "spendingByDayOfWeek"
+ },
+ "mark": "bar",
+ "encoding": {
+ "x": {
+ "field": "dayName",
+ "type": "ordinal",
+ "title": "Day of Week",
+ "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
+ },
+ "y": {
+ "field": "totalSpent",
+ "type": "quantitative",
+ "title": "Total Spent ($)"
+ },
+ "color": {
+ "field": "totalSpent",
+ "type": "quantitative",
+ "scale": {
+ "range": ["#e8f4f8", "#2e86ab"]
+ },
+ "legend": null
+ },
+ "tooltip": [
+ {"field": "dayName", "type": "nominal", "title": "Day"},
+ {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"},
+ {"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
+ ]
+ }
}
}
}
From d087848dfbe0c2e36da47110adcef6d987ba569c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 18:12:19 +0000
Subject: [PATCH 6/7] Add horizontal bar chart with trellising by category
showing spending per description
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
.../web-deploy/json/bank-statement.idoc.json | 124 +++++++++++++++++-
1 file changed, 121 insertions(+), 3 deletions(-)
diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json
index f0c6430c..b0205399 100644
--- a/packages/web-deploy/json/bank-statement.idoc.json
+++ b/packages/web-deploy/json/bank-statement.idoc.json
@@ -4,13 +4,14 @@
"style": {
"css": [
"body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }",
- "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }",
+ "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'breakdown breakdown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }",
".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }",
"#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }",
"#summary { grid-area: summary; text-align: center; min-width: 0; }",
"#chart { grid-area: chart; min-width: 0; }",
"#transactions { grid-area: transactions; min-width: 0; }",
"#drilldown { grid-area: drilldown; min-width: 0; overflow: hidden; }",
+ "#breakdown { grid-area: breakdown; min-width: 0; overflow: hidden; }",
"#trends { grid-area: trends; min-width: 0; overflow: hidden; }",
"#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }",
"h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }",
@@ -21,7 +22,7 @@
".compact-table { font-size: 0.85em; }",
".compact-table .tabulator-header { height: 30px; }",
".compact-table .tabulator-row { height: 28px; }",
- "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'trends' 'patterns'; } }"
+ "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'breakdown' 'trends' 'patterns'; } }"
]
},
"dataLoaders": [
@@ -49,7 +50,35 @@
"2024-01-25,Clothing Store,Shopping,-89.99,expense",
"2024-01-26,Savings Transfer,Savings,-500.00,transfer",
"2024-01-28,Gas Station,Transportation,-38.75,expense",
- "2024-01-30,Phone Bill,Utilities,-45.00,expense"
+ "2024-01-30,Phone Bill,Utilities,-45.00,expense",
+ "2024-02-01,Supermarket,Food,-95.20,expense",
+ "2024-02-02,Coffee Shop,Food,-8.50,expense",
+ "2024-02-03,Fast Food,Food,-15.75,expense",
+ "2024-02-04,Grocery Store,Food,-78.90,expense",
+ "2024-02-05,Dining Out,Food,-65.00,expense",
+ "2024-02-06,Water Bill,Utilities,-35.50,expense",
+ "2024-02-07,Gas Bill,Utilities,-125.75,expense",
+ "2024-02-08,Cable TV,Utilities,-89.99,expense",
+ "2024-02-09,Bus Pass,Transportation,-55.00,expense",
+ "2024-02-10,Uber Ride,Transportation,-18.50,expense",
+ "2024-02-11,Parking Fee,Transportation,-12.00,expense",
+ "2024-02-12,Train Ticket,Transportation,-25.75,expense",
+ "2024-02-13,Online Store,Shopping,-145.00,expense",
+ "2024-02-14,Department Store,Shopping,-89.50,expense",
+ "2024-02-15,Bookstore,Shopping,-35.99,expense",
+ "2024-02-16,Electronics Store,Shopping,-299.99,expense",
+ "2024-02-17,Streaming Service,Entertainment,-15.99,expense",
+ "2024-02-18,Concert Tickets,Entertainment,-85.00,expense",
+ "2024-02-19,Game Purchase,Entertainment,-49.99,expense",
+ "2024-02-20,Movie Theater,Entertainment,-32.50,expense",
+ "2024-02-21,Doctor Visit,Healthcare,-150.00,expense",
+ "2024-02-22,Prescription,Healthcare,-45.50,expense",
+ "2024-02-23,Dental Cleaning,Healthcare,-125.00,expense",
+ "2024-02-24,Vitamins,Healthcare,-35.99,expense",
+ "2024-02-25,Mortgage Payment,Housing,-1200.00,expense",
+ "2024-02-26,Home Insurance,Housing,-85.00,expense",
+ "2024-02-27,Property Tax,Housing,-450.00,expense",
+ "2024-02-28,Home Repairs,Housing,-125.50,expense"
]
}
],
@@ -259,6 +288,33 @@
}
]
}
+ },
+ {
+ "variableId": "expensesByDescription",
+ "type": "object",
+ "isArray": true,
+ "initialValue": [],
+ "calculation": {
+ "dataSourceNames": ["editableTransactions"],
+ "dataFrameTransformations": [
+ {
+ "type": "filter",
+ "expr": "datum.type === 'expense'"
+ },
+ {
+ "type": "formula",
+ "expr": "abs(datum.amount)",
+ "as": "absAmount"
+ },
+ {
+ "type": "aggregate",
+ "groupby": ["category", "description"],
+ "ops": ["sum"],
+ "fields": ["absAmount"],
+ "as": ["totalAmount"]
+ }
+ ]
+ }
}
],
"groups": [
@@ -441,6 +497,17 @@
}
]
},
+ {
+ "groupId": "breakdown",
+ "elements": [
+ "### 📊 Spending Breakdown by Description",
+ "**Amount spent per description within each category**",
+ {
+ "type": "chart",
+ "chartKey": "expensesByDescriptionChart"
+ }
+ ]
+ },
{
"groupId": "trends",
"elements": [
@@ -573,6 +640,57 @@
{"field": "transactionCount", "type": "quantitative", "title": "Transactions"}
]
}
+ },
+ "expensesByDescriptionChart": {
+ "$schema": "https://vega.github.io/schema/vega-lite/v6.json",
+ "width": "container",
+ "height": 400,
+ "data": {
+ "name": "expensesByDescription"
+ },
+ "mark": "bar",
+ "encoding": {
+ "row": {
+ "field": "category",
+ "type": "nominal",
+ "title": "Category",
+ "header": {
+ "labelAngle": 0,
+ "labelAlign": "left",
+ "labelFontSize": 12,
+ "labelFontWeight": "bold"
+ }
+ },
+ "y": {
+ "field": "description",
+ "type": "nominal",
+ "title": "Description",
+ "sort": {"field": "totalAmount", "order": "descending"}
+ },
+ "x": {
+ "field": "totalAmount",
+ "type": "quantitative",
+ "title": "Amount Spent ($)"
+ },
+ "color": {
+ "field": "category",
+ "type": "nominal",
+ "scale": {
+ "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"]
+ },
+ "legend": null
+ },
+ "tooltip": [
+ {"field": "category", "type": "nominal", "title": "Category"},
+ {"field": "description", "type": "nominal", "title": "Description"},
+ {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"}
+ ]
+ },
+ "resolve": {
+ "scale": {
+ "y": "independent"
+ }
+ }
}
}
}
From bbfed5d32df52dffb67150cb8c3f93287339be87 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 16 Sep 2025 22:20:20 +0000
Subject: [PATCH 7/7] Fix trellis chart clipping by removing fixed height and
adding spacing
Co-authored-by: danmarshall <11507384+danmarshall@users.noreply.github.com>
---
packages/web-deploy/json/bank-statement.idoc.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json
index b0205399..4bfa6f09 100644
--- a/packages/web-deploy/json/bank-statement.idoc.json
+++ b/packages/web-deploy/json/bank-statement.idoc.json
@@ -644,11 +644,11 @@
"expensesByDescriptionChart": {
"$schema": "https://vega.github.io/schema/vega-lite/v6.json",
"width": "container",
- "height": 400,
"data": {
"name": "expensesByDescription"
},
"mark": "bar",
+ "spacing": 20,
"encoding": {
"row": {
"field": "category",