From a5294e6ba7fcf82eb3d22c0c187ce351ee698ce5 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 6 Jul 2023 14:19:55 -0400
Subject: basic histogram

---
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 6b564b0c9..289cecb6b 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -20,7 +20,7 @@ export interface DataPoint {
     x: number;
     y: number;
 }
-interface SelectedDataPoint extends DataPoint {
+export interface SelectedDataPoint extends DataPoint {
     elem?: d3.Selection<d3.BaseType, unknown, SVGGElement, unknown>;
 }
 export interface LineChartProps {
@@ -60,6 +60,8 @@ export class LineChart extends React.Component<LineChartProps> {
             .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
     @computed get incomingSelected() {
+        // return selected x and y axes
+        // otherwise, use the selection of whatever is linked to us
         return this.incomingLinks // all links that are pointing to this node
             .map(anchor => DocumentManager.Instance.getFirstDocumentView(anchor)?.ComponentView as DataVizBox) // get their data viz boxes
             .filter(dvb => dvb)
-- 
cgit v1.2.3-70-g09d2


From 9418db69bad9e6cc862ccccb95e04d9a9430c283 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Sun, 9 Jul 2023 12:28:51 -0400
Subject: chart axis labels

---
 src/client/views/nodes/DataVizBox/components/Chart.scss   |  5 +++++
 .../views/nodes/DataVizBox/components/Histogram.tsx       | 15 +++++++++++++--
 .../views/nodes/DataVizBox/components/LineChart.tsx       | 15 +++++++++++++++
 3 files changed, 33 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index d4f7bfb32..05bb1655d 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -3,6 +3,11 @@
     flex-direction: column;
     align-items: center;
     cursor: default;
+    margin-top: 10px;
+
+    .graph{
+        overflow: visible;
+    }
 
     .tooltip {
         // make the height width bigger
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index cb0b8cd9a..1da803076 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -244,10 +244,10 @@ export class Histogram extends React.Component<HistogramProps> {
         let uniqueArr = [...new Set(data)]
         var numBins = uniqueArr.length
         if (+d3.max(data)!) numBins = +d3.max(data)!
-        // var numBins = (+d3.max(data)!)? +d3.max(data)!  : 3;
 
         const svg = d3.select(this._histogramRef.current)
             .append("svg")
+                .attr("class", "graph")
                 .attr("width", width + this.props.margin.right + this.props.margin.left)
                 .attr("height", height + this.props.margin.top + this.props.margin.bottom)
             .append("g")
@@ -297,6 +297,18 @@ export class Histogram extends React.Component<HistogramProps> {
             .attr("transform", "translate(" + translateXAxis + ", " + height + ")")
             .call(xAxis)
 
+        // axis titles
+        svg.append("text")
+            .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")")
+            .style("text-anchor", "middle")
+            .text(field);
+        svg.append("text")
+            .attr("transform", "rotate(-90)")
+            .attr("x", -(height/2))
+            .attr("y", -20)
+            .style("text-anchor", "middle")
+            .text('frequency');
+
         d3.format('.0f')
 
         svg.selectAll("rect")
@@ -305,7 +317,6 @@ export class Histogram extends React.Component<HistogramProps> {
             .append("rect")
               .attr("x", 1)
               .attr("transform", function(d) { return "translate(" + x(d.x0! - 1) + "," + y(d.length) + ")"; })
-            //   .attr("width", function(d) { return x(d.x1!) - x(d.x0! )  ; })
               .attr("width", width/(numBins))
               .attr("height", function(d) { return height - y(d.length); })
               .attr("style", "outline: thin solid black;")
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 289cecb6b..b1a759c1f 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -240,6 +240,7 @@ export class LineChart extends React.Component<LineChartProps> {
         const svg = (this._lineChartSvg = d3
             .select(this._lineChartRef.current)
             .append('svg')
+            .attr("class", "graph")
             .attr('width', `${width + margin.left + margin.right}`)
             .attr('height', `${height + margin.top + margin.bottom}`)
             .append('g')
@@ -295,6 +296,20 @@ export class LineChart extends React.Component<LineChartProps> {
             .on('mouseout', () => tooltip.transition().duration(300).style('opacity', 0))
             .on('mousemove', mousemove)
             .on('click', onPointClick);
+
+        // axis titles
+        svg.append("text")
+            .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")")
+            .style("text-anchor", "middle")
+            .text(this.props.axes[0]);
+        svg.append("text")
+            .attr("transform", "rotate(-90)")
+            .attr("x", -(height/2))
+            .attr("y", -20)
+            .attr("height", 20)
+            .attr("width", 20)
+            .style("text-anchor", "middle")
+            .text(this.props.axes[1]);
     };
 
     private updateTooltip(
-- 
cgit v1.2.3-70-g09d2


From 144375b1b8b3fb8119997a9c691b501cfae39826 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 11 Jul 2023 13:07:10 -0400
Subject: drawing line chart fix

---
 .../views/nodes/DataVizBox/components/LineChart.tsx       | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index b1a759c1f..d87f5ae1b 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -252,13 +252,20 @@ export class LineChart extends React.Component<LineChartProps> {
         xAxisCreator(svg.append('g'), height, xScale);
         yAxisCreator(svg.append('g'), width, yScale);
 
-        // draw the plot line
+        // get valid data points
         const data = dataSet[0];
         const lineGen = createLineGenerator(xScale, yScale);
-        drawLine(svg.append('path'), data, lineGen);
-
+        var validData = data.filter((d => {
+            var valid = true;
+            Object.keys(data[0]).map(key => {
+                if (!d[key] || Number.isNaN(d[key])) valid = false;
+            })
+            return valid;
+        }))
+        // draw the plot line
+        drawLine(svg.append('path'), validData, lineGen);
         // draw the datapoint circle
-        this.drawDataPoints(data, 0, xScale, yScale);
+        this.drawDataPoints(validData, 0, xScale, yScale);
 
         const higlightFocusPt = svg.append('g').style('display', 'none');
         higlightFocusPt.append('circle').attr('r', 5).attr('class', 'circle');
-- 
cgit v1.2.3-70-g09d2


From c5740deae879fffdc46a862b81be2c96ae9366b4 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Wed, 12 Jul 2023 17:28:20 -0400
Subject: graph type option ui + problem fixes

---
 src/client/views/nodes/DataVizBox/DataVizBox.scss          | 5 +++++
 src/client/views/nodes/DataVizBox/DataVizBox.tsx           | 8 ++++----
 src/client/views/nodes/DataVizBox/components/Histogram.tsx | 2 +-
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 2 +-
 src/client/views/nodes/DataVizBox/components/PieChart.tsx  | 2 +-
 5 files changed, 12 insertions(+), 7 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index cd500e9ae..424f8b0f1 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -1,4 +1,9 @@
 .dataviz {
     overflow: auto;
     height: 100%;
+
+    .datatype-button{
+        margin: 0;
+        border: 1px solid white;
+    }
 }
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 2a0f6c17d..e6d08d47f 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -150,10 +150,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     )
                 }>
                 {/* <button onClick={e => this.changeViewHandler(e)}>{this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE}</button> */}
-                <button onClick={e => this.layoutDoc._dataVizView = DataVizView.TABLE}> TABLE </button>
-                <button onClick={e => this.layoutDoc._dataVizView = DataVizView.LINECHART}> LINE CHART </button>
-                <button onClick={e => this.layoutDoc._dataVizView = DataVizView.HISTOGRAM}> HISTOGRAM </button>
-                <button onClick={e => this.layoutDoc._dataVizView = DataVizView.PIECHART}> PIE CHART </button>
+                <button className={'datatype-button'} style={{background: this.layoutDoc._dataVizView == DataVizView.TABLE? 'grey': 'black'}} onClick={e => this.layoutDoc._dataVizView = DataVizView.TABLE}> TABLE </button>
+                <button className={'datatype-button'} style={{background: this.layoutDoc._dataVizView == DataVizView.LINECHART? 'grey': 'black'}} onClick={e => this.layoutDoc._dataVizView = DataVizView.LINECHART}> LINE CHART </button>
+                <button className={'datatype-button'} style={{background: this.layoutDoc._dataVizView == DataVizView.HISTOGRAM? 'grey': 'black'}} onClick={e => this.layoutDoc._dataVizView = DataVizView.HISTOGRAM}> HISTOGRAM </button>
+                <button className={'datatype-button'} style={{background: this.layoutDoc._dataVizView == DataVizView.PIECHART? 'grey': 'black'}} onClick={e => this.layoutDoc._dataVizView = DataVizView.PIECHART}> PIE CHART </button>
                 {this.selectView}
             </div>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index e4267aee3..0ea492ff1 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -305,7 +305,7 @@ export class Histogram extends React.Component<HistogramProps> {
             bins.forEach(d => d.x0 = d.x0!)
             xAxis = d3.axisBottom(x)
                 .ticks(numBins-1)
-                .tickFormat( i => uniqueArr[i])
+                .tickFormat( i => uniqueArr[i.valueOf])
                 .tickPadding(10)
             translateXAxis = eachRectWidth / 2;
         }
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index d87f5ae1b..dfb9f54c1 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -221,7 +221,7 @@ export class LineChart extends React.Component<LineChartProps> {
     }
 
     // TODO: nda - can use d3.create() to create html element instead of appending
-    drawChart = (dataSet: DataPoint[][], rangeVals: { xMin?: number; xMax?: number; yMin?: number; yMax?: number }, width: number, height: number) => {
+    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();
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index c746e6fc1..121e6db3d 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -272,7 +272,7 @@ export class PieChart extends React.Component<PieChartProps> {
             })
             .attr("d", arc);
         arcs.append("text")
-            .attr("transform",function(d){ return "translate("+ (arc.centroid(d))  + ")"; })
+            .attr("transform",function(d){ return "translate("+ (arc.centroid(d as unknown as d3.DefaultArcObject))  + ")"; })
             .attr("text-anchor", "middle")
             .text(function(d){ return dataSet[data.indexOf(d.value)][percentField] + ' ' + dataSet[data.indexOf(d.value)][descriptionField]})
 
-- 
cgit v1.2.3-70-g09d2


From 51718316b592e86c0009b7a27e1e32ba74d2488b Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 18 Jul 2023 13:22:04 -0400
Subject: click to select for pie charts + some histograms

---
 src/client/views/nodes/DataVizBox/DataVizBox.scss  |  2 +-
 .../views/nodes/DataVizBox/components/Chart.scss   |  4 +++
 .../nodes/DataVizBox/components/Histogram.tsx      | 39 +++++++++++++++++++---
 .../nodes/DataVizBox/components/LineChart.tsx      |  2 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx | 32 ++++++++++++++----
 5 files changed, 65 insertions(+), 14 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index 424f8b0f1..b3cbc89aa 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -1,5 +1,5 @@
 .dataviz {
-    overflow: auto;
+    overflow: hidden;
     height: 100%;
 
     .datatype-button{
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index 6c3d59879..808300c2c 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -56,4 +56,8 @@
         // change the color of the circle element to be red
         fill: red;
     }
+
+    .selected-data{
+        text-align: center;
+    }
 }
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 34fc9ce82..b8be9bd13 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -38,7 +38,7 @@ export class Histogram extends React.Component<HistogramProps> {
     private _histogramRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _histogramSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
     private numericalData: boolean = false;
-    @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
 
     @computed get _histogramData() {
@@ -329,14 +329,33 @@ export class Histogram extends React.Component<HistogramProps> {
 
         const onPointClick = action((e: any) => {
             var pointerX = d3.pointer(e)[0];
+            var index = -1;
+            var sameAsCurrent: boolean;
             const selected = svg.selectAll('.histogram-bar').filter((d: any) => {
-                if ((d.x0*eachRectWidth ) <= pointerX && pointerX <= (d.x1*eachRectWidth )){
-                    console.log(d)
+                index++;
+                var left = this.numericalData? d.x0-1: d.x0;
+                var right = (this.numericalData && d.x0!=d.x1)? d.x1-1: d.x1;
+                if ((left*eachRectWidth ) <= pointerX && pointerX <= (right*eachRectWidth )){
+                    // var showSelected = !this.numericalData? dataSet[index] : this.props.pairs[index];
+                    var showSelected = dataSet[index]
+                    showSelected['frequency'] = d.length;
+                    console.log('showSelected', showSelected)
+                    console.log('current', this._currSelected)
+                    sameAsCurrent = this._currSelected? 
+                        (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
+                      && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
+                        : false;
+                    this._currSelected = sameAsCurrent? undefined: showSelected;
                     return true
                 }
                 return false;
             });
-            selected.attr('class')=='histogram-bar hover'? selected.attr('class', 'histogram-bar'): selected.attr('class', 'histogram-bar hover')
+            // selected.attr('class')=='histogram-bar hover'? selected.attr('class', 'histogram-bar'): selected.attr('class', 'histogram-bar hover')
+            const elements = document.querySelectorAll('.histogram-bar');
+            for (let i = 0; i < elements.length; i++) {
+                elements[i].classList.remove('hover');
+            }
+            if (!sameAsCurrent!) selected.attr('class', 'histogram-bar hover');
         });
 
         svg.on('click', onPointClick);
@@ -367,10 +386,20 @@ export class Histogram extends React.Component<HistogramProps> {
 
     render() {
         
+        var selected: string;
+        if (this._currSelected){
+            selected = '{ ';
+            Object.keys(this._currSelected).map(key => {
+                key!=''? selected += key + ': ' + this._currSelected[key] + ', ': '';
+            })
+            selected = selected.substring(0, selected.length-2);
+            selected += ' }';
+        }
+        else selected = 'none';
         return (
             this.props.axes.length >= 1 && (this.incomingSelected? this.incomingSelected.length>0 : true) ? (
             <div ref={this._histogramRef} className="chart-container">
-                <span> {`Selected: ${Object.keys(this._histogramData[0])[0]}`}</span>
+                <span className={'selected-data'}> {`Selected: ${selected}`}</span>
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index dfb9f54c1..cb6ba6fe7 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -339,7 +339,7 @@ export class LineChart extends React.Component<LineChartProps> {
         const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
         return (
             <div ref={this._lineChartRef} className="chart-container">
-                <span> {this.props.axes.length < 2 ? 'first use table view to select two axes to plot' : `Selected: ${selectedPt}`}</span>
+                <span className={'selected-data'}> {this.props.axes.length < 2 ? 'first use table view to select two axes to plot' : `Selected: ${selectedPt}`}</span>
             </div>
         );
     }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 0d3c74c32..6241e6221 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -38,7 +38,7 @@ export class PieChart extends React.Component<PieChartProps> {
     private _piechartRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _piechartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
     private byCategory: boolean = true; // whether the data is organized by category or by specified number percentages/ratios
-    @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
 
     @computed get _piechartData() {
@@ -284,8 +284,8 @@ export class PieChart extends React.Component<PieChartProps> {
         const onPointClick = action((e: any) => {
             // check the 4 'corners' of each slice and see if the pointer is within those bounds to get the slice the user clicked on
             const pointer = d3.pointer(e);
-            var selectedSlice;
             var index = -1;
+            var sameAsCurrent: boolean;
             const selected = svg.selectAll('.slice').filter((d: any) => {
                 index++;
                 var p1 = [0,0];
@@ -305,14 +305,22 @@ export class PieChart extends React.Component<PieChartProps> {
                 if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){
                     if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; }
                 if (lineCrossCount % 2 != 0) {
-                    selectedSlice = pieDataSet[index];
+                    var showSelected = this.byCategory? pieDataSet[index] : this.props.pairs[index];
+                    sameAsCurrent = (this.byCategory && this._currSelected)? 
+                        (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
+                      && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
+                        : 
+                        this._currSelected===showSelected;
+                    this._currSelected = sameAsCurrent? undefined: showSelected;
                     return true;
                 }
                 return false;
             });
-            console.log('selectedSlice', selectedSlice)
-            
-            selected.attr('class')=='slice hover'? selected.attr('class', 'slice'): selected.attr('class', 'slice hover')
+            const elements = document.querySelectorAll('.slice');
+            for (let i = 0; i < elements.length; i++) {
+                elements[i].classList.remove('hover');
+            }
+            if (!sameAsCurrent!) selected.attr('class', 'slice hover');
         });
 
         var percentField = Object.keys(pieDataSet[0])[0]
@@ -352,10 +360,20 @@ export class PieChart extends React.Component<PieChartProps> {
 
     render() {
 
+        var selected: string;
+        if (this._currSelected){
+            selected = '{ ';
+            Object.keys(this._currSelected).map(key => {
+                key!=''? selected += key + ': ' + this._currSelected[key] + ', ': '';
+            })
+            selected = selected.substring(0, selected.length-2);
+            selected += ' }';
+        }
+        else selected = 'none';
         return (
             this.props.axes.length >= 1 && (this.incomingSelected? this.incomingSelected.length>0 : true) ? (
             <div ref={this._piechartRef} className="chart-container">
-                <span> {`Selected: ${Object.keys(this._piechartData[0])[0]}`}</span>
+                <span className={'selected-data'}> {`Selected: ${selected}`}</span>
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
-- 
cgit v1.2.3-70-g09d2


From 900efdb5c08397e53e1d00555fc6eac208eff5a1 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 18 Jul 2023 16:24:57 -0400
Subject: brushed graph has can have multiple links + still link to the correct
 graph for data

---
 src/client/views/nodes/DataVizBox/DataVizBox.scss          | 1 +
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 4 ++--
 src/client/views/nodes/DataVizBox/components/TableBox.tsx  | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index b3cbc89aa..5e7230271 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -1,6 +1,7 @@
 .dataviz {
     overflow: hidden;
     height: 100%;
+    width: 100%;
 
     .datatype-button{
         margin: 0;
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index cb6ba6fe7..637ed0ead 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -1,7 +1,6 @@
 import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-// import d3
 import * as d3 from 'd3';
 import { Doc, DocListCast } from '../../../../../fields/Doc';
 import { Id } from '../../../../../fields/FieldSymbols';
@@ -56,7 +55,8 @@ export class LineChart extends React.Component<LineChartProps> {
     }
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-            .filter(link => link.link_anchor_1 !== this.props.rootDoc) // get links where this chart doc is the target of the link
+            .filter(link => {
+                return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link
             .map(link => DocCast(link.link_anchor_1)); // then return the source of the link
     }
     @computed get incomingSelected() {
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 8c8264861..ff43f67d9 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -51,6 +51,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                             const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
                                                             embedding._dataVizView = DataVizView.LINECHART;
                                                             embedding._data_vizAxes = new List<string>([col, col]);
+                                                            embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
                                                             embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
                                                             return embedding;
                                                         };
-- 
cgit v1.2.3-70-g09d2


From 3a177316c1f104da538ed4a53c6a442c6f3fcdc4 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Wed, 26 Jul 2023 16:27:12 -0400
Subject: histogram reorganized to accommodate more data types

---
 src/client/documents/Documents.ts                  |   2 +-
 .../nodes/DataVizBox/components/Histogram.tsx      | 134 ++++++++++++---------
 .../nodes/DataVizBox/components/LineChart.tsx      |   2 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx |  13 +-
 4 files changed, 86 insertions(+), 65 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5ef033e35..426eaa14d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1143,7 +1143,7 @@ export namespace Docs {
         }
 
         export function DataVizDocument(url: string, options?: DocumentOptions, overwriteDoc?: Doc) {
-            return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', ...options }, undefined, undefined, undefined, overwriteDoc);
+            return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz',  ...options }, undefined, undefined, undefined, overwriteDoc);
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index c07c85f7e..5fbe92563 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -38,6 +38,9 @@ export class Histogram extends React.Component<HistogramProps> {
     private _histogramRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _histogramSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
     private numericalData: boolean = false;
+    private numericalXData: boolean = false; // whether the data is organized by numbers rather than categoreis
+    private numericalYData: boolean = false; // whether the y axis is controlled by provided data rather than frequency
+    private maxBins = 15; // maximum number of bins that is readable on a normal sized doc
     @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
 
@@ -45,7 +48,7 @@ export class Histogram extends React.Component<HistogramProps> {
         if (this.props.axes.length < 1) return [];
         if (this.props.axes.length < 2) {
             var ax0 = this.props.axes[0];
-            if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalData = true }
+            if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true }
             return this.props.pairs
                 ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
@@ -53,7 +56,8 @@ export class Histogram extends React.Component<HistogramProps> {
 
         var ax0 = this.props.axes[0];
         var ax1 = this.props.axes[1];
-        if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalData = true;}
+        if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;}
+        if (/\d/.test(this.props.pairs[0][ax1]) && this.props.pairs.length < this.maxBins) { this.numericalYData = true;}
         return this.props.pairs
             ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
@@ -79,7 +83,7 @@ export class Histogram extends React.Component<HistogramProps> {
             .lastElement();
     }
     @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } {
-        if (this.numericalData){
+        if (this.numericalXData){
             const data = this.data(this._histogramData);
             return {xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin:0, yMax:0}
         }
@@ -182,7 +186,7 @@ export class Histogram extends React.Component<HistogramProps> {
     getAnchor = (pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
             //
-            title: 'line doc selection' + this._currSelected?.x,
+            title: 'histogram doc selection' + this._currSelected?.x,
         });
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc);
         anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
@@ -227,9 +231,9 @@ export class Histogram extends React.Component<HistogramProps> {
             })
             return valid;
         })
-        var field = dataSet[0]? Object.keys(dataSet[0])[0]: undefined;
+        var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined;
         const data = validData.map((d: { [x: string]: any; }) => {
-            if (this.numericalData) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '') }
+            if (this.numericalXData) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '') }
             return d[field!]
         })
         return data;
@@ -239,26 +243,43 @@ export class Histogram extends React.Component<HistogramProps> {
         d3.select(this._histogramRef.current).select('svg').remove();
         d3.select(this._histogramRef.current).select('.tooltip').remove();
 
-        var field = Object.keys(dataSet[0])[0]
-        const data = this.data(dataSet);
+        var data = this.data(dataSet);
         
         let uniqueArr: unknown[] = [...new Set(data)]
-        var numBins = uniqueArr.length
-        var startingPoint = 0;
-        var endingPoint = numBins;
-        var translateXAxis = 0;
-        if (this.numericalData) {
-            if (Number.isInteger(this.rangeVals.xMin!)){
-                numBins = this.rangeVals.xMax! - this.rangeVals.xMin! + 1;
+        var numBins = this.numericalXData? (this.rangeVals.xMax! - this.rangeVals.xMin! + 1) : uniqueArr.length
+        var translateXAxis = !this.numericalXData || numBins<this.maxBins ?  width/(numBins+1)/2 : 0;
+        if (numBins>this.maxBins) numBins = this.maxBins;
+        var startingPoint = this.numericalXData? this.rangeVals.xMin! : 0;
+        var endingPoint = this.numericalXData? this.rangeVals.xMax! : numBins;
+        var xAxisTitle = Object.keys(dataSet[0])[0]
+        var yAxisTitle = this.numericalYData ? Object.keys(dataSet[0])[1] : 'frequency';
+        var histDataSet = dataSet.filter((d: { [x: string]: unknown; }) => {
+            var valid = true;
+            Object.keys(dataSet[0]).map(key => {
+                if (!d[key] || Number.isNaN(d[key])) valid = false;
+            })
+            return valid;
+        });
+        if (!this.numericalXData) {
+            var histStringDataSet: { frequency: any, label: any }[] = [];
+            if (this.numericalYData){
+                for (let i=0; i<dataSet.length; i++){
+                    histStringDataSet.push({frequency: dataSet[i][yAxisTitle], label: dataSet[i][xAxisTitle]})
+                }
+            }
+            else{
+                for (let i=0; i<uniqueArr.length; i++){
+                    histStringDataSet.push({frequency: 0, label: uniqueArr[i]})
+                }
+                for (let i=0; i<data.length; i++){
+                    let sliceData = histStringDataSet.filter(each => each.label==data[i])
+                    sliceData[0].frequency = sliceData[0].frequency + 1;
+                }
             }
-            startingPoint = this.rangeVals.xMin!;
-            endingPoint = this.rangeVals.xMax!;
-            if (numBins>15) numBins = 15;
-            else translateXAxis = width/(numBins+1) / 2;
+            histDataSet = histStringDataSet
         }
-        else translateXAxis = width/(numBins+1) / 2;
 
-        const svg = (this._histogramSvg = d3
+        var svg = (this._histogramSvg = d3
             .select(this._histogramRef.current)
             .append("svg")
                 .attr("class", "graph")
@@ -268,32 +289,24 @@ export class Histogram extends React.Component<HistogramProps> {
                 .attr("transform",
                       "translate(" + this.props.margin.left + "," + this.props.margin.top + ")"));
 
-        var x: any;
-        if (this.numericalData){
-            x = d3.scaleLinear()
-                .domain([startingPoint!, endingPoint!])
+        var x = d3.scaleLinear()
+                .domain(this.numericalXData? [startingPoint!, endingPoint!] : [0, numBins])
                 .range([0, width ]);
-        }
-        else {
-            x = d3.scaleLinear()
-                .domain([0, numBins])
-                .range([0, width]);
-        }
-        
         var histogram = d3.histogram()
             .value(function(d) {return d})
             .domain([startingPoint!, endingPoint!])
             .thresholds(x.ticks(numBins-1))
         var bins = histogram(data)
         var eachRectWidth = width/(bins.length)
-        var graphStartingPoint = bins[0].x1! - (bins[1].x1! - bins[1].x0!)
+        var graphStartingPoint = bins[0].x1? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0;
         bins[0].x0 = graphStartingPoint;
         x = x.domain([graphStartingPoint, endingPoint])
              .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ])
         var xAxis;
 
-        if (!this.numericalData) { // if the data is strings rather than numbers
-            uniqueArr.sort()
+        if (!this.numericalXData) { // reorganize if the data is strings rather than numbers
+            // uniqueArr.sort()
+            histDataSet.sort()
             for (let i=0; i<data.length; i++){
                 var index = 0
                 for (let j=0; j<uniqueArr.length; j++){
@@ -303,23 +316,27 @@ export class Histogram extends React.Component<HistogramProps> {
                 }
                 bins[index].push(data[i])
             }
+            bins.pop();
+            eachRectWidth = width/(bins.length)
             bins.forEach(d => d.x0 = d.x0!)
             xAxis = d3.axisBottom(x)
-                .ticks(numBins-1)
+                .ticks(bins.length-1)
                 .tickFormat( i => uniqueArr[i])
                 .tickPadding(10)
+            x.range([0, width-eachRectWidth])
+            x.domain([0, bins.length-1])
             translateXAxis = eachRectWidth / 2;
         }
         else {
             xAxis = d3.axisBottom(x)
                 .ticks(numBins-1)
         }
-
-        const maxFrequency = d3.max(bins, function(d) { return d.length; })
+        const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d) {return d.frequency.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')})
+                    : d3.max(bins, function(d) { return d.length; })
 
         var y = d3.scaleLinear()
             .range([height, 0]);
-            y.domain([0, maxFrequency!]);
+            y.domain([0, +maxFrequency!]);
         var yAxis = d3.axisLeft(y)
             .ticks(maxFrequency!)
         svg.append("g")
@@ -337,16 +354,14 @@ export class Histogram extends React.Component<HistogramProps> {
                 var left = this.numericalData? d.x0-1: d.x0;
                 var right = (this.numericalData && d.x0!=d.x1)? d.x1-1: d.x1;
                 if ((left*eachRectWidth ) <= pointerX && pointerX <= (right*eachRectWidth )){
-                    // var showSelected = !this.numericalData? dataSet[index] : this.props.pairs[index];
-                    var showSelected = dataSet[index]
-                    showSelected['frequency'] = d.length;
-                    console.log('showSelected', showSelected)
-                    console.log('current', this._currSelected)
+                    var showSelected = histDataSet[index]
+                    var selectedDisplay = {[xAxisTitle]: showSelected.label, [yAxisTitle]: showSelected.frequency}
+                    // showSelected['frequency'] = d.length;
                     sameAsCurrent = this._currSelected? 
-                        (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
-                      && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
+                        (selectedDisplay[xAxisTitle]==this._currSelected![xAxisTitle] 
+                      && selectedDisplay[yAxisTitle]==this._currSelected![yAxisTitle])
                         : false;
-                    this._currSelected = sameAsCurrent? undefined: showSelected;
+                    this._currSelected = sameAsCurrent? undefined: selectedDisplay;
                     return true
                 }
                 return false;
@@ -358,30 +373,37 @@ export class Histogram extends React.Component<HistogramProps> {
             }
             if (!sameAsCurrent!) selected.attr('class', 'histogram-bar hover');
         });
-
         svg.on('click', onPointClick);
 
-        // axis titles
         svg.append("text")
             .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")")
             .style("text-anchor", "middle")
-            .text(field);
+            .text(xAxisTitle);
         svg.append("text")
-            .attr("transform", "rotate(-90)")
+            .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")")
             .attr("x", -(height/2))
             .attr("y", -20)
             .style("text-anchor", "middle")
-            .text('frequency');
-
+            .text(yAxisTitle);
         d3.format('.0f')
-
         svg.selectAll("rect")
             .data(bins)
             .enter()
             .append("rect")
-              .attr("transform", function(d) { return "translate(" + x(d.x0!) + "," + y(d.length) + ")"; })
+              .attr("transform", this.numericalYData?
+                    function (d) {
+                        var eachData = histDataSet.filter((data: { label: number; }) => {return data.label==d[0]}) 
+                        var length = eachData[0].frequency.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '');
+                        return "translate(" + x(d.x0!) + "," + y(length) + ")";
+                    }
+                    : function(d) { return "translate(" + x(d.x0!) + "," + y(d.length) + ")"; })
+              .attr("height", this.numericalYData? 
+                    function(d) {
+                        var eachData = histDataSet.filter((data: { label: number; }) => {return data.label==d[0]}) 
+                        var length = eachData[0].frequency.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '');
+                        return height-y(length)}
+                    : function(d) { return height - y(d.length)})
               .attr("width", eachRectWidth)
-              .attr("height", function(d) { return height - y(d.length); })
               .attr("class", 'histogram-bar')
     };
 
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 637ed0ead..91baf095d 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -310,7 +310,7 @@ export class LineChart extends React.Component<LineChartProps> {
             .style("text-anchor", "middle")
             .text(this.props.axes[0]);
         svg.append("text")
-            .attr("transform", "rotate(-90)")
+            .attr("transform", "rotate(-90)" + " " + "translate( 0, " + -10 + ")")
             .attr("x", -(height/2))
             .attr("y", -20)
             .attr("height", 20)
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 37c435411..fc24e5821 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -182,7 +182,7 @@ export class PieChart extends React.Component<PieChartProps> {
     getAnchor = (pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
             //
-            title: 'line doc selection' + this._currSelected?.x,
+            title: 'piechart doc selection' + this._currSelected?.x,
         });
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc);
         anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
@@ -260,12 +260,6 @@ export class PieChart extends React.Component<PieChartProps> {
             })
             return valid;
         });
-
-        var pie = d3.pie();
-        var arc = d3.arc()
-            .innerRadius(0)
-            .outerRadius(radius);
-        
         if (this.byCategory){
             let uniqueCategories = [...new Set(data)]
             var pieStringDataSet: { frequency: any, label: any }[] = [];
@@ -282,6 +276,11 @@ export class PieChart extends React.Component<PieChartProps> {
         var trackDuplicates : {[key: string]: any} = {};
         data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
 
+        var pie = d3.pie();
+        var arc = d3.arc()
+            .innerRadius(0)
+            .outerRadius(radius);
+
         const onPointClick = action((e: any) => {
             // check the 4 'corners' of each slice and see if the pointer is within those bounds to get the slice the user clicked on
             const pointer = d3.pointer(e);
-- 
cgit v1.2.3-70-g09d2


From ad6cbd1e4abf97cff81d160b3b3afa0bc9b8c204 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 27 Jul 2023 13:55:56 -0400
Subject: titles

---
 .../views/nodes/DataVizBox/components/Chart.scss       | 11 +++++++----
 .../views/nodes/DataVizBox/components/Histogram.tsx    | 14 ++++++++++++--
 .../views/nodes/DataVizBox/components/LineChart.tsx    | 11 +++++++++--
 .../views/nodes/DataVizBox/components/PieChart.tsx     | 18 ++++++++++++++----
 4 files changed, 42 insertions(+), 12 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index 808300c2c..5945840b5 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -8,6 +8,13 @@
     .graph{
         overflow: visible;
     }
+    .graph-title{
+        align-items: center;
+        font-size: larger;
+    }
+    .selected-data{
+        align-items: center;
+    }
     .slice {
         &.hover {
             stroke: black;
@@ -56,8 +63,4 @@
         // change the color of the circle element to be red
         fill: red;
     }
-
-    .selected-data{
-        text-align: center;
-    }
 }
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index c9cd49aa1..479f6584c 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -66,6 +66,14 @@ export class Histogram extends React.Component<HistogramProps> {
             .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
             .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
+    @computed get graphTitle(){
+        var ax0 = this.props.axes[0];
+        var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
+        if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){
+            return ax0 + " Histogram";
+        }
+        else return ax1 + " by " + ax0 + " Histogram";
+    }    
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
             .filter(link => {
@@ -416,8 +424,10 @@ export class Histogram extends React.Component<HistogramProps> {
         else selected = 'none';
         return (
             this.props.axes.length >= 1 ? (
-            <div ref={this._histogramRef} className="chart-container">
-                <span className={'selected-data'}> {`Selected: ${selected}`}</span>
+            <div className="chart-container" >
+                <div className="graph-title"> {this.graphTitle} </div>
+                <div className={'selected-data'}> {`Selected: ${selected}`}</div>
+                <div ref={this._histogramRef} />
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 91baf095d..da79df476 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -53,6 +53,9 @@ export class LineChart extends React.Component<LineChartProps> {
             .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
             .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
+    @computed get graphTitle(){
+        return this.props.axes[1] + " vs. " + this.props.axes[0] + " Line Chart";
+    }  
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
             .filter(link => {
@@ -338,9 +341,13 @@ export class LineChart extends React.Component<LineChartProps> {
     render() {
         const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
         return (
-            <div ref={this._lineChartRef} className="chart-container">
-                <span className={'selected-data'}> {this.props.axes.length < 2 ? 'first use table view to select two axes to plot' : `Selected: ${selectedPt}`}</span>
+            this.props.axes.length >= 2 ? (
+            <div className="chart-container" >
+                <div className="graph-title"> {this.graphTitle} </div>
+                <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
+                <div ref={this._lineChartRef} />
             </div>
+            ) : <span className="chart-container"> {'first use table view to select two axes to plot'}</span>
         );
     }
 }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index cead40d92..27653b847 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -53,7 +53,7 @@ export class PieChart extends React.Component<PieChartProps> {
 
         var ax0 = this.props.axes[0];
         var ax1 = this.props.axes[1];
-        if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false;}
+        if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; }
         return this.props.pairs
             ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
@@ -63,6 +63,14 @@ export class PieChart extends React.Component<PieChartProps> {
             .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
             .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
+    @computed get graphTitle(){
+        var ax0 = this.props.axes[0];
+        var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
+        if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){
+            return ax0 + " Pie Chart";
+        }
+        else return ax1 + " by " + ax0 + " Pie Chart";
+    }    
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
             .filter(link => {
@@ -333,7 +341,7 @@ export class PieChart extends React.Component<PieChartProps> {
             .append("g")
         arcs.append("path")
             .attr("fill", (data, i)=>{ return d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
-            .attr("class", `${pieDataSet[0][percentField]} slice`)
+            .attr("class", 'slice')
             .attr("d", arc)
             .on('click', onPointClick)
         arcs.append("text")
@@ -373,8 +381,10 @@ export class PieChart extends React.Component<PieChartProps> {
         else selected = 'none';
         return (
             this.props.axes.length >= 1 ? (
-            <div ref={this._piechartRef} className="chart-container">
-                <span className={'selected-data'}> {`Selected: ${selected}`}</span>
+            <div className="chart-container">
+                <div className="graph-title"> {this.graphTitle} </div>
+                <div className={'selected-data'}> {`Selected: ${selected}`}</div>
+                <div ref={this._piechartRef} />
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
-- 
cgit v1.2.3-70-g09d2


From 591533a40c847f84e23428ab757b8822edbc2a61 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 1 Aug 2023 17:41:09 -0400
Subject: things save: editable title for all 3 + color for histogram

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   | 42 ++++++----------------
 .../views/nodes/DataVizBox/components/Chart.scss   |  3 ++
 .../nodes/DataVizBox/components/Histogram.tsx      | 37 ++++++++++---------
 .../nodes/DataVizBox/components/LineChart.tsx      | 28 +++++++++++++--
 .../views/nodes/DataVizBox/components/PieChart.tsx | 20 ++++++-----
 .../views/nodes/DataVizBox/components/TableBox.tsx | 26 +++++++++++---
 6 files changed, 95 insertions(+), 61 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 12aa2ae34..710c049a2 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -14,7 +14,7 @@ import { TableBox } from './components/TableBox';
 import './DataVizBox.scss';
 import { Histogram } from './components/Histogram';
 import { PieChart } from './components/PieChart';
-import { Toggle, ToggleType } from 'browndash-components';
+import { Toggle, ToggleType, Type } from 'browndash-components';
 
 export enum DataVizView {
     TABLE = 'table',
@@ -25,6 +25,7 @@ export enum DataVizView {
 
 @observer
 export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(DataVizBox, fieldKey);
     }
@@ -97,37 +98,16 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
     selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List<string>(axes));
 
-    @computed get table(){
-        if (!this.pairs) return 'no data';
-        return <TableBox pairs={this.pairs} axes={this.axes} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
-    }
-    @computed get lineChart(){
-        const width = this.props.PanelWidth() * 0.9;
-        const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
-        const margin = { top: 10, right: 25, bottom: 50, left: 25 };
-        if (!this.pairs) return 'no data';
-        return <LineChart ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
-    }
-    @computed get histogram(){
-        const width = this.props.PanelWidth() * 0.9;
-        const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
-        const margin = { top: 10, right: 25, bottom: 50, left: 25 };
-        if (!this.pairs) return 'no data';
-        return <Histogram height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
-    }
-    @computed get pieChart(){
+    @computed get selectView() {
         const width = this.props.PanelWidth() * 0.9;
         const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
         const margin = { top: 10, right: 25, bottom: 50, left: 25 };
         if (!this.pairs) return 'no data';
-        return <PieChart height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
-    }
-    @computed get selectView() {
         switch (this.dataVizView) {
-            case DataVizView.TABLE:     return this.table;
-            case DataVizView.LINECHART: return this.lineChart;
-            case DataVizView.HISTOGRAM: return this.histogram;
-            case DataVizView.PIECHART: return this.pieChart;
+            case DataVizView.TABLE:     return <TableBox pairs={this.pairs} axes={this.axes} height={height} width={width} margin={margin} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
+            case DataVizView.LINECHART: return <LineChart layoutDoc={this.layoutDoc} ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
+            case DataVizView.HISTOGRAM: return <Histogram layoutDoc={this.layoutDoc} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
+            case DataVizView.PIECHART: return <PieChart layoutDoc={this.layoutDoc} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
         }
     }
     @computed get dataUrl() {
@@ -176,19 +156,19 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                     )
                 }>
                 <div className={'datatype-button'}>
-                    <Toggle text={"TABLE"} toggleType={ToggleType.BUTTON} type={"secondary"} color={"black"} 
+                    <Toggle text={"TABLE"} toggleType={ToggleType.BUTTON} type={Type.SEC} color={"black"} 
                         onClick={e => this.layoutDoc._dataVizView = DataVizView.TABLE} 
                         toggleStatus={this.layoutDoc._dataVizView == DataVizView.TABLE} 
                     />
-                    <Toggle text={"LINECHART"} toggleType={ToggleType.BUTTON} type={"secondary"} color={"black"} 
+                    <Toggle text={"LINECHART"} toggleType={ToggleType.BUTTON} type={Type.SEC} color={"black"} 
                         onClick={e => this.layoutDoc._dataVizView = DataVizView.LINECHART} 
                         toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} 
                     />
-                    <Toggle text={"HISTOGRAM"} toggleType={ToggleType.BUTTON} type={"secondary"} color={"black"} 
+                    <Toggle text={"HISTOGRAM"} toggleType={ToggleType.BUTTON} type={Type.SEC} color={"black"} 
                         onClick={e => this.layoutDoc._dataVizView = DataVizView.HISTOGRAM} 
                         toggleStatus={this.layoutDoc._dataVizView == DataVizView.HISTOGRAM} 
                     />
-                    <Toggle text={"PIE CHART"} toggleType={ToggleType.BUTTON} type={"secondary"} color={"black"} 
+                    <Toggle text={"PIE CHART"} toggleType={ToggleType.BUTTON} type={Type.SEC} color={"black"} 
                         onClick={e => this.layoutDoc._dataVizView = DataVizView.PIECHART} 
                         toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} 
                     />
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index fc0c4cea3..6c87241b8 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -75,3 +75,6 @@
         fill: red;
     }
 }
+.table-container{
+    overflow: scroll;
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 64e61fca8..740ee6e3a 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -1,10 +1,10 @@
 import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../../../fields/Doc";
+import { Doc, DocListCast, FieldResult } from "../../../../../fields/Doc";
 import * as React from 'react';
 import * as d3 from 'd3';
 import { IReactionDisposer, action, computed, observable, reaction } from "mobx";
 import { LinkManager } from "../../../../util/LinkManager";
-import { Cast, DocCast} from "../../../../../fields/Types";
+import { Cast, DocCast, StrCast} from "../../../../../fields/Types";
 import { DataPoint, SelectedDataPoint } from "./LineChart";
 import { DocumentManager } from "../../../../util/DocumentManager";
 import { Id } from "../../../../../fields/FieldSymbols";
@@ -19,6 +19,7 @@ import { FaFillDrip } from "react-icons/fa";
 
 export interface HistogramProps {
     rootDoc: Doc;
+    layoutDoc: Doc;
     axes: string[];
     pairs: { [key: string]: any }[];
     width: number;
@@ -44,9 +45,6 @@ export class Histogram extends React.Component<HistogramProps> {
     private maxBins = 15; // maximum number of bins that is readable on a normal sized doc
     @observable _currSelected: any | undefined = undefined;
     private curBarSelected: any = undefined;
-    private barColors: any = {};
-    private defaultBarColor: string = '#69b3a2';
-    @observable graphTitle: string = this.defaultGraphTitle;
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _histogramData() {
@@ -75,7 +73,7 @@ export class Histogram extends React.Component<HistogramProps> {
     @computed get defaultGraphTitle(){
         var ax0 = this.props.axes[0];
         var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
-        if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){
+        if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1 || !this.numericalYData){
             return ax0 + " Histogram";
         }
         else return ax1 + " by " + ax0 + " Histogram";
@@ -285,8 +283,8 @@ export class Histogram extends React.Component<HistogramProps> {
                     histStringDataSet.push({[yAxisTitle]: 0, [xAxisTitle]: uniqueArr[i]})
                 }
                 for (let i=0; i<data.length; i++){
-                    let sliceData = histStringDataSet.filter(each => each[xAxisTitle]==data[i])
-                    sliceData[0][yAxisTitle] = sliceData[0][yAxisTitle] + 1;
+                    let barData = histStringDataSet.filter(each => each[xAxisTitle]==data[i])
+                    barData[0][yAxisTitle] = barData[0][yAxisTitle] + 1;
                 }
             }
             histDataSet = histStringDataSet
@@ -426,27 +424,33 @@ export class Histogram extends React.Component<HistogramProps> {
                         return height - y(d.length)})
               .attr("width", eachRectWidth)
               .attr("class", 'histogram-bar')
-              .attr("fill", (d)=>{ return this.barColors[d[0]]? this.barColors[d[0]] : this.defaultBarColor})
+              .attr("fill", (d)=>{ return this.props.layoutDoc['histogramBarColors-'+d[0]]? StrCast(this.props.layoutDoc['histogramBarColors-'+d[0]]) : this.props.layoutDoc.defaultHistogramColor? StrCast(this.props.layoutDoc.defaultHistogramColor): '#69b3a2'})
     };
 
     @action changeSelectedColor = (color: string) => {
         this.curBarSelected.attr("fill", color);
-        this.barColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')] = color;
+        var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))
+        this.props.layoutDoc['histogramBarColors-'+barName] = color;
     };
     
     @action changeDefaultColor = (color: string) => {
         const defaultColorBars = this._histogramSvg!.selectAll('.histogram-bar').filter((d: any) => {
-            if (this.barColors[d[0]]) return false;
+            if (this.props.layoutDoc['histogramBarColors-'+d[0]]) return false;
             else return true;
         })
         defaultColorBars.attr("fill", color);
-        this.defaultBarColor = color;
+        this.props.layoutDoc.defaultHistogramColor = color;
     };
 
     render() {
-        const title = this.graphTitle;
+        var curSelectedBarName;
+        var titleAccessor: any='';
+        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
+        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]]);
+        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
         var selected: string;
         if (this._currSelected){
+            curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))
             selected = '{ ';
             Object.keys(this._currSelected).map(key => {
                 key!=''? selected += key + ': ' + this._currSelected[key] + ', ': '';
@@ -461,7 +465,8 @@ export class Histogram extends React.Component<HistogramProps> {
                 <div className="graph-title"> 
                     <EditableText
                         val={title}
-                        setVal={action(val => this.graphTitle = val as string)}
+                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['histogram-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
+                            : this.props.layoutDoc['histogram-title-'+this.props.axes[0]] = val as string})}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
@@ -471,7 +476,7 @@ export class Histogram extends React.Component<HistogramProps> {
                         tooltip={'Change Default Bar Color'} 
                         type={Type.SEC} 
                         icon={<FaFillDrip/>}
-                        selectedColor={this.defaultBarColor}
+                        selectedColor={this.props.layoutDoc.defaultHistogramColor? StrCast(this.props.layoutDoc.defaultHistogramColor): '#69b3a2'}
                         setSelectedColor={color => this.changeDefaultColor(color)}
                         size={Size.XSMALL}
                     />
@@ -484,7 +489,7 @@ export class Histogram extends React.Component<HistogramProps> {
                             tooltip={'Change Slice Color'} 
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
-                            selectedColor={this.curBarSelected.attr("fill")}
+                            selectedColor={this.props.layoutDoc['histogramBarColors-'+curSelectedBarName]? this.props.layoutDoc['histogramBarColors-'+curSelectedBarName] : this.curBarSelected.attr("fill")}
                             setSelectedColor={color => this.changeSelectedColor(color)}
                             size={Size.XSMALL}
                         />
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index da79df476..0142e96ad 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -6,7 +6,7 @@ import { Doc, DocListCast } from '../../../../../fields/Doc';
 import { Id } from '../../../../../fields/FieldSymbols';
 import { List } from '../../../../../fields/List';
 import { listSpec } from '../../../../../fields/Schema';
-import { Cast, DocCast } from '../../../../../fields/Types';
+import { Cast, DocCast, StrCast } from '../../../../../fields/Types';
 import { Docs } from '../../../../documents/Documents';
 import { DocumentManager } from '../../../../util/DocumentManager';
 import { LinkManager } from '../../../../util/LinkManager';
@@ -14,6 +14,7 @@ import { PinProps, PresBox } from '../../trails';
 import { DataVizBox } from '../DataVizBox';
 import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils';
 import './Chart.scss';
+import { EditableText, Size } from 'browndash-components';
 
 export interface DataPoint {
     x: number;
@@ -24,6 +25,7 @@ export interface SelectedDataPoint extends DataPoint {
 }
 export interface LineChartProps {
     rootDoc: Doc;
+    layoutDoc: Doc;
     axes: string[];
     pairs: { [key: string]: any }[];
     width: number;
@@ -185,6 +187,15 @@ export class LineChart extends React.Component<LineChartProps> {
         return this.props.width - this.props.margin.left - this.props.margin.right;
     }
 
+    @computed get defaultGraphTitle(){
+        var ax0 = this.props.axes[0];
+        var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
+        if (this.props.axes.length<2 || !/\d/.test(this.props.pairs[0][ax0]) || !ax1){
+            return ax0 + " Line Chart";
+        }
+        else return ax1 + " by " + ax0 + " Line Chart";
+    } 
+
     setupTooltip() {
         return d3
             .select(this._lineChartRef.current)
@@ -339,11 +350,24 @@ export class LineChart extends React.Component<LineChartProps> {
     }
 
     render() {
+        var titleAccessor:any = '';
+        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
+        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]]);
+        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
         const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
         return (
             this.props.axes.length >= 2 ? (
             <div className="chart-container" >
-                <div className="graph-title"> {this.graphTitle} </div>
+                <div className="graph-title"> 
+                    <EditableText
+                        val={title}
+                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
+                            : this.props.layoutDoc['lineChart-title-'+this.props.axes[0]] = val as string})}
+                        color={"black"}
+                        size={Size.LARGE}
+                        fillWidth
+                    />
+                </div>
                 <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
                 <div ref={this._lineChartRef} />
             </div>
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 47d4fb23e..f0c27866d 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import * as d3 from 'd3';
 import { IReactionDisposer, action, computed, observable, reaction } from "mobx";
 import { LinkManager } from "../../../../util/LinkManager";
-import { Cast, DocCast} from "../../../../../fields/Types";
+import { Cast, DocCast, StrCast} from "../../../../../fields/Types";
 import { DataPoint, SelectedDataPoint } from "./LineChart";
 import { DocumentManager } from "../../../../util/DocumentManager";
 import { Id } from "../../../../../fields/FieldSymbols";
@@ -19,6 +19,7 @@ import { FaFillDrip } from "react-icons/fa";
 
 export interface PieChartProps {
     rootDoc: Doc;
+    layoutDoc: Doc;
     axes: string[];
     pairs: { [key: string]: any }[];
     width: number;
@@ -42,8 +43,6 @@ export class PieChart extends React.Component<PieChartProps> {
     private byCategory: boolean = true; // whether the data is organized by category or by specified number percentages/ratios
     @observable _currSelected: any | undefined = undefined;
     private curSliceSelected: any = undefined;
-    private sliceColors: any = {};
-    @observable graphTitle: string = this.defaultGraphTitle;
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _piechartData() {
@@ -254,7 +253,7 @@ export class PieChart extends React.Component<PieChartProps> {
         
         var percentField = Object.keys(dataSet[0])[0]
         var descriptionField = Object.keys(dataSet[0])[1]!
-        var radius = Math.min(width, height) / 2 - Math.max(this.props.margin.top, this.props.margin.bottom, this.props.margin.left, this.props.margin.right)
+        var radius = Math.min(width, height-this.props.margin.top-this.props.margin.bottom) /2
         var svg = (this._piechartSvg = d3
             .select(this._piechartRef.current)
             .append("svg")
@@ -349,7 +348,7 @@ export class PieChart extends React.Component<PieChartProps> {
             .enter()
             .append("g")
         arcs.append("path")
-            .attr("fill", (data, i)=>{ return this.sliceColors[data.data.valueOf()]? this.sliceColors[data.data.valueOf()] : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
+            .attr("fill", (data, i)=>{ return this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]? StrCast(this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
             .attr("class", 'slice')
             .attr("d", arc)
             .on('click', onPointClick)
@@ -379,11 +378,15 @@ export class PieChart extends React.Component<PieChartProps> {
 
     @action changeSelectedColor = (color: string) => {
         this.curSliceSelected.attr("fill", color);
-        this.sliceColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')] = color;
+        var sliceName = this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')
+        this.props.layoutDoc['pieSliceColors-'+sliceName] = color;
     };
 
     render() {
-        const title = this.graphTitle;
+        var titleAccessor: any='';
+        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['pieChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
+        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['pieChart-title-'+this.props.axes[0]]);
+        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
         var selected: string;
         if (this._currSelected){
             selected = '{ ';
@@ -400,7 +403,8 @@ export class PieChart extends React.Component<PieChartProps> {
                 <div className="graph-title"> 
                     <EditableText
                         val={title}
-                        setVal={action(val => this.graphTitle = val as string)}
+                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['pieChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
+                            : this.props.layoutDoc['pieChart-title-'+this.props.axes[0]] = val as string})}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index aaedba202..64c6dc940 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -9,14 +9,24 @@ import { DragManager } from '../../../../util/DragManager';
 import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
 import { LinkManager } from '../../../../util/LinkManager';
-import { DocCast } from '../../../../../fields/Types';
+import { Cast, DocCast } from '../../../../../fields/Types';
 import { EditableText, Size, Type } from 'browndash-components';
+import './Chart.scss';
+import { listSpec } from '../../../../../fields/Schema';
 
 interface TableBoxProps {
     rootDoc: Doc;
     pairs: { [key: string]: any }[];
     selectAxes: (axes: string[]) => void;
     axes: string[];
+    width: number;
+    height: number;
+    margin: {
+        top: number;
+        right: number;
+        bottom: number;
+        left: number;
+    };
     docView?: () => DocumentView | undefined;
 }
 
@@ -27,6 +37,7 @@ export class TableBox extends React.Component<TableBoxProps> {
 
     @computed get _tableData() {
         if (this.incomingLinks.length! <= 0) return this.props.pairs;
+        /// StrListCast(this.incomingLinks[0].anchor_1.selected) ==> list of guids that the parent has selected
         return this.props.pairs?.filter(pair => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
     }
 
@@ -44,7 +55,7 @@ export class TableBox extends React.Component<TableBoxProps> {
 
     // render() {
     //     return (
-    //         <div className="table-container">
+    //         <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
     //             <table className="table">
     //                 <thead>
     //                     <tr className="table-row">
@@ -144,7 +155,7 @@ export class TableBox extends React.Component<TableBoxProps> {
 
     render() {
         return (
-            <div className="table-container">
+            <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
                 <table className="table">
                     <thead>
                         <tr className="table-row">
@@ -214,7 +225,14 @@ export class TableBox extends React.Component<TableBoxProps> {
                     <tbody>
                         {this._tableData?.map((p, i) => {
                             return (
-                                <tr key={i} className="table-row" onClick={action(e => (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}>
+                                <tr key={i} className="table-row" onClick={action(e => {
+                                        // if (!this.props.docView?.()!.layoutDoc.selected) 
+                                        //     this.props.docView!.()!.layoutDoc.selected = new List<string>();
+                                        // const selected = Cast(this.props.docView?.()!.layoutDoc.selected, listSpec("string"), null);
+                                        //                    // StrListCast(this.props.docView?.()!.layoutDoc.selected)
+                                        // selected.push(p.guid);
+                                        (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]])
+                                    })}>
                                     {this.columns.map(col => (
                                         <td key={this.columns.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>
                                             {p[col]}
-- 
cgit v1.2.3-70-g09d2


From 49fa6721e2a7af21db5da339cd3c7d90d3e8bf8b Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Wed, 2 Aug 2023 12:37:52 -0400
Subject: linking title bug fix

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  5 ++--
 .../nodes/DataVizBox/components/Histogram.tsx      | 11 ++++---
 .../nodes/DataVizBox/components/LineChart.tsx      | 12 ++++----
 .../views/nodes/DataVizBox/components/PieChart.tsx | 35 +++++++++++++++++-----
 4 files changed, 40 insertions(+), 23 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index f167346de..9a4de3c36 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -70,8 +70,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List<string>(StrListCast(data.presDataVizAxes)));
         Object.keys(this.layoutDoc).map(key => {
             if (key.startsWith('histogram-title') || key.startsWith('histogramBarColors') || key.startsWith('defaultHistogramColor')
-                || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){
-                    console.log(key)
+                || key.startsWith('lineChart-title') || key.startsWith('pieChart-title') || key.startsWith('pieSliceColors')){
                     this.layoutDoc['_'+key] = data[key];
                 }
         })
@@ -97,7 +96,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         anchor.presDataVizAxes = this.axes.length ? new List<string>(this.axes) : undefined;
         Object.keys(this.layoutDoc).map(key => {
             if (key.startsWith('histogram-title') || key.startsWith('histogramBarColors') || key.startsWith('defaultHistogramColor')
-                || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){
+                || key.startsWith('lineChart-title') || key.startsWith('pieChart-title') || key.startsWith('pieSliceColors')){
                     anchor[key] = this.layoutDoc[key];
                 }
         })
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index c6e3b4cd1..e5e3ccd53 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -446,9 +446,9 @@ export class Histogram extends React.Component<HistogramProps> {
         this.componentDidMount();
         var curSelectedBarName;
         var titleAccessor: any='';
-        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
-        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['histogram-title-'+this.props.axes[0]]);
-        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
+        if (this.props.axes.length==2) titleAccessor = 'histogram-title-'+this.props.axes[0]+'-'+this.props.axes[1];
+        else if (this.props.axes.length>0) titleAccessor = 'histogram-title-'+this.props.axes[0];
+        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
         var selected: string;
         if (this._currSelected){
             curSelectedBarName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))
@@ -465,9 +465,8 @@ export class Histogram extends React.Component<HistogramProps> {
             <div className="chart-container" >
                 <div className="graph-title"> 
                     <EditableText
-                        val={title}
-                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['histogram-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
-                            : this.props.layoutDoc['histogram-title-'+this.props.axes[0]] = val as string})}
+                        val={StrCast(this.props.layoutDoc[titleAccessor])}
+                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 0142e96ad..0e699bb99 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -350,19 +350,19 @@ export class LineChart extends React.Component<LineChartProps> {
     }
 
     render() {
+        this.componentDidMount();
         var titleAccessor:any = '';
-        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
-        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['lineChart-title-'+this.props.axes[0]]);
-        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
+        if (this.props.axes.length==2) titleAccessor = 'lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1];
+        else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+this.props.axes[0];
+        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
         const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
         return (
             this.props.axes.length >= 2 ? (
             <div className="chart-container" >
                 <div className="graph-title"> 
                     <EditableText
-                        val={title}
-                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['lineChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
-                            : this.props.layoutDoc['lineChart-title-'+this.props.axes[0]] = val as string})}
+                        val={StrCast(this.props.layoutDoc[titleAccessor])}
+                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index f0c27866d..98c79f95a 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -348,10 +348,27 @@ export class PieChart extends React.Component<PieChartProps> {
             .enter()
             .append("g")
         arcs.append("path")
-            .attr("fill", (data, i)=>{ return this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]? StrCast(this.props.layoutDoc['pieSliceColors-'+data.data.valueOf()]) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
+            .attr("fill", (d, i)=>{ 
+                var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => {
+                    try {
+                        return each[percentField].replace(/[^0-9]/g,"")==d.data.toString().replace(/[^0-9]/g,"")
+                    } catch (error) {
+                        return each[percentField]==d.data
+                    }})
+                var dataPoint;
+                if (possibleDataPoints.length==1) dataPoint = possibleDataPoints[0];
+                else{
+                    dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]]
+                    trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1;
+                }
+                var accessByName = descriptionField? dataPoint[descriptionField] : dataPoint[percentField];
+                return this.props.layoutDoc['pieSliceColors-'+accessByName]? StrCast(this.props.layoutDoc['pieSliceColors-'+accessByName]) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
             .attr("class", 'slice')
             .attr("d", arc)
             .on('click', onPointClick)
+
+        trackDuplicates = {};
+        data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
         arcs.append("text")
             .attr("transform",function(d){ 
                 var centroid = arc.centroid(d as unknown as d3.DefaultArcObject)
@@ -383,12 +400,15 @@ export class PieChart extends React.Component<PieChartProps> {
     };
 
     render() {
+        this.componentDidMount();
         var titleAccessor: any='';
-        if (this.props.axes.length==2) titleAccessor = StrCast(this.props.layoutDoc['pieChart-title-'+this.props.axes[0]+'-'+this.props.axes[1]]);
-        else if (this.props.axes.length>0) titleAccessor = StrCast(this.props.layoutDoc['pieChart-title-'+this.props.axes[0]]);
-        const title = titleAccessor? titleAccessor : this.defaultGraphTitle;
+        if (this.props.axes.length==2) titleAccessor = 'pieChart-title-'+this.props.axes[0]+'-'+this.props.axes[1];
+        else if (this.props.axes.length>0) titleAccessor = 'pieChart-title-'+this.props.axes[0];
+        if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
         var selected: string;
+        var curSelectedSliceName;
         if (this._currSelected){
+            curSelectedSliceName = StrCast(this._currSelected![this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))
             selected = '{ ';
             Object.keys(this._currSelected).map(key => {
                 key!=''? selected += key + ': ' + this._currSelected[key] + ', ': '';
@@ -402,9 +422,8 @@ export class PieChart extends React.Component<PieChartProps> {
             <div className="chart-container">
                 <div className="graph-title"> 
                     <EditableText
-                        val={title}
-                        setVal={action(val => {this.props.axes.length>1? this.props.layoutDoc['pieChart-title-'+this.props.axes[0]+"-"+this.props.axes[1]] = val as string
-                            : this.props.layoutDoc['pieChart-title-'+this.props.axes[0]] = val as string})}
+                        val={StrCast(this.props.layoutDoc[titleAccessor])}
+                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
@@ -418,7 +437,7 @@ export class PieChart extends React.Component<PieChartProps> {
                             tooltip={'Change Slice Color'} 
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
-                            selectedColor={this.curSliceSelected.attr("fill")}
+                            selectedColor={this.props.layoutDoc['pieSliceColors-'+curSelectedSliceName]? this.props.layoutDoc['pieSliceColors-'+curSelectedSliceName] : this.curSliceSelected.attr("fill")}
                             setSelectedColor={color => this.changeSelectedColor(color)}
                             size={Size.XSMALL}
                         />
-- 
cgit v1.2.3-70-g09d2


From 23e0ee2dcad8df2bc3467647e05c433f27787d54 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 3 Aug 2023 14:38:47 -0400
Subject: table fixes (selected by guid not extra row + ui changes)

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  17 +-
 .../views/nodes/DataVizBox/components/Chart.scss   |   1 +
 .../nodes/DataVizBox/components/Histogram.tsx      |  56 +---
 .../nodes/DataVizBox/components/LineChart.tsx      |   4 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx |  47 +---
 .../views/nodes/DataVizBox/components/TableBox.tsx | 310 +++++++--------------
 6 files changed, 135 insertions(+), 300 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 9a4de3c36..80586d7c7 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,9 +1,9 @@
-import { action, computed, observable, ObservableMap, ObservableSet } from 'mobx';
+import { action, computed, ObservableMap, ObservableSet } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, StrListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
-import { Cast, CsvCast, NumCast, StrCast } from '../../../../fields/Types';
+import { Cast, CsvCast, StrCast } from '../../../../fields/Types';
 import { CsvField } from '../../../../fields/URLField';
 import { Docs } from '../../../documents/Documents';
 import { ViewBoxAnnotatableComponent } from '../../DocComponent';
@@ -15,6 +15,7 @@ import './DataVizBox.scss';
 import { Histogram } from './components/Histogram';
 import { PieChart } from './components/PieChart';
 import { Toggle, ToggleType, Type } from 'browndash-components';
+import { Utils } from '../../../../Utils';
 
 export enum DataVizView {
     TABLE = 'table',
@@ -35,9 +36,11 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     // @observable private pairs: { [key: string]: FieldResult }[] = [];
     static pairSet = new ObservableMap<string, { [key: string]: string }[]>();
     @computed.struct get pairs() {
-        return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
+        var pairs = DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
+        pairs?.map(pair => {if (!pair.guid) pair.guid = Utils.GenerateGuid()})
+        return pairs;
     }
-    private _chartRenderer: LineChart | undefined;
+    private _chartRenderer: LineChart | Histogram | PieChart | undefined;
     // // another way would be store a schema that defines the type of data we are expecting from an imported doc
 
     // method1() {
@@ -116,10 +119,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const margin = { top: 10, right: 25, bottom: 50, left: 25 };
         if (!this.pairs) return 'no data';
         switch (this.dataVizView) {
-            case DataVizView.TABLE:     return <TableBox pairs={this.pairs} axes={this.axes} height={height} width={width} margin={margin} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
+            case DataVizView.TABLE:     return <TableBox layoutDoc={this.layoutDoc} pairs={this.pairs} axes={this.axes} height={height} width={width} margin={margin} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
             case DataVizView.LINECHART: return <LineChart layoutDoc={this.layoutDoc} ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
-            case DataVizView.HISTOGRAM: return <Histogram layoutDoc={this.layoutDoc} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
-            case DataVizView.PIECHART: return <PieChart layoutDoc={this.layoutDoc} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
+            case DataVizView.HISTOGRAM: return <Histogram layoutDoc={this.layoutDoc} ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
+            case DataVizView.PIECHART: return <PieChart layoutDoc={this.layoutDoc} ref={r => (this._chartRenderer = r ?? undefined)} height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
         }
     }
     @computed get dataUrl() {
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index 6c87241b8..996183cb8 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -77,4 +77,5 @@
 }
 .table-container{
     overflow: scroll;
+    margin: 10px;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 89dcf87db..efe17297b 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -1,15 +1,13 @@
 import { observer } from "mobx-react";
-import { Doc, DocListCast, FieldResult } from "../../../../../fields/Doc";
+import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc";
 import * as React from 'react';
 import * as d3 from 'd3';
 import { IReactionDisposer, action, computed, observable, reaction } from "mobx";
 import { LinkManager } from "../../../../util/LinkManager";
-import { Cast, DocCast, StrCast} from "../../../../../fields/Types";
-import { DataPoint, SelectedDataPoint } from "./LineChart";
+import { DocCast, StrCast} from "../../../../../fields/Types";
 import { DocumentManager } from "../../../../util/DocumentManager";
 import { Id } from "../../../../../fields/FieldSymbols";
 import { DataVizBox } from "../DataVizBox";
-import { listSpec } from "../../../../../fields/Schema";
 import { PinProps, PresBox } from "../../trails";
 import { Docs } from "../../../../documents/Documents";
 import { List } from "../../../../../fields/List";
@@ -54,7 +52,7 @@ export class Histogram extends React.Component<HistogramProps> {
             var ax0 = this.props.axes[0];
             if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true }
             return this.props.pairs
-                ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+                ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
         };
 
@@ -63,13 +61,8 @@ export class Histogram extends React.Component<HistogramProps> {
         if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;}
         if (/\d/.test(this.props.pairs[0][ax1]) && this.props.pairs.length < this.maxBins) { this.numericalYData = true;}
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
-            // .sort((a, b) => (a[ax0] < b[ax0] ? -1 : 1));
-        return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
-            .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
-            .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
     @computed get defaultGraphTitle(){
         var ax0 = this.props.axes[0];
@@ -181,27 +174,16 @@ export class Histogram extends React.Component<HistogramProps> {
     }
 
     @action
-    restoreView = (data: Doc) => {
-        const coords = Cast(data.presDataVizSelection, listSpec('number'), null);
-        if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) {
-            this.setCurrSelected(coords[0], coords[1]);
-            return true;
-        }
-        if (this._currSelected) {
-            this.setCurrSelected();
-            return true;
-        }
-        return false;
-    };
+    restoreView = (data: Doc) => {};
 
     // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc)
     getAnchor = (pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
             //
-            title: 'histogram doc selection' + this._currSelected?.x,
+            title: 'histogram doc selection' + this._currSelected,
         });
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc);
-        anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
+        anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected]) : undefined;
         return anchor;
     };
 
@@ -213,28 +195,6 @@ export class Histogram extends React.Component<HistogramProps> {
         return this.props.width - this.props.margin.left - this.props.margin.right;
     }
 
-    setupTooltip() {
-        return d3
-            .select(this._histogramRef.current)
-            .append('div')
-            .attr('class', 'tooltip')
-            .style('opacity', 0)
-            .style('background', '#fff')
-            .style('border', '1px solid #ccc')
-            .style('padding', '5px')
-            .style('position', 'absolute')
-            .style('font-size', '12px');
-    }
-
-    // TODO: nda - use this everyewhere we update currSelected?
-    @action
-    setCurrSelected(x?: number, y?: number) {
-        // TODO: nda - get rid of svg element in the list?
-        this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined;
-        this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true));
-        this.props.pairs.forEach(pair => (pair.selected = pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y ? true : undefined));
-    }
-
     data = (dataSet: any) => {
         var validData = dataSet.filter((d: { [x: string]: unknown; }) => {
             var valid = true;
@@ -364,7 +324,7 @@ export class Histogram extends React.Component<HistogramProps> {
             const selected = svg.selectAll('.histogram-bar').filter((d: any) => {
                 barCounter++;
                 if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){
-                    var showSelected = this.numericalYData? this.props.pairs.filter((data: { [x: string]: any; }) => data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')==d[0])[0] 
+                    var showSelected = this.numericalYData? this._histogramData.filter((data: { [x: string]: any; }) => data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')==d[0])[0] 
                     : histDataSet.filter((data: { [x: string]: any; }) => data[xAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')==d[0])[0];
                     if (this.numericalXData){
                         if (d[0] && d[1] && d[0]!=d[1]){
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 0e699bb99..da5f7dbbb 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -2,7 +2,7 @@ import { action, computed, IReactionDisposer, observable, reaction } from 'mobx'
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import * as d3 from 'd3';
-import { Doc, DocListCast } from '../../../../../fields/Doc';
+import { Doc, DocListCast, StrListCast } from '../../../../../fields/Doc';
 import { Id } from '../../../../../fields/FieldSymbols';
 import { List } from '../../../../../fields/List';
 import { listSpec } from '../../../../../fields/Schema';
@@ -51,7 +51,7 @@ export class LineChart extends React.Component<LineChartProps> {
     @computed get _lineChartData() {
         if (this.props.axes.length <= 1) return [];
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
             .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
             .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index d01d4429f..f3a72a53b 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -1,15 +1,13 @@
 import { observer } from "mobx-react";
-import { Doc, DocListCast } from "../../../../../fields/Doc";
+import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc";
 import * as React from 'react';
 import * as d3 from 'd3';
 import { IReactionDisposer, action, computed, observable, reaction } from "mobx";
 import { LinkManager } from "../../../../util/LinkManager";
-import { Cast, DocCast, StrCast} from "../../../../../fields/Types";
-import { DataPoint, SelectedDataPoint } from "./LineChart";
+import { DocCast, StrCast} from "../../../../../fields/Types";
 import { DocumentManager } from "../../../../util/DocumentManager";
 import { Id } from "../../../../../fields/FieldSymbols";
 import { DataVizBox } from "../DataVizBox";
-import { listSpec } from "../../../../../fields/Schema";
 import { PinProps, PresBox } from "../../trails";
 import { Docs } from "../../../../documents/Documents";
 import { List } from "../../../../../fields/List";
@@ -52,7 +50,7 @@ export class PieChart extends React.Component<PieChartProps> {
             var ax0 = this.props.axes[0];
             if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false }
             return this.props.pairs
-                ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+                ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
         };
 
@@ -60,13 +58,8 @@ export class PieChart extends React.Component<PieChartProps> {
         var ax1 = this.props.axes[1];
         if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; }
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+            ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
-            // .sort((a, b) => (a[ax0] < b[ax0] ? -1 : 1));
-        return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
-            .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
-            .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
     @computed get defaultGraphTitle(){
         var ax0 = this.props.axes[0];
@@ -178,27 +171,16 @@ export class PieChart extends React.Component<PieChartProps> {
     }
 
     @action
-    restoreView = (data: Doc) => {
-        const coords = Cast(data.presDataVizSelection, listSpec('number'), null);
-        if (coords?.length > 1 && (this._currSelected?.x !== coords[0] || this._currSelected?.y !== coords[1])) {
-            this.setCurrSelected(coords[0], coords[1]);
-            return true;
-        }
-        if (this._currSelected) {
-            this.setCurrSelected();
-            return true;
-        }
-        return false;
-    };
+    restoreView = (data: Doc) => {};
 
     // create a document anchor that stores whatever is needed to reconstruct the viewing state (selection,zoom,etc)
     getAnchor = (pinProps?: PinProps) => {
         const anchor = Docs.Create.ConfigDocument({
             //
-            title: 'piechart doc selection' + this._currSelected?.x,
+            title: 'piechart doc selection' + this._currSelected,
         });
         PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: pinProps?.pinData }, this.props.dataDoc);
-        anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected.x, this._currSelected.y]) : undefined;
+        anchor.presDataVizSelection = this._currSelected ? new List<number>([this._currSelected]) : undefined;
         return anchor;
     };
 
@@ -210,19 +192,6 @@ export class PieChart extends React.Component<PieChartProps> {
         return this.props.width - this.props.margin.left - this.props.margin.right;
     }
 
-    setupTooltip() {
-        return d3
-            .select(this._piechartRef.current)
-            .append('div')
-            .attr('class', 'tooltip')
-            .style('opacity', 0)
-            .style('background', '#fff')
-            .style('border', '1px solid #ccc')
-            .style('padding', '5px')
-            .style('position', 'absolute')
-            .style('font-size', '12px');
-    }
-
     // TODO: nda - use this everyewhere we update currSelected?
     @action
     setCurrSelected(x?: number, y?: number) {
@@ -322,7 +291,7 @@ export class PieChart extends React.Component<PieChartProps> {
                 if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){
                     if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; }
                 if (lineCrossCount % 2 != 0) {
-                    var showSelected = this.byCategory? pieDataSet[index] : this.props.pairs[index];
+                    var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index];
                     sameAsCurrent = (this.byCategory && this._currSelected)? 
                         (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
                       && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 64c6dc940..5653adbce 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,21 +1,20 @@
-import { action, computed, observable } from 'mobx';
+import { action, computed, } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc } from '../../../../../fields/Doc';
-import { Id } from '../../../../../fields/FieldSymbols';
+import { Doc, StrListCast } from '../../../../../fields/Doc';
 import { List } from '../../../../../fields/List';
-import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../../../Utils';
+import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils';
 import { DragManager } from '../../../../util/DragManager';
 import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
 import { LinkManager } from '../../../../util/LinkManager';
 import { Cast, DocCast } from '../../../../../fields/Types';
-import { EditableText, Size, Type } from 'browndash-components';
 import './Chart.scss';
 import { listSpec } from '../../../../../fields/Schema';
 
 interface TableBoxProps {
     rootDoc: Doc;
+    layoutDoc: Doc;
     pairs: { [key: string]: any }[];
     selectAxes: (axes: string[]) => void;
     axes: string[];
@@ -32,13 +31,10 @@ interface TableBoxProps {
 
 @observer
 export class TableBox extends React.Component<TableBoxProps> {
-    @observable editableHeaders = this.columns;
-    @observable editableCells = this._tableData;
 
     @computed get _tableData() {
         if (this.incomingLinks.length! <= 0) return this.props.pairs;
-        /// StrListCast(this.incomingLinks[0].anchor_1.selected) ==> list of guids that the parent has selected
-        return this.props.pairs?.filter(pair => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+        return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))
     }
 
     @computed get incomingLinks() {
@@ -49,204 +45,110 @@ export class TableBox extends React.Component<TableBoxProps> {
     }
 
     @computed get columns() {
-        // return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : [];
-        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : [];
+        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='guid' && header!='') : [];
     }
 
-    // render() {
-    //     return (
-    //         <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
-    //             <table className="table">
-    //                 <thead>
-    //                     <tr className="table-row">
-    //                         {this.editableHeaders
-    //                             .filter(col => !col.startsWith('select'))
-    //                             .map(col => {
-    //                                 const header = React.createRef<HTMLElement>();
-    //                                 const displayColName = col;
-    //                                 return (
-    //                                     <th
-    //                                         key={this.editableHeaders.indexOf(col)}
-    //                                         ref={header as any}
-    //                                         style={{
-    //                                             color: this.props.axes.slice().reverse().lastElement() === col ? 'green' : this.props.axes.lastElement() === col ? 'red' : undefined,
-    //                                             fontWeight: this.props.axes.includes(col) ? 'bolder' : 'normal',
-    //                                         }}
-    //                                         onPointerDown={e => {
-    //                                             const downX = e.clientX;
-    //                                             const downY = e.clientY;
-    //                                             setupMoveUpEvents(
-    //                                                 {},
-    //                                                 e,
-    //                                                 e => {
-    //                                                     const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
-    //                                                     const targetCreator = (annotationOn: Doc | undefined) => {
-    //                                                         const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
-    //                                                         embedding._dataVizView = DataVizView.LINECHART;
-    //                                                         embedding._data_vizAxes = new List<string>([col, col]);
-    //                                                         embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
-    //                                                         embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
-    //                                                         return embedding;
-    //                                                     };
-    //                                                     if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
-    //                                                         DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
-    //                                                             dragComplete: e => {
-    //                                                                 if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-    //                                                                     e.linkDocument.link_displayLine = true;
-    //                                                                     e.linkDocument.link_matchEmbeddings = true;
-    //                                                                     // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
-    //                                                                     // e.annoDragData.linkSourceDoc.followLinkZoom = false;
-    //                                                                 }
-    //                                                             },
-    //                                                         });
-    //                                                         return true;
-    //                                                     }
-    //                                                     return false;
-    //                                                 },
-    //                                                 emptyFunction,
-    //                                                 action(e => {
-    //                                                     const newAxes = this.props.axes;
-    //                                                     if (newAxes.includes(col)) {
-    //                                                         newAxes.splice(newAxes.indexOf(col), 1);
-    //                                                     } else if (newAxes.length >= 1) {
-    //                                                         newAxes[1] = col;
-    //                                                     } else {
-    //                                                         newAxes[0] = col;
-    //                                                     }
-    //                                                     this.props.selectAxes(newAxes);
-    //                                                 })
-    //                                             );
-    //                                         }}>
-    //                                         <EditableText
-    //                                             val={displayColName}
-    //                                             setVal={action(val => {
-    //                                                 this.editableHeaders[this.editableHeaders.indexOf(col)] = val as string
-    //                                                 this.props.pairs.map(pair => {
-    //                                                     pair[val as string] = pair[col];
-    //                                                     delete pair[col]
-    //                                                 })
-    //                                             })}
-    //                                             color={"black"}
-    //                                             size={Size.LARGE}
-    //                                         />
-    //                                     </th>
-    //                                 );
-    //                             })}
-    //                     </tr>
-    //                 </thead>
-    //                 <tbody>
-    //                     {this._tableData?.map((p, i) => {
-    //                         return (
-    //                             <tr key={i} className="table-row" onClick={action(e => (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}>
-    //                                 {this.editableHeaders.map(col => (
-    //                                     <td key={this.editableHeaders.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>
-    //                                         {p[col]}
-    //                                     </td>
-    //                                 ))}
-    //                             </tr>
-    //                         );
-    //                     })}
-    //                 </tbody>
-    //             </table>
-    //         </div>
-    //     );
-    // }
-
-
     render() {
-        return (
-            <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
-                <table className="table">
-                    <thead>
-                        <tr className="table-row">
-                            {this.columns
-                                .filter(col => !col.startsWith('select'))
-                                .map(col => {
-                                    const header = React.createRef<HTMLElement>();
-                                    return (
-                                        <th
-                                            key={this.columns.indexOf(col)}
-                                            ref={header as any}
-                                            style={{
-                                                color: this.props.axes.slice().reverse().lastElement() === col ? 'green' : this.props.axes.lastElement() === col ? 'red' : undefined,
-                                                fontWeight: this.props.axes.includes(col) ? 'bolder' : 'normal',
-                                            }}
-                                            onPointerDown={e => {
-                                                const downX = e.clientX;
-                                                const downY = e.clientY;
-                                                setupMoveUpEvents(
-                                                    {},
-                                                    e,
-                                                    e => {
-                                                        const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
-                                                        const targetCreator = (annotationOn: Doc | undefined) => {
-                                                            const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
-                                                            embedding._dataVizView = DataVizView.LINECHART;
-                                                            embedding._data_vizAxes = new List<string>([col, col]);
-                                                            embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
-                                                            embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
-                                                            return embedding;
-                                                        };
-                                                        if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
-                                                            DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
-                                                                dragComplete: e => {
-                                                                    if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
-                                                                        e.linkDocument.link_displayLine = true;
-                                                                        e.linkDocument.link_matchEmbeddings = true;
-                                                                        // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
-                                                                        // e.annoDragData.linkSourceDoc.followLinkZoom = false;
-                                                                    }
-                                                                },
-                                                            });
-                                                            return true;
-                                                        }
-                                                        return false;
-                                                    },
-                                                    emptyFunction,
-                                                    action(e => {
-                                                        const newAxes = this.props.axes;
-                                                        if (newAxes.includes(col)) {
-                                                            newAxes.splice(newAxes.indexOf(col), 1);
-                                                        } else if (newAxes.length >= 1) {
-                                                            newAxes[1] = col;
-                                                        } else {
-                                                            newAxes[0] = col;
-                                                        }
-                                                        this.props.selectAxes(newAxes);
-                                                    })
-                                                );
-                                            }}>
-                                            {col}
-                                        </th>
-                                    );
-                                })}
-                        </tr>
-                    </thead>
-                    <tbody>
-                        {this._tableData?.map((p, i) => {
-                            return (
-                                <tr key={i} className="table-row" onClick={action(e => {
-                                        // if (!this.props.docView?.()!.layoutDoc.selected) 
-                                        //     this.props.docView!.()!.layoutDoc.selected = new List<string>();
-                                        // const selected = Cast(this.props.docView?.()!.layoutDoc.selected, listSpec("string"), null);
-                                        //                    // StrListCast(this.props.docView?.()!.layoutDoc.selected)
-                                        // selected.push(p.guid);
-                                        (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]])
-                                    })}>
-                                    {this.columns.map(col => (
-                                        <td key={this.columns.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>
-                                            {p[col]}
-                                        </td>
-                                    ))}
-                                </tr>
-                            );
-                        })}
-                    </tbody>
-                </table>
+        if (this._tableData.length>0){
+            return (
+                <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
+                    <table className="table">
+                        <thead>
+                            <tr className="table-row">
+                                {this.columns
+                                    .filter(col => !col.startsWith('select'))
+                                    .map(col => {
+                                        const header = React.createRef<HTMLElement>();
+                                        return (
+                                            <th
+                                                key={this.columns.indexOf(col)}
+                                                ref={header as any}
+                                                style={{
+                                                    color: this.props.axes.slice().reverse().lastElement() === col ? 'green' : this.props.axes.lastElement() === col ? 'red' : undefined,
+                                                    fontWeight: 'bolder', border: '3px solid black'
+                                                }}
+                                                onPointerDown={e => {
+                                                    const downX = e.clientX;
+                                                    const downY = e.clientY;
+                                                    setupMoveUpEvents(
+                                                        {},
+                                                        e,
+                                                        e => {
+                                                            const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
+                                                            const targetCreator = (annotationOn: Doc | undefined) => {
+                                                                const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
+                                                                embedding._dataVizView = DataVizView.TABLE;
+                                                                embedding._data_vizAxes = new List<string>([col, col]);
+                                                                embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
+                                                                embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
+                                                                return embedding;
+                                                            };
+                                                            if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
+                                                                DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, {
+                                                                    dragComplete: e => {
+                                                                        if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) {
+                                                                            e.linkDocument.link_displayLine = true;
+                                                                            e.linkDocument.link_matchEmbeddings = true;
+                                                                            // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc;
+                                                                            // e.annoDragData.linkSourceDoc.followLinkZoom = false;
+                                                                        }
+                                                                    },
+                                                                });
+                                                                return true;
+                                                            }
+                                                            return false;
+                                                        },
+                                                        emptyFunction,
+                                                        action(e => {
+                                                            const newAxes = this.props.axes;
+                                                            if (newAxes.includes(col)) {
+                                                                newAxes.splice(newAxes.indexOf(col), 1);
+                                                            } else if (newAxes.length >= 1) {
+                                                                newAxes[1] = col;
+                                                            } else {
+                                                                newAxes[0] = col;
+                                                            }
+                                                            this.props.selectAxes(newAxes);
+                                                        })
+                                                    );
+                                                }}>
+                                                {col}
+                                            </th>
+                                        );
+                                    })}
+                            </tr>
+                        </thead>
+                        <tbody>
+                            {this._tableData?.map((p, i) => {
+                                return (
+                                    <tr key={i} className="table-row" onClick={action(e => {
+                                            if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List<string>();
+                                            const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null);
+                                            if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1);
+                                            else {
+                                                selected.push(p.guid)};
+                                        })} style={
+                                            { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%',
+                                            background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}>
+                                        {this.columns.map(col => (
+                                            (this.props.layoutDoc.selected)?
+                                                <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}>
+                                                    {p[col]}
+                                                </td>
+                                            : <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}> {p[col]} </td>
+                                        ))}
+                                    </tr>
+                                );
+                            })}
+                        </tbody>
+                    </table>
+                </div>
+            );
+        }
+        else return (
+            <div className='chart-container'>
+                Selected rows of data from the incoming DataVizBox to display.
             </div>
-        );
+        )
     }
-
-
-
 }
-- 
cgit v1.2.3-70-g09d2


From bee66361d878c366e8c753ca844abc2f78fbf7f3 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Fri, 4 Aug 2023 14:52:35 -0400
Subject: better row guids so selected rows stay on refresh

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx        |  5 +----
 .../views/nodes/DataVizBox/components/Histogram.tsx     |  5 +++--
 .../views/nodes/DataVizBox/components/LineChart.tsx     |  3 ++-
 .../views/nodes/DataVizBox/components/PieChart.tsx      |  5 +++--
 .../views/nodes/DataVizBox/components/TableBox.tsx      | 17 +++++++++++------
 5 files changed, 20 insertions(+), 15 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index a92fc1eb9..8b951a002 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -15,7 +15,6 @@ import './DataVizBox.scss';
 import { Histogram } from './components/Histogram';
 import { PieChart } from './components/PieChart';
 import { Toggle, ToggleType, Type } from 'browndash-components';
-import { Utils } from '../../../../Utils';
 
 export enum DataVizView {
     TABLE = 'table',
@@ -36,9 +35,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     // @observable private pairs: { [key: string]: FieldResult }[] = [];
     static pairSet = new ObservableMap<string, { [key: string]: string }[]>();
     @computed.struct get pairs() {
-        var pairs = DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
-        pairs?.map(pair => {if (!pair.guid) pair.guid = Utils.GenerateGuid()})
-        return pairs;
+        return DataVizBox.pairSet.get(CsvCast(this.rootDoc[this.fieldKey]).url.href);
     }
     private _chartRenderer: LineChart | Histogram | PieChart | undefined;
     // // another way would be store a schema that defines the type of data we are expecting from an imported doc
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 02f1ddbbb..a9be151bc 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -49,12 +49,13 @@ export class Histogram extends React.Component<HistogramProps> {
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _histogramData() {
+        var guids = StrListCast(this.props.layoutDoc.rowGuids);
         if (this.props.axes.length < 1) return [];
         if (this.props.axes.length < 2) {
             var ax0 = this.props.axes[0];
             if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalXData = true }
             return this.props.pairs
-                ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
+                ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
         };
 
@@ -63,7 +64,7 @@ export class Histogram extends React.Component<HistogramProps> {
         if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;}
         if (/\d/.test(this.props.pairs[0][ax1]) && this.props.pairs.length < this.maxBins) { this.numericalYData = true;}
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
+            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
     }
     @computed get defaultGraphTitle(){
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index da5f7dbbb..77b3acf47 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -49,9 +49,10 @@ export class LineChart extends React.Component<LineChartProps> {
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _lineChartData() {
+        var guids = StrListCast(this.props.layoutDoc.rowGuids);
         if (this.props.axes.length <= 1) return [];
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
+            ?.filter(pair => (!this.incomingLinks.length ? true : this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])))
             .map(pair => ({ x: Number(pair[this.props.axes[0]]), y: Number(pair[this.props.axes[1]]) }))
             .sort((a, b) => (a.x < b.x ? -1 : 1));
     }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 8fdead3d7..cc5cc231b 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -46,12 +46,13 @@ export class PieChart extends React.Component<PieChartProps> {
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _piechartData() {
+        var guids = StrListCast(this.props.layoutDoc.rowGuids);
         if (this.props.axes.length < 1) return [];
         if (this.props.axes.length < 2) {
             var ax0 = this.props.axes[0];
             if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false }
             return this.props.pairs
-                ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
+                ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
         };
 
@@ -59,7 +60,7 @@ export class PieChart extends React.Component<PieChartProps> {
         var ax1 = this.props.axes[1];
         if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; }
         return this.props.pairs
-            ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid)))
+            ?.filter(pair => (!this.incomingLinks.length ? true :  this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)])))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
     }
     @computed get defaultGraphTitle(){
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index f244502a4..7d6f934b9 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -34,7 +34,8 @@ export class TableBox extends React.Component<TableBoxProps> {
 
     @computed get _tableData() {
         if (this.incomingLinks.length! <= 0) return this.props.pairs;
-        return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(pair.guid))
+        var guids = StrListCast(this.props.layoutDoc.rowGuids);
+        return this.props.pairs?.filter(pair => this.incomingLinks[0]!.selected && StrListCast(this.incomingLinks[0].selected).includes(guids[this.props.pairs.indexOf(pair)]))
     }
 
     @computed get incomingLinks() {
@@ -45,7 +46,10 @@ export class TableBox extends React.Component<TableBoxProps> {
     }
 
     @computed get columns() {
-        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='guid' && header!='') : [];
+        if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List<string>();
+        const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null);
+        if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid()));
+        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : [];
     }
 
     render() {
@@ -121,18 +125,19 @@ export class TableBox extends React.Component<TableBoxProps> {
                         <tbody>
                             {this._tableData?.map((p, i) => {
                                 var containsData = false;
+                                var guid = StrListCast(this.props.layoutDoc.rowGuids)![this.props.pairs.indexOf(p)]
                                 this.columns.map(col => {if (p[col]!='' && p[col]!=null && p[col]!=undefined) containsData = true})
                                 if (containsData){
                                     return (
                                         <tr key={i} className="table-row" onClick={action(e => {
                                                 if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List<string>();
                                                 const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null);
-                                                if (selected.includes(p.guid)) selected.splice(selected.indexOf(p.guid), 1);
+                                                if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1);
                                                 else {
-                                                    selected.push(p.guid)};
+                                                    selected.push(guid)};
                                             })} style={
-                                                { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'bold' : '' , width: '110%',
-                                                background: StrListCast(this.props.layoutDoc.selected).includes(p.guid) ? 'lightgrey' : '' }}>
+                                                { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'bold' : '' , width: '110%',
+                                                background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}>
                                             {this.columns.map(col => (
                                                 (this.props.layoutDoc.selected)?
                                                     <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}>
-- 
cgit v1.2.3-70-g09d2


From 85f91733a21c7b41829eb9280ce33e90783c926d Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Mon, 7 Aug 2023 13:30:40 -0400
Subject: selected data at bottom of graph

---
 src/client/views/nodes/DataVizBox/DataVizBox.scss          | 2 +-
 src/client/views/nodes/DataVizBox/DataVizBox.tsx           | 2 +-
 src/client/views/nodes/DataVizBox/components/Chart.scss    | 7 +++++--
 src/client/views/nodes/DataVizBox/components/Histogram.tsx | 2 +-
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 5 +++--
 src/client/views/nodes/DataVizBox/components/PieChart.tsx  | 2 +-
 src/client/views/nodes/DataVizBox/components/TableBox.tsx  | 4 ++--
 7 files changed, 14 insertions(+), 10 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index ab2f19726..a69881b7c 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -1,5 +1,5 @@
 .dataviz {
-    overflow: hidden;
+    overflow: scroll;
     height: 100%;
     width: 100%;
 
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 8b951a002..9a4546900 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -116,7 +116,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     @computed get selectView() {
         const width = this.props.PanelWidth() * 0.9;
         const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
-        const margin = { top: 10, right: 25, bottom: 50, left: 25 };
+        const margin = { top: 10, right: 25, bottom: 75, left: 45 };
         if (!this.pairs) return 'no data';
         switch (this.dataVizView) {
             case DataVizView.TABLE:     return <TableBox layoutDoc={this.layoutDoc} pairs={this.pairs} axes={this.axes} height={height} width={width} margin={margin} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index 996183cb8..35e5187b2 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -4,6 +4,7 @@
     align-items: center;
     cursor: default;
     margin-top: 10px;
+    overflow-y: visible;
 
     .graph{
         overflow: visible;
@@ -22,8 +23,8 @@
         display: flex;
         flex-direction: row;
         margin: 10px;
-        margin-top: 0px;
-        margin-bottom: -5px;
+        margin-top: -25px;
+        margin-bottom: 5px;
     }
     .slice {
         &.hover {
@@ -78,4 +79,6 @@
 .table-container{
     overflow: scroll;
     margin: 10px;
+    margin-left: 25px;
+    margin-top: 25px;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 2a47abf32..cb882cf4a 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -454,6 +454,7 @@ export class Histogram extends React.Component<HistogramProps> {
                         size={Size.XSMALL}
                     />
                 </div>
+                <div ref={this._histogramRef} />
                 {selected != 'none' ? 
                     <div className={'selected-data'}>
                         Selected: {selected}
@@ -477,7 +478,6 @@ export class Histogram extends React.Component<HistogramProps> {
                         />
                     </div>
                 : null}
-                <div ref={this._histogramRef} />
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 77b3acf47..3a416c401 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -216,7 +216,6 @@ export class LineChart extends React.Component<LineChartProps> {
         // TODO: nda - get rid of svg element in the list?
         this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined;
         this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true));
-        this.props.pairs.forEach(pair => (pair.selected = pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y ? true : undefined));
     }
 
     drawDataPoints(data: DataPoint[], idx: number, xScale: d3.ScaleLinear<number, number, never>, yScale: d3.ScaleLinear<number, number, never>) {
@@ -369,8 +368,10 @@ export class LineChart extends React.Component<LineChartProps> {
                         fillWidth
                     />
                 </div>
-                <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
                 <div ref={this._lineChartRef} />
+                {selectedPt!='none'? 
+                    <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
+                : null}
             </div>
             ) : <span className="chart-container"> {'first use table view to select two axes to plot'}</span>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index cc5cc231b..ca93a2942 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -410,6 +410,7 @@ export class PieChart extends React.Component<PieChartProps> {
                         fillWidth
                     />
                 </div>
+                <div ref={this._piechartRef} />
                 {selected != 'none' ? 
                     <div className={'selected-data'}>
                         Selected: {selected}
@@ -424,7 +425,6 @@ export class PieChart extends React.Component<PieChartProps> {
                         />
                     </div>
                 : null}
-                <div ref={this._piechartRef} />
             </div>
             ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index a7cc3f2fb..38dd62d8d 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -49,7 +49,7 @@ export class TableBox extends React.Component<TableBoxProps> {
         if (!this.props.layoutDoc.rowGuids) this.props.layoutDoc.rowGuids = new List<string>();
         const guids = Cast(this.props.layoutDoc.rowGuids, listSpec("string"), null);
         if (guids.length==0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid()));
-        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : [];
+        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : [];
     }
 
     filterSelectedRowsDown() {
@@ -66,7 +66,7 @@ export class TableBox extends React.Component<TableBoxProps> {
         this.filterSelectedRowsDown();
         if (this._tableData.length>0){
             return (
-                <div className="table-container" style={{height: this.props.height+this.props.margin.top+this.props.margin.bottom}}>
+                <div className="table-container" style={{height: this.props.height}}>
                     <table className="table">
                         <thead>
                             <tr className="table-row">
-- 
cgit v1.2.3-70-g09d2


From b44722cc4e35b994ad50d47cf2586785b3e0ab2d Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 8 Aug 2023 11:19:54 -0400
Subject: hover vs click working for all 3 graph types

---
 .../nodes/DataVizBox/components/Histogram.tsx      |   6 +-
 .../nodes/DataVizBox/components/LineChart.tsx      |   3 +-
 .../views/nodes/DataVizBox/components/PieChart.tsx | 102 +++++++++++++--------
 3 files changed, 68 insertions(+), 43 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 092718e17..6591581f7 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -282,7 +282,7 @@ export class Histogram extends React.Component<HistogramProps> {
                 }
                 for (let i=0; i<data.length; i++){
                     let barData = histStringDataSet.filter(each => each[xAxisTitle]==data[i])
-                    barData[0][yAxisTitle] = barData[0][yAxisTitle] + 1;
+                    barData[0][yAxisTitle] = Number(barData[0][yAxisTitle]) + 1;
                 }
             }
             histDataSet = histStringDataSet
@@ -340,7 +340,7 @@ export class Histogram extends React.Component<HistogramProps> {
             xAxis = d3.axisBottom(x)
                 .ticks(numBins-1)
         }
-        const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d) { return d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')})
+        const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { return d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')})
                     : d3.max(bins, function(d) { return d.length; })
 
         var y = d3.scaleLinear()
@@ -366,7 +366,7 @@ export class Histogram extends React.Component<HistogramProps> {
         const updateHighlights = () => {
             const hoverOverBar = this.hoverOverData;
             const selectedData = this.selectedData;
-            svg.selectAll('rect').attr("class", function(d) { return ((hoverOverBar && hoverOverBar[0]==d[0]) || selectedData && selectedData[0]==d[0])? 'histogram-bar hover' : 'histogram-bar'; })
+            svg.selectAll('rect').attr("class", function(d: any) { return ((hoverOverBar && hoverOverBar[0]==d[0]) || selectedData && selectedData[0]==d[0])? 'histogram-bar hover' : 'histogram-bar'; })
         }
 
         svg.on('click', onPointClick)
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 3a416c401..16794886e 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -214,7 +214,8 @@ export class LineChart extends React.Component<LineChartProps> {
     @action
     setCurrSelected(x?: number, y?: number) {
         // TODO: nda - get rid of svg element in the list?
-        this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined;
+        if (this._currSelected && this._currSelected.x==x && this._currSelected.y==y) this._currSelected = undefined;
+        else this._currSelected = x !== undefined && y !== undefined ? { x, y } : undefined;
         this.props.pairs.forEach(pair => pair[this.props.axes[0]] === x && pair[this.props.axes[1]] === y && (pair.selected = true));
     }
 
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index ca93a2942..913bdd9a4 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -43,6 +43,7 @@ export class PieChart extends React.Component<PieChartProps> {
     @observable _currSelected: any | undefined = undefined;
     private curSliceSelected: any = undefined;
     private selectedData: any = undefined;
+    private hoverOverData: any = undefined;
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
     @computed get _piechartData() {
@@ -219,6 +220,50 @@ export class PieChart extends React.Component<PieChartProps> {
         return data;
     }
 
+    highlightSelectedSlice = (changeSelectedVariables: boolean, svg: any, arc: any, radius: any, pointer: any, pieDataSet: any) => {
+            var index = -1;
+            var sameAsCurrent: boolean;
+            const selected = svg.selectAll('.slice').filter((d: any) => {
+                index++;
+                var p1 = [0,0];
+                var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2];
+                var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)];
+                var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)];
+
+                // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge
+                var lineCrossCount = 0;
+                // if for all 4 lines
+                if (Math.min(p1[1], p2[1])<=pointer[1] && pointer[1]<=Math.max(p1[1], p2[1])){ // within y bounds
+                    if (pointer[0] <= (pointer[1]-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1])+p1[0]) lineCrossCount++; } // intercepts x
+                if (Math.min(p2[1], p3[1])<=pointer[1] && pointer[1]<=Math.max(p2[1], p3[1])){
+                    if (pointer[0] <= (pointer[1]-p2[1])*(p3[0]-p2[0])/(p3[1]-p2[1])+p2[0]) lineCrossCount++; }
+                if (Math.min(p3[1], p4[1])<=pointer[1] && pointer[1]<=Math.max(p3[1], p4[1])){
+                    if (pointer[0] <= (pointer[1]-p3[1])*(p4[0]-p3[0])/(p4[1]-p3[1])+p3[0]) lineCrossCount++; }
+                if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){
+                    if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; }
+                if (lineCrossCount % 2 != 0) {
+                    var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index];
+
+                    if (changeSelectedVariables){
+                        sameAsCurrent = (this.byCategory && this._currSelected)? 
+                            (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
+                        && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
+                            : 
+                            this._currSelected===showSelected;
+                        this._currSelected = sameAsCurrent? undefined: showSelected;
+                        this.selectedData = sameAsCurrent? undefined: d;
+                    }
+                    else this.hoverOverData = d;
+                    return true;
+                }
+                return false;
+            });
+            if (changeSelectedVariables){
+                if (sameAsCurrent!) this.curSliceSelected = undefined;
+                else  this.curSliceSelected = selected;
+            }
+    }
+
     drawChart = (dataSet: any, width: number, height: number) => {
         d3.select(this._piechartRef.current).select('svg').remove();
         d3.select(this._piechartRef.current).select('.tooltip').remove();
@@ -269,45 +314,22 @@ export class PieChart extends React.Component<PieChartProps> {
             .innerRadius(0)
             .outerRadius(radius);
 
-        const onPointClick = action((e: any) => {
-            // check the 4 'corners' of each slice and see if the pointer is within those bounds to get the slice the user clicked on
-            const pointer = d3.pointer(e);
-            var index = -1;
-            var sameAsCurrent: boolean;
-            const selected = svg.selectAll('.slice').filter((d: any) => {
-                index++;
-                var p1 = [0,0];
-                var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2];
-                var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)];
-                var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)];
-
-                // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge
-                var lineCrossCount = 0;
-                // if for all 4 lines
-                if (Math.min(p1[1], p2[1])<=pointer[1] && pointer[1]<=Math.max(p1[1], p2[1])){ // within y bounds
-                    if (pointer[0] <= (pointer[1]-p1[1])*(p2[0]-p1[0])/(p2[1]-p1[1])+p1[0]) lineCrossCount++; } // intercepts x
-                if (Math.min(p2[1], p3[1])<=pointer[1] && pointer[1]<=Math.max(p2[1], p3[1])){
-                    if (pointer[0] <= (pointer[1]-p2[1])*(p3[0]-p2[0])/(p3[1]-p2[1])+p2[0]) lineCrossCount++; }
-                if (Math.min(p3[1], p4[1])<=pointer[1] && pointer[1]<=Math.max(p3[1], p4[1])){
-                    if (pointer[0] <= (pointer[1]-p3[1])*(p4[0]-p3[0])/(p4[1]-p3[1])+p3[0]) lineCrossCount++; }
-                if (Math.min(p4[1], p1[1])<=pointer[1] && pointer[1]<=Math.max(p4[1], p1[1])){
-                    if (pointer[0] <= (pointer[1]-p4[1])*(p1[0]-p4[0])/(p1[1]-p4[1])+p4[0]) lineCrossCount++; }
-                if (lineCrossCount % 2 != 0) {
-                    var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index];
-                    sameAsCurrent = (this.byCategory && this._currSelected)? 
-                        (showSelected[Object.keys(showSelected)[0]]==this._currSelected![Object.keys(showSelected)[0]] 
-                      && showSelected[Object.keys(showSelected)[1]]==this._currSelected![Object.keys(showSelected)[1]])
-                        : 
-                        this._currSelected===showSelected;
-                    this._currSelected = sameAsCurrent? undefined: showSelected;
-                    this.selectedData = sameAsCurrent? undefined: d;
-                    return true;
-                }
-                return false;
-            });
-            if (sameAsCurrent!) this.curSliceSelected = undefined;
-            else  this.curSliceSelected = selected;
-        });
+        const onPointClick = action((e: any) => this.highlightSelectedSlice(true, svg, arc, radius, d3.pointer(e), pieDataSet));
+        const onHover = action((e: any) => {
+            const selected = this.highlightSelectedSlice(false, svg, arc, radius, d3.pointer(e), pieDataSet)
+            updateHighlights();
+        })
+        const mouseOut = action((e: any) => {
+            this.hoverOverData = undefined;
+            updateHighlights();
+        })
+        const updateHighlights = () => {
+            const hoverOverSlice = this.hoverOverData;
+            const selectedData = this.selectedData;
+            svg.selectAll('path').attr("class", function(d: any) { 
+                return ((selectedData && d.startAngle==selectedData.startAngle && d.endAngle==selectedData.endAngle)
+                    || ((hoverOverSlice && d.startAngle==hoverOverSlice.startAngle && d.endAngle==hoverOverSlice.endAngle)))? 'slice hover' : 'slice'; })
+        }
 
         var selected = this.selectedData;
         var arcs = g.selectAll("arc")
@@ -339,6 +361,8 @@ export class PieChart extends React.Component<PieChartProps> {
                 }: function(d) {return 'slice'})
             .attr("d", arc)
             .on('click', onPointClick)
+            .on('mouseover', onHover)
+            .on('mouseout', mouseOut);
 
         trackDuplicates = {};
         data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
-- 
cgit v1.2.3-70-g09d2


From 79a5cddf969a027811a9b7069f8ae8614b825a05 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Wed, 9 Aug 2023 12:58:59 -0400
Subject: display clarification for when a string column is given to a
 LineChart

---
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 16794886e..053696807 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -358,7 +358,7 @@ export class LineChart extends React.Component<LineChartProps> {
         if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
         const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
         return (
-            this.props.axes.length >= 2 ? (
+            this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
             <div className="chart-container" >
                 <div className="graph-title"> 
                     <EditableText
@@ -374,7 +374,7 @@ export class LineChart extends React.Component<LineChartProps> {
                     <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
                 : null}
             </div>
-            ) : <span className="chart-container"> {'first use table view to select two axes to plot'}</span>
+            ) : <span className="chart-container"> {'first use table view to select two numerical axes to plot'}</span>
         );
     }
 }
-- 
cgit v1.2.3-70-g09d2


From a89ba9afe33d973c50c0a66aec73db1e22367913 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 10 Aug 2023 11:28:09 -0400
Subject: undo/redo for colors + titles

---
 src/client/views/nodes/DataVizBox/components/Histogram.tsx | 9 +++++----
 src/client/views/nodes/DataVizBox/components/LineChart.tsx | 3 ++-
 src/client/views/nodes/DataVizBox/components/PieChart.tsx  | 5 +++--
 3 files changed, 10 insertions(+), 7 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index ed663006f..883cc006b 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -14,6 +14,7 @@ import { FaFillDrip } from "react-icons/fa";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { listSpec } from "../../../../../fields/Schema";
 import { scaleCreatorNumerical, yAxisCreator } from "../utils/D3Utils";
+import { undoBatch, undoable } from "../../../../util/UndoManager";
 
 export interface HistogramProps {
     rootDoc: Doc;
@@ -426,7 +427,7 @@ export class Histogram extends React.Component<HistogramProps> {
                 <div className="graph-title"> 
                     <EditableText
                         val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
+                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
@@ -437,7 +438,7 @@ export class Histogram extends React.Component<HistogramProps> {
                         type={Type.SEC} 
                         icon={<FaFillDrip/>}
                         selectedColor={StrCast(this.props.layoutDoc.defaultHistogramColor)}
-                        setSelectedColor={color => this.props.layoutDoc.defaultHistogramColor = color}
+                        setSelectedColor={undoable (color => this.props.layoutDoc.defaultHistogramColor = color, "Change Default Bar Color")}
                         size={Size.XSMALL}
                     />
                 </div>
@@ -451,7 +452,7 @@ export class Histogram extends React.Component<HistogramProps> {
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
                             selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")}
-                            setSelectedColor={color => this.changeSelectedColor(color)}
+                            setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Bar Color")}
                             size={Size.XSMALL}
                         />
                         &nbsp;
@@ -461,7 +462,7 @@ export class Histogram extends React.Component<HistogramProps> {
                             color={'black'} 
                             type={Type.SEC}
                             tooltip={'Revert to the default bar color'}
-                            onClick={action(() => this.eraseSelectedColor())}
+                            onClick={undoable (action(() => this.eraseSelectedColor()), "Change Selected Bar Color")}
                         />
                     </div>
                 : null}
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 053696807..49ef577e4 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -15,6 +15,7 @@ import { DataVizBox } from '../DataVizBox';
 import { createLineGenerator, drawLine, minMaxRange, scaleCreatorNumerical, xAxisCreator, xGrid, yAxisCreator, yGrid } from '../utils/D3Utils';
 import './Chart.scss';
 import { EditableText, Size } from 'browndash-components';
+import { undoable } from '../../../../util/UndoManager';
 
 export interface DataPoint {
     x: number;
@@ -363,7 +364,7 @@ export class LineChart extends React.Component<LineChartProps> {
                 <div className="graph-title"> 
                     <EditableText
                         val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
+                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 6581b6b75..de725209d 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -12,6 +12,7 @@ import './Chart.scss';
 import { ColorPicker, EditableText, Size, Type } from "browndash-components";
 import { FaFillDrip } from "react-icons/fa";
 import { listSpec } from "../../../../../fields/Schema";
+import { undoable } from "../../../../util/UndoManager";
 
 export interface PieChartProps {
     rootDoc: Doc;
@@ -342,7 +343,7 @@ export class PieChart extends React.Component<PieChartProps> {
                 <div className="graph-title"> 
                     <EditableText
                         val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={action(val => this.props.layoutDoc[titleAccessor] = val as string)}
+                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
                         color={"black"}
                         size={Size.LARGE}
                         fillWidth
@@ -358,7 +359,7 @@ export class PieChart extends React.Component<PieChartProps> {
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
                             selectedColor={selectedSliceColor? selectedSliceColor : this.curSliceSelected.attr("fill")}
-                            setSelectedColor={color => this.changeSelectedColor(color)}
+                            setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Slice Color")}
                             size={Size.XSMALL}
                         />
                     </div>
-- 
cgit v1.2.3-70-g09d2


From da893c2739c9589bac04c00df3d22ebbfd78c09d Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Sun, 13 Aug 2023 17:13:31 -0400
Subject: LineChart ui fixes + selected columns bolded

---
 .../views/nodes/DataVizBox/components/LineChart.tsx     |  4 ++--
 .../views/nodes/DataVizBox/components/TableBox.tsx      | 17 ++++++++---------
 2 files changed, 10 insertions(+), 11 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 49ef577e4..d27aaafbc 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -348,7 +348,7 @@ export class LineChart extends React.Component<LineChartProps> {
         tooltip
             .html(() => `<b>(${d0.x},${d0.y})</b>`) // text content for tooltip
             .style('pointer-events', 'none')
-            .style('transform', `translate(${xScale(d0.x) - this.width / 2}px,${yScale(d0.y) - 30}px)`);
+            .style('transform', `translate(${xScale(d0.x)-this.width}px,${yScale(d0.y)}px)`);
     }
 
     render() {
@@ -357,7 +357,7 @@ export class LineChart extends React.Component<LineChartProps> {
         if (this.props.axes.length==2) titleAccessor = 'lineChart-title-'+this.props.axes[0]+'-'+this.props.axes[1];
         else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+this.props.axes[0];
         if (!this.props.layoutDoc[titleAccessor]) this.props.layoutDoc[titleAccessor] = this.defaultGraphTitle;
-        const selectedPt = this._currSelected ? `x: ${this._currSelected.x} y: ${this._currSelected.y}` : 'none';
+        const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none';
         return (
             this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
             <div className="chart-container" >
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index f80cbdf99..f56d34fa6 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -81,7 +81,8 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                 key={this.columns.indexOf(col)}
                                                 ref={header as any}
                                                 style={{
-                                                    color: this.props.axes.slice().reverse().lastElement() === col ? 'green' : this.props.axes.lastElement() === col ? 'red' : undefined,
+                                                    color: this.props.axes.slice().reverse().lastElement() === col ? 'darkgreen' : this.props.axes.lastElement() === col ? 'darkred' : undefined,
+                                                    background: this.props.axes.slice().reverse().lastElement() === col ? '#E3fbdb' : this.props.axes.lastElement() === col ? '#Fbdbdb' : undefined,
                                                     fontWeight: 'bolder', border: '3px solid black'
                                                 }}
                                                 onPointerDown={e => {
@@ -151,17 +152,15 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                 if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1);
                                                 else {
                                                     selected.push(guid)};
-                                            })} style={
-                                                { fontWeight: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'bold' : '' , width: '110%',
-                                                background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}>
-                                            {this.columns.map(col => (
-                                                (this.props.layoutDoc.selected)?
+                                            })} style={{ background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '', width: '110%' }}>
+                                            {this.columns.map(col => {
                                                     // each cell
-                                                    <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}>
+                                                    var colSelected = this.props.axes[0]==col || this.props.axes[1]==col;
+                                                    return (
+                                                    <td key={this.columns.indexOf(col)} style={{border: colSelected? '3px solid black' : '1px solid black', fontWeight: colSelected? 'bolder' : 'normal'}}>
                                                         {p[col]}
                                                     </td>
-                                                : <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}> {p[col]} </td>
-                                            ))}
+                                             )})}
                                         </tr>
                                     );
                                 }
-- 
cgit v1.2.3-70-g09d2


From 9dbd9efeb0080418fcb44c5c78511fffa09ad229 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Sun, 13 Aug 2023 17:37:02 -0400
Subject: just one histogram bar bug fix + message displayed when graphs have
 no incoming data rows selected

---
 .../nodes/DataVizBox/components/Histogram.tsx      | 94 ++++++++++++----------
 .../nodes/DataVizBox/components/LineChart.tsx      | 42 ++++++----
 .../views/nodes/DataVizBox/components/PieChart.tsx | 62 +++++++-------
 3 files changed, 111 insertions(+), 87 deletions(-)

(limited to 'src/client/views/nodes/DataVizBox/components/LineChart.tsx')

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index df713c462..df6aac6bc 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -263,7 +263,7 @@ export class Histogram extends React.Component<HistogramProps> {
             eachRectWidth = width/(bins.length)
             bins.forEach(d => d.x0 = d.x0!)
             xAxis = d3.axisBottom(x)
-                .ticks(bins.length-1)
+                .ticks(bins.length>1? bins.length-1: 1)
                 .tickFormat( i => uniqueArr[i.valueOf()] as string)
                 .tickPadding(10)
             x.range([0, width-eachRectWidth])
@@ -428,54 +428,62 @@ export class Histogram extends React.Component<HistogramProps> {
         barColors.map(each => {if (each[0]==curSelectedBarName!) selectedBarColor = each[1]});
 
         this.componentDidMount();
-        return (
-            this.props.axes.length >= 1 ? (
-            <div className="chart-container" >
-                <div className="graph-title"> 
-                    <EditableText
-                        val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
-                        color={"black"}
-                        size={Size.LARGE}
-                        fillWidth
-                    />
-                    &nbsp; &nbsp; 
-                    <ColorPicker
-                        tooltip={'Change Default Bar Color'} 
-                        type={Type.SEC} 
-                        icon={<FaFillDrip/>}
-                        selectedColor={StrCast(this.props.layoutDoc.defaultHistogramColor)}
-                        setSelectedColor={undoable (color => this.props.layoutDoc.defaultHistogramColor = color, "Change Default Bar Color")}
-                        size={Size.XSMALL}
-                    />
-                </div>
-                <div ref={this._histogramRef} />
-                {selected != 'none' ? 
-                    <div className={'selected-data'}>
-                        Selected: {selected}
-                        &nbsp; &nbsp;
+
+        if (this._histogramData.length>0){
+            return (
+                this.props.axes.length >= 1 ? (
+                <div className="chart-container" >
+                    <div className="graph-title"> 
+                        <EditableText
+                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
+                            color={"black"}
+                            size={Size.LARGE}
+                            fillWidth
+                        />
+                        &nbsp; &nbsp; 
                         <ColorPicker
-                            tooltip={'Change Bar Color'} 
+                            tooltip={'Change Default Bar Color'} 
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
-                            selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")}
-                            setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Bar Color")}
+                            selectedColor={StrCast(this.props.layoutDoc.defaultHistogramColor)}
+                            setSelectedColor={undoable (color => this.props.layoutDoc.defaultHistogramColor = color, "Change Default Bar Color")}
                             size={Size.XSMALL}
                         />
-                        &nbsp;
-                        <IconButton
-                            icon={<FontAwesomeIcon icon={'eraser'} />} 
-                            size={Size.XSMALL} 
-                            color={'black'} 
-                            type={Type.SEC}
-                            tooltip={'Revert to the default bar color'}
-                            onClick={undoable (action(() => this.eraseSelectedColor()), "Change Selected Bar Color")}
-                        />
                     </div>
-                : null}
+                    <div ref={this._histogramRef} />
+                    {selected != 'none' ? 
+                        <div className={'selected-data'}>
+                            Selected: {selected}
+                            &nbsp; &nbsp;
+                            <ColorPicker
+                                tooltip={'Change Bar Color'} 
+                                type={Type.SEC} 
+                                icon={<FaFillDrip/>}
+                                selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")}
+                                setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Bar Color")}
+                                size={Size.XSMALL}
+                            />
+                            &nbsp;
+                            <IconButton
+                                icon={<FontAwesomeIcon icon={'eraser'} />} 
+                                size={Size.XSMALL} 
+                                color={'black'} 
+                                type={Type.SEC}
+                                tooltip={'Revert to the default bar color'}
+                                onClick={undoable (action(() => this.eraseSelectedColor()), "Change Selected Bar Color")}
+                            />
+                        </div>
+                    : null}
+                </div>
+                ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
+            );
+        }
+        else return (
+            // when it is a brushed table and the incoming table doesn't have any rows selected
+            <div className='chart-container'>
+                Selected rows of data from the incoming DataVizBox to display.
             </div>
-            ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
-        );
+        )
     }
-
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index d27aaafbc..8bace941f 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -358,24 +358,32 @@ export class LineChart extends React.Component<LineChartProps> {
         else if (this.props.axes.length>0) titleAccessor = 'lineChart-title-'+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';
-        return (
-            this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
-            <div className="chart-container" >
-                <div className="graph-title"> 
-                    <EditableText
-                        val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
-                        color={"black"}
-                        size={Size.LARGE}
-                        fillWidth
-                    />
+        if (this._lineChartData.length>0){
+            return (
+                this.props.axes.length>=2 && /\d/.test(this.props.pairs[0][this.props.axes[0]]) && /\d/.test(this.props.pairs[0][this.props.axes[1]]) ? (
+                <div className="chart-container" >
+                    <div className="graph-title"> 
+                        <EditableText
+                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
+                            color={"black"}
+                            size={Size.LARGE}
+                            fillWidth
+                        />
+                    </div>
+                    <div ref={this._lineChartRef} />
+                    {selectedPt!='none'? 
+                        <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
+                    : null}
                 </div>
-                <div ref={this._lineChartRef} />
-                {selectedPt!='none'? 
-                    <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div>
-                : null}
+                ) : <span className="chart-container"> {'first use table view to select two numerical axes to plot'}</span>
+            );
+        }
+        else return (
+            // when it is a brushed table and the incoming table doesn't have any rows selected
+            <div className='chart-container'>
+                Selected rows of data from the incoming DataVizBox to display.
             </div>
-            ) : <span className="chart-container"> {'first use table view to select two numerical axes to plot'}</span>
-        );
+        )
     }
 }
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 03c9efdd1..0c54d0a4e 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -337,36 +337,44 @@ export class PieChart extends React.Component<PieChartProps> {
         var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::'));
         sliceColors.map(each => {if (each[0]==curSelectedSliceName!) selectedSliceColor = each[1]});
 
-        return (
-            this.props.axes.length >= 1 ? (
-            <div className="chart-container">
-                <div className="graph-title"> 
-                    <EditableText
-                        val={StrCast(this.props.layoutDoc[titleAccessor])}
-                        setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
-                        color={"black"}
-                        size={Size.LARGE}
-                        fillWidth
-                    />
-                </div>
-                <div ref={this._piechartRef} />
-                {selected != 'none' ? 
-                    <div className={'selected-data'}>
-                        Selected: {selected}
-                        &nbsp; &nbsp;
-                        <ColorPicker
-                            tooltip={'Change Slice Color'} 
-                            type={Type.SEC} 
-                            icon={<FaFillDrip/>}
-                            selectedColor={selectedSliceColor? selectedSliceColor : this.curSliceSelected.attr("fill")}
-                            setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Slice Color")}
-                            size={Size.XSMALL}
+        if (this._piechartData.length>0){
+            return (
+                this.props.axes.length >= 1 ? (
+                <div className="chart-container">
+                    <div className="graph-title"> 
+                        <EditableText
+                            val={StrCast(this.props.layoutDoc[titleAccessor])}
+                            setVal={undoable (action(val => this.props.layoutDoc[titleAccessor] = val as string), "Change Graph Title")}
+                            color={"black"}
+                            size={Size.LARGE}
+                            fillWidth
                         />
                     </div>
-                : null}
+                    <div ref={this._piechartRef} />
+                    {selected != 'none' ? 
+                        <div className={'selected-data'}>
+                            Selected: {selected}
+                            &nbsp; &nbsp;
+                            <ColorPicker
+                                tooltip={'Change Slice Color'} 
+                                type={Type.SEC} 
+                                icon={<FaFillDrip/>}
+                                selectedColor={selectedSliceColor? selectedSliceColor : this.curSliceSelected.attr("fill")}
+                                setSelectedColor={undoable (color => this.changeSelectedColor(color), "Change Selected Slice Color")}
+                                size={Size.XSMALL}
+                            />
+                        </div>
+                    : null}
+                </div>
+                ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
+            );
+        }
+        else return (
+            // when it is a brushed table and the incoming table doesn't have any rows selected
+            <div className='chart-container'>
+                Selected rows of data from the incoming DataVizBox to display.
             </div>
-            ) : <span className="chart-container"> {'first use table view to select a column to graph'}</span>
-        );
+        )
     }
 
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

