Parsing csv with javascript or d3js: how to skip a column? - javascript

I have two versions of a horizontal bar chart, stacked and paired (aka grouped). The code for each is stuffed into their own functions.
Refer to lines 35-43 (var stacked = function (){ ... }) and lines 117-121 (var paired = function (){ ... }) to see how the CSV is currently being parsed: http://tributary.io/inlet/8832116
Uncomment line 197 and below to see the stacked version rendered. To do this I manually changed the data, not ideal.
GOAL: I want to parse the csv file and drop a column programmatically, rather than remove it manually and save 2 separate csv files.
I need to parse the csv and remove this with native d3 or javascript code, but how?
Shown in code.
I have:
Category,Total,Under $1000, ...
Music,14744,1434, ...
Art,12796,1216, ...
I need total removed:
Category,Under $1000, ...
Music,1434, ...
Art,1216, ...

If you have the CSV string in memory (a variable string), split on \n to get the lines, loop over each line and split on ,. This will give you an array of the column values for a given line.
Splice out the column you don't want, and then join line back with , - this will get you back a line of CSV data that you can push onto a result array.
Finally at the end, join the result array with \n and there you have it - a new string containing CSV data without column you don't want.
Note that this will not properly handle quotes / other gotcha's that come with CSV data, but if your data doesn't contain any of that you're in the clear.
Sample using map:
// raw CSV data from somewhere
var csv =
'Category,Total,Under $1000\n' +
'Music,14744,1434,3450\n' +
'Art,12796,1216,7748\n';
// split on newlines, map over each line
var newCsv = csv.split('\n').map(function(line) {
var columns = line.split(','); // get the columns
columns.splice(1, 1); // remove total column
return columns;
}).join('\n'); // join on newlines
console.log(newCsv);
http://jsfiddle.net/PZ9vM/

Add the column removal as suggested by Trevor to this and your csv parser can handle stuff like quotes as well.

Maybe just use some splicing and slicing?
var data; //note, you're loading it in as a flat file with $.get()
$.get("/url/to/the/csvfile", function(d){
data = d.splice("\n");
var length = data.length; //so as to save loop runtime
for (var i = 0; i < length; i ++){
data[i] = data[i].splice(",")[0] + data[i].splice(",").slice(2)
//this will split data[i] into the first piece before the comma
//along with everything from the 2nd index to the end of the
//array that was spliced with ","
}
}
splicing and slicing are so much fun...
edit:
I forgot that you don't need to specify the end index with .slice().

Here's a nifty little vanilla JavaScript for you to remove a column from CSV data:
Working Demo
Code:
var csv =
'Category,Total,Under $1000\n' +
'Music,14744,1434,3450\n' +
'Art,12796,1216,7748\n';
// Made it a function to make it reusable!
function removeColumn(data, colIndex) {
var temp = data.split("\n");
for(var i = 0; i < temp.length; ++i) {
temp[i] = temp[i].split(",");
temp[i].splice(colIndex,1);
temp[i] = temp[i].join(","); // comment this if you want a 2D array
}
return temp.join("\n"); // returns CSV
return temp; // returns 2D array
return d3.csv.parse(temp); // returns a parsed object
}
console.log(removeColumn(csv,1));

Related

How do I insert an array into a Google Doc using data from Google Sheets?

I am trying to pull a range of names from a Google sheet and place it into a Google Doc.In the spreadsheet, the last names("lastNames") come before the first names ("firstNames"), and both are in separate columns. I am trying to place the first and last names together into my doc with the first names first.
I used a for loop to put the first and last names together into an array ("fullNames"), and that part works just fine. When I used Logger.log, all the first names and last names are together in an array, with each full name separated by a common, just the way I wanted them to be.
What I can't figure out how to do is actually insert this new array into the body of the document. I am using the appendTable method, but every time I try to I get the following error: "The parameters (number[]) don't match the method signature for DocumentApp.Body.appendTable."
What changes do I have to make to my code to actually place my new array into my google doc?
function namePusher() {
var ss = SpreadsheetApp.openById("1CHvnejDrrb9W5txeXVMXxBoVjLpvWSi40ehZkGZYjaY");
var lastNames = ss.getSheetByName("Campbell").getRange(2, 2, 18).getValues();
var firstNames = ss.getSheetByName("Campbell").getRange(2, 3, 18).getValues();
//Logger.log(firstNames);
var fullNames = [];
for(var i = 0; i < firstNames.length; i++){
var nameConcat = firstNames[i] + " " + lastNames[i]
fullNames.push(nameConcat);
}
//Logger.log(fullNames);
var doc = DocumentApp.getActiveDocument().getBody();
doc.appendTable(fullNames);
}
Modification points:
I think that there 2 reasons in your issue.
Values retrieved by getValues() is 2 dimensional array.
data of appendTable(data) is required to be 2 dimensional array.
In your script, fullNames is 1 dimensional array. By this, such error occurs.
In your script, the values are retrieved 2 columns using 2 getValues(). In this case, the cost will become a bit high. You can retrieve the values using one getValues().
When these points are reflected to your script, it becomes as follows.
Modified script:
function namePusher() {
var ss = SpreadsheetApp.openById("1CHvnejDrrb9W5txeXVMXxBoVjLpvWSi40ehZkGZYjaY");
var values = ss.getSheetByName("Campbell").getRange("B2:C19").getValues(); // Modified
var fullNames = [];
for(var i = 0; i < values.length; i++){ // Modified
var nameConcat = [values[i][1] + " " + values[i][0]]; // Modified
fullNames.push(nameConcat);
}
var doc = DocumentApp.getActiveDocument().getBody();
doc.appendTable(fullNames);
}
References:
getValues()
appendTable(cells)
One simple way to fix your code is by replacing
fullNames.push(nameConcat);
by
fullNames.push([nameConcat]);
The problem with your script is that fullNames is an Array of strings but your should pass an Array of Arrays of strings (or objects that might be coerced to strings).
Basic demo
var data = [
['A','B','C'],
[1, 'Apple','Red'],
[2, 'Banana','Yellow']
];
function myFunction() {
const doc = DocumentApp.getActiveDocument();
const body = doc.getBody();
body.appendTable(data);
}
As mentioned on Tanaike's answer there are other "improvement opportunities"
Reduce the number of calls to the Google Apps Script Classes and Methods
Use better ways to manage Arrays and to concatenate strings.

Merging Multiple Arrays Evenly/Alternating with Javascript and Google AppScript

I'm trying to merge multiple arrays evenly/alternating in javascript/Google appScript. There are several arrays (5 or 6). I've tried 2 different methods, but neither worked. I don't work a lot with javascript honestly and I've managed to get the code to this point, but I can't get it merge properly; and most of them said merging two arrays to one (might be my problem).
I've seen plenty on php examples that were on how to do this and they are pretty straight forward in logic reading and I understand them better, but all javascript methods I've looked at and tried so far have failed to produce the results I want. I'm not sure if it's the way AppScript is formatting the arrays or they're just no made to handle more that 2.
My data looks similar to this at the moment:
var title = ["sometitle1","sometitle2","sometitle3"];
var link = ["somelink1","somelink2","somelink3"];
var date = ["somedate1","somedate2","somedate3"];
var data = ["somedata1","somedata2","somedata3"];
var all = [title,link,date,data];
var mix = [];
Note: all the variable data will/should be the same length since the data is being pulled from a spreadsheet.
My desired output is:
mix = ["sometitle1","somelink1","somedate1","somedata1","sometitle2","somelink2","somedate2","somedata2","sometitle3","somelink3","somedate3","somedata3"];
I tried using appscript to merge them with this: return ContentService.createTextOutput(title + link + data + date), but it didn't work out properly, it printed them in that order instead of merging the way I'd like them too.
Then I tried using a loop merge that I found here on sstackoverflow:
for (var i = 0; all.length !== 0; i++) {
var j = 0;
while (j < all.length) {
if (i >= all[j].length) {
all.splice(j, 1);
} else {
mix.push(all[j][i]);
j += 1;
}
}
}
But it splice merges every letter with a comma
mix = [s,o,m,e,t,i,t,l,e,1,s,o,m,e,t,i,t,l,e,2,s,o,m,e,t,i,t,l,e,3,s,o,m,e,l,i,n,k,1,...]
and doesn't alternate data either.
The code (2 version) I'm working on is: here with Output
&
Here with Output
(Also, dumb question, but do I use title[i] + \n OR title[i] + "\n" for adding new lines?)
Use a for loop and the push() method like this :
function test(){
var title = ["sometitle1","sometitle2","sometitle3"];
var link = ["somelink1","somelink2","somelink3"];
var date = ["somedate1","somedate2","somedate3"];
var data = ["somedata1","somedata2","somedata3"];
//var all = [title,link,date,data];
var mix = [];
for(var n=0;n<title.length;n++){
mix.push(title[n],link[n],date[n],data[n]);
}
Logger.log(JSON.stringify(mix));
}
And also : title[i] + "\n" for adding new lines
Edit following comments :
Your code should end like this :
...
for(var n=0;n<titles.length;n++){
mix.push(titles[n],links[n],descriptions[n],pubdates[n],authors[n]);
}
var mixString = mix.join('');// convert the array to a string without separator or choose the separator you want by changing the argument.
//Print data and set mimetype
return ContentService.createTextOutput(mixString)
.setMimeType(ContentService.MimeType.RSS);
}

converting plain text into json

Suppose I have a text file that I want to convert into json file. Precisely, I want to convert each line $line to "$line":"someid" . Is there a proper way to do that using bash script langage or javascript.
For example
I want to
convert
text into
json
would output
{{"I want to":"1"},{"convert","2"},{"text into":"3"},{"json":"4"}}
You can't do your expected output like that because you will produce a syntax error, but you can put multiple objects in an array instead. Something like this:
HTML
<div id="id">
I want to
convert
text into
json
</div>
JS
var textArr = document.querySelector('#id').innerHTML.split('\n');
function produceJSON(textArr) {
var arr = [];
// we loop from 1 to 1 less than the length because
// the first two elements are empty due to the way the split worked
for (var i = 1, l = text.length - 1; i < l; i++) {
var obj = {};
obj[text[i]] = i;
arr.push(obj);
}
return JSON.stringify(arr);
}
var json = produceJSON(textArr);
DEMO

Return a specific line from a csv file using the data.split function in jquery

I am using the following code to get contents from a csv file
$.get(file , function(data) {
var lines = data.split('\n');
$.each(lines, function (lineNo, line) {
var items = line.split(',');
// MORE STUFF
});
});
The above code gives me all the lines that are available in my csv file. Here is an example of the data returned
one,0,0,
two,0,0
three,0,0
What i would like is to retrieve only a specific line from the file. for example "two,0,0"
How do i acheive this ?
Thanks
Once you split a string, the result is a numeric array with each portion of the string. So all of your lines are now numbered like any other numeric array. If you wanted the second line, you would just use the key to ask for it:
var lines = data.split("\n");
var secondLine = lines[1];

how to load two dimensional array in javascript

I have a string containing many lines of the following format:
<word1><101>
<word2><102>
<word3><103>
I know how to load each line into an array cell using this:
var arrayOfStuff = stringOfStuff.split("\n");
But the above makes one array cell per line, I need a two-dimensional array.
Is there a way to do that using similar logic to the above without having to re-read and re-process the array. I know how to do it in two phases, but would rather do it all in one step.
Thanks in advance,
Cliff
It sounds like you're hoping for something like Python's list comprehension (e.g. [line.split(" ") for line in lines.split("\n")]), but Javascript has no such feature. The very simplest way to get the same result in Javascript is to use a loop:
var lines = lines.split("\n");
for (var i = 0; i < lines.length; i++) {
lines[i] = lines[i].split(" ");
// or alternatively, something more complex using regexes:
var match = /<([^>]+)><([^>]+)>/.exec(lines[i]);
lines[i] = [match[1], match[2]];
}
Not really. There are no native javascript functions that return a two-dimensional array.
If you wanted to parse a CSV for example, you can do
var parsedStuff = [];
stringOfStuff.replace(/\r\n/g, '\n') // Normalize newlines
// Parse lines and dump them in parsedStuff.
.replace(/.*/g, function (_) { parsedStuff.push(_ ? _.split(/,/g)) : []; })
Running
stringOfStuff = 'foo,bar\n\nbaz,boo,boo'
var parsedStuff = [];
stringOfStuff.replace(/\r\n/g, '\n')
.replace(/.*/g, function (_) { parsedStuff.push(_ ? _.split(/,/g)) : []; })
JSON.stringify(parsedStuff);
outputs
[["foo","bar"],[],["baz","boo","boo"]]
You can adjust the /,/ to suite whatever record separator you use.

Categories