I am stuck.. Error is thrown # Line 63 and sometimes at line 50. Both using the appendTableRow() method. I can't find anything wrong.
row3.appendTableCell(entryDesc)
Link to generated file: Link
Execution Transcript: Link
I am new so if you notice any "bad practices" feel free to aim a finger.
// Import data from the Calendar to the timesheet document
function importDataToTS (dateStart,dateFinish,doc) {
if (!dateStart) {
var dateStart = new Date('January 1, 2014');
}
var cal = CalendarApp.getCalendarById('0k2s9lfibn50scj41gcuurovck#group.calendar.google.com')
var events = cal.getEvents(dateStart, dateFinish);
var oldDate = new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate() - 1);
var paragraph = "";
var totalHoursWorked = 0
// START --- Text element styles
// Date
var entryDateStyle = {};
entryDateStyle[DocumentApp.Attribute.BOLD] = true;
entryDateStyle[DocumentApp.Attribute.FONT_SIZE] = 18;
// Title
var entryTitleStyle = {};
entryTitleStyle[DocumentApp.Attribute.FONT_SIZE] = 14;
// entryTimes
var entryTimesStyle = {};
entryTimesStyle[DocumentApp.Attribute.BOLD] = true;
entryTimesStyle[DocumentApp.Attribute.FONT_SIZE] = 12;
// entryDescription
var entryDescriptionStyle = {};
entryDescriptionStyle[DocumentApp.Attribute.ITALIC] = true;
entryDescriptionStyle[DocumentApp.Attribute.FONT_SIZE] = 10;
// END --- Text element styles
var entriesTable = doc.appendTable();
Logger.log(entriesTable.getType());
for (var i = 0; i in events; i++) {
var entryDate = events[i].getStartTime();
if (i > 0) {
oldDate = (events[i-1].getStartTime());
}
// If it's a new day add a full width cell
if (entryDate.getDate() > oldDate.getDate()) {
var row1 = entriesTable.appendTableRow();
row1.appendTableCell(shortDate(entryDate,4));
//.setAttributes(entryDateStyle);
}
// Add title, start/end times & hours worked
// Add title, start/end times & hours worked
var entryTitle = events[i].getTitle();
Logger.log(i + ": " + entryTitle);
var entryTimes = shortTime(events[i].getStartTime(),2) + " - " + shortTime(events[i].getEndTime(),2);
Logger.log(i + ": " + entryTimes);
var entryHoursWorked = ((events[i].getEndTime() - events[i].getStartTime())/(1000*60*60)%24) + "hr(s)";
Logger.log(i + ": " + entryHoursWorked);
var row2 = entriesTable.appendTableRow();
row2.appendTableCell(entryTitle);
//.setAttributes(entryTitleStyle);
row2.appendTableCell(entryTimes + "\t\t" + entryHoursWorked);
//.setAttributes(entryTimesStyle);
// Add entry description
var entryDesc = (events[i].getDescription().length > 1) ? events[i].getDescription().toString() : "";
if (entryDesc.length > 1) {
var row3 = entriesTable.appendTableRow();
row3.appendTableCell();
row3.appendTableCell(entryDesc);
//.setAttributes(entryDescriptionStyle);
}
totalHoursWorked += entryHoursWorked;
if (i === (events.length - 1)) {
var lastRow = entriesTable.appendTableRow();
lastRow.appendTableCell("Total Hours: " + totalHoursWorked);
}
}
for (var i = 0; i in entriesTable; i++) {
for (var j = 0; j in entriesTable[i]; j++) {
Logger.log(i + ":" + j + " " + entriesTable[i][j].toString());
}
}
doc.appendTable(entriesTable);
}
shortDate() && shorttTime()
function shortDate(date,n) {
// Returns a date object as "MMMDD";
if (date) {
switch (n) {
case 1:
//Jul6
return Utilities.formatDate(date, "EST", "MMMdd")
break;
case 2:
//Jul 6
return Utilities.formatDate(date, "EST", "MMM dd")
break;
case 3:
//July 6
return Utilities.formatDate(date, "EST", "MMMM dd")
break;
case 4:
return Utilities.formatDate(date, "EST", "EEE, MMM dd")
break;
default:
//Full Date unchanged
return date;
}
}
}
function shortTime(date) {
//Returns time string formatted as "hh:mm"am/pm
//Still needs to be updated with Utilities.formatDate
if (date) {
var hours = (date.getHours() > 12) ? (date.getHours() - 12) : date.getHours();
var ampm = (date.getHours() > 12) ? "pm" : "am";
var minutes = (date.getMinutes() == 0) ? "00" : date.getMinutes();
var time = hours + ":" + minutes + ampm
return time.toString();
}
}
I found a solution, it appears that: body.appendTableCell(); doesn't handle line breaks "\n". When the script was importing a multi-line event description from the calendar I would get a "server error" message. Adding split('\n') to the description row solved the problem. This worked: body.appendTableCell(data).split("\n");
Finished code:
var entryDesc = (events[i].getDescription().length > 1) ? events[i].getDescription() : "";
if (entryDesc) {
var row3 = entriesTable.appendTableRow();
row3.appendTableCell("");
row3.appendTableCell(entryDesc.split("\n"))
.setAttributes(entryDescriptionStyle);
}
I don't have a complete answer but I thought it might be interesting in the mean time to show a version that works without the event description.
I changed the calculation of total time that didn't work either.
Code can be tested on any default calendar using test function.
function test(){
//dateStart,dateFinish,doc
var doc = DocumentApp.getActiveDocument();
var dateStart = new Date('January 1, 2014');
var dateFinish = new Date('April 1, 2014')
importDataToTS (dateStart,dateFinish,doc);
}
function importDataToTS (dateStart,dateFinish,doc) {
if (!dateStart) {
var dateStart = new Date('January 1, 2014');
}
var cal = CalendarApp.getDefaultCalendar();
var events = cal.getEvents(dateStart, dateFinish);
var oldDate = new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate() - 1);
var paragraph = "";
var totalHoursWorked = 0
// START --- Text element styles
// Date
var entryDateStyle = {};
entryDateStyle[DocumentApp.Attribute.BOLD] = true;
entryDateStyle[DocumentApp.Attribute.FONT_SIZE] = 18;
// Title
var entryTitleStyle = {};
entryTitleStyle[DocumentApp.Attribute.FONT_SIZE] = 14;
// entryTimes
var entryTimesStyle = {};
entryTimesStyle[DocumentApp.Attribute.BOLD] = true;
entryTimesStyle[DocumentApp.Attribute.FONT_SIZE] = 12;
// entryDescription
var entryDescriptionStyle = {};
entryDescriptionStyle[DocumentApp.Attribute.ITALIC] = true;
entryDescriptionStyle[DocumentApp.Attribute.FONT_SIZE] = 10;
// END --- Text element styles
var entriesTable = doc.appendTable();
Logger.log('events.length = '+events.length);
for (var i = 0; i <events.length; i++) {
var entryDate = events[i].getStartTime();
if (i > 0) {
oldDate = (events[i-1].getStartTime());
}
Logger.log('i = '+i);
// If it's a new day add a full width cell
if (entryDate.getDate() > oldDate.getDate()) {
var row1 = entriesTable.appendTableRow();
row1.appendTableCell(shortDate(entryDate,4))
.setAttributes(entryDateStyle);
}
// Add title, start/end times & hours worked
var entryTitle = events[i].getTitle();
var entryTimes = shortTime(events[i].getStartTime(),2) + " - " + shortTime(events[i].getEndTime(),2);
var entryHoursWorked = (events[i].getEndTime().getTime() - events[i].getStartTime().getTime())/(1000*60*60) + "hr(s)";
var row2 = entriesTable.appendTableRow();
row2.appendTableCell(entryTitle)
.setAttributes(entryTitleStyle);
row2.appendTableCell(entryTimes + "\t\t" + entryHoursWorked)
.setAttributes(entryTimesStyle);
// Add entry description
var entryDesc = (events[i].getDescription().length > 2) ? events[i].getDescription() : "";
totalHoursWorked += Number(entryHoursWorked.replace(/\D/g,''));
if (i === (events.length - 1)) {
var lastRow = entriesTable.appendTableRow();
lastRow.appendTableCell("Total Hours: " + totalHoursWorked+' Hours');
}
}
for (var i = 0; i in entriesTable; i++) {
for (var j = 0; j in entriesTable[i]; j++) {
Logger.log(i + ":" + j + " " + entriesTable[i][j].toString());
}
}
doc.saveAndClose();
}
Related
Basically the code (you guys probably can write it much cleaner than I) works perfectly on the first run through.
var doorSelection = ["a", "b", "c"];
var started = false;
var notPicked = true;
var notFinalChosen = true;
var wins = 0;
var losses = 0;
let roundComplete = false;
document.querySelector(".scoreCorrect").textContent = wins;
document.querySelector(".scoreWrong").textContent = losses;
document.querySelector(".heresText").classList.add("invisible");
document.querySelector(".startButton").addEventListener("click", function(){
document.querySelector(".startButton").classList.add("invisible");
mhGame();
started = true;
})
function mhGame(){
document.querySelector(".heresText").classList.remove("invisible");
var doorNumber = Math.floor(Math.random() * 3);
var doorPicker = doorSelection[doorNumber];
console.log(doorNumber + " " + doorPicker);
var doorContainer = document.querySelectorAll(".doorcontainer")[doorNumber];
var car = document.querySelector(".car");
car.classList.remove("invisible");
var doorContainerRect = doorContainer.getBoundingClientRect();
var carRect = car.getBoundingClientRect();
var carPosLeft = doorContainerRect.left - carRect.left + 50;
var carPosTop = doorContainerRect.top - carRect.top + 240;
car.style.left = carPosLeft + "px";
car.style.top = carPosTop + "px";
for(var i=0; i<3; i++){
document.querySelectorAll(".doorcontainer")[i].addEventListener("click", function(){
if (started && notPicked){
var firstPicked = this.textContent.trim();
console.log(firstPicked);
darkenDoor(firstPicked);
notPicked = false;
setTimeout(function(){
var doorsLeft = doorSelection.filter(function(door) {
return door !== firstPicked && door !== doorPicker;
});
var doorToReveal = doorsLeft[Math.floor(Math.random() * doorsLeft.length)];
console.log(doorToReveal);
hostReveal(doorToReveal);
document.querySelector(".heresText").classList.add("invisible");
document.querySelector(".switch").classList.remove("invisible");
document.querySelector(".stay").classList.remove("invisible");
for(var j=0; j<2; j++){
document.querySelectorAll(".buttonChoice div")[j].addEventListener("click", function(){
if(notFinalChosen){
var finalChoice = this.textContent;
if (finalChoice === "Switch"){
removeDarken(firstPicked);
var finalDoor = doorSelection.filter(function(newdoor){
return newdoor !== firstPicked && newdoor !== doorToReveal;
})
var openFinalChoice = "." + finalDoor + " .door";
document.querySelector(openFinalChoice).classList.add("invisible");
notFinalChosen = false;
console.log(finalDoor + ", " + doorPicker);
if(finalDoor == doorPicker){
document.querySelector(".heading").textContent = "You Win!";
wins++;
}
else{
document.querySelector(".heading").textContent = "Fail!";
losses++;
}
document.querySelector(".scoreCorrect").textContent = wins;
document.querySelector(".scoreWrong").textContent = losses;
}
else {
var openFinalChoice = "." + firstPicked + " .door";
removeDarken(firstPicked);
document.querySelector(openFinalChoice).classList.add("invisible");
notFinalChosen = false;
if(firstPicked === doorPicker){
document.querySelector(".heading").textContent = "You Win!";
wins++;
}
else{
document.querySelector(".heading").textContent = "Fail!";
losses++;
}
document.querySelector(".scoreCorrect").textContent = wins;
document.querySelector(".scoreWrong").textContent = losses;
}
}
resetGame();
})
}
}, 2000)
}
})
}
}
function darkenDoor(varsTemp){
var doorVars = document.querySelector("." + varsTemp);
doorVars.classList.add("darken");
}
function removeDarken(varsTemp2){
var doorVars2 = document.querySelector("." + varsTemp2);
doorVars2.classList.remove("darken");
}
function hostReveal(revealed){
var revealedDoor ="." + revealed + " .door";
document.querySelector(revealedDoor).classList.add("invisible");
}
function resetGame(){
setTimeout(function(){
console.log(doorSelection);
roundComplete = false;
started = false;
notPicked = true;
notFinalChosen = true;
document.querySelector(".switch").classList.add("invisible");
document.querySelector(".stay").classList.add("invisible");
document.querySelector(".car").classList.add("invisible");
document.querySelector(".car").style.left = 0 + "px";
document.querySelector(".car").style.top = 0 + "px";
document.querySelector(".startButton").classList.remove("invisible");
doorPicker = null;
doorNumber = null;
doorToReveal = null;
finalChoice = null;
finalDoor = null;
doorsLeft = null;
openFinalChoice = null;
for(var m=0; m<doorSelection.length; m++){
document.querySelectorAll(".door")[m].classList.remove("invisible");
}
document.querySelector(".heading").textContent = "Welcome to the Monty Hall Game!";
}, 3000)
}
But once I call resetGame(); and I've tried many different things including a true/false statement to trigger it, and placing it in different places (I have no idea what I'm doing with this part now), it opens the door with the car in it on the second round, then doesn't remove the "darken" by the third round, and by maybe the 4th or 5th round, the "start" button stops working as a whole.
I am working on HOCR format of tesseract OCR, i am stuck when i have a text based on multiple lines. HOCR Format contains bounding box for every word and multi-line text issue can be solve if i merge all the texts of words if they have same x1.
I am using java script for this task.
This is sample image i am using, due to privacy issues i have masked the confidential data.
Here is my code, i know its not well written so i am open to any cretic.
//merging 2 lines(currentLine, previousLine)
function merge2lines(ocrLine, ocrPrevLine)
{
var stringOutCome="";
var stringOutComeOuterLine="";
//get all the words in this line
var lineItems = $(ocrLine).children();
var CoordinatesOfItemForFirstLineOfSecondLine='';
var textOfItemForFirstLineOfSecondLine='';
var prevLineItems = $(ocrPrevLine).children();
//loop over all words
var lineItemsCount = lineItems.length;
for (var i=0;i<lineItemsCount;i++)
{
var stringInfo = lineItems[i].textContent;
if (typeof stringInfo === 'string' && stringInfo.trim().length > 0)
{
var str = lineItems[i].title;
var title = (str).split(";");
var firstSpace = title[0].indexOf(" ");
var newStr = title[0].slice(firstSpace);
var coordinates = newStr.split(' ');
if(i==0){
CoordinatesOfItemForFirstWordOfSecondLine = coordinates;
textOfItemForFirstWordOfSecondLine = lineItems[i].textContent;
}
//check and remove text
if(! stringOutComeOuterLine.includes(lineItems[i].textContent))
{
stringOutComeOuterLine = stringOutComeOuterLine+" "+lineItems[i].textContent;
}
// stringOutComeOuterLine = stringOutComeOuterLine+" "+lineItems[i].textContent;
if(i<lineItemsCount-1)
{
var str2 = lineItems[i+1].title;
var title2 = (str2).split(";");
var firstSpace2 = title2[0].indexOf(" ");
var newStr2 = title2[0].slice(firstSpace2);
var coordinates2 = newStr2.split(' ');
var differenceOfCordinates = Math.abs(coordinates[3] - coordinates2[1]);
// console.log(lineItems[i].textContent,+" pakistan <- -> Block B",lineItems[i+1].textContent," DIfference: ",differenceOfCordinates);
if(parseInt(differenceOfCordinates) < 100)
{
stringOutComeOuterLine = stringOutComeOuterLine+" "+lineItems[i+1].textContent;
}
else{
var check = true;
// check previousLineitem x
for (var j=0;j<prevLineItems.length;j++)
{
var prevString = prevLineItems[j].textContent;
if (typeof prevString === 'string' && prevString.trim().length > 0)
{
var previousLineTitle = prevLineItems[j].title;
var splittedPreviousLineTitle = (previousLineTitle).split(";");
var previousLineItemFirstSpace = splittedPreviousLineTitle[0].indexOf(" ");
var previousLineItemCoordinates = splittedPreviousLineTitle[0].slice(previousLineItemFirstSpace);
var previousLineItemCoordinatesList = previousLineItemCoordinates.split(' ');
var stringDifference = Math.abs(previousLineItemCoordinatesList[1] - CoordinatesOfItemForFirstWordOfSecondLine[1]);
// console.log(prevLineItems[j].textContent,"->",textOfItemForFirstWordOfSecondLine,"Diff:", stringDifference);
if(stringDifference < 20 && check == true)
{
check = false;
// stringOutComeOuterLine = prevLineItems[j].textContent +" "+ stringOutComeOuterLine;
stringOutCome = stringOutCome+" "+prevLineItems[j].textContent;
}
else{
if(j<prevLineItems.length-1)
{
console.log(prevLineItems[j+1].textContent);
var previousLineTitleNext = prevLineItems[j+1].title;
var splittedPreviousLineTitleNext = (previousLineTitleNext).split(";");
var previousLineItemFirstSpaceNext = splittedPreviousLineTitleNext[0].indexOf(" ");
var previousLineItemCoordinatesNext = splittedPreviousLineTitleNext[0].slice(previousLineItemFirstSpaceNext);
var previousLineItemCoordinatesListNext = previousLineItemCoordinatesNext.split(' ');
var previousLineDiff = Math.abs(previousLineItemCoordinatesList[3] - previousLineItemCoordinatesListNext[1]);
// console.log("Previous Item",prevLineItems[j].textContent,"->Next Item:",prevLineItems[j+1].textContent,"previousLineDiff:", previousLineDiff);
// console.log("<br> left coordinat: ",previousLineItemCoordinatesList[3]," Right Item: ",previousLineItemCoordinatesListNext[1]);
if(previousLineDiff < 120){
stringOutCome = stringOutCome+" "+prevLineItems[j].textContent;//+" "+prevLineItems[j+1].textContent;
// console.log(stringOutCome,"previousLineDiff:", previousLineDiff);
}
else{
// stringOutComeOuterLine = prevLineItems[j].textContent +" "+ stringOutComeOuterLine;
stringOutCome = stringOutCome +" "+stringOutComeOuterLine;
}
}else{
// console.log("Else Part");
stringOutComeOuterLine = stringOutCome +" "+stringOutComeOuterLine;
}
}
// console.log(stringOutComeOuterLine);
}
}
}
}else{
// stringOutComeOuterLine = lineItems[i].textContent+" "+stringOutComeOuterLine;
// check previousLineitem x
for (var j=0;j<prevLineItems.length;j++)
{
var prevString = prevLineItems[j].textContent;
if (typeof prevString === 'string' && prevString.trim().length > 0)
{
var previousLineTitle = prevLineItems[j].title;
var splittedPreviousLineTitle = (previousLineTitle).split(";");
var previousLineItemFirstSpace = splittedPreviousLineTitle[0].indexOf(" ");
var previousLineItemCoordinates = splittedPreviousLineTitle[0].slice(previousLineItemFirstSpace);
var previousLineItemCoordinatesList = previousLineItemCoordinates.split(' ');
// console.log(prevLineItems[j].textContent,"->",textOfItemForFirstWordOfSecondLine,"Diff:", stringDifference);
if(j<prevLineItems.length-1)
{
console.log(prevLineItems[j+1].textContent);
var previousLineTitleNext = prevLineItems[j+1].title;
var splittedPreviousLineTitleNext = (previousLineTitleNext).split(";");
var previousLineItemFirstSpaceNext = splittedPreviousLineTitleNext[0].indexOf(" ");
var previousLineItemCoordinatesNext = splittedPreviousLineTitleNext[0].slice(previousLineItemFirstSpaceNext);
var previousLineItemCoordinatesListNext = previousLineItemCoordinatesNext.split(' ');
var previousLineDiff = Math.abs(previousLineItemCoordinatesList[3] - previousLineItemCoordinatesListNext[1]);
// console.log("Previous Item",prevLineItems[j].textContent,"->Next Item:",prevLineItems[j+1].textContent,"previousLineDiff:", previousLineDiff);
// console.log("<br> left coordinat: ",previousLineItemCoordinatesList[3]," Right Item: ",previousLineItemCoordinatesListNext[1]);
if(previousLineDiff < 120){
stringOutCome = stringOutCome+" "+prevLineItems[j].textContent;//+" "+prevLineItems[j+1].textContent;
// console.log(stringOutCome,"previousLineDiff:", previousLineDiff);
}
else{
// stringOutComeOuterLine = prevLineItems[j].textContent +" "+ stringOutComeOuterLine;
stringOutCome = stringOutCome +" "+stringOutComeOuterLine;
}
}else{
// console.log("Else Part");
stringOutComeOuterLine = stringOutCome +" "+stringOutComeOuterLine;
}
// console.log(stringOutComeOuterLine);
}
}
}
}
}
console.log(stringOutComeOuterLine);
return stringOutComeOuterLine;
}
With Google Apps Script I created a stacked bar chart. This is the result:
https://drive.google.com/file/d/1DZ2ZtSu2A81OAMc9ds9A4y-bS0l_oftL/view?usp=sharing
I would like to hide the labels on the bars when they are too wide compared to the available space. Following the instructions I found at this address https://developers.google.com/chart/interactive/docs/reference#DataView_setColumns I tried to use a custom function instead of "stringify" in the "annotationObj" object ( see the code) to create a label of zero length, but my function is not recognized when I try to create the chart (error message: Unknown function "getValueAt").
This is my code:
function CHARTS_002() { //
var ABCarray = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ','BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ','CA','CB','CC','CD','CE','CF','CG','CH','CI','CJ','CK','CL','CM','CN','CO','CP','CQ','CR','CS','CT','CU','CV','CW','CX','CY','CZ'];
var ssId = '1KA2BnUsC-Lp64UhxjtN5Gtth2dOiHp3-pRwIQjAYOLI';
var shName = 'TopGrossingFilms';
var aScale = ["Poco d'accordo","Né d’accordo né in disaccordo","Abbastanza d'accordo","Totalmente d'accordo","Media"];
var aRange = [['B',2],['N',12]];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName(shName);
var row = aRange[0][1];
var column = ABCarray.indexOf(aRange[0][0]) + 1;
var numRows = aRange[1][1] - aRange[0][1];
var numColumns = ABCarray.indexOf(aRange[1][0]) - ABCarray.indexOf(aRange[0][0]) + 1;
var sheetV = sheet.getRange(aRange[0][1], ABCarray.indexOf(aRange[0][0]) + 1, numRows, numColumns).getValues();
var sheetT1D = sheetV[0];
var aData = [];
for (var r in sheetV) {
aData.push(sheetV[r])
}
for (var r in aData) {
for (var c in aData[r]) {
if (!isNaN(aData[r][c])) {
aData[r][c] = round(aData[r][c],2);
if (aData[0][c] == 'Media') {
aData[r][c] = 13;
}
}
}
}
var data = Charts.newDataTable();
var annotationObj = { calc: "stringify",
//calc: "getValueAt",
//calc: "function(data, row) { var ret = data[row][§col§]; if (ret < 7) {return '';} else {return JSON.stringify(ret)} }",
sourceColumn: -1,
type: "string",
role: "annotation"
}
var aAnnotation = [];
for (var r in aData) {
if (r < 1) { continue; }
if (r == 1) {
for (var c in aData[r]) {
aAnnotation.push(c);
if (isNaN(aData[r][c])) {
data.addColumn(Charts.ColumnType.STRING, aData[0][c]);
} else {
data.addColumn(Charts.ColumnType.NUMBER, aData[0][c]);
if (aScale.indexOf(aData[0][c]) != -1) {
var myObj = JSON.parse(JSON.stringify(annotationObj));
var myCol = Number(c);
if (aData[0][c] == 'Media') {
myCol = Number(c) + 1;
}
myObj.sourceColumn = myCol;
myObj.calc = myObj.calc.replace("§col§",myCol)
aAnnotation.push(myObj);
}
}
}
}
data.addRow(aData[r]);
}
var dataViewDefinition = Charts.newDataViewDefinition().setColumns(aAnnotation);
var aTicks = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
var chartBuilder = Charts.newBarChart()
.setDimensions(1200, 700)
.setOption("hAxis", { ticks: aTicks})
.setOption('legend',{ position:'top', maxLines:3 })
.setOption('chartArea',{ left:650 })
.setOption('series',{
6: {type:'line', color:'00FF00', lineWidth:3, visibleInLegend: false}
})
.setDataTable(data)
.setDataViewDefinition(dataViewDefinition)
.setOption('bar', { groupWidth: "80%" })
.setStacked()
.setColors(['#C10000','#F1C12A','#BFBFBF','#0070C1','#244062','00FF00']);
var chart = chartBuilder.build();
var chartImage = chart.getAs('image/png').copyBlob();
DriveApp.createFile(chartImage).setName('NewBarChart.png');
}
function getValueAt(column, dataTable, row) {
var value = dataTable(row, column);
var ret = '';
if (value > 7) { ret = value.toString()}
return ret;
}
function round(value, exp) {
var funcName = 'round';
if (typeof exp === 'undefined' || +exp === 0)
return Math.round(value);
value = +value;
exp = +exp;
if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
return NaN;
// Shift
value = value.toString().split('e');
value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
// Shift back
value = value.toString().split('e');
return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
}
The chart that is produced can be seen in this public folder: https://drive.google.com/file/d/1DZ2ZtSu2A81OAMc9ds9A4y-bS0l_oftL/view?usp=sharing
Does anyone know how to get the result I would like to get?
Thanks in advance.
For a while now, I've been trying to create an autolabeler for Gmail in Google Apps Script. This script parses through an email's body and looks for a line with the form "#DL:", extracts the text after that (which is a date), runs this string through a standardizer I have coded, calculates the date difference between that date and now, and if it's urgent, assigns a color to that. It gets all that information and labels that email. Here is the code I use:
var filters = [{
match: /[\n\r][ \t]*#DL:[ \t]*([^\n\r]*)/,
archive: false
}, ];
var from = [];
function labeler() {
var batchSize = 10;
var labelCache = {};
var query = "in:anywhere";
var threads = GmailApp.search(query, 0, batchSize);
GmailApp.getMessagesForThreads(threads);
var findOrCreateLabel = function(name) {
if (labelCache[name] === undefined) {
labelCache[name] = GmailApp.getUserLabelByName(name) || createLabelByGmailApi(name);
}
//GmailApp.createLabel(name);
//createLabelByGmailApi(name);
return labelCache[name];
}
var applyLabel = function(name, thread) {
var label = null;
var labelName = "";
name.split('&').forEach(function(labelPart, i) {
labelName = labelName + (i === 0 ? "" : "&") + labelPart.trim();
label = findOrCreateLabel(labelName);
});
thread.addLabel(label);
}
threads.forEach(function(thread) {
var messages = thread.getMessages();
if (messages == null) return;
var message = messages[messages.length - 1];
var body = message.getRawContent();
var archive = true;
filters.forEach(function(filter) {
var matches = filter.match.exec(body);
if (matches !== null) {
var label = filter.name || matches[1];
var data = datestd(label);
var cor = datecalc(data);
label = "Datas/" + data;
if (label !== undefined) applyLabel(label, thread);
if (filter.archive !== undefined && !filter.archive) archive = false;
}
});
if (archive) thread.moveToArchive();
});
}
function createLabelByGmailApi(name, color) {
var label = GmailApp.getUserLabelByName(name);
if (label) return label;
var textColor = "#ffffff";
if (color == 'red') {
var backgroundColor = "#ac2b16";
} else if (color == 'yellow') {
var backgroundColor = "#fad165";
} else if (color == 'green') {
var backgroundColor = "#076239";
} else {
var backgroundColor = "#41236d";
}
var userId = "me";
var resource = Gmail.newLabel();
resource.labelListVisibility = "labelShow";
resource.messageListVisibility = "show";
resource.name = name;
var labelColor = Gmail.newLabelColor();
labelColor.textColor = textColor;
labelColor.backgroundColor = backgroundColor;
resource.color = labelColor;
Gmail.Users.Labels.create(resource, userId);
return GmailApp.getUserLabelByName(name);
}
function datecalc(stringdata) {
var len = stringdata.length
var min = stringdata.slice(len - 2, len);
var hora = stringdata.slice(len - 5, len - 3);
var mes = stringdata.slice(len - 9, len - 7);
var dia = stringdata.slice(len - 12, len - 10);
min = Number(min);
hora = Number(hora);
mes = Number(mes);
dia = Number(dia);
var data = new Date(2019, mes - 1, dia, hora, min);
var data2 = Date.now();
var diff = data - data2;
diff = diff / 86400000
var color;
if (diff <= 1.5) {
color = 'red'
} else if (diff > 1.5 && diff <= 4) {
color = 'yellow'
} else {
color = 'green'
}
return color;
}
function mesnum(mon) {
var m = {
'jan': '01',
'fev': '02',
'mar': '03',
'abr': '04',
'mai': '05',
'jun': '06',
'jul': '07',
'ago': '08',
'set': '09',
'out': '10',
'nov': '11',
'dez': '12'
};
var s = mon.slice(0, 3)
var idc = String(m[s]);
if (idc.length < 2) {
idc = "0" + idc;
}
return idc;
}
function datestd(date) {
var ano = "2019";
var whitelistdias = ["terça-feira", "quarta-feira",
"quinta-feira", "sexta-feira", "sábado", "domingo",
"segunda", "terça", "quarta", "quinta", "sexta", "sabado",
"terca"
];
var whitelistmes = ["janeiro", "fevereiro", "março", "abril", "maio", "junho",
"julho", "agosto", "setembro", "outubro", "novembro",
"dezembro", "jan", "fev", "mar", "abr", "mai", "jun",
"jul", "ago", "set", "out", "nov", "dez"
];
var whitelistchar = ["/", "-", "."];
var idk = date.toLowerCase();
idk = idk.replace(/,/g, " ,");
idk = idk.split(" ");
var v;
var pos;
var dia;
var hora;
var mes;
var searchd;
var posfinal;
if (whitelistmes.some(function(v) {
return idk.indexOf(v) !== -1;
}) == true) {
idk = String(idk);
whitelistmes.forEach(function(strs) {
return idk.replace(strs, "");
});
whitelistdias.forEach(function(strq) {
return idk.replace(strq, "");
});
idk = String(idk);
idk = idk.replace("[", "");
idk = idk.replace(".", ":");
idk = idk.replace("]", "");
idk = idk.replace("de", "");
idk = idk.replace(" ", "");
idk = idk.replace("'", "");
idk = idk.replace("as", ",");
idk = idk.replace("at", ",");
idk = idk.replace("of", ",");
idk = idk.replace("às", ",");
idk = idk.replace("h", "");
idk = idk.replace(ano, "");
pos = idk.indexOf(",");
dia = idk.slice(0, pos);
idk = String(idk);
hora = idk.slice(idk.lastIndexOf(",") + 1, idk.length);
idk = idk.split(",");
mes = idk.filter(function(n) {
return whitelistmes.indexOf(n) !== -1;
});
mes = String(mes);
return dia + "/" + mesnum(mes) + ", " + hora;
} else {
idk = String(idk);
if (idk.includes("/") || idk.includes("-")) {
whitelistmes.forEach(function(strs) {
return idk.replace(strs, "");
});
whitelistdias.forEach(function(strq) {
return idk.replace(strq, "");
});
}
idk = String(idk);
idk = idk.replace(".", ":");
idk = idk.replace("[", "");
idk = idk.replace("]", "");
idk = idk.replace("de", "");
idk = idk.replace(/ /g, "");
idk = idk.replace("'", "");
idk = idk.replace("as", ",");
idk = idk.replace("às", ",");
idk = idk.replace(ano, "");
var hmm = new Array();
idk = idk.split('');
hmm = idk.reduce(function(matches, character, index) {
if (whitelistchar.includes(character)) hmm.push(index);
return hmm;
}, []);
hmm = String(hmm);
hmm = hmm.replace("[", "");
hmm = hmm.replace("]", "");
hmm = hmm.replace(" ", "");
var pos1 = hmm.indexOf(",");
if (pos1 !== -1) {
var prim = hmm.slice(0, pos1);
prim = Number(prim);
var seg = hmm.slice(pos1 + 1, hmm.length);
seg = Number(seg);
dia = idk.slice(0, prim);
mes = idk.slice(prim + 1, seg);
hora = idk.slice(seg + 1, idk.length);
} else {
hmm = Number(hmm);
pos1 = idk.indexOf(",");
dia = idk.slice(0, hmm);
mes = idk.slice(hmm + 1, pos1);
hora = idk.slice(pos1 + 1, idk.length);
}
hora = String(hora);
searchd = hora.match(/\d/);
posfinal = hora.indexOf(searchd);
hora = hora.slice(posfinal, hora.length);
idk = String(idk);
idk = idk.replace(/,/g, "");
dia = String(dia);
mes = String(mes);
hora = String(hora);
dia = dia.replace(/,/g, "");
mes = mes.replace(/,/g, "");
hora = hora.replace(/,/g, "");
hora = hora.replace(/h/g, "");
return dia + "/" + mes + ", " + hora;
}
}
To give some context to what's happening:
The labeler function gets the string from the email, sends it to the datestd function to get standardized, and that output is the name of the label. That output is also used to calculate the date difference between that date and now, through the function datecalc, which outputs a color. This color will be used by the createLabelByGmailApi function to create a label with that name and color. After this, the labeler function applies that label to the email in question.
There are 2 problems I am trying to fix, to no avail:
1. Invalid Argument Error
When running the code above, I get an "Invalid Argument" error in the thread.addLabel(label); line (the argument is label), and I don't know why.
2. Can't seem to fetch the color for the createLabelByGmailApi function
Due to the way the code is structured, I can't seem to fetch the color for the function, since this color depends on the date, which depends on the parsing of the email body, which happens later in the function. I can't seem to find a way to rearrange this so I am able to provide a color for the function, would be great if you could help.
I know this is a handful, and thanks so much for reading this, your help would be much appreciated.
How about this modification?
It seems that the reason of your issue is the crated label is not reflected soon when Gmail.Users.Labels.create() is run. By this, label became null. In order to remove this issue, I added the label using Gmail.Users.Threads.modify() when the label was created with Gmail.Users.Labels.create(). Please modify as follows.
Modified script:
Please modify applyLabel() of labeler() as follows.
From:
var applyLabel = function(name, thread) {
var label = null;
var labelName = "";
name.split('&').forEach(function(labelPart, i) {
labelName = labelName + (i === 0 ? "" : "&") + labelPart.trim();
label = findOrCreateLabel(labelName);
});
thread.addLabel(label);
}
To:
var applyLabel = function(name, thread) {
var label = null;
var labelName = "";
name.split('&').forEach(function(labelPart, i) {
labelName = labelName + (i === 0 ? "" : "&") + labelPart.trim();
label = findOrCreateLabel(labelName);
});
if (typeof label == "string") {
Gmail.Users.Threads.modify({addLabelIds: [label]}, "me", thread.getId());
} else {
thread.addLabel(label);
}
}
And, please modify createLabelByGmailApi() as follows.
From:
Gmail.Users.Labels.create(resource, userId);
return GmailApp.getUserLabelByName(name);
To:
return Gmail.Users.Labels.create(resource, userId).id;
Note:
At labelCache[name] = GmailApp.getUserLabelByName(name) || createLabelByGmailApi(name);, when createLabelByGmailApi(name) is called, name is used as the argument. But at the function of createLabelByGmailApi(name, color), name and color are used as the arguments. I think that in the current situation, #41236d is used as the default value. Please confirm this.
When I see the function of datestd(), I noticed that includes() is used. In the current stage, it cannot be used for Google Apps Script. So includes() is declared at elsewhere?
If I misunderstood your situation and this was not the direction you want, I apologize.
I am using node.js with my WebStorm IDE to parse a large JSON file (~500 megabytes). Here is my code:
fs = require("fs");
fs.readFile('C:/Users/.../Documents/AAPL.json', 'utf8', function (err,data) {
for (i = 0; i < 1000; i++) {
var hex = JSON.parse(data)[i]._source.layers.data["data.data"];
var askPrice = parseInt(hex.substring(215, 239).split(":").reverse().join(""),16);
var bidPrice = parseInt(hex.substring(192, 215).split(":").reverse().join(""),16);
var symbol = hex.substring(156, 179);
var timestamp = hex.substring(132, 155);
var askSize = hex.substring(240, 251);
var bidSize = hex.substring(180, 191);
var price = String((+bidPrice+askPrice)/2);
var realprice = price.slice(0, price.length - 4) + "." + price.slice(price.length - 4);
function hex2a(hexx) {
var hex = hexx.toString();
var str = '';
for (var i = 0; i < hex.length; i += 2)
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
return str;
}
if(JSON.parse(data)[i]._source.layers.data["data.len"] == 84 && realprice.length == 8 && +realprice <154 && +realprice >145) {
console.log(i + " " + hex2a(symbol.replace(/:/g, "")) + " sold for " + realprice + " at " + parseInt(timestamp.split(":").reverse().join(""), 16));
}
}
});
The problem I am running into however is that my IDE is parsing this file at an extremely slow speed, roughly 1 iteration a second. I do not think this is because I have a slow computer, for I have a high end rig with a core i7 7700k and a gtx 1070. I tried executing the code in the console with the same result. I tried trimming down the code and again I achieved the same speed:
fs = require("fs");
fs.readFile('C:/Users/Brandt Winkler Prins/Documents/AAPL.json', 'utf8', function (err,data) {
for (i = 0; i < 12000; i++) {
var hex = JSON.parse(data)[i]._source.layers.data["data.data"];
var askPrice = parseInt(hex.substring(215, 239).split(":").reverse().join(""),16);
var bidPrice = parseInt(hex.substring(192, 215).split(":").reverse().join(""),16);
var price = String((+bidPrice+askPrice)/2);
var realprice = price.slice(0, price.length - 4) + "." + price.slice(price.length - 4);
if(+realprice <154 && +realprice >145) {
console.log(realprice);
}
}
});
How should I execute my code to get my data as fast as possible?
You're running JSON.parse(data) every iteration, that might take quite some time for a 500MB json file.
The solution would be to move it out of the loop and reuse the parsed object:
var obj = JSON.parse(data);
for (...