diff --git a/apps/web/components/dashboard/analytics/AnalyticsView.tsx b/apps/web/components/dashboard/analytics/AnalyticsView.tsx
index b9130c8..1fafab7 100644
--- a/apps/web/components/dashboard/analytics/AnalyticsView.tsx
+++ b/apps/web/components/dashboard/analytics/AnalyticsView.tsx
@@ -57,7 +57,7 @@ export default function AnalyticsView() {
const [dateRange, setDateRange] = useState(initialDateRange);
const [datePickerRange, setDatePickerRange] = useState(initialDateRange);
- const [hideSleep, setHideSleep] = useState(true);
+ const [hideSleep, setHideSleep] = useState(false);
useEffect(() => {
if (datePickerRef.current?.getAttribute("aria-expanded") === "false") {
@@ -260,7 +260,7 @@ export default function AnalyticsView() {
{
weightData.length === 0 ? :
-
+
}
diff --git a/apps/web/components/dashboard/analytics/Timeseries.tsx b/apps/web/components/dashboard/analytics/Timeseries.tsx
index f7e15f3..9412b1b 100644
--- a/apps/web/components/dashboard/analytics/Timeseries.tsx
+++ b/apps/web/components/dashboard/analytics/Timeseries.tsx
@@ -3,10 +3,17 @@ import { LineChart, Line, YAxis, XAxis, CartesianGrid, Tooltip, Area, Label } fr
import spacetime from 'spacetime';
import regression from 'regression';
-function polynomialTrendline(data, degree) {
+interface DataPoint {
+ id: string; // measurement.id
+ datetime: Date;
+ value: number;
+ unit: string;
+};
+
+function polynomialTrendline(data: DataPoint[], degree: number) {
// Map your data to the form required by regression-js: [x, y]
// Here we convert datetime to a numeric value (e.g., milliseconds since epoch)
- const regressionData = data.map((dp, i) => [i, dp.value]);
+ const regressionData = data.map((dp, i) => [i, dp.value]) as [number, number][];
const result = regression.polynomial(regressionData, { order: degree });
// result.equation contains the polynomial coefficients,
@@ -14,11 +21,24 @@ function polynomialTrendline(data, degree) {
return result;
}
-function formatXAxis(tickItem) {
- return spacetime(tickItem).format('{date}');
+function formatXAxis(tickItem: [number, number]) {
+ const month = spacetime(tickItem).format('{month-short}');
+ if (spacetime(tickItem).day() === 1) {
+ return spacetime(tickItem).format('{month-short} {date}');
+ } else {
+ return spacetime(tickItem).format('{date}');
+ }
}
-export default function TimeseriesChart({ data }) {
+function yAxisTicks(data: DataPoint[]) {
+ const bounds = data.map(dp => Math.round(dp.value)).sort().filter((_v, i, a) => i === 0 || i === a.length - 1);
+ const lowerBound = bounds[0] - (bounds[0] % 2);
+ const upperBound = bounds[1] + (2 - bounds[1] % 2);
+ // Create an array of ticks from lowerBound to upperBound in increments of 2
+ return Array.from({ length: (upperBound - lowerBound) / 2 + 1 }, (_, i) => lowerBound + 2 * i);
+}
+
+export default function TimeseriesChart({ data, timeseriesName }: { data: DataPoint[], timeseriesName: string }) {
const unit = data[0] ? data[0].unit : '';
const polyResult = polynomialTrendline(data, 1)// 2 for quadratic
@@ -33,17 +53,20 @@ export default function TimeseriesChart({ data }) {
return (
- Trend: {7 * polyResult.equation[0]} {unit}/week
+ Trend: {(7 * polyResult.equation[0]).toFixed(1)} {unit}/week
-
+
`${spacetime(d).format("{month-short} {date}")}`}
- labelStyle={{ color: 'black' }}
+ labelFormatter={(d) => `${spacetime(d).format("{month-short} {date}, {hour}{ampm}")}`}
+ labelStyle={{ color: 'white' }}
+ formatter={(value, name, props) => [value, name === 'smoothed' ? 'Trend' : timeseriesName]}
+ contentStyle={{ backgroundColor: 'hsl(var(--border))', color: 'black' }}
/>
-
-
+
+ i === 0 || i === yAxisTicks(data).length - 1)}
+ allowDecimals={false}
+ ticks={yAxisTicks(data)} />
0 ? "red" : "green"} dot={false} />
diff --git a/apps/web/package.json b/apps/web/package.json
index 383b8e8..48eebf0 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -116,6 +116,7 @@
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"@types/react-syntax-highlighter": "^15.5.13",
+ "@types/regression": "^2.0.6",
"@types/request-ip": "^0.0.41",
"autoprefixer": "^10.4.17",
"postcss": "^8.4.35",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ce07116..4c97058 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -452,6 +452,9 @@ importers:
'@types/react-syntax-highlighter':
specifier: ^15.5.13
version: 15.5.13
+ '@types/regression':
+ specifier: ^2.0.6
+ version: 2.0.6
'@types/request-ip':
specifier: ^0.0.41
version: 0.0.41
@@ -4464,6 +4467,9 @@ packages:
'@types/react@18.2.61':
resolution: {integrity: sha512-NURTN0qNnJa7O/k4XUkEW2yfygA+NxS0V5h1+kp9jPwhzZy95q3ADoGMP0+JypMhrZBTTgjKAUlTctde1zzeQA==}
+ '@types/regression@2.0.6':
+ resolution: {integrity: sha512-sa+sHOUxh9fywFuAFLCcyupFN0CKX654QUZGW5fAZCmV51I4e5nQy1xL2g/JMUW/PeDoF3Yq2lDXb7MoC3KDNg==}
+
'@types/request-ip@0.0.41':
resolution: {integrity: sha512-Qzz0PM2nSZej4lsLzzNfADIORZhhxO7PED0fXpg4FjXiHuJ/lMyUg+YFF5q8x9HPZH3Gl6N+NOM8QZjItNgGKg==}
@@ -18248,6 +18254,8 @@ snapshots:
'@types/scheduler': 0.16.3
csstype: 3.1.2
+ '@types/regression@2.0.6': {}
+
'@types/request-ip@0.0.41':
dependencies:
'@types/node': 20.11.24