-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Heart Rate Chart #247
base: main
Are you sure you want to change the base?
Heart Rate Chart #247
Conversation
src/components/container/IntradayHeartRateChart/IntradayHeartRateChart.tsx
Show resolved
Hide resolved
innerRef?: React.Ref<HTMLDivElement> | ||
} | ||
|
||
export default function MdhLineChart(props: LineChartProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely wouldnt' call this "LineChart" as that is far too vague of a name. I think we should make this at least somewhat opininated.
Putting aside whether it makes sense to combine this with @ajmenca 's PR, I would propose that this be called "IntradayLineChart" and be hardcoded to a 24 hour interval with the x-axis as I described and it could take data as data points in that interval...do not think it makes sense to make a generally reusable "line chart" as that is what recharts already gives us
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do agree LineChart is too vague.
What I do want to avoid is recreating the threshold interface and the display of it across components. We currently consume BarChartThreshold in vbuilder. Adding LineChartThreshold here is no help. Would be nice to have a simple ChartThreshold interface that is used across charts, along with not having to copy/paste the display of thresholds across components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will integrate the feedback around making it more opinionated and hang tight on the Threshold stuff
const xValues: any[] = data.map(d => d.date.getTime()); | ||
const xMax = Math.max(...xValues); | ||
const xMin = Math.min(...xValues); | ||
axis.xRange = [xMin, xMax]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Axis should be hardcoded
if (!props.axis || (props.axis && !props.axis.yRange)) { | ||
const yValues: number[] = data.map(d => d.value); | ||
const yMax = Math.max(...yValues); | ||
axis.yRange = [0, yMax]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious why you need to do this...I think just not supplying a domain will be sufficient
<ReferenceLine key={`threshref_${index}`} y={threshold.value} stroke={resolveColor(layoutContext.colorScheme, threshold.referenceLineColor)} /> | ||
)} | ||
<YAxis tick={YAxisTick} type='number' domain={axis?.yRange ?? [0,100]} /> | ||
<XAxis tick={XAxisTick} axisLine={true} dataKey="date" tickMargin={0} minTickGap={0} tickCount={24} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where I think you need to specify the "interval" to get the axis ticks to show up at 3/6/9 etc.
previewState?: IntradayHeartRatePreviewState, | ||
dataSource: DeviceDataV2Namespace, | ||
aggregationOption: AggregationOption, | ||
aggregationIntervalAmount: number, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's just call this "aggregationIntervalMinutes" and not have aggregationIntervalType...this is intraday so no need to complicate with extra params
@@ -0,0 +1,29 @@ | |||
import MyDataHelps, { Guid, DeviceDataV2AggregateQuery, DeviceDataV2AggregatePage, DeviceDataV2Aggregate } from "@careevolution/mydatahelps-js"; | |||
|
|||
export default async function (query: DeviceDataV2AggregateQuery): Promise<DeviceDataV2Aggregate[]> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this have to do with heart rate data - this seems like a general "queryAllDeviceDataV2" function more than anything to do with heart rates?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So seems like it would go in the same bucket as query all survey answers etc.
|
||
export default function IntradayHeartRateChart(props: IntradayHeartRateChartProps) { | ||
const [data, setData] = useState<LineChartDataPoint[]>([]); | ||
const [axis, setAxis] = useState<LineChartAxis>({ yRange: [0, 200], yIncrement: 30, xIncrement: props.aggregationIntervalAmount }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think yRange needs to be specified at all or yIncrement - in my branch it worked fine without having to specify these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The value of having some default x or y axis in place is so the chart renders when there is no data.
If nothing displays at all, the user may not be aware their device is is not connected. An empty chart could reinforce that the participant should connect their device
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we would want to mimic the "Daily data chart"'s no data state here which does not display a y-axis but does display the x-axis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something kind of strange - the line seems to fly in from the right as the animation? I think we'd want to use whatever animation the default DailyDataChart uses for instance (which I think kind of comes up from the bottom)... |
|
||
export interface IntradayHeartRateChartProps { | ||
previewState?: IntradayHeartRatePreviewState, | ||
dataSource: DeviceDataV2Namespace, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per the spec this should accept multiple, e.g. Apple Health AND Fitbit:
It should query data for all data sources specified as props; if there happens to be data for 2 data sources for an interval it should use the data source that is first in the array (e.g. Fitbit by default)
dataPoints = dataPoints.sort((a, b) => a.date.getTime() - b.date.getTime()); | ||
|
||
if (dataPoints.length){ | ||
let yValues: number[] = dataPoints.map(d => d.value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if you have a gap in the middle of the day e.g. where the user wasn't wearing their device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@chrisnowak The line will continue without breaks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right - my point is that is not the right behavior though, right? Since you need each heart rate data point to be represented at the time for the data point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is corrected, and a story is in place for showing the behavior (line break).
Broadly still a little confused...my branch seems like it was a good chunk of the way there on the presentation layer...seemed mostly like it just needed:
This seems to have gone off in a a bit of a different direction and doesn't quite match the spec or the example screenshot? |
Let's also figure out a way to get the line colors perfect - right now it obviously is a bit fuzzy - but the line should solidly change color when it is above the threshold...I can maybe help with that |
…, generate all times for being able to showcase nulls as line gaps
a99d985
to
cd3b167
Compare
This is now corrected when not using the date range navigator. When using the navigator the data will swing in from the same direction navigated to. |
@chrisnowak I've addressed most of the feedback, though getting the colors to sharply change at the threshold is still outstanding. Will work on that in next round of changes |
@chrisnowak The issue with line colors + incomplete data is fixed. |
@CodiumAI-Agent /review |
PR Review 🔍
Code feedback:
|
Overview
This line chart will display the heart rate data from Fitbit Heart Rate Intraday, or AppleHealth via the DeviceDataV2 endpoints.
Security
REMINDER: All file contents are public.
Describe briefly what security risks you considered, why they don't apply, or how they've been mitigated.
Checklist
Testing
Documentation
Consider "Squash and merge" as needed to keep the commit history reasonable on
main
.Reviewers
Assign to the appropriate reviewer(s). Minimally, a second set of eyes is needed ensure no non-public information is published. Consider also including: