From 444e20f5b1c8dda9e5728b42729c1e14623583d9 Mon Sep 17 00:00:00 2001 From: ryan Date: Tue, 4 Feb 2025 14:40:17 -0800 Subject: [PATCH] Touch up weight graph --- .../dashboard/analytics/AnalyticsView.tsx | 4 +- .../dashboard/analytics/Timeseries.tsx | 47 ++++++++++++++----- apps/web/package.json | 1 + pnpm-lock.yaml | 8 ++++ 4 files changed, 46 insertions(+), 14 deletions(-) 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