/api/trends prints pie of each of last N months
parent
18a19e52f5
commit
b8c78fe55e
|
|
@ -205,6 +205,10 @@
|
||||||
<summary><i>Look at this graph</i></summary>
|
<summary><i>Look at this graph</i></summary>
|
||||||
<iframe style="background: white; width: 100%;" src="/api/reg?x=y&mode=reg&likeName=Withdrawal:[0123]&chart=stack&predictionMonths=6&prediction=autoContributions=&bpi=true&zoomStart=YYYY-MM"></iframe>
|
<iframe style="background: white; width: 100%;" src="/api/reg?x=y&mode=reg&likeName=Withdrawal:[0123]&chart=stack&predictionMonths=6&prediction=autoContributions=&bpi=true&zoomStart=YYYY-MM"></iframe>
|
||||||
</details>
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary><i>Where did the money go</i></summary>
|
||||||
|
<iframe style="background: white; width: 100%;" src="/api/trends"></iframe>
|
||||||
|
</details>
|
||||||
</details>
|
</details>
|
||||||
<details open style="display: none;">
|
<details open style="display: none;">
|
||||||
<summary>Edit</summary>
|
<summary>Edit</summary>
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ func (router Router) API(w http.ResponseWriter, r *http.Request) {
|
||||||
router.APITransactions(w, r)
|
router.APITransactions(w, r)
|
||||||
case "/api/amend":
|
case "/api/amend":
|
||||||
router.APIAmend(w, r)
|
router.APIAmend(w, r)
|
||||||
|
case "/api/trends":
|
||||||
|
router.APITrends(w, r)
|
||||||
case "/api/reg", "/api/bal":
|
case "/api/reg", "/api/bal":
|
||||||
router.APIReg(w, r)
|
router.APIReg(w, r)
|
||||||
default:
|
default:
|
||||||
|
|
@ -110,6 +112,51 @@ func (router Router) APITransactions(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (router Router) APITrends(w http.ResponseWriter, r *http.Request) {
|
||||||
|
bpis, err := router.bpis()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
deltas, err := router.files.Deltas()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
recent := time.Hour * 24 * 365 / 2
|
||||||
|
recentHouseRelatedDeltas := deltas.
|
||||||
|
Like(ledger.LikeTransactions(
|
||||||
|
deltas.Like(ledger.LikeName(`^House`))...,
|
||||||
|
)).
|
||||||
|
Like(ledger.LikeAfter(time.Now().Add(-1 * recent).Format("2006-01"))).
|
||||||
|
Group(ledger.GroupName(`Withdrawal:[0-9]*:[^:]*`)).
|
||||||
|
Group(ledger.GroupDate(`^[0-9]*-[0-9]*`)).
|
||||||
|
Like(ledger.LikeNotName(`^$`))
|
||||||
|
|
||||||
|
monthsToDeltas := map[string]ledger.Deltas{}
|
||||||
|
for _, delta := range recentHouseRelatedDeltas {
|
||||||
|
monthsToDeltas[delta.Date] = append(monthsToDeltas[delta.Date], delta)
|
||||||
|
}
|
||||||
|
months := []string{}
|
||||||
|
for k := range monthsToDeltas {
|
||||||
|
months = append(months, k)
|
||||||
|
}
|
||||||
|
slices.Sort(months)
|
||||||
|
|
||||||
|
fmt.Fprintln(w, "<!DOCTYPE html>")
|
||||||
|
for _, month := range months {
|
||||||
|
balances := monthsToDeltas[month].Balances().WithBPIs(bpis)
|
||||||
|
chart := view.NewChart("pie")
|
||||||
|
for category, balance := range balances {
|
||||||
|
chart.AddY(category, []int{int(balance[ledger.USD])})
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, "<h2>", month, "</h2>")
|
||||||
|
if err := chart.Render(w); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (router Router) APIAmend(w http.ResponseWriter, r *http.Request) {
|
func (router Router) APIAmend(w http.ResponseWriter, r *http.Request) {
|
||||||
b, _ := io.ReadAll(r.Body)
|
b, _ := io.ReadAll(r.Body)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ func LikeAfter(date string) Like {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LikeNotName(pattern string) Like {
|
||||||
|
return func(d Delta) bool {
|
||||||
|
return !like(pattern, d.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LikeName(pattern string) Like {
|
func LikeName(pattern string) Like {
|
||||||
return func(d Delta) bool {
|
return func(d Delta) bool {
|
||||||
return like(pattern, d.Name)
|
return like(pattern, d.Name)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ func NewChart(name string) Chart {
|
||||||
return NewBar()
|
return NewBar()
|
||||||
case "stack":
|
case "stack":
|
||||||
return NewStack()
|
return NewStack()
|
||||||
|
case "pie":
|
||||||
|
return NewPie()
|
||||||
default:
|
default:
|
||||||
panic("bad chart name " + name)
|
panic("bad chart name " + name)
|
||||||
}
|
}
|
||||||
|
|
@ -107,3 +109,33 @@ func (stack Stack) AddY(name string, v []int) {
|
||||||
Stack: "stackA",
|
Stack: "stackA",
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Pie struct {
|
||||||
|
*charts.Pie
|
||||||
|
series []opts.PieData
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPie() *Pie {
|
||||||
|
return &Pie{Pie: charts.NewPie()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pie *Pie) AddX(v interface{}) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pie *Pie) Render(w io.Writer) error {
|
||||||
|
pie.AddSeries("", pie.series)
|
||||||
|
return pie.Pie.Render(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pie *Pie) AddY(name string, v []int) {
|
||||||
|
for _, v := range v {
|
||||||
|
pie.series = append(pie.series, opts.PieData{
|
||||||
|
Name: fmt.Sprintf("%s ($%d)", name, v),
|
||||||
|
Value: v,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pie *Pie) Overlap(other Chart) {
|
||||||
|
panic("nope")
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue