From 6220445cc7832039029b74bc683f21f850daab8f Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Tue, 11 Jul 2023 10:23:08 -0400
Subject: importing tables from wikipedia -> DataVizBox

---
 .../collections/collectionFreeForm/MarqueeView.tsx | 62 +++++++++-------------
 1 file changed, 26 insertions(+), 36 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5febbe83e..35b3ca5d8 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -170,6 +170,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
             this.props.addDocument?.(slide);
             e.stopPropagation();
+        } else if (e.key === 't' && e.ctrlKey) {
+            e.preventDefault();
+            (async () => {
+                const text: string = await navigator.clipboard.readText();
+                const ns = text.split('\n').filter(t => t.trim() !== '\r' && t.trim() !== '');
+                this.pasteTable(ns, x, y);
+            })();
+            e.stopPropagation();
         } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
             FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
             FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note');
@@ -185,44 +193,26 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
     //         any row that has only one column is a section header-- this header is then added as a column to subsequent rows until the next header
     // assumes each cell is a string or a number
     pasteTable(ns: string[], x: number, y: number) {
-        while (ns.length > 0 && ns[0].split('\t').length < 2) {
-            ns.splice(0, 1);
-        }
-        if (ns.length > 0) {
-            const columns = ns[0].split('\t');
-            const docList: Doc[] = [];
-            let groupAttr: string | number = '';
-            const rowProto = new Doc();
-            rowProto.title = rowProto.Id;
-            rowProto._width = 200;
-            rowProto.isDataDoc = true;
-            for (let i = 1; i < ns.length - 1; i++) {
-                const values = ns[i].split('\t');
-                if (values.length === 1 && columns.length > 1) {
-                    groupAttr = values[0];
-                    continue;
-                }
-                const docDataProto = Doc.MakeDelegate(rowProto);
-                docDataProto.isDataDoc = true;
-                columns.forEach((col, i) => (docDataProto[columns[i]] = values.length > i ? (values[i].indexOf(Number(values[i]).toString()) !== -1 ? Number(values[i]) : values[i]) : undefined));
-                if (groupAttr) {
-                    docDataProto._group = groupAttr;
-                }
-                docDataProto.title = i.toString();
-                const doc = Doc.MakeDelegate(docDataProto);
-                doc._width = 200;
-                docList.push(doc);
+        let csvRows = [];
+        const headers = ns[0].split('\t');
+        csvRows.push(headers.join(','));
+        ns[0] = '';
+        const eachCell = ns.join('\t').split('\t')
+        let eachRow = []
+        for (let i=1; i<eachCell.length; i++){
+            eachRow.push(eachCell[i]);
+            if (i % headers.length == 0){
+                csvRows.push(eachRow)
+                eachRow = [];
             }
-            const newCol = Docs.Create.SchemaDocument([...(groupAttr ? [new SchemaHeaderField('_group', '#f1efeb')] : []), ...columns.filter(c => c).map(c => new SchemaHeaderField(c, '#f1efeb'))], docList, {
-                x: x,
-                y: y,
-                title: 'droppedTable',
-                _width: 300,
-                _height: 100,
-            });
-
-            this.props.addDocument?.(newCol);
         }
+        
+        const blob = new Blob([csvRows.join('\n')], {type: 'text/csv'})
+        const options = { x: x, y: y, title: 'droppedTable', _width: 300, _height: 100, type:'text/csv'}
+        const file = new File([blob], 'droppedTable', options);
+        const loading = Docs.Create.LoadingDocument(file, options);
+        DocUtils.uploadFileToDoc(file, {}, loading);
+        this.props.addDocument?.(loading);
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2


From 258d9f39bb2eb8b871ad01070eeab033b30c397b Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Fri, 14 Jul 2023 15:17:03 -0400
Subject: pie chart groupings

---
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 .../nodes/DataVizBox/components/Histogram.tsx      | 10 ++--
 .../views/nodes/DataVizBox/components/PieChart.tsx | 62 +++++++++++++++-------
 3 files changed, 50 insertions(+), 24 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 35b3ca5d8..fc737c4b9 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -200,7 +200,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const eachCell = ns.join('\t').split('\t')
         let eachRow = []
         for (let i=1; i<eachCell.length; i++){
-            eachRow.push(eachCell[i]);
+            eachRow.push(eachCell[i].replace(/\,/g, ''));
             if (i % headers.length == 0){
                 csvRows.push(eachRow)
                 eachRow = [];
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index b6ae15709..7a866d742 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -91,7 +91,7 @@ export class Histogram extends React.Component<HistogramProps> {
         this._disposers.chartData = reaction(
             () => ({ dataSet: this._histogramData, w: this.width, h: this.height }),
             ({ dataSet, w, h }) => {
-                if (dataSet) {
+                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
@@ -226,10 +226,10 @@ export class Histogram extends React.Component<HistogramProps> {
             })
             return valid;
         })
-        var field = Object.keys(dataSet[0])[0]
+        var field = dataSet[0]? Object.keys(dataSet[0])[0]: undefined;
         const data = validData.map((d: { [x: string]: any; }) => {
-            if (this.numericalData) { return +d[field].replace(/\$/g, '').replace(/\%/g, '') }
-            return d[field]
+            if (this.numericalData) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '') }
+            return d[field!]
         })
         return data;
     }
@@ -241,7 +241,7 @@ export class Histogram extends React.Component<HistogramProps> {
         var field = Object.keys(dataSet[0])[0]
         const data = this.data(dataSet);
         
-        let uniqueArr = [...new Set(data)]
+        let uniqueArr: unknown[] = [...new Set(data)]
         var numBins = uniqueArr.length
         var startingPoint = 0;
         var endingPoint = numBins;
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 5b6bdc4cf..7d532e790 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -37,7 +37,7 @@ export class PieChart extends React.Component<PieChartProps> {
     private _disposers: { [key: string]: IReactionDisposer } = {};
     private _piechartRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _piechartSvg: d3.Selection<SVGGElement, unknown, null, undefined> | undefined;
-    private numericalData: boolean = false;
+    private byCategory: boolean = true; // whether the data is organized by category or by specified number percentages/ratios
     @observable _currSelected: SelectedDataPoint | undefined = undefined;
     // TODO: nda - some sort of mapping that keeps track of the annotated points so we can easily remove when annotations list updates
 
@@ -45,7 +45,7 @@ export class PieChart extends React.Component<PieChartProps> {
         if (this.props.axes.length < 1) return [];
         if (this.props.axes.length < 2) {
             var ax0 = this.props.axes[0];
-            if (/\d/.test(this.props.pairs[0][ax0])){ this.numericalData = true }
+            if (/\d/.test(this.props.pairs[0][ax0])){ this.byCategory = false }
             return this.props.pairs
                 ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
                 .map(pair => ({ [ax0]: (pair[this.props.axes[0]])}))
@@ -53,7 +53,7 @@ export class PieChart extends React.Component<PieChartProps> {
 
         var ax0 = this.props.axes[0];
         var ax1 = this.props.axes[1];
-        if (/\d/.test(this.props.pairs[0][ax0])) { this.numericalData = true;}
+        if (/\d/.test(this.props.pairs[0][ax0])) { this.byCategory = false;}
         return this.props.pairs
             ?.filter(pair => (!this.incomingLinks.length ? true : Array.from(Object.keys(pair)).some(key => pair[key] && key.startsWith('select'))))
             .map(pair => ({ [ax0]: (pair[this.props.axes[0]]), [ax1]: (pair[this.props.axes[1]]) }))
@@ -78,7 +78,7 @@ export class PieChart extends React.Component<PieChartProps> {
             .lastElement();
     }
     @computed get rangeVals(): { xMin?: number; xMax?: number; yMin?: number; yMax?: number } {
-        if (this.numericalData){
+        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}
         }
@@ -91,7 +91,7 @@ export class PieChart extends React.Component<PieChartProps> {
         this._disposers.chartData = reaction(
             () => ({ dataSet: this._piechartData, w: this.width, h: this.height }),
             ({ dataSet, w, h }) => {
-                if (dataSet) {
+                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
@@ -226,10 +226,10 @@ export class PieChart extends React.Component<PieChartProps> {
             })
             return valid;
         })
-        var field = Object.keys(dataSet[0])[0]
+        var field = dataSet[0]? Object.keys(dataSet[0])[0] : undefined;
         const data = validData.map((d: { [x: string]: any; }) => {
-            if (this.numericalData) { return +d[field].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '') }
-            return d[field]
+            if (!this.byCategory) { return +d[field!].replace(/\$/g, '').replace(/\%/g, '').replace(/\</g, '') }
+            return d[field!]
         })
         return data;
     }
@@ -251,24 +251,38 @@ export class PieChart extends React.Component<PieChartProps> {
             .attr("transform",
                     "translate(" + (width/2 + this.props.margin.left) + "," + height/2 + ")");
 
-        var data = this.data(this._piechartData);
+        var data = this.data(dataSet);
+        var pieDataSet = dataSet;
+
         var pie = d3.pie();
         var arc = d3.arc()
             .innerRadius(0)
             .outerRadius(radius);
+        
+        if (this.byCategory){
+            let uniqueCategories = [...new Set(data)]
+            var pieStringDataSet: { frequency: any, label: any }[] = [];
+            for (let i=0; i<uniqueCategories.length; i++){
+                pieStringDataSet.push({frequency: 0, label: uniqueCategories[i]})
+            }
+            for (let i=0; i<data.length; i++){
+                let sliceData = pieStringDataSet.filter(each => each.label==data[i])
+                sliceData[0].frequency = sliceData[0].frequency + 1;
+            }
+            pieDataSet = pieStringDataSet
+            data = this.data(pieStringDataSet)
+        }
+        var trackDuplicates : {[key: string]: any} = {};
+        data.forEach((eachData: any) => !trackDuplicates[eachData]? trackDuplicates[eachData] = 0: null)
 
-        //Generate groups
-        var percentField = Object.keys(dataSet[0])[0]
-        var descriptionField = Object.keys(dataSet[0])[1]!
+        var percentField = Object.keys(pieDataSet[0])[0]
+        var descriptionField = Object.keys(pieDataSet[0])[1]!
         var arcs = g.selectAll("arc")
             .data(pie(data))
             .enter()
             .append("g")
         arcs.append("path")
-            .attr("fill", (data, i)=>{
-                let value=data.data;
-                return d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12];
-            })
+            .attr("fill", (data, i)=>{ return d3.schemeSet3[i]? d3.schemeSet3[i]: d3.schemeSet3[i%12] })
             .attr("d", arc);
         arcs.append("text")
             .attr("transform",function(d){ 
@@ -277,8 +291,20 @@ export class PieChart extends React.Component<PieChartProps> {
                 return "translate("+ (centroid[0]+centroid[0]/(radius*.02)) + "," + (centroid[1]+heightOffset)  + ")"; })
             .attr("text-anchor", "middle")
             .text(function(d){ 
-                return dataSet[data.indexOf(d.value)][percentField] 
-                + (!descriptionField? '' : (' - ' + dataSet[data.indexOf(d.value)][descriptionField]))})
+                var possibleDataPoints = pieDataSet.filter((each: { [x: string]: any | { valueOf(): number; }; }) => {
+                    try {
+                        return each[percentField].replace(/[^0-9]/g,"")==d.data.toString().replace(/[^0-9]/g,"")
+                    } catch (error) {
+                        return each[percentField]==d.data
+                    }})
+                var dataPoint;
+                if (possibleDataPoints.length==1) dataPoint = possibleDataPoints[0];
+                else{
+                    dataPoint = possibleDataPoints[trackDuplicates[d.data.toString()]]
+                    trackDuplicates[d.data.toString()] = trackDuplicates[d.data.toString()] + 1;
+                }
+                return dataPoint[percentField]! 
+                + (!descriptionField? '' : (' - ' + dataPoint[descriptionField]))!})
 
     };
 
-- 
cgit v1.2.3-70-g09d2


From 47d5a651e1725ceca285cb489b059d6df4ef00da Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Thu, 27 Jul 2023 15:23:00 -0400
Subject: merge

---
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 7e574e839..ba8585749 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -170,7 +170,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
             this.props.addDocument?.(slide);
             e.stopPropagation();
-        } else if (e.key === 't' && e.ctrlKey) {
+        }*/ else if (e.key === 't' && e.ctrlKey) {
             e.preventDefault();
             (async () => {
                 const text: string = await navigator.clipboard.readText();
@@ -178,7 +178,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 this.pasteTable(ns, x, y);
             })();
             e.stopPropagation();
-        }*/ else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
+        } else if (!e.ctrlKey && !e.metaKey && SelectionManager.Views().length < 2) {
             FormattedTextBox.SelectOnLoadChar = Doc.UserDoc().defaultTextLayout && !this.props.childLayoutString ? e.key : '';
             FormattedTextBox.LiveTextUndo = UndoManager.StartBatch('type new note');
             this.props.addLiveTextDocument(DocUtils.GetNewTextDoc('-typed text-', x, y, 200, 100, this.props.xPadding === 0));
-- 
cgit v1.2.3-70-g09d2


From 74b3a04a40338a4f16027560e52ec771b7aa19be Mon Sep 17 00:00:00 2001
From: srichman333 <sarah_n_richman@brown.edu>
Date: Mon, 31 Jul 2023 17:18:48 -0400
Subject: import table on windows

---
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/collections/collectionFreeForm/MarqueeView.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ba8585749..158588e8a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -170,7 +170,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
             this.props.addDocument?.(slide);
             e.stopPropagation();
-        }*/ else if (e.key === 't' && e.ctrlKey) {
+        }*/ else if (e.key === 'p' && e.ctrlKey) {
             e.preventDefault();
             (async () => {
                 const text: string = await navigator.clipboard.readText();
-- 
cgit v1.2.3-70-g09d2

