From 65ab8c985a86f18ebb51a269f20d7865dcfc6589 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 18 Jul 2023 10:50:16 -0400
Subject: click on histograms

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

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

diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index d84e34d52..8c8264861 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -33,6 +33,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                     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,
@@ -90,9 +91,9 @@ export class TableBox extends React.Component<TableBoxProps> {
                     <tbody>
                         {this.props.pairs?.map((p, i) => {
                             return (
-                                <tr 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 => (p['select' + this.props.docView?.()?.rootDoc![Id]] = !p['select' + this.props.docView?.()?.rootDoc![Id]]))}>
                                     {this.columns.map(col => (
-                                        <td style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>{p[col]}</td>
+                                        <td key={this.columns.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>{p[col]}</td>
                                     ))}
                                 </tr>
                             );
-- 
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/TableBox.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 27441b60e7af8ea93f277ab3bdc2990ad25ea326 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 19 Jul 2023 19:03:59 -0400
Subject: fixed showing of link lines for data visualization views.

---
 src/client/views/nodes/DataVizBox/components/TableBox.tsx | 5 ++++-
 src/client/views/nodes/DocumentView.tsx                   | 8 ++++----
 2 files changed, 8 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index ff43f67d9..ca888e13f 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -60,6 +60,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                                 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;
                                                                     }
@@ -94,7 +95,9 @@ export class TableBox extends React.Component<TableBoxProps> {
                             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.columns.map(col => (
-                                        <td key={this.columns.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>{p[col]}</td>
+                                        <td key={this.columns.indexOf(col)} style={{ fontWeight: p['select' + this.props.docView?.()?.rootDoc![Id]] ? 'bold' : '' }}>
+                                            {p[col]}
+                                        </td>
                                     ))}
                                 </tr>
                             );
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d7b4ca317..4211b8a81 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -975,8 +975,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         TraceMobx();
         return LinkManager.Instance.getAllRelatedLinks(this.rootDoc).filter(
             link =>
-                Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc) ||
-                Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc) ||
+                (link.link_matchEmbeddings ? link.link_anchor_1 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_1 as Doc, this.rootDoc)) ||
+                (link.link_matchEmbeddings ? link.link_anchor_2 === this.rootDoc : Doc.AreProtosEqual(link.link_anchor_2 as Doc, this.rootDoc)) ||
                 ((link.link_anchor_1 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_1 as Doc)?.annotationOn as Doc, this.rootDoc)) ||
                 ((link.link_anchor_2 as Doc)?.layout_unrendered && Doc.AreProtosEqual((link.link_anchor_2 as Doc)?.annotationOn as Doc, this.rootDoc))
         );
@@ -1237,7 +1237,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         const renderDoc = this.renderDoc({
             borderRadius: this.borderRounding,
             outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px',
-            border:  highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined,
+            border: highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined,
             boxShadow,
             clipPath: borderPath?.clipPath,
         });
@@ -1351,7 +1351,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         return this.docView?._componentView;
     }
     get allLinks() {
-        return this.docView?.allLinks || [];
+        return (this.docView?.allLinks || []).filter(link => !link.link_matchEmbeddings || link.link_anchor_1 === this.rootDoc || link.link_anchor_2 === this.rootDoc);
     }
     get LayoutFieldKey() {
         return this.docView?.LayoutFieldKey || 'layout';
-- 
cgit v1.2.3-70-g09d2


From 371f0309ec6b10a86b4a456d233be5b53cf93356 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 20 Jul 2023 17:58:24 -0400
Subject: components + links + brushed TableBox

---
 src/client/views/nodes/DataVizBox/DataVizBox.scss  |  4 ++--
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   | 26 +++++++++++++++++-----
 .../nodes/DataVizBox/components/Histogram.tsx      |  3 ++-
 .../views/nodes/DataVizBox/components/PieChart.tsx |  4 ++--
 .../views/nodes/DataVizBox/components/TableBox.tsx | 22 ++++++++++++++++--
 5 files changed, 46 insertions(+), 13 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index 5e7230271..32c0bbfc1 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -4,7 +4,7 @@
     width: 100%;
 
     .datatype-button{
-        margin: 0;
-        border: 1px solid white;
+        display: flex;
+        flex-direction: row;
     }
 }
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 25098baf1..4ddebb833 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -14,6 +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';
 
 export enum DataVizView {
     TABLE = 'table',
@@ -103,7 +104,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         if (!this.pairs) return 'no data';
         // prettier-ignore
         switch (this.dataVizView) {
-            case DataVizView.TABLE:     return <TableBox pairs={this.pairs} axes={this.axes} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
+            case DataVizView.TABLE:     return <TableBox pairs={this.pairs} axes={this.axes} rootDoc={this.rootDoc} docView={this.props.DocumentView} selectAxes={this.selectAxes}/>;
             case DataVizView.LINECHART: 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} />;
             case DataVizView.HISTOGRAM: return <Histogram 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 height={height} width={width} fieldKey={this.fieldKey} margin={margin} rootDoc={this.rootDoc} axes={this.axes} pairs={this.pairs} dataDoc={this.dataDoc} />;
@@ -150,11 +151,24 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         { passive: false }
                     )
                 }>
-                {/* <button onClick={e => this.changeViewHandler(e)}>{this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE}</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>
+                <div className={'datatype-button'}>
+                    <Toggle text={"TABLE"} toggleType={ToggleType.BUTTON} type={"secondary"} 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"} 
+                        onClick={e => this.layoutDoc._dataVizView = DataVizView.LINECHART} 
+                        toggleStatus={this.layoutDoc._dataVizView == DataVizView.LINECHART} 
+                    />
+                    <Toggle text={"HISTOGRAM"} toggleType={ToggleType.BUTTON} type={"secondary"} 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"} 
+                        onClick={e => this.layoutDoc._dataVizView = DataVizView.PIECHART} 
+                        toggleStatus={this.layoutDoc._dataVizView == DataVizView.PIECHART} 
+                    />
+                </div>
                 {this.selectView}
             </div>
         );
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index b8be9bd13..01e6709fa 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -65,7 +65,8 @@ export class Histogram extends React.Component<HistogramProps> {
     }
     @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/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 6241e6221..05a2f1588 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -65,7 +65,8 @@ export class PieChart extends React.Component<PieChartProps> {
     }
     @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() {
@@ -359,7 +360,6 @@ export class PieChart extends React.Component<PieChartProps> {
     };
 
     render() {
-
         var selected: string;
         if (this._currSelected){
             selected = '{ ';
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index ca888e13f..500e7b639 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -8,8 +8,11 @@ import { emptyFunction, returnFalse, setupMoveUpEvents, Utils } from '../../../.
 import { DragManager } from '../../../../util/DragManager';
 import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
+import { LinkManager } from '../../../../util/LinkManager';
+import { DocCast } from '../../../../../fields/Types';
 
 interface TableBoxProps {
+    rootDoc: Doc;
     pairs: { [key: string]: any }[];
     selectAxes: (axes: string[]) => void;
     axes: string[];
@@ -18,9 +21,24 @@ interface TableBoxProps {
 
 @observer
 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 => (Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
+    }
+
+    @computed get incomingLinks() {
+        return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
+            .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 columns() {
-        return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : [];
+        // return this.props.pairs.length ? Array.from(Object.keys(this.props.pairs[0])) : [];
+        return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : [];
     }
+
     render() {
         return (
             <div className="table-container">
@@ -91,7 +109,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                         </tr>
                     </thead>
                     <tbody>
-                        {this.props.pairs?.map((p, i) => {
+                        {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.columns.map(col => (
-- 
cgit v1.2.3-70-g09d2


From 710cb3aa93ea30799479ca7c79444f05aeab2209 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Mon, 31 Jul 2023 18:49:44 -0400
Subject: TableBox editable headers start

---
 .../nodes/DataVizBox/components/Histogram.tsx      |  23 ++---
 .../views/nodes/DataVizBox/components/PieChart.tsx |  24 ++---
 .../views/nodes/DataVizBox/components/TableBox.tsx | 108 ++++++++++++++++++++-
 3 files changed, 125 insertions(+), 30 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 6d0a8bf75..64e61fca8 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -443,21 +443,8 @@ export class Histogram extends React.Component<HistogramProps> {
         this.defaultBarColor = color;
     };
 
-    @computed get editableTitle() {
-        const title = this.graphTitle;
-        return (
-            <EditableText
-                val={title}
-                setVal={action(val => this.graphTitle = val as string)}
-                color={"black"}
-                size={Size.LARGE}
-                fillWidth
-            />
-        );
-    }
-
     render() {
-        
+        const title = this.graphTitle;
         var selected: string;
         if (this._currSelected){
             selected = '{ ';
@@ -472,7 +459,13 @@ export class Histogram extends React.Component<HistogramProps> {
             this.props.axes.length >= 1 ? (
             <div className="chart-container" >
                 <div className="graph-title"> 
-                    {this.editableTitle} 
+                    <EditableText
+                        val={title}
+                        setVal={action(val => this.graphTitle = val as string)}
+                        color={"black"}
+                        size={Size.LARGE}
+                        fillWidth
+                    />
                     &nbsp; &nbsp; 
                     <ColorPicker
                         tooltip={'Change Default Bar Color'} 
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 5080f0c74..47d4fb23e 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -382,20 +382,8 @@ export class PieChart extends React.Component<PieChartProps> {
         this.sliceColors[this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')] = color;
     };
 
-    @computed get editableTitle() {
-        const title = this.graphTitle;
-        return (
-            <EditableText
-                val={title}
-                setVal={action(val => this.graphTitle = val as string)}
-                color={"black"}
-                size={Size.LARGE}
-                fillWidth
-            />
-        );
-    }
-
     render() {
+        const title = this.graphTitle;
         var selected: string;
         if (this._currSelected){
             selected = '{ ';
@@ -409,7 +397,15 @@ export class PieChart extends React.Component<PieChartProps> {
         return (
             this.props.axes.length >= 1 ? (
             <div className="chart-container">
-                <div className="graph-title"> {this.editableTitle} </div>
+                <div className="graph-title"> 
+                    <EditableText
+                        val={title}
+                        setVal={action(val => this.graphTitle = val as string)}
+                        color={"black"}
+                        size={Size.LARGE}
+                        fillWidth
+                    />
+                </div>
                 {selected != 'none' ? 
                     <div className={'selected-data'}>
                         Selected: {selected}
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 500e7b639..aaedba202 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc } from '../../../../../fields/Doc';
@@ -10,6 +10,7 @@ import { DocumentView } from '../../DocumentView';
 import { DataVizView } from '../DataVizBox';
 import { LinkManager } from '../../../../util/LinkManager';
 import { DocCast } from '../../../../../fields/Types';
+import { EditableText, Size, Type } from 'browndash-components';
 
 interface TableBoxProps {
     rootDoc: Doc;
@@ -21,6 +22,8 @@ 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;
@@ -39,6 +42,106 @@ export class TableBox extends React.Component<TableBoxProps> {
         return this._tableData.length ? Array.from(Object.keys(this._tableData[0])) : [];
     }
 
+    // render() {
+    //     return (
+    //         <div className="table-container">
+    //             <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">
@@ -125,4 +228,7 @@ export class TableBox extends React.Component<TableBoxProps> {
             </div>
         );
     }
+
+
+
 }
-- 
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/TableBox.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 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/TableBox.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 8bdae208c4ae44766241c285f2f7234027b9b80f Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 3 Aug 2023 15:56:11 -0400
Subject: histogram small data fix

---
 .../nodes/DataVizBox/components/Histogram.tsx      |  6 ++--
 .../views/nodes/DataVizBox/components/TableBox.tsx | 42 ++++++++++++----------
 2 files changed, 26 insertions(+), 22 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index efe17297b..1077df844 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -267,10 +267,10 @@ export class Histogram extends React.Component<HistogramProps> {
         var histogram = d3.histogram()
             .value(function(d) {return d})
             .domain([startingPoint!, endingPoint!])
-            .thresholds(x.ticks(numBins-1))
+            .thresholds(x.ticks(numBins))
         var bins = histogram(data)
         var eachRectWidth = width/(bins.length)
-        var graphStartingPoint = bins[0].x1? bins[0].x1! - (bins[1].x1! - bins[1].x0!) : 0;
+        var graphStartingPoint = (bins[0].x1 && bins[1])? 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 ])
@@ -286,7 +286,7 @@ export class Histogram extends React.Component<HistogramProps> {
                         index = j;
                     }
                 }
-                bins[index].push(data[i])
+                if (bins[index]) bins[index].push(data[i])
             }
             bins.pop();
             eachRectWidth = width/(bins.length)
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 5653adbce..f244502a4 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -120,25 +120,29 @@ export class TableBox extends React.Component<TableBoxProps> {
                         </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>
-                                );
+                                var containsData = false;
+                                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);
+                                                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>
-- 
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/TableBox.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 8cbfb72751a3f8814c0dbda54c8ed22c8bb58783 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Fri, 4 Aug 2023 15:17:25 -0400
Subject: color stays on dragged charts + erase bar color is on individual bars

---
 .../nodes/DataVizBox/components/Histogram.tsx      | 28 ++++++++++++++--------
 .../views/nodes/DataVizBox/components/TableBox.tsx |  5 +++-
 2 files changed, 22 insertions(+), 11 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index a9be151bc..2a47abf32 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -400,6 +400,14 @@ export class Histogram extends React.Component<HistogramProps> {
         barColors.map(each => { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) });
         barColors.push(StrCast(barName + '::' + color));
     };
+    
+    @action eraseSelectedColor= () => {
+        this.curBarSelected.attr("fill", this.props.layoutDoc.defaultHistogramColor);
+        var barName = StrCast(this._currSelected[this.props.axes[0]].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))
+
+        const barColors = Cast(this.props.layoutDoc.histogramBarColors, listSpec("string"), null);
+        barColors.map(each => { if (each.split('::')[0] == barName) barColors.splice(barColors.indexOf(each), 1) });
+    };
 
     render() {
         var curSelectedBarName;
@@ -445,28 +453,28 @@ export class Histogram extends React.Component<HistogramProps> {
                         setSelectedColor={color => this.props.layoutDoc.defaultHistogramColor = color}
                         size={Size.XSMALL}
                     />
-                    &nbsp;
-                    <IconButton
-                        icon={<FontAwesomeIcon icon={'eraser'} />} 
-                        size={Size.XSMALL} 
-                        color={'black'} 
-                        type={Type.SEC}
-                        tooltip={'Revert all bars to the default color'}
-                        onClick={action(() => {this.props.layoutDoc.histogramBarColors = new List<string>()})}
-                    />
                 </div>
                 {selected != 'none' ? 
                     <div className={'selected-data'}>
                         Selected: {selected}
                         &nbsp; &nbsp;
                         <ColorPicker
-                            tooltip={'Change Slice Color'} 
+                            tooltip={'Change Bar Color'} 
                             type={Type.SEC} 
                             icon={<FaFillDrip/>}
                             selectedColor={selectedBarColor? selectedBarColor : this.curBarSelected.attr("fill")}
                             setSelectedColor={color => this.changeSelectedColor(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={action(() => this.eraseSelectedColor())}
+                        />
                     </div>
                 : null}
                 <div ref={this._histogramRef} />
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 7d6f934b9..8a99d332f 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -1,7 +1,7 @@
 import { action, computed, } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Doc, StrListCast } from '../../../../../fields/Doc';
+import { Doc, Field, StrListCast } from '../../../../../fields/Doc';
 import { List } from '../../../../../fields/List';
 import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils';
 import { DragManager } from '../../../../util/DragManager';
@@ -85,6 +85,9 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                                 embedding._data_vizAxes = new List<string>([col, col]);
                                                                 embedding._draggedFrom = this.props.docView?.()!.rootDoc!;
                                                                 embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!;
+                                                                embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors);
+                                                                embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor;
+                                                                embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors);
                                                                 return embedding;
                                                             };
                                                             if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) {
-- 
cgit v1.2.3-70-g09d2


From 1bfa61ae441458cdcd860eb39e617417d013f1fa Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Mon, 7 Aug 2023 10:53:09 -0400
Subject: Issues when you remove a highlighted row more than 1 chart up the
 tree fixed

---
 src/client/views/nodes/DataVizBox/components/TableBox.tsx | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 8a99d332f..a7cc3f2fb 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -52,7 +52,18 @@ export class TableBox extends React.Component<TableBoxProps> {
         return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='') : [];
     }
 
+    filterSelectedRowsDown() {
+        if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List<string>();
+        const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null);
+        const incomingSelected = this.incomingLinks.length? StrListCast(this.incomingLinks[0].selected) : undefined;
+        if (incomingSelected){
+            selected.map(guid => {
+                if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1)}); // filters through selected to remove guids that were removed in the incoming data
+        }
+    }
+
     render() {
+        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}}>
@@ -133,7 +144,6 @@ export class TableBox extends React.Component<TableBoxProps> {
                                 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(guid)) selected.splice(selected.indexOf(guid), 1);
                                                 else {
-- 
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/TableBox.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 318d56e1dff94204b100f5636e1a3288724aaffc Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 8 Aug 2023 16:15:36 -0400
Subject: comments + cleanups

---
 src/client/views/nodes/DataVizBox/DataVizBox.tsx   |  47 +------
 .../nodes/DataVizBox/components/Histogram.tsx      | 120 ++++------------
 .../views/nodes/DataVizBox/components/PieChart.tsx | 155 +++++----------------
 .../views/nodes/DataVizBox/components/TableBox.tsx |   7 +-
 src/client/views/nodes/DataVizBox/utils/D3Utils.ts |   1 -
 5 files changed, 78 insertions(+), 252 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 9a4546900..e71739231 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -26,45 +26,20 @@ export enum DataVizView {
 @observer
 export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
-    public static LayoutString(fieldKey: string) {
-        return FieldView.LayoutString(DataVizBox, fieldKey);
-    }
-    // says we have an object and any string
-    // 2 ways of doing it
-    // @observable private pairs: { [key: string]: number | string | undefined }[] = [];
-    // @observable private pairs: { [key: string]: FieldResult }[] = [];
+    // all data
     static pairSet = new ObservableMap<string, { [key: string]: string }[]>();
     @computed.struct get 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
-
-    // method1() {
-    //     this.pairs[0].x = 3;
-    // }
-
-    // method() {
-    //     // this.pairs[0].x = 3;
-    //     // go through the pairs
-    //     const x = this.pairs[0].x;
-    //     if (typeof x == 'number') {
-    //         let x1 = Number(x);
-    //         // let x1 = NumCast(x);
-    //     }
-    // }
 
-    // could use field result
-    // [key: string]: FieldResult;
-    // instead of numeric x,y in there,
-
-    // TODO: nda - use onmousedown and onmouseup when dragging and changing height and width to update the height and width props only when dragging stops
+    private _chartRenderer: LineChart | Histogram | PieChart | undefined;
 
+    // current displayed chart type
     @computed get dataVizView(): DataVizView {
         return StrCast(this.layoutDoc._dataVizView, 'table') as DataVizView;
     }
 
-    @action
+    @action // pinned / linked anchor doc includes selected rows, graph titles, and graph colors
     restoreView = (data: Doc) => {
         const changedView = this.dataVizView !== data.presDataVizView && (this.layoutDoc._dataVizView = data.presDataVizView);
         const changedAxes = this.axes.join('') !== StrListCast(data.presDataVizAxes).join('') && (this.layoutDoc._data_vizAxes = new List<string>(StrListCast(data.presDataVizAxes)));
@@ -75,7 +50,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         Object.keys(this.layoutDoc).map(key => {
             if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ this.layoutDoc['_'+key] = data[key]; }
         })
-
         const func = () => this._chartRenderer?.restoreView(data);
         if (changedView || changedAxes) {
             setTimeout(func, 100);
@@ -83,7 +57,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
         return func() ?? false;
     };
-
     getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
         const anchor = !pinProps
             ? this.rootDoc
@@ -93,7 +66,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                   // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
                   /*put in some options*/
               });
-
         anchor.presDataVizView = this.dataVizView;
         anchor.presDataVizAxes = this.axes.length ? new List<string>(this.axes) : undefined;
         anchor.selected = Field.Copy(this.layoutDoc.selected);
@@ -103,7 +75,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         Object.keys(this.layoutDoc).map(key => {
             if (key.startsWith('histogram-title') || key.startsWith('lineChart-title') || key.startsWith('pieChart-title')){ anchor[key] = this.layoutDoc[key]; }
         })
-
         this.addDocument(anchor);
         return anchor;
     };
@@ -113,6 +84,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     }
     selectAxes = (axes: string[]) => (this.layoutDoc.data_vizAxes = new List<string>(axes));
 
+    // toggles for user to decide which chart type to view the data in
     @computed get selectView() {
         const width = this.props.PanelWidth() * 0.9;
         const height = (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9;
@@ -125,6 +97,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             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() {
         return Cast(this.dataDoc[this.fieldKey], CsvField);
     }
@@ -141,16 +114,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
             .then(res => res.json().then(action(res => !res.errno && DataVizBox.pairSet.set(CsvCast(this.rootDoc[this.fieldKey]).url.href, res))));
     }
 
-    // handle changing the view using a button
-    @action changeViewHandler(e: React.MouseEvent<HTMLButtonElement>) {
-        e.preventDefault();
-        e.stopPropagation();
-        this.layoutDoc._dataVizView = this.dataVizView === DataVizView.TABLE ? DataVizView.LINECHART : DataVizView.TABLE;
-    }
-
     render() {
         if (!this.layoutDoc._dataVizView) this.layoutDoc._dataVizView = this.dataVizView;
         return !this.pairs?.length ? (
+            // displays how to get data into the DataVizBox if its empty
             <div className="start-message">
                 To create a DataViz box, either import / drag a CSV file into your canvas
                 or copy a data table and use the command 'ctrl + t' to bring the data table
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index 26c40045c..0b35f2856 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -44,12 +44,12 @@ export class Histogram extends React.Component<HistogramProps> {
     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;
-    private curBarSelected: 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
+    @observable _currSelected: any | undefined = undefined; // Object of selected bar
+    private curBarSelected: any = undefined; // histogram bin of selected bar
+    private selectedData: any = undefined; // Selection of selected bar
+    private hoverOverData: any = undefined; // Selection of bar being hovered over
 
+    // filters all data to just display selected data if brushed (created from an incoming link)
     @computed get _histogramData() {
         var guids = StrListCast(this.props.layoutDoc.rowGuids);
         if (this.props.axes.length < 1) return [];
@@ -60,7 +60,6 @@ export class Histogram extends React.Component<HistogramProps> {
                 ?.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]])}))
         };
-
         var ax0 = this.props.axes[0];
         var ax1 = this.props.axes[1];
         if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalXData = true;}
@@ -69,6 +68,7 @@ export class Histogram extends React.Component<HistogramProps> {
             ?.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(){
         var ax0 = this.props.axes[0];
         var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
@@ -77,21 +77,13 @@ export class Histogram extends React.Component<HistogramProps> {
         }
         else return ax1 + " by " + ax0 + " Histogram";
     }    
+
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-            .filter(link => {
-                return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link
+            .filter(link => 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() {
-        // 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)
-            .map(dvb => dvb.pairs?.filter((pair: { [x: string]: any; }) => pair['select' + dvb.rootDoc[Id]])) // get all the datapoints they have selected field set by incoming anchor
-            .lastElement();
-    }
+
     @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } {
         if (this.numericalXData){
             const data = this.data(this._histogramData);
@@ -99,6 +91,7 @@ export class Histogram extends React.Component<HistogramProps> {
         }
         return {xMin:0, xMax:0, yMin:0, yMax:0}
     }
+
     componentWillUnmount() {
         Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]());
     }
@@ -108,79 +101,14 @@ export class Histogram extends React.Component<HistogramProps> {
             ({ dataSet, w, h }) => {
                 if (dataSet!.length>0) {
                     this.drawChart(dataSet, w, h);
-
-                    // redraw annotations when the chart data has changed, or the local or inherited selection has changed
-                    this.clearAnnotations();
-                    this._currSelected && this.drawAnnotations(Number(this._currSelected.x), Number(this._currSelected.y), true);
-                    this.incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]])));
                 }
             },
             { fireImmediately: true }
         );
-        this._disposers.annos = reaction(
-            () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']),
-            annotations => {
-                // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way
-                // could be blue colored to make it look like anchor
-                // this.drawAnnotations()
-                // loop through annotations and draw them
-                annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y)));
-                // this.drawAnnotations(annotations.x, annotations.y);
-            },
-            { fireImmediately: true }
-        );
-        this._disposers.highlights = reaction(
-            () => ({
-                selected: this._currSelected,
-                incomingSelected: this.incomingSelected,
-            }),
-            ({ selected, incomingSelected }) => {
-                // redraw annotations when the chart data has changed, or the local or inherited selection has changed
-                this.clearAnnotations();
-                selected && this.drawAnnotations(Number(selected.x), Number(selected.y), true);
-                incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]])));
-            },
-            { fireImmediately: true }
-        );
     };
 
-    // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that
-
-    clearAnnotations = () => {
-        const elements = document.querySelectorAll('.datapoint');
-        for (let i = 0; i < elements.length; i++) {
-            const element = elements[i];
-            element.classList.remove('brushed');
-            element.classList.remove('selected');
-        }
-    };
-    // gets called whenever the "data_annotations" fields gets updated
-    drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => {
-        // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements
-        // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY
-        // if it exists, then highlight it
-        // if it doesn't exist, then remove the highlight
-        const elements = document.querySelectorAll('.datapoint');
-        for (let i = 0; i < elements.length; i++) {
-            const element = elements[i];
-            const x = element.getAttribute('data-x');
-            const y = element.getAttribute('data-y');
-            if (x === dataX.toString() && y === dataY.toString()) {
-                element.classList.add(selected ? 'selected' : 'brushed');
-            }
-            // TODO: nda - this remove highlight code should go where we remove the links
-            // } else {
-            // }
-        }
-    };
-
-    removeAnnotations(dataX: number, dataY: number) {
-        // loop through and remove any annotations that no longer exist
-    }
-
     @action
     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({
@@ -188,7 +116,6 @@ export class Histogram extends React.Component<HistogramProps> {
             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]) : undefined;
         return anchor;
     };
 
@@ -200,6 +127,7 @@ export class Histogram extends React.Component<HistogramProps> {
         return this.props.width - this.props.margin.left - this.props.margin.right;
     }
 
+    // cleans data by converting numerical data to numbers and taking out empty cells
     data = (dataSet: any) => {
         var validData = dataSet.filter((d: { [x: string]: unknown; }) => {
             var valid = true;
@@ -216,21 +144,24 @@ export class Histogram extends React.Component<HistogramProps> {
         return data;
     }
 
+    // outlines the bar selected / hovered over
     highlightSelectedBar = (changeSelectedVariables: boolean, svg: any, eachRectWidth: any, pointerX: any, xAxisTitle: any, yAxisTitle: any, histDataSet: any) => {
         var sameAsCurrent: boolean;
         var barCounter = -1;
         const selected = svg.selectAll('.histogram-bar').filter((d: any) => {
-            barCounter++;
+            barCounter++; // uses the order of bars and width of each bar to find which one the pointer is over
             if ((barCounter*eachRectWidth ) <= pointerX && pointerX <= ((barCounter+1)*eachRectWidth)){
                 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){
+                    // calculating frequency
                     if (d[0] && d[1] && d[0]!=d[1]){
                         showSelected = {[xAxisTitle]: (d3.min(d) + " to " + d3.max(d)), frequency: d.length}
                     }
                     else if (!this.numericalYData) showSelected = {[xAxisTitle]: showSelected[xAxisTitle], frequency: d.length}
                 } 
                 if (changeSelectedVariables){
+                    // for when a bar is selected - not just hovered over
                     sameAsCurrent = this._currSelected? 
                         (showSelected[xAxisTitle]==this._currSelected![xAxisTitle] 
                     && showSelected[yAxisTitle]==this._currSelected![yAxisTitle])
@@ -249,12 +180,12 @@ export class Histogram extends React.Component<HistogramProps> {
         }
     }
 
+    // draws the histogram
     drawChart = (dataSet: any, width: number, height: number) => {
         d3.select(this._histogramRef.current).select('svg').remove();
         d3.select(this._histogramRef.current).select('.tooltip').remove();
 
         var data = this.data(dataSet);
-        
         var xAxisTitle = Object.keys(dataSet[0])[0]
         var yAxisTitle = this.numericalYData ? Object.keys(dataSet[0])[1] : 'frequency';
         let uniqueArr: unknown[] = [...new Set(data)]
@@ -263,6 +194,8 @@ export class Histogram extends React.Component<HistogramProps> {
         if (numBins>this.maxBins) numBins = this.maxBins;
         var startingPoint = this.numericalXData? this.rangeVals.xMin! : 0;
         var endingPoint = this.numericalXData? this.rangeVals.xMax! : numBins;
+
+        // converts data into Objects
         var histDataSet = dataSet.filter((d: { [x: string]: unknown; }) => {
             var valid = true;
             Object.keys(dataSet[0]).map(key => {
@@ -289,6 +222,7 @@ export class Histogram extends React.Component<HistogramProps> {
             histDataSet = histStringDataSet
         }
 
+        // initial graph and binning data for histogram
         var svg = (this._histogramSvg = d3
             .select(this._histogramRef.current)
             .append("svg")
@@ -298,7 +232,6 @@ export class Histogram extends React.Component<HistogramProps> {
             .append("g")
                 .attr("transform",
                       "translate(" + this.props.margin.left + "," + this.props.margin.top + ")"));
-
         var x = d3.scaleLinear()
                 .domain(this.numericalXData? [startingPoint!, endingPoint!] : [0, numBins])
                 .range([0, width ]);
@@ -314,6 +247,8 @@ export class Histogram extends React.Component<HistogramProps> {
              .range([0, Number.isInteger(this.rangeVals.xMin!)? (width-eachRectWidth) : width ])
         var xAxis;
 
+        // more calculations based on bins
+        // x-axis
         if (!this.numericalXData) { // reorganize if the data is strings rather than numbers
             // uniqueArr.sort()
             histDataSet.sort()
@@ -331,7 +266,7 @@ export class Histogram extends React.Component<HistogramProps> {
             bins.forEach(d => d.x0 = d.x0!)
             xAxis = d3.axisBottom(x)
                 .ticks(bins.length-1)
-                .tickFormat( i => uniqueArr[i])
+                .tickFormat( i => uniqueArr[i.valueOf()] as string)
                 .tickPadding(10)
             x.range([0, width-eachRectWidth])
             x.domain([0, bins.length-1])
@@ -343,10 +278,10 @@ export class Histogram extends React.Component<HistogramProps> {
             xAxis = d3.axisBottom(x)
                 .ticks(numBins-1)
         }
+        // y-axis
         const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { 
             return Number(d[yAxisTitle]!.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!]);
@@ -363,7 +298,8 @@ export class Histogram extends React.Component<HistogramProps> {
         svg.append("g")
             .attr("transform", "translate(" + translateXAxis + ", " + height + ")")
             .call(xAxis)
-        
+
+        // click/hover
         const onPointClick = action((e: any) => this.highlightSelectedBar(true, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet));
         const onHover = action((e: any) => {
             const selected = this.highlightSelectedBar(false, svg, eachRectWidth, d3.pointer(e)[0], xAxisTitle, yAxisTitle, histDataSet)
@@ -378,12 +314,11 @@ export class Histogram extends React.Component<HistogramProps> {
             const selectedData = this.selectedData;
             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)
             .on('mouseover', onHover)
             .on('mouseout', mouseOut)
 
-        var selected = this.selectedData;
+        // axis titles
         svg.append("text")
             .attr("transform", "translate(" + (width/2) + " ," + (height+40) + ")")
             .style("text-anchor", "middle")
@@ -395,6 +330,9 @@ export class Histogram extends React.Component<HistogramProps> {
             .style("text-anchor", "middle")
             .text(yAxisTitle);
         d3.format('.0f')
+
+        // draw bars
+        var selected = this.selectedData;
         svg.selectAll("rect")
             .data(bins)
             .enter()
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 0fd4f6b54..d4570dee2 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -40,12 +40,12 @@ 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: 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
+    @observable _currSelected: any | undefined = undefined; // Object of selected slice
+    private curSliceSelected: any = undefined; // d3 data of selected slice
+    private selectedData: any = undefined; // Selection of selected slice
+    private hoverOverData: any = undefined; // Selection of slice being hovered over
 
+    // filters all data to just display selected data if brushed (created from an incoming link)
     @computed get _piechartData() {
         var guids = StrListCast(this.props.layoutDoc.rowGuids);
         if (this.props.axes.length < 1) return [];
@@ -56,7 +56,6 @@ export class PieChart extends React.Component<PieChartProps> {
                 ?.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]])}))
         };
-
         var ax0 = this.props.axes[0];
         var ax1 = this.props.axes[1];
         if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false; }
@@ -64,6 +63,7 @@ export class PieChart extends React.Component<PieChartProps> {
             ?.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(){
         var ax0 = this.props.axes[0];
         var ax1 = (this.props.axes.length>1)? this.props.axes[1] : undefined;
@@ -72,28 +72,13 @@ export class PieChart extends React.Component<PieChartProps> {
         }
         else return ax1 + " by " + ax0 + " Pie Chart";
     }    
+
     @computed get incomingLinks() {
         return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links
-            .filter(link => {
-                return link.link_anchor_1 == this.props.rootDoc.draggedFrom}) // get links where this chart doc is the target of the link
+            .filter(link => 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() {
-        // 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)
-            .map(dvb => dvb.pairs?.filter((pair: { [x: string]: any; }) => pair['select' + dvb.rootDoc[Id]])) // get all the datapoints they have selected field set by incoming anchor
-            .lastElement();
-    }
-    @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } {
-        if (!this.byCategory){
-            const data = this.data(this._piechartData);
-            return {xMin: Math.min.apply(null, data), xMax: Math.max.apply(null, data), yMin:0, yMax:0}
-        }
-        return {xMin:0, xMax:0, yMin:0, yMax:0}
-    }
+
     componentWillUnmount() {
         Array.from(Object.keys(this._disposers)).forEach(key => this._disposers[key]());
     }
@@ -103,79 +88,14 @@ export class PieChart extends React.Component<PieChartProps> {
             ({ dataSet, w, h }) => {
                 if (dataSet!.length>0) {
                     this.drawChart(dataSet, w, h);
-
-                    // redraw annotations when the chart data has changed, or the local or inherited selection has changed
-                    this.clearAnnotations();
-                    this._currSelected && this.drawAnnotations(Number(this._currSelected.x), Number(this._currSelected.y), true);
-                    this.incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]])));
                 }
             },
             { fireImmediately: true }
         );
-        this._disposers.annos = reaction(
-            () => DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']),
-            annotations => {
-                // modify how d3 renders so that anything in this annotations list would be potentially highlighted in some way
-                // could be blue colored to make it look like anchor
-                // this.drawAnnotations()
-                // loop through annotations and draw them
-                annotations.forEach(a => this.drawAnnotations(Number(a.x), Number(a.y)));
-                // this.drawAnnotations(annotations.x, annotations.y);
-            },
-            { fireImmediately: true }
-        );
-        this._disposers.highlights = reaction(
-            () => ({
-                selected: this._currSelected,
-                incomingSelected: this.incomingSelected,
-            }),
-            ({ selected, incomingSelected }) => {
-                // redraw annotations when the chart data has changed, or the local or inherited selection has changed
-                this.clearAnnotations();
-                selected && this.drawAnnotations(Number(selected.x), Number(selected.y), true);
-                incomingSelected?.forEach((pair: any) => this.drawAnnotations(Number(pair[this.props.axes[0]]), Number(pair[this.props.axes[1]])));
-            },
-            { fireImmediately: true }
-        );
-    };
-
-    // anything that doesn't need to be recalculated should just be stored as drawCharts (i.e. computed values) and drawChart is gonna iterate over these observables and generate svgs based on that
-
-    clearAnnotations = () => {
-        const elements = document.querySelectorAll('.datapoint');
-        for (let i = 0; i < elements.length; i++) {
-            const element = elements[i];
-            element.classList.remove('brushed');
-            element.classList.remove('selected');
-        }
-    };
-    // gets called whenever the "data_annotations" fields gets updated
-    drawAnnotations = (dataX: number, dataY: number, selected?: boolean) => {
-        // TODO: nda - can optimize this by having some sort of mapping of the x and y values to the individual circle elements
-        // loop through all html elements with class .circle-d1 and find the one that has "data-x" and "data-y" attributes that match the dataX and dataY
-        // if it exists, then highlight it
-        // if it doesn't exist, then remove the highlight
-        const elements = document.querySelectorAll('.datapoint');
-        for (let i = 0; i < elements.length; i++) {
-            const element = elements[i];
-            const x = element.getAttribute('data-x');
-            const y = element.getAttribute('data-y');
-            if (x === dataX.toString() && y === dataY.toString()) {
-                element.classList.add(selected ? 'selected' : 'brushed');
-            }
-            // TODO: nda - this remove highlight code should go where we remove the links
-            // } else {
-            // }
-        }
     };
 
-    removeAnnotations(dataX: number, dataY: number) {
-        // loop through and remove any annotations that no longer exist
-    }
-
     @action
     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({
@@ -183,7 +103,6 @@ export class PieChart extends React.Component<PieChartProps> {
             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]) : undefined;
         return anchor;
     };
 
@@ -195,15 +114,7 @@ export class PieChart extends React.Component<PieChartProps> {
         return this.props.width - this.props.margin.left - this.props.margin.right;
     }
 
-    // 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));
-    }
-
+    // cleans data by converting numerical data to numbers and taking out empty cells
     data = (dataSet: any) => {
         var validData = dataSet.filter((d: { [x: string]: unknown; }) => {
             var valid = true;
@@ -220,15 +131,16 @@ export class PieChart extends React.Component<PieChartProps> {
         return data;
     }
 
+    // outlines the slice selected / hovered over
     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)];
+                var p1 = [0,0]; // center of pie
+                var p3 = [arc.centroid(d)[0]*2, arc.centroid(d)[1]*2]; // outward peak of arc
+                var p2 = [radius*Math.sin(d.startAngle), -radius*Math.cos(d.startAngle)]; // start of arc
+                var p4 = [radius*Math.sin(d.endAngle), -radius*Math.cos(d.endAngle)]; // end of arc
 
                 // draw an imaginary horizontal line from the pointer to see how many times it crosses a slice edge
                 var lineCrossCount = 0;
@@ -241,10 +153,10 @@ export class PieChart extends React.Component<PieChartProps> {
                     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) {
+                if (lineCrossCount % 2 != 0) { // inside the slice of it crosses an odd number of edges
                     var showSelected = this.byCategory? pieDataSet[index] : this._piechartData[index];
-
                     if (changeSelectedVariables){
+                        // for when a bar is selected - not just hovered over
                         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]])
@@ -264,6 +176,7 @@ export class PieChart extends React.Component<PieChartProps> {
             }
     }
 
+    // draws the pie chart
     drawChart = (dataSet: any, width: number, height: number) => {
         d3.select(this._piechartRef.current).select('svg').remove();
         d3.select(this._piechartRef.current).select('.tooltip').remove();
@@ -271,18 +184,8 @@ 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-this.props.margin.top-this.props.margin.bottom) /2
-        var svg = (this._piechartSvg = d3
-            .select(this._piechartRef.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"));
-    
-        let g = svg.append("g")
-            .attr("transform",
-                    "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")");
 
+        // converts data into Objects
         var data = this.data(dataSet);
         var pieDataSet = dataSet.filter((d: { [x: string]: unknown; }) => {
             var valid = true;
@@ -293,12 +196,12 @@ export class PieChart extends React.Component<PieChartProps> {
         });
         if (this.byCategory){
             let uniqueCategories = [...new Set(data)]
-            var pieStringDataSet: { frequency: number, [percentField]: string }[] = [];
+            var pieStringDataSet: { frequency: number }[] = [];
             for (let i=0; i<uniqueCategories.length; i++){
                 pieStringDataSet.push({frequency: 0, [percentField]: uniqueCategories[i]})
             }
             for (let i=0; i<data.length; i++){
-                let sliceData = pieStringDataSet.filter(each => each[percentField]==data[i])
+                let sliceData = pieStringDataSet.filter((each: any) => each[percentField]==data[i])
                 sliceData[0].frequency = sliceData[0].frequency + 1;
             }
             pieDataSet = pieStringDataSet
@@ -309,11 +212,23 @@ export class PieChart extends React.Component<PieChartProps> {
         var trackDuplicates : {[key: string]: any} = {};
         data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
 
+        // initial chart
+        var svg = (this._piechartSvg = d3
+            .select(this._piechartRef.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"));
+        let g = svg.append("g")
+            .attr("transform",
+                    "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")");
         var pie = d3.pie();
         var arc = d3.arc()
             .innerRadius(0)
             .outerRadius(radius);
 
+        // click/hover
         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)
@@ -331,6 +246,7 @@ export class PieChart extends React.Component<PieChartProps> {
                     || ((hoverOverSlice && d.startAngle==hoverOverSlice.startAngle && d.endAngle==hoverOverSlice.endAngle)))? 'slice hover' : 'slice'; })
         }
 
+        // drawing the slices
         var selected = this.selectedData;
         var arcs = g.selectAll("arc")
             .data(pie(data))
@@ -359,11 +275,12 @@ export class PieChart extends React.Component<PieChartProps> {
                 function(d) {
                     return (selected && d.startAngle==selected.startAngle && d.endAngle==selected.endAngle)? 'slice hover' : 'slice';
                 }: function(d) {return 'slice'})
-            .attr("d", arc)
+            .attr('d', arc)
             .on('click', onPointClick)
             .on('mouseover', onHover)
             .on('mouseout', mouseOut);
 
+        // adding labels
         trackDuplicates = {};
         data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
         arcs.append("text")
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 38dd62d8d..277ee83ec 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -32,6 +32,7 @@ interface TableBoxProps {
 @observer
 export class TableBox extends React.Component<TableBoxProps> {
 
+    // filters all data to just display selected data if brushed (created from an incoming link)
     @computed get _tableData() {
         if (this.incomingLinks.length! <= 0) return this.props.pairs;
         var guids = StrListCast(this.props.layoutDoc.rowGuids);
@@ -52,6 +53,7 @@ export class TableBox extends React.Component<TableBoxProps> {
         return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header!='' && header!=undefined) : [];
     }
 
+    // updates the 'selected' field to no longer include rows that aren't in the table
     filterSelectedRowsDown() {
         if (!this.props.layoutDoc.selected) this.props.layoutDoc.selected = new List<string>();
         const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null);
@@ -88,7 +90,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                     setupMoveUpEvents(
                                                         {},
                                                         e,
-                                                        e => {
+                                                        e => { // dragging off a column to create a brushed DataVizBox
                                                             const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!;
                                                             const targetCreator = (annotationOn: Doc | undefined) => {
                                                                 const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!);
@@ -144,6 +146,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                 if (containsData){
                                     return (
                                         <tr key={i} className="table-row" onClick={action(e => {
+                                                // selecting a row
                                                 const selected = Cast(this.props.layoutDoc.selected, listSpec("string"), null);
                                                 if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1);
                                                 else {
@@ -153,6 +156,7 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                 background: StrListCast(this.props.layoutDoc.selected).includes(guid) ? 'lightgrey' : '' }}>
                                             {this.columns.map(col => (
                                                 (this.props.layoutDoc.selected)?
+                                                    // each cell
                                                     <td key={this.columns.indexOf(col)} style={{border: '1px solid black'}}>
                                                         {p[col]}
                                                     </td>
@@ -168,6 +172,7 @@ export class TableBox extends React.Component<TableBoxProps> {
             );
         }
         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>
diff --git a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
index e1ff6f8eb..10bfb0c64 100644
--- a/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
+++ b/src/client/views/nodes/DataVizBox/utils/D3Utils.ts
@@ -34,7 +34,6 @@ export const createLineGenerator = (xScale: d3.ScaleLinear<number, number, never
 };
 
 export const xAxisCreator = (g: d3.Selection<SVGGElement, unknown, null, undefined>, height: number, xScale: d3.ScaleLinear<number, number, never>) => {
-    console.log('x axis creator being called');
     g.attr('class', 'x-axis').attr('transform', `translate(0,${height})`).call(d3.axisBottom(xScale).tickSize(15));
 };
 
-- 
cgit v1.2.3-70-g09d2


From 481a847b1074c9544e947e409b96778ac4d4f852 Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Wed, 9 Aug 2023 15:24:03 -0400
Subject: numerical y axis data fix

---
 .../views/nodes/DataVizBox/components/Histogram.tsx | 11 ++++-------
 .../views/nodes/DataVizBox/components/PieChart.tsx  | 21 +++++++++------------
 .../views/nodes/DataVizBox/components/TableBox.tsx  |  4 ++--
 3 files changed, 15 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index e04d37094..ed663006f 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -1,13 +1,10 @@
 import { observer } from "mobx-react";
-import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc";
+import { Doc, 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 { DocumentManager } from "../../../../util/DocumentManager";
-import { Id } from "../../../../../fields/FieldSymbols";
-import { DataVizBox } from "../DataVizBox";
 import { PinProps, PresBox } from "../../trails";
 import { Docs } from "../../../../documents/Documents";
 import { List } from "../../../../../fields/List";
@@ -299,7 +296,7 @@ export class Histogram extends React.Component<HistogramProps> {
         }
         // y-axis
         const maxFrequency = this.numericalYData? d3.max(histDataSet, function(d: any) { 
-            return Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))})
+            return d[yAxisTitle]? Number(d[yAxisTitle]!.replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '')) : 0})
                     : d3.max(bins, function(d) { return d.length; })
         var y = d3.scaleLinear()
             .range([height, 0]);
@@ -359,14 +356,14 @@ export class Histogram extends React.Component<HistogramProps> {
               .attr("transform", this.numericalYData?
                     function (d) {
                         var eachData = histDataSet.filter((data: { [x: string]: number; }) => {return data[xAxisTitle]==d[0]}) 
-                        var length = eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '');
+                        var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '') : 0;
                         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: { [x: string]: number; }) => {return data[xAxisTitle]==d[0]}) 
-                        var length = eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '');
+                        var length = eachData.length? eachData[0][yAxisTitle].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '') : 0;
                         return height-y(length)}
                     : function(d) { 
                         return height - y(d.length)})
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 133e3a33a..6581b6b75 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -1,13 +1,10 @@
 import { observer } from "mobx-react";
-import { Doc, DocListCast, StrListCast } from "../../../../../fields/Doc";
+import { Doc, 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 { DocumentManager } from "../../../../util/DocumentManager";
-import { Id } from "../../../../../fields/FieldSymbols";
-import { DataVizBox } from "../DataVizBox";
 import { PinProps, PresBox } from "../../trails";
 import { Docs } from "../../../../documents/Documents";
 import { List } from "../../../../../fields/List";
@@ -256,7 +253,7 @@ export class PieChart extends React.Component<PieChartProps> {
             .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,"")
+                        return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))==Number(d.data)
                     } catch (error) {
                         return each[percentField]==d.data
                     }})
@@ -266,10 +263,12 @@ export class PieChart extends React.Component<PieChartProps> {
                     dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]]
                     trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1;
                 }
-                var accessByName = descriptionField? dataPoint[descriptionField] : dataPoint[percentField];
                 var sliceColor;
-                var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::'));
-                sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]});
+                if (dataPoint){
+                    var accessByName = descriptionField? dataPoint[descriptionField] : dataPoint[percentField];
+                    var sliceColors = StrListCast(this.props.layoutDoc.pieSliceColors).map(each => each.split('::'));
+                    sliceColors.map(each => {if (each[0]==StrCast(accessByName)) sliceColor = each[1]});
+                }
                 return sliceColor? StrCast(sliceColor) : d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%(d3.schemeSet3.length)] })
                 .attr("class", selected? 
                 function(d) {
@@ -292,7 +291,7 @@ export class PieChart extends React.Component<PieChartProps> {
             .text(function(d){ 
                 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,"")
+                        return Number(each[percentField].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, ''))==Number(d.data)
                     } catch (error) {
                         return each[percentField]==d.data
                     }})
@@ -302,9 +301,7 @@ export class PieChart extends React.Component<PieChartProps> {
                     dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]]
                     trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1;
                 }
-                return dataPoint[percentField]! 
-                + (!descriptionField? '' : (' - ' + dataPoint[descriptionField]))!})
-
+                return dataPoint? dataPoint[percentField]! + (!descriptionField? '' : (' - ' + dataPoint[descriptionField]))! : ''})
     };
 
     @action changeSelectedColor = (color: string) => {
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index 277ee83ec..f80cbdf99 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -123,10 +123,10 @@ export class TableBox extends React.Component<TableBoxProps> {
                                                             const newAxes = this.props.axes;
                                                             if (newAxes.includes(col)) {
                                                                 newAxes.splice(newAxes.indexOf(col), 1);
-                                                            } else if (newAxes.length >= 1) {
+                                                            } else if (newAxes.length > 1) {
                                                                 newAxes[1] = col;
                                                             } else {
-                                                                newAxes[0] = col;
+                                                                newAxes.push(col);
                                                             }
                                                             this.props.selectAxes(newAxes);
                                                         })
-- 
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/TableBox.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

