Commit 02be8f45 authored by Administrator's avatar Administrator

get more resilient against missing values

parent 2157e330
......@@ -82,42 +82,43 @@ class Lap {
}
static String averageHeartRate({List<Event> records}) {
var heartRates = records.map((record) => record.db.heartRate);
List<int> heartRates =
records.map((record) => record.db.heartRate).nonZero();
return heartRates.mean().toStringAsFixed(1);
}
static String sdevHeartRate({List<Event> records}) {
var heartRates = records.map((record) => record.db.heartRate);
var heartRates = records.map((record) => record.db.heartRate).nonZero();
return heartRates.sdev().toStringAsFixed(2);
}
static String minHeartRate({List<Event> records}) {
var heartRates = records.map((record) => record.db.heartRate);
var heartRates = records.map((record) => record.db.heartRate).nonZero();
return heartRates.min().toStringAsFixed(1);
}
static String maxHeartRate({List<Event> records}) {
var heartRates = records.map((record) => record.db.heartRate);
var heartRates = records.map((record) => record.db.heartRate).nonZero();
return heartRates.max().toStringAsFixed(1);
}
static String averagePower({List<Event> records}) {
var powers = records.map((record) => record.db.power);
var powers = records.map((record) => record.db.power).nonZero();
return powers.mean().toStringAsFixed(1);
}
static String sdevPower({List<Event> records}) {
var powers = records.map((record) => record.db.power);
var powers = records.map((record) => record.db.power).nonZero();
return powers.sdev().toStringAsFixed(2);
}
static String minPower({List<Event> records}) {
var powers = records.map((record) => record.db.power);
var powers = records.map((record) => record.db.power).nonZero();
return powers.min().toStringAsFixed(1);
}
static String maxPower({List<Event> records}) {
var powers = records.map((record) => record.db.power);
var powers = records.map((record) => record.db.power).nonZero();
return powers.max().toStringAsFixed(1);
}
}
import 'dart:math' as math;
extension StatisticFunctions on Iterable {
double mean() {
var nonZeroValues = this.nonZero();
var sum = nonZeroValues.reduce((a, b) => a + b);
var number = nonZeroValues.length;
double mean(){
List<int> values = this;
var sum = values.reduce((a, b) => a + b);
var number = this.length;
return sum / number;
}
double sdev() {
var nonZeroValues = this.nonZero();
var mean = nonZeroValues.mean();
var mean = this.toList().mean();
var sumOfErrorSquares = nonZeroValues.fold(
0.0, (double sum, next) => sum + math.pow(next - mean, 2));
var variance = sumOfErrorSquares / nonZeroValues.length;
var sumOfErrorSquares =
this.fold(0.0, (double sum, next) => sum + math.pow(next - mean, 2));
var variance = sumOfErrorSquares / this.length;
return math.sqrt(variance);
}
int min() {
return this.nonZero().reduce(math.min);
List<int> values = this.toList();
return values.reduce(math.min);
}
int max() {
return this.nonZero().reduce(math.max);
List<int> values = this.toList();
return values.reduce(math.max);
}
List<int> nonZero() {
......
......@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/models/lap.dart';
import 'package:encrateia/utils/list_utils.dart';
class ActivityHeartRateWidget extends StatelessWidget {
final Activity activity;
......@@ -14,41 +15,47 @@ class ActivityHeartRateWidget extends StatelessWidget {
future: Event.recordsByActivity(activity: activity),
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.deepOrange,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.pets),
title: Text(Lap.averageHeartRate(records: records)),
subtitle: Text("average heart rate"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minHeartRate(records: records)),
subtitle: Text("minimum heart rate"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxHeartRate(records: records)),
subtitle: Text("maximum heart rate"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevHeartRate(records: records)),
subtitle: Text("standard deviation heart rate"),
),
],
),
);
var heartRates = snapshot.data.map((value) => value.db.heartRate).nonZero();
if (heartRates.length > 0) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.deepOrange,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.pets),
title: Text(Lap.averageHeartRate(records: records)),
subtitle: Text("average heart rate"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minHeartRate(records: records)),
subtitle: Text("minimum heart rate"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxHeartRate(records: records)),
subtitle: Text("maximum heart rate"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevHeartRate(records: records)),
subtitle: Text("standard deviation heart rate"),
),
],
),
);
} else {
return Center(
child: Text("No heart rate data available."),
);
}
} else {
return Center(
child: Text("Loading"),
......
......@@ -59,8 +59,8 @@ class ActivityOverviewWidget extends StatelessWidget {
),
ListTile(
leading: Icon(Icons.pets),
title: Text("${(activity.db.avgRunningCadence * 2).round()} spm / "
"${activity.db.maxRunningCadence * 2} spm"),
title: Text("${(activity.db.avgRunningCadence ?? 0 * 2).round()} spm / "
"${activity.db.maxRunningCadence ?? 0 * 2} spm"),
subtitle: Text('avg / max steps per minute'),
),
ListTile(
......
......@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:encrateia/models/activity.dart';
import 'package:encrateia/models/lap.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/utils/list_utils.dart';
class ActivityPowerWidget extends StatelessWidget {
final Activity activity;
......@@ -14,41 +15,47 @@ class ActivityPowerWidget extends StatelessWidget {
future: Event.recordsByActivity(activity: activity),
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.deepOrange,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.ev_station),
title: Text(Lap.averagePower(records: records) + " W"),
subtitle: Text("average power"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minPower(records: records) + " W"),
subtitle: Text("minimum power"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxPower(records: records) + " W"),
subtitle: Text("maximum power"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevPower(records: records) + " W"),
subtitle: Text("standard deviation power"),
),
],
),
);
var powerValues = snapshot.data.map((value) => value.db.power).nonZero();
if (powerValues.length > 0) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.deepOrange,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.ev_station),
title: Text(Lap.averagePower(records: records) + " W"),
subtitle: Text("average power"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minPower(records: records) + " W"),
subtitle: Text("minimum power"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxPower(records: records) + " W"),
subtitle: Text("maximum power"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevPower(records: records) + " W"),
subtitle: Text("standard deviation power"),
),
],
),
);
} else {
return Center(
child: Text("No power data available."),
);
}
} else {
return Center(
child: Text("Loading"),
......
import 'package:flutter/material.dart';
import 'package:encrateia/models/lap.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/utils/list_utils.dart';
class LapHeartRateWidget extends StatelessWidget {
final Lap lap;
......@@ -13,41 +14,47 @@ class LapHeartRateWidget extends StatelessWidget {
future: Event.recordsByLap(lap: lap),
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.lightGreen,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.pets),
title: Text(Lap.averageHeartRate(records: records)),
subtitle: Text("average heart rate"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minHeartRate(records: records)),
subtitle: Text("minimum heart rate"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxHeartRate(records: records)),
subtitle: Text("maximum heart rate"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevHeartRate(records: records)),
subtitle: Text("standard deviation heart rate"),
),
],
),
);
var heartRates = snapshot.data.map((value) => value.db.heartRate).nonZero();
if (heartRates.length > 0) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.lightGreen,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.pets),
title: Text(Lap.averageHeartRate(records: records)),
subtitle: Text("average heart rate"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minHeartRate(records: records)),
subtitle: Text("minimum heart rate"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxHeartRate(records: records)),
subtitle: Text("maximum heart rate"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevHeartRate(records: records)),
subtitle: Text("standard deviation heart rate"),
),
],
),
);
} else {
return Center(
child: Text("No heart rate data available."),
);
}
} else {
return Center(
child: Text("Loading"),
......
......@@ -51,8 +51,8 @@ class LapOverviewWidget extends StatelessWidget {
),
ListTile(
leading: Icon(Icons.pets),
title: Text("${(lap.db.avgRunningCadence * 2).round()} spm / "
"${lap.db.maxRunningCadence * 2} spm"),
title: Text("${(lap.db.avgRunningCadence ?? 0 * 2).round()} spm / "
"${lap.db.maxRunningCadence ?? 0 * 2} spm"),
subtitle: Text('avg / max steps per minute'),
),
ListTile(
......
import 'package:flutter/material.dart';
import 'package:encrateia/models/lap.dart';
import 'package:encrateia/models/event.dart';
import 'package:encrateia/utils/list_utils.dart';
class LapPowerWidget extends StatelessWidget {
final Lap lap;
......@@ -13,41 +14,47 @@ class LapPowerWidget extends StatelessWidget {
future: Event.recordsByLap(lap: lap),
builder: (BuildContext context, AsyncSnapshot<List<Event>> snapshot) {
if (snapshot.hasData) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.lightGreen,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.ev_station),
title: Text(Lap.averagePower(records: records) + " W"),
subtitle: Text("average power"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minPower(records: records) + " W"),
subtitle: Text("minimum power"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxPower(records: records) + " W"),
subtitle: Text("maximum power"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevPower(records: records) + " W"),
subtitle: Text("standard deviation power"),
),
],
),
);
var powerValues = snapshot.data.map((value) => value.db.power).nonZero();
if (powerValues.length > 0) {
var records = snapshot.data;
return ListTileTheme(
iconColor: Colors.lightGreen,
child: ListView(
padding: EdgeInsets.only(left: 25),
children: <Widget>[
ListTile(
leading: Icon(Icons.playlist_add),
title: Text(records.length.toString()),
subtitle: Text("number of measurements"),
),
ListTile(
leading: Icon(Icons.ev_station),
title: Text(Lap.averagePower(records: records) + " W"),
subtitle: Text("average power"),
),
ListTile(
leading: Icon(Icons.expand_more),
title: Text(Lap.minPower(records: records) + " W"),
subtitle: Text("minimum power"),
),
ListTile(
leading: Icon(Icons.expand_less),
title: Text(Lap.maxPower(records: records) + " W"),
subtitle: Text("maximum power"),
),
ListTile(
leading: Icon(Icons.unfold_more),
title: Text(Lap.sdevPower(records: records) + " W"),
subtitle: Text("standard deviation power"),
),
],
),
);
} else {
return Center(
child: Text("No power data available."),
);
}
} else {
return Center(
child: Text("Loading"),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment