diff --git a/src/locales/de.json b/src/locales/de.json index 3482b031..74fab962 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Kontoliste", "This Week": "Diese Woche", "This Month": "Dieser Monat", diff --git a/src/locales/en.json b/src/locales/en.json index c5a99cf0..96ada796 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Account List", "This Week": "This Week", "This Month": "This Month", diff --git a/src/locales/es.json b/src/locales/es.json index 5cbaa21e..a291eaf2 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Recuento de transacciones", "Average Amount": "Importe Medio", "Median Amount": "Importe Mediano", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Lista de Cuentas", "This Week": "Esta Semana", "This Month": "Este Mes", diff --git a/src/locales/fr.json b/src/locales/fr.json index af50809f..bdbbfd98 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Liste des comptes", "This Week": "Cette semaine", "This Month": "Ce mois", diff --git a/src/locales/it.json b/src/locales/it.json index 51cc1b38..a0ecef41 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Elenco account", "This Week": "Questa settimana", "This Month": "Questo mese", diff --git a/src/locales/ja.json b/src/locales/ja.json index 241543af..3880071a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "口座リスト", "This Week": "今週", "This Month": "今月", diff --git a/src/locales/kn.json b/src/locales/kn.json index 752e320d..b65bb37a 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "ಖಾತೆಗಳ ಪಟ್ಟಿ", "This Week": "ಈ ವಾರ", "This Month": "ಈ ತಿಂಗಳು", diff --git a/src/locales/ko.json b/src/locales/ko.json index 6fbe5d5e..30f60b53 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1784,6 +1784,13 @@ "Transaction Count": "거래 수", "Average Amount": "평균 금액", "Median Amount": "중간 금액", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "계좌 목록", "This Week": "이번 주", "This Month": "이번 달", diff --git a/src/locales/nl.json b/src/locales/nl.json index e219d901..ba2e60b6 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Rekeningenlijst", "This Week": "Deze week", "This Month": "Deze maand", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index fbd6cb9a..506eb25d 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Lista de Contas", "This Week": "Esta Semana", "This Month": "Este Mês", diff --git a/src/locales/ru.json b/src/locales/ru.json index c53a4682..edeeaffe 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Количество транзакций", "Average Amount": "Средняя сумма", "Median Amount": "Медиана сумм", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Список счетов", "This Week": "На этой неделе", "This Month": "В этом месяце", diff --git a/src/locales/sl.json b/src/locales/sl.json index 7c307df6..c829704f 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Število transakcij", "Average Amount": "Povprečni znesek", "Median Amount": "Mediana zneska", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Seznam računov", "This Week": "Ta teden", "This Month": "Ta mesec", diff --git a/src/locales/ta.json b/src/locales/ta.json index ba5fb5ee..9e8514d7 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -1784,6 +1784,13 @@ "Transaction Count": "பரிவர்த்தனை எண்ணிக்கை", "Average Amount": "சராசரி தொகை", "Median Amount": "நடுநிலை தொகை", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "கணக்குகளின் பட்டியல்", "This Week": "இந்த வாரம்", "This Month": "இந்த மாதம்", diff --git a/src/locales/th.json b/src/locales/th.json index 99f883b3..07a31328 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "รายการบัญชี", "This Week": "สัปดาห์นี้", "This Month": "เดือนนี้", diff --git a/src/locales/tr.json b/src/locales/tr.json index 98e303c2..3d996435 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Hesap Listesi", "This Week": "Bu Hafta", "This Month": "Bu Ay", diff --git a/src/locales/uk.json b/src/locales/uk.json index 8ad5b0f4..99bf280c 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Список рахунків", "This Week": "Цього тижня", "This Month": "Цього місяця", diff --git a/src/locales/vi.json b/src/locales/vi.json index 26adcfde..d74d3eb8 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1784,6 +1784,13 @@ "Transaction Count": "Transaction Count", "Average Amount": "Average Amount", "Median Amount": "Median Amount", + "90th Percentile Amount": "90th Percentile Amount", + "Top 5 Amount Share": "Top 5 Amount Share", + "Transactions for 80% of Amount": "Transactions for 80% of Amount", + "Range (Max - Min)": "Range (Max - Min)", + "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Variance": "Variance", + "Standard Deviation": "Standard Deviation", "Account List": "Danh sách tài khoản", "This Week": "Tuần này", "This Month": "Tháng này", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 0f2821d0..520eebce 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1784,6 +1784,13 @@ "Transaction Count": "交易数量", "Average Amount": "平均金额", "Median Amount": "中位数金额", + "90th Percentile Amount": "90百分位金额", + "Top 5 Amount Share": "前5大金额占比", + "Transactions for 80% of Amount": "贡献80%金额的交易占比", + "Range (Max - Min)": "极差 (最大值 - 最小值)", + "Interquartile Range (Q3 - Q1)": "四分位距 (Q3 - Q1)", + "Variance": "方差", + "Standard Deviation": "标准差", "Account List": "账户列表", "This Week": "本周", "This Month": "本月", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index 8b2205a3..29946619 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1784,6 +1784,13 @@ "Transaction Count": "交易數量", "Average Amount": "平均金額", "Median Amount": "中位數金額", + "90th Percentile Amount": "90百分位數金額", + "Top 5 Amount Share": "前5大金額占比", + "Transactions for 80% of Amount": "貢獻80%金額的交易占比", + "Range (Max - Min)": "極差 (最大值 - 最小值)", + "Interquartile Range (Q3 - Q1)": "四分位距 (Q3 - Q1)", + "Variance": "變異數", + "Standard Deviation": "標準差", "Account List": "帳戶清單", "This Week": "本週", "This Month": "本月", diff --git a/src/stores/explorer.ts b/src/stores/explorer.ts index 35eb07e0..cb994963 100644 --- a/src/stores/explorer.ts +++ b/src/stores/explorer.ts @@ -8,7 +8,7 @@ import { useTransactionCategoriesStore } from './transactionCategory.ts'; import { useTransactionTagsStore } from './transactionTag.ts'; import { useExchangeRatesStore } from './exchangeRates.ts'; -import { type BeforeResolveFunction, itemAndIndex, keys, values } from '@/core/base.ts'; +import { type BeforeResolveFunction, itemAndIndex, reversed, keys, values } from '@/core/base.ts'; import { AmountFilterType } from '@/core/numeral.ts'; import { DateRangeScene, DateRange } from '@/core/datetime.ts'; import { TimezoneTypeForStatistics } from '@/core/timezone.ts'; @@ -114,10 +114,20 @@ export interface CategoriedTransactionExplorerDataItem extends SeriesInfo { export interface InsightsExplorerTransactionStatisticData { totalCount: number; totalAmount: number; + totalIncome: number; + totalExpense: number; + netIncome: number; averageAmount: number; medianAmount: number; + p90Amount: number; + top5AmountShare: number; + transactionsFor80PercentAmount: number; minimumAmount: number; maximumAmount: number; + range: number; + interquartileRange: number; + variance: number; + standardDeviation: number; } export const useExplorersStore = defineStore('explorers', () => { @@ -591,10 +601,20 @@ export const useExplorersStore = defineStore('explorers', () => { const statisticData: InsightsExplorerTransactionStatisticData = { totalCount: 0, totalAmount: 0, + totalIncome: 0, + totalExpense: 0, + netIncome: 0, averageAmount: 0, medianAmount: 0, + p90Amount: 0, + top5AmountShare: 0, + transactionsFor80PercentAmount: 0, minimumAmount: Number.MAX_SAFE_INTEGER, - maximumAmount: Number.MIN_SAFE_INTEGER + maximumAmount: Number.MIN_SAFE_INTEGER, + range: 0, + interquartileRange: 0, + variance: 0, + standardDeviation: 0 }; const sourceAmounts: number[] = []; @@ -603,6 +623,12 @@ export const useExplorersStore = defineStore('explorers', () => { statisticData.totalCount++; statisticData.totalAmount += transaction.sourceAmount; + if (transaction.type === TransactionType.Income) { + statisticData.totalIncome += transaction.sourceAmount; + } else if (transaction.type === TransactionType.Expense) { + statisticData.totalExpense += transaction.sourceAmount; + } + if (transaction.sourceAmount >= 0 && transaction.sourceAmount < statisticData.minimumAmount) { statisticData.minimumAmount = transaction.sourceAmount; } @@ -614,14 +640,7 @@ export const useExplorersStore = defineStore('explorers', () => { sourceAmounts.push(transaction.sourceAmount); } - if (statisticData.totalCount > 0) { - statisticData.averageAmount = Math.trunc(statisticData.totalAmount / statisticData.totalCount); - } - - if (sourceAmounts.length > 0) { - sourceAmounts.sort((a, b) => a - b); - statisticData.medianAmount = sourceAmounts[Math.floor(sourceAmounts.length / 2)] as number; - } + statisticData.netIncome = statisticData.totalIncome - statisticData.totalExpense; if (statisticData.minimumAmount === Number.MAX_SAFE_INTEGER) { statisticData.minimumAmount = 0; @@ -631,6 +650,47 @@ export const useExplorersStore = defineStore('explorers', () => { statisticData.maximumAmount = 0; } + if (statisticData.totalCount > 0) { + statisticData.averageAmount = Math.trunc(statisticData.totalAmount / statisticData.totalCount); + } + + statisticData.range = statisticData.maximumAmount - statisticData.minimumAmount; + + if (sourceAmounts.length > 0) { + sourceAmounts.sort((a, b) => a - b); + statisticData.medianAmount = sourceAmounts[Math.floor(sourceAmounts.length / 2)] as number; + statisticData.p90Amount = sourceAmounts[Math.floor(sourceAmounts.length * 9 / 10)] as number; + + const q1 = sourceAmounts[Math.floor(sourceAmounts.length / 4)] as number; + const q3 = sourceAmounts[Math.floor(sourceAmounts.length * 3 / 4)] as number; + statisticData.interquartileRange = q3 - q1; + } + + if (sourceAmounts.length > 5) { + const top5Count = Math.ceil(sourceAmounts.length * 0.05); + const top5AmountSum = sourceAmounts.slice(-top5Count).reduce((sum, amount) => sum + amount, 0); + statisticData.top5AmountShare = statisticData.totalAmount > 0 ? 100.0 * top5AmountSum / statisticData.totalAmount : 0; + } else { + statisticData.top5AmountShare = 100.0; + } + + const eightyPercentAmountThreshold: number = 0.8 * statisticData.totalAmount; + let cumulativeAmount: number = 0; + let cumulativeCount: number = 0; + for (const amount of reversed(sourceAmounts)) { + cumulativeAmount += amount; + cumulativeCount++; + + if (cumulativeAmount >= eightyPercentAmountThreshold) { + statisticData.transactionsFor80PercentAmount = 100.0 * cumulativeCount / statisticData.totalCount; + break; + } + } + + const sumOfSquaredDifferences: number = sourceAmounts.reduce((sum, amount) => sum + Math.pow(amount / 100.0 - statisticData.averageAmount / 100.0, 2), 0); + statisticData.variance = sourceAmounts.length > 0 ? sumOfSquaredDifferences / sourceAmounts.length : 0; + statisticData.standardDeviation = Math.sqrt(statisticData.variance); + return statisticData; }); diff --git a/src/views/desktop/insights/tabs/ExplorerDataTableTab.vue b/src/views/desktop/insights/tabs/ExplorerDataTableTab.vue index 53ea7b0a..7b321797 100644 --- a/src/views/desktop/insights/tabs/ExplorerDataTableTab.vue +++ b/src/views/desktop/insights/tabs/ExplorerDataTableTab.vue @@ -48,6 +48,18 @@ {{ tt('Total Amount') }} {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.totalAmount) }} + + {{ tt('Total Income') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.totalIncome) }} + + + {{ tt('Total Expense') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.totalExpense) }} + + + {{ tt('Net Income') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.netIncome) }} + {{ tt('Average Amount') }} {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.averageAmount) }} @@ -56,6 +68,18 @@ {{ tt('Median Amount') }} {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.medianAmount) }} + + {{ tt('90th Percentile Amount') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.p90Amount) }} + + + {{ tt('Top 5 Amount Share') }} + {{ formatPercentToLocalizedNumerals(filteredTransactionsStatistic.top5AmountShare, 2, '<0.01') }} + + + {{ tt('Transactions for 80% of Amount') }} + {{ formatPercentToLocalizedNumerals(filteredTransactionsStatistic.transactionsFor80PercentAmount, 2, '<0.01') }} + {{ tt('Minimum Amount') }} {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.minimumAmount) }} @@ -64,6 +88,22 @@ {{ tt('Maximum Amount') }} {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.maximumAmount) }} + + {{ tt('Range (Max - Min)') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.range) }} + + + {{ tt('Interquartile Range (Q3 - Q1)') }} + {{ formatAmountToLocalizedNumeralsWithCurrency(filteredTransactionsStatistic.interquartileRange) }} + + + {{ tt('Variance') }} + {{ formatNumberToLocalizedNumerals(filteredTransactionsStatistic.variance, 2) }} + + + {{ tt('Standard Deviation') }} + {{ formatNumberToLocalizedNumerals(filteredTransactionsStatistic.standardDeviation, 2) }} + @@ -210,7 +250,8 @@ const { formatDateTimeToGregorianDefaultDateTime, formatAmountToWesternArabicNumeralsWithoutDigitGrouping, formatAmountToLocalizedNumeralsWithCurrency, - formatNumberToLocalizedNumerals + formatNumberToLocalizedNumerals, + formatPercentToLocalizedNumerals } = useI18n(); const settingsStore = useSettingsStore();