aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/components/LineChart.tsx
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-03-10 09:48:15 -0400
committerbobzel <zzzman@gmail.com>2024-03-10 09:48:15 -0400
commit36d18da80e5e5e1c6cae0dc21c1677a7ab9c1d77 (patch)
tree69dae37de1312ff8704e661a8e9dda98da30346a /src/client/views/nodes/DataVizBox/components/LineChart.tsx
parent2279f029ce19c9f7f886a6966ea5f23be9468890 (diff)
parenta9eb266296d1b71f1016c867f39e20299c011eea (diff)
Merge branch 'master' into eleanor-starter
Diffstat (limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')
-rw-r--r--src/client/views/nodes/DataVizBox/components/LineChart.tsx90
1 files changed, 72 insertions, 18 deletions
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 2a9a8b354..e093ec648 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -28,6 +28,7 @@ export interface LineChartProps {
Document: Doc;
layoutDoc: Doc;
axes: string[];
+ titleCol: string;
records: { [key: string]: any }[];
width: number;
height: number;
@@ -46,7 +47,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
private _disposers: { [key: string]: IReactionDisposer } = {};
private _lineChartRef: React.RefObject<HTMLDivElement> = React.createRef();
private _lineChartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
- @observable _currSelected: SelectedDataPoint | undefined = undefined;
+ @observable _currSelected: any | undefined = undefined;
// TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
constructor(props: any) {
super(props);
@@ -235,21 +236,16 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
}
}
- // TODO: nda - can use d3.create() to create html element instead of appending
drawChart = (dataSet: any[][], rangeVals: { xMin?: number; xMax?: number; yMin?: number; yMax?: number }, width: number, height: number) => {
// clearing tooltip and the current chart
d3.select(this._lineChartRef.current).select('svg').remove();
d3.select(this._lineChartRef.current).select('.tooltip').remove();
- const { xMin, xMax, yMin, yMax } = rangeVals;
+ var { xMin, xMax, yMin, yMax } = rangeVals;
if (xMin === undefined || xMax === undefined || yMin === undefined || yMax === undefined) {
return;
}
- // creating the x and y scales
- const xScale = scaleCreatorNumerical(xMin, xMax, 0, width);
- const yScale = scaleCreatorNumerical(0, yMax, height, 0);
-
// adding svg
const margin = this._props.margin;
const svg = (this._lineChartSvg = d3
@@ -261,24 +257,71 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`));
+ var validSecondData;
+ if (this._props.axes.length>2){ // for when there are 2 lines on the chart
+ var next = this._tableData.map(record => ({ x: Number(record[this._props.axes[0]]), y: Number(record[this._props.axes[2]]) })).sort((a, b) => (a.x < b.x ? -1 : 1));
+ validSecondData = next.filter(d => {
+ if (!d.x || Number.isNaN(d.x) || !d.y || Number.isNaN(d.y)) return false;
+ return true;
+ });
+ var secondDataRange = minMaxRange([validSecondData]);
+ if (secondDataRange.xMax!>xMax) xMax = secondDataRange.xMax;
+ if (secondDataRange.yMax!>yMax) yMax = secondDataRange.yMax;
+ if (secondDataRange.xMin!<xMin) xMin = secondDataRange.xMin;
+ if (secondDataRange.yMin!<yMin) yMin = secondDataRange.yMin;
+ }
+
+ // creating the x and y scales
+ const xScale = scaleCreatorNumerical(xMin!, xMax!, 0, width);
+ const yScale = scaleCreatorNumerical(0, yMax!, height, 0);
+ const lineGen = createLineGenerator(xScale, yScale);
+
// create x and y grids
xGrid(svg.append('g'), height, xScale);
yGrid(svg.append('g'), width, yScale);
xAxisCreator(svg.append('g'), height, xScale);
yAxisCreator(svg.append('g'), width, yScale);
+ if (validSecondData) {
+ drawLine(svg.append('path'), validSecondData, lineGen, true);
+ this.drawDataPoints(validSecondData, 0, xScale, yScale);
+ svg.append('path').attr("stroke", "red");
+
+ // legend
+ var color = d3.scaleOrdinal()
+ .range(["black", "blue"])
+ .domain([this._props.axes[1], this._props.axes[2]])
+ svg.selectAll("mydots")
+ .data([this._props.axes[1], this._props.axes[2]])
+ .enter()
+ .append("circle")
+ .attr("cx", 5)
+ .attr("cy", function(d,i){ return -30 + i*15})
+ .attr("r", 7)
+ .style("fill", function(d){ return color(d)})
+ svg.selectAll("mylabels")
+ .data([this._props.axes[1], this._props.axes[2]])
+ .enter()
+ .append("text")
+ .attr("x", 25)
+ .attr("y", function(d,i){ return -30 + i*15})
+ .style("fill", function(d){ return color(d)})
+ .text(function(d){ return d})
+ .attr("text-anchor", "left")
+ .style("alignment-baseline", "middle")
+ }
+
// get valid data points
const data = dataSet[0];
- const lineGen = createLineGenerator(xScale, yScale);
var validData = data.filter(d => {
- var valid = true;
Object.keys(data[0]).map(key => {
- if (!d[key] || Number.isNaN(d[key])) valid = false;
+ if (!d[key] || Number.isNaN(d[key])) return false;
});
- return valid;
+ return true;
});
+
// draw the plot line
- drawLine(svg.append('path'), validData, lineGen);
+ drawLine(svg.append('path'), validData, lineGen, false);
// draw the datapoint circle
this.drawDataPoints(validData, 0, xScale, yScale);
@@ -291,7 +334,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
const xPos = d3.pointer(e)[0];
const x0 = Math.min(data.length - 1, bisect(data, xScale.invert(xPos - 5))); // shift x by -5 so that you can reach points on the left-side axis
const d0 = data[x0];
- if (!d0) return;
+ if (d0) this.updateTooltip(higlightFocusPt, xScale, d0, yScale, tooltip);
this.updateTooltip(higlightFocusPt, xScale, d0, yScale, tooltip);
});
@@ -327,7 +370,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
svg.append('text')
.attr('transform', 'rotate(-90)' + ' ' + 'translate( 0, ' + -10 + ')')
.attr('x', -(height / 2))
- .attr('y', -20)
+ .attr('y', -30)
.attr('height', 20)
.attr('width', 20)
.style('text-anchor', 'middle')
@@ -351,11 +394,22 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
}
render() {
- var titleAccessor: any = '';
- if (this._props.axes.length == 2) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0] + '-' + this._props.axes[1];
- else if (this._props.axes.length > 0) titleAccessor = 'dataViz_lineChart_title' + this._props.axes[0];
+ var titleAccessor: any = 'dataViz_lineChart_title';
+ if (this._props.axes.length == 2) titleAccessor = titleAccessor + this._props.axes[0] + '-' + this._props.axes[1];
+ else if (this._props.axes.length > 0) titleAccessor = titleAccessor + this._props.axes[0];
if (!this._props.layoutDoc[titleAccessor]) this._props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none';
+ var selectedTitle = "";
+ if (this._currSelected && this._props.titleCol){
+ selectedTitle+= "\n" + this._props.titleCol + ": "
+ this._tableData.forEach(each => {
+ var mapThisEntry = false;
+ if (this._currSelected.x==each[this._props.axes[0]] && this._currSelected.y==each[this._props.axes[1]]) mapThisEntry = true;
+ else if (this._currSelected.y==each[this._props.axes[0]] && this._currSelected.x==each[this._props.axes[1]]) mapThisEntry = true;
+ if (mapThisEntry) selectedTitle += each[this._props.titleCol] + ", ";
+ })
+ selectedTitle = selectedTitle.slice(0,-1).slice(0,-1);
+ }
if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) {
return this._props.axes.length >= 2 && /\d/.test(this._props.records[0][this._props.axes[0]]) && /\d/.test(this._props.records[0][this._props.axes[1]]) ? (
<div className="chart-container" style={{ width: this._props.width + this._props.margin.right }}>
@@ -375,9 +429,9 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
{selectedPt != 'none' ? (
<div className={'selected-data'}>
{`Selected: ${selectedPt}`}
+ {`${selectedTitle}`}
<Button
onClick={e => {
- console.log('test plzz');
this._props.vizBox.sidebarBtnDown;
this._props.vizBox.sidebarAddDocument;
}}></Button>