aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgutmet <me.git@gutmet.org>2020-06-14 11:06:20 +0200
committergutmet <me.git@gutmet.org>2020-06-14 11:06:20 +0200
commitb1c5b729d17905cfaef32b57edaa7b51a35317af (patch)
treea247b6c094095e90f54e570a1b508683227c3f79
parent79282317b13e09b84f961819db2153b30e6430a6 (diff)
downloadhdiet-b1c5b729d17905cfaef32b57edaa7b51a35317af.tar.gz
fix trend calculation if days are missing by linear interpolationHEADmaster
-rw-r--r--hdiet.go76
1 files changed, 60 insertions, 16 deletions
diff --git a/hdiet.go b/hdiet.go
index d7261aa..7dc3560 100644
--- a/hdiet.go
+++ b/hdiet.go
@@ -102,14 +102,21 @@ type yRange struct {
max float64
}
-func process(file string) ([]point, error) {
+func readFile(file string) (map[time.Time]float64, time.Time, time.Time) {
+ optPanic := func(err error) {
+ if err != nil {
+ panic("process:" + err.Error())
+ }
+ }
weights, err := goutil.ReadFile(file)
if err != nil {
- return nil, err
+ return nil, time.Time{}, time.Time{}
}
lines := strings.Split(weights, "\n")
- trend := 0.0
- s := []point{}
+ var firstDay time.Time
+ firstDayIsSet := false
+ var lastDay time.Time
+ dateToWeight := make(map[time.Time]float64)
for _, line := range lines {
line = strings.TrimSpace(line)
if len(line) == 0 {
@@ -117,18 +124,58 @@ func process(file string) ([]point, error) {
}
splitline := strings.Split(line, "\t")
if len(splitline) < 2 {
- return nil, errors.New("process - invalid line in weight file: " + line)
+ optPanic(errors.New("invalid line in weight file " + file + ": " + line))
+ }
+ date, err := time.Parse(dateLayout, splitline[0])
+ optPanic(err)
+ weight, err := strconv.ParseFloat(splitline[1], 64)
+ optPanic(err)
+ if !firstDayIsSet {
+ firstDay = date
+ firstDayIsSet = true
+ }
+ lastDay = date
+ dateToWeight[date] = weight
+ }
+ return dateToWeight, firstDay, lastDay
+}
+
+func process(file string) []point {
+ dateToWeight, firstDay, lastDay := readFile(file)
+ if dateToWeight == nil {
+ return []point{}
+ }
+ trend := 0.0
+ points := []point{}
+ for d := firstDay; d.Before(lastDay) || d == lastDay; d = d.AddDate(0, 0, 1) {
+ var weight float64
+ if w, ok := dateToWeight[d]; ok {
+ weight = w
+ } else {
+ prevPoint := points[len(points)-1]
+ prevDay := prevPoint.date
+ prevWeight := prevPoint.weight
+ var nextWeight float64
+ var nextDay time.Time
+ for nextDay = d.AddDate(0, 0, 1); nextDay.Before(lastDay) || nextDay == lastDay; nextDay = nextDay.AddDate(0, 0, 1) {
+ if w, ok := dateToWeight[nextDay]; ok {
+ nextWeight = w
+ break
+ }
+ }
+ days := nextDay.Sub(prevDay).Hours() / 24
+ changePerDay := (nextWeight - prevWeight) / days
+ weight = prevWeight + changePerDay
}
- date, _ := time.Parse(dateLayout, splitline[0])
- weight, _ := strconv.ParseFloat(splitline[1], 64)
if trend == 0.0 {
trend = weight
} else {
trend = math.Floor((trend+0.1*(weight-trend))*100) / 100
}
- s = append(s, point{date, weight, trend})
+ points = append(points, point{d, weight, trend})
+
}
- return s, nil
+ return points
}
type showFlags struct {
@@ -138,11 +185,8 @@ type showFlags struct {
}
func show(args showFlags) error {
- points, err := process(logfile)
- if err != nil {
- return err
- }
- dietpoints, _ := process(dietfile)
+ points := process(logfile)
+ dietpoints := process(dietfile)
var to time.Time
var from time.Time
if args.to.date != nil {
@@ -170,7 +214,7 @@ func show(args showFlags) error {
YRange.min = math.Floor(YRange.min) - 1.0
YRange.max = math.Ceil(YRange.max) + 1.0
graph := graph(xticks(xRange), s1, s2, s3, YRange)
- err = writeGraphToFile(graph)
+ err := writeGraphToFile(graph)
if err != nil {
return err
}
@@ -194,7 +238,7 @@ func showCommand() (goutil.CommandFlagsInit, goutil.CommandFunc) {
func writeDietFile(from time.Time, initial float64, goal float64, change float64) error {
date := from
weight := initial
- s := "#Date\tTarget\n"
+ s := ""
s += fmt.Sprintf("%s\t%.1f\n", date.Format(dateLayout), weight)
for weight > goal {
date = date.AddDate(0, 0, 1)