-
Notifications
You must be signed in to change notification settings - Fork 29
Add D3.js time axis to generic-xy-view with sampling data #363
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
base: master
Are you sure you want to change the base?
Conversation
1e339d5 to
3f37ad8
Compare
| axis = d3.axisBottom(scale).ticks(5).tickSizeInner(-parseInt(String(this.props.style.height)) + this.margin.top + this.margin.bottom) | ||
| .tickFormat((d) => { | ||
| const date = d instanceof Date ? d : new Date(d as number); | ||
| const rangeIndex = Math.floor((date.getTime() - domain[0].getTime()) / (domain[1].getTime() - domain[0].getTime()) * (sampling.length - 1)); |
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.
Change to add ticks on edges, not on centers.
| axis = d3.axisBottom(scale).ticks(5).tickSizeInner(-parseInt(String(this.props.style.height)) + this.margin.top + this.margin.bottom); | ||
| } else if (isRangeSampling(sampling)) { | ||
| const timestamps = sampling.map(range => Number(range.start) / 1000000); | ||
| console.log('Raw timestamps (ms):', timestamps.slice(0, 3)); |
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.
remove all logs.
| const dates = timestamps.map(ts => new Date(ts)); | ||
| console.log('Converted dates:', dates.slice(0, 3)); | ||
| const domain = d3.extent(dates) as [Date, Date]; | ||
| console.log('Domain:', domain); |
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.
remove
| const timestamps = sampling.map(range => Number(range.start) / 1000000); | ||
| console.log('Raw timestamps (ms):', timestamps.slice(0, 3)); | ||
| const dates = timestamps.map(ts => new Date(ts)); | ||
| console.log('Converted dates:', dates.slice(0, 3)); |
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.
remove
3f37ad8 to
e100b54
Compare
| let axis: d3.Axis<any>; | ||
|
|
||
| if (isTimestampSampling(sampling)) { | ||
| const domain = d3.extent(sampling.map(ts => new Date(Number(ts) / 1000000))) as [Date, Date]; |
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.
maybe extract...
| allTicks.forEach(tick => { | ||
| const tickPos = (scale as any)(tick) as number; | ||
| const canAdd = majorTicks.length === 0 || | ||
| Math.abs(tickPos - ((scale as any)(majorTicks[majorTicks.length - 1]) as number)) >= 100; |
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.
definitely extract.
This makes sense, I will try it out. One issue. Let's say that we have as an example: Month-day as buckets so we have January-Monday, January-Tuesday, etc... And we have 1000 categories on a 1920 pixel wide axis, even ... will fail. I will make it do ... when it can, and nothing when it cannot, is this OK with you? |
Yes, sounds good. I think that's the best we can do. |
1c5f7f9 to
0f6a98f
Compare
bhufmann
left a comment
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'm not able to test it because the Function Duration Density view is not rendering the x-axis. So, I just comment based on what the code.
| formatX?: (x: number | bigint | string) => string; | ||
| formatY?: (y: number) => string; | ||
| stacked?: boolean; | ||
| timelineUnit?: string; |
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.
Those are never set in any of the existing code (nor the above). Nor the other ones of the props.
| cursor: 'default', | ||
| showTree: true | ||
| showTree: true, | ||
| timelineUnit: this.props.timelineUnit || 'ms', |
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 state for timelineUnit is never updated because it's never passed as props nor the unit is taken from the x-axis description of the xy-query, see here for the axis description definition: https://github.com/eclipse-cdt-cloud/trace-server-protocol/blob/72af35675446ed5da6acbe1bc8175ad7e8769166/API.yaml#L2688
| showTree: true | ||
| showTree: true, | ||
| timelineUnit: this.props.timelineUnit || 'ms', | ||
| timelineUnitType: this.props.timelineUnitType || 'time' |
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 state timeline unit type is never set otherwise since it's never passed to the props. I think what you mean hear is the data type that is part of the x-axis description: https://github.com/eclipse-cdt-cloud/trace-server-protocol/blob/72af35675446ed5da6acbe1bc8175ad7e8769166/API.yaml#L2688
| } | ||
|
|
||
| private renderTimeline(): React.ReactNode { | ||
| if (this.state.timelineUnitType === 'time' && !this.isTimeAxis) return <svg/>; |
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 timelineUnitType is always 'time', even for ranges as x-axis or categories a x-axis. For ranges or categories it will return here because for those xy series this.isTimeAxis is false.
|
|
||
| private updateTimeline(): void { | ||
| if (!this.timelineRef.current) return; | ||
| if (this.state.timelineUnitType === 'time' && !this.isTimeAxis) return; |
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 timelineUnitType is always 'time', even for ranges as x-axis or categories a x-axis. For ranges or categories it will return here because for those xy series this.isTimeAxis is false.
| } | ||
|
|
||
| private getTimelineRange(): { start: number; end: number } { | ||
| switch (this.state.timelineUnitType) { |
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 what you intended was to use the data type of the axis description. See here for the supported data types:
https://github.com/eclipse-cdt-cloud/trace-server-protocol/blob/72af35675446ed5da6acbe1bc8175ad7e8769166/API.yaml#L2688
In your switch-case statement you are using non-specified values. The would need to be added to the TSP or removed here for now.
| } | ||
|
|
||
| private formatDataRate(rate: number): string { | ||
| const units = ['B/s', 'KB/s', 'MB/s', 'GB/s']; |
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.
Those format methods should be in a central utility. I think we have already some code somewhere that is related. Check if we can unify those in a common utility.
| case 'bytes/sec': | ||
| case 'iterations/sec': | ||
| // For non-time units, use the data range | ||
| const labels = this.state.xyData.labels; |
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 labels are strings and not actual numbers. I think it will fail for the case that the x-values are ranges or categories. It those case the labels are formatted, for example for ranges:
[${range.start} ${unit}, ${range.end} ${unit}].
| timelineUnitType: TimelineUnitType; | ||
| } | ||
|
|
||
| type TimelineUnitType = 'time' | 'cycles' | 'bytes' | 'calls' | 'bytes/sec' | 'iterations/sec'; |
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.
They should be aligned with the data type of the x-axis: https://github.com/eclipse-cdt-cloud/trace-server-protocol/blob/72af35675446ed5da6acbe1bc8175ad7e8769166/API.yaml#L2688. If some are missing then need to add them in the TSP and in the backend
|
@MatthewKhouzam @siwei-zhang-work @PatrickTasse Reminder that due to eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator#236, to use latest Trace Compass trace server and vscode-trace-extension for testing. |
ba893ea to
db92a31
Compare
| } from 'tsp-typescript-client/lib/models/sampling'; | ||
| import { signalManager } from 'traceviewer-base/lib/signals/signal-manager'; | ||
| import { EntryTree } from './utils/filter-tree/entry-tree'; | ||
| import { TimeRange } from 'traceviewer-base/src/utils/time-range'; |
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 line is incorrect and causes the build to fail. It should reference the lib directory and not the src directory.
d03ba61 to
2faa6db
Compare
- Add configurable timeline bar below XY charts with D3.js - Support multiple unit types: time, cycles, bytes, calls, data rates - Include automatic unit formatting (bytes/KB/MB/GB, rates) - Add timeline props: timelineUnit and timelineUnitType - Update timeline on chart resize and data changes Note: this patch was made with the assistance of claude-sonnet-4 Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
2faa6db to
1f9cee7
Compare
bhufmann
left a comment
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 recent changes work well with the Function Duration Density of the Trace Compass server where the x-values are duration ranges and the buckets are evenly distributed over the full range of all buckets. However, for other cases where the buckets are not evenly distributed, the x-axis not correct.
Please let me know if you'd like to merge this PR as is and then add another PR where the x-axis is handling the second case above?
|
Let's merge and fix for the other. Upon inspection, I think the axis is correct, not the chart. I will confirm. |

What it does
Add an x axis for density views.
How to test
Open a function density view.
Follow-ups
Review checklist