Error "Cannot find method insertChart(EmbeddedChartBuilder)" when using Apps Script to create Embedded Charts - google-apps-script

I will like to take data from a spreadsheet "dataSheet" (shared with me as View only) to create a chart and output to my own spreadsheet "sheet".
I use Apps Script to create an embeddedChart and encountered this error: Cannot find method insertChart(EmbeddedChartBuilder).
I have followed Google's guide closely https://developers.google.com/apps-script/reference/spreadsheet/embedded-chart but can't resolve the error.
I have debugged step-by-step and realised the error happens at .insertChart (last line of code).
var chartBuilder = sheet.newChart();
chartBuilder.addRange(dataSheet.getRange('R'+earliestRowUsed + 'C1:R'+latestRowUsed + 'C1'))
.setChartType(Charts.ChartType.COLUMN)
.setPosition(5,5,0,0);
//collect data from dataSheet to add to Range.
for (indicator = 0; indicator < indicatorP.length; indicator++) {
indicatorIndex = indicatorList[0].indexOf(indicatorP[indicator]);
chartBuilder.addRange(dataSheet.getRange('R'+earliestRowUsed + 'C'+(dataCol + indicatorIndex) +':'+ 'R'+latestRowUsed + 'C'+(dataCol + indicatorIndex)));
}
chartBuilder.setMergeStrategy(Charts.ChartMergeStrategy.MERGE_COLUMNS); //join columns to create a table
chartBuilder.build();
sheet.insertChart(chartBuilder); //error takes place here.
I am open to using Charts or EmbeddedCharts to create my chart for my purpose (which is to take data from a shared view-only sheet to create a chart and embed in my sheet).
For working with Charts and Sheets, I found this Google guide https://developers.google.com/chart/interactive/docs/spreadsheets#embedding-achart-in-a-spreadsheet.
However the guide only shows a manual process to create Charts, and not with Apps Script. If anyone knows how, will appreciate your sharing as I haven't been able to find anything online.
Thank you.

I think your problem is the "View Only" permissions. Pretty sure that if you want to take data from a sheet programmatically and use it somewhere else you'll need to ask for Edit privileges.

After trialing a few scenarios, I found the problem to be due to EmbeddedCharts not being able to use data from another sheet file (view-only or owned). Using data from any sheets within the file EmbeddedCharts is to be created in works.

Related

Getting gsheet Combo Charts to send them by email

This is my first question here, though I've had some helpful guidance from lots of questions before. I hope I don't miss anything important in this question.
I am currently writing a script in Google Apps Script to send some charts from a Google Sheets document by email, as images. My issue is that with Combined Charts, when I try to read them and get them as images, I get an error.
I've reduced the code to the minimum that will still throw the error I'm talking about.
function test_chart_fails(){
let gdoc_id = "xxxxxxxxxxxx";
let sheet_name = "test2";
let document = SpreadsheetApp.openById(gdoc_id);
let sheet = document.getSheetByName(sheet_name);
let charts = sheet.getCharts();
let chart = charts[2];
let inLineImages = {};
inLineImages["chartC"] = chart.getAs('image/png');
}
I get the following error:
Exception: Service Spreadsheets failed while accessing document with id xxxxxxxxxxxxxxxxxxxxxxxxxx.
test_chart_fails # AppsScriptFile.gs:305
Where 305 is the last line of my sample code (the one with 'chart.getAs').
Now some additional info that may be relevant (or not):
The sheet in question has 9 charts in total. I get this error if I try to access 7 of the 9, which are only the combined charts. Other charts will work fine, and I can put them in an email sent through MailApp. All the charts were created manually in the Gsheets document.
Regarding the data in the sheet that builds the charts, the sheet has 103 rows and 44 columns. All data in the sheet is formulas, not values.
I've searched for existing questions in this and other sites where this error message appears, but I didn't find a question where the error was related to Chart retrieval - specifically no instance related to Combo Charts. One instance mentioned an error related to the sheet size, so I mentioned the data size (rows x columns), but I don't think that is the issue - because the script runs fine for non-Combo Charts based on the same dataset.
Is this expected for combined charts? Is there a way I can 'retrieve' them and send them in an email like I do the others?
This appears to be a bug
https://issuetracker.google.com/182701055
SpreadsheetApp.getActive().getSheetByName().getCharts().getAs() returns this error: "Service Spreadsheets failed while accessing document with id" ... when the line chart has a right vertical axis
I would encourage you to go and star this issue to let Google know that it affects you and to subscribe to updates.
You are also encouraged to post any further reproduction steps and workarounds there if they haven't been mentioned yet.
Workaround you mentioned
How to obtain a correct image of a ComboChart with Google App Script?

Google Apps Script - Creating and Saving Filters for Google Sheets

I feel like a bit of a chump, but I cannot work this out...
I have been given the job of producing a new master analysis sheet each month from a supplied XML file that combines with various columns of our (multiple) sheets. No problems, so far. I have got all of that working the way I want. :-)
My issue is that we also have about 6-8 filters saved with a specific sheet that allow our auditors to focus on specific areas (and as you can understand, our auditors want these to work EXACTLY as they specify).
I have tried using createFilter() but there doesn't appear any way to save multiple filters to that sheet (maybe I am missing something). No joy! :-(
I have tried recording a macro which I could then run to create the filters. No joy here either :-(
Do I have to tell these pesky auditors to create there own filters each month (they do know how, but it's beneath them), or is there a way I can script them up and get them off my back?
Unfortunately (as much as I would like to) I cannot share our sheets or scripts as we have significant IP embedded there.
I would really appreciate some guidance as to how you might approach this (if it is possible).
Kind regards
Ian
If you're indeed talking about the 'Create new filter view', I suggest making an template sheet. So instead of creating a new sheet every month, make one template spreadsheet and add all the filter views your auditors desire. Then copy that spreadsheet, and paste the new data in it.
The correct way to create a filter using Apps Script and the createFilter() is this one:
function setFilters() {
var ss = SpreadsheetApp.getActiveSheet();
var rangeFilter = ss.getRange("INPUT_YOUR_RANGE_HERE");
var filter = rangeFilter1.createFilter();
var filterCriteria = SpreadsheetApp.newFilterCriteria();
filterCriteria.ADD_YOUR_CRITERIA_HERE;
filter.setColumnFilterCriteria(columnPosition, filterCriteria.build());
}
As you can see, you must use build() in order to build the criteria for the filter you have created.
You can also use the Sheets advanced services and create the filters using the Sheets API, something similar to this:
var filterSettings = {
//YOUR FILTER SETTINGS
};
var request = [{
"setBasicFilter": {
"filter": filterSettings
}
}];
And as for calling the Sheets service and applying the above filter, you can use this:
Sheets.Spreadsheets.batchUpdate({'requests': request}, SPREADSHEET_ID);
Reference
Range Class Apps Script createFilter();
Filter Class Apps Script;
Apps Script Google Advanced Services.

Error Connecting to Google Server using Script Editor

I am trying to use the Google Sheet's Script Editor to write a script for a Dependent List using the following script:
function setDataValid_(range, sourceRange) {
var rule =
SpreadsheetApp.newDataValidation().requireValueInRange(sourceRange,
true).build();
range.setDataValidation(rule);
}
function onEdit(){
var pageCell = SpreadsheetApp.getActiveSheet().getActiveCell();
var pageColumn = pageCell.getColumn();
if (pageColumn == 6 && SpreadsheetApp.getActiveSheet().getName() ==
'raw_data'){
var range = SpreadsheetApp.getActiveSheet().getRange(pageCell.getRow(),
pageColumn + 2);
var sourceRange =
SpreadsheetApp.getActiveSpreadsheet().getRangeByName(pageCell.getValue());
setDataValid_(range, sourceRange);
}
}
There are two different tabs I am using in this spreadsheet, "raw_data" and "Range". I had created a drop down list in column F of "raw_data" that lists values from a specified range in "range". Each of these values is also the title of a named range in that tab. The script above is suppose to read the value selected in column F and then two columns over, in column H, create another drop down list based on the values associated with that named range.
The problem I keep having is every time I click run I get the error message "Could not connect to server. Please save and try again" or if I try to set up a project trigger I get "We're sorry, a sever error occured. Please wait a bit and try again".
I have created new spread sheets, recreated the named ranges, created new script files and tried running the script from a separate computer but error message continues.
I haven't been able to find a solution to this and even when I try to use the dubug tool it gives me an error message. Does anyone know what the issue is or how I might resolve this?
I think this may be a legitimate server error at the moment because I'm getting the same error when I try to run any scripts. Same for a co-worker.
I have tried resaving several copies of my most recent script, all resulting in
Server error occurred. Please try saving the project again.
so I think that this is an issue on Google's side for some reason today.
My older scripts are running fine.
So I tried the script again this morning and it is working now. Hopefully it continues that way. Thanks for y'alls input!
Just checked the G Suite Status Dashboard and all products seems fine. This page offers performance information for G Suite services. Unless otherwise noted, this status information applies to consumer services as well as services for organizations using G Suite. No issues mentioned on Google's server as of this posting.
In script.google.com:
Resources -> Advance Google Services
Enable Drive API
You will be asked to enable it in the Google Dev console. Click the link and enable Drive API. Your script should run as intended now.

Publishing / sharing a Google Sheet via Github

I have a Google Sheet. It has a custom script (read: set of functions) associated with. I'd like to share this sheet template (i.e., tool), not with colleagues (i.e., adding them via email address as is a traditional Google drive share) but with anyone who would like a copy for themselves to use it for themselves (i.e., not my copy, their own copy). Ideally, I'd repo this project / tool on GitHub (or similar) and let them grab it there.
I can "Download As..." the sheet but the script doesn't stay "attached". Are such scripts now what Google considers Add-ons? If so, how to I keep the sheet + script as a "whole".
Also, as a temporary workaround, I tried to copy / paste the script from my working copy to another copy of the sheet (created via Download as and then opened again under a diff Google accnt). However, that didn't go as planned either. There's a function within my scrip that checks to make sure the sheet is on the first tab / sheet (i.e., getActiveSheet().getSheetId() == 0). This works on my dev / working copy. However once I copy / paste the SheetId return a 7 or 8 digit #. Is there a way to keep the SheetId relative to the sheet, and not all sheets (or whatever that Id represents.)
Note: I'm by no means a Google Sheets expert. This was just a side project for myself that I ended up building out to the point of wanting to share it with others. Please presume I know even less than you probably think I know. Thanks :)
To fix your problem with finding the first tab / sheet, use the sheet index instead of the sheet id. So instead of getActiveSheet().getSheetId() == 0, it'll be getActiveSheet().getIndex() == 0 instead.
As for downloading the script - it looks like you've created a container-bound script. There are two types of scripts that you can create, standalone and container-bound scripts. (See Google's explanation here). Standalone scripts are created by going directly to script.google.com, but I'm guessing (please correct me if I've assumed wrong) that you clicked Tools->Script editor, so that the script is locked to that specific spreadsheet. That's fine, but a) it means like you can't download it separately through Google Drive as I originally suggested, and b) when you're download the sheet, it downloads it as an Excel worksheet (which doesn't support Google App Script, so of course the script doesn't come with it).
Here's my suggestion for your use case:
Instead of downloading the spreadsheet, make a new copy of it named yourspreadsheet_public or something along those lines by going to File -> Make a Copy. (You can potentially skip this step if you just want to make your personal spreadsheet available to the world.)
Make the copy available to anyone to view by clicking Share -> Change -> Anyone with the Link (or Public on the Web) -> select "Can View" from the dropdown -> Save.
Now, you can distribute the link to whoever wants it. Anyone who has access to the file is able to make a copy in the same way you did in the first step to their own Google Drive, where they'll be able to edit their own private copy, including your script.
Let me know if that helps!
I don't understand why you want to use an external service to make copies of a spreadsheet. Since Google Scripts only run in Google spreadsheets I don't see any use case where it can be useful... but that's not the point, you do what you want.
That said, the easiest (and probably the only) one would be to share the document with someone and create an onOpen function that suggests to create a copy of it. This script should be executed after the required authorization and the copy will be their own copy, without any link to your G account anymore (which was the goal if I understood you well).
More simple and straightforward than that I can't imagine.
To avoid that their copy keeps the same onOpen behavior just setup a variable stored in userProperties so that when present this part of the onOpen doesn't execute.
This is a workflow I have already used and it works nicely.
edit :
I can suggest a completely different workflow to let other people get a personal copy of your SS.
Here is a test , give it a try and let me know if you're interested.
EDIT2 : since the other answer provides a similar workflow I decided to show the code I use in this answer to make that process more userfriendly.
I use 2 webApps :
one that runs as "me" that have access to my drive and runs without authorization for its user and that does nothing else than show a warning and a link.(accessible to anyone even anonymous)
And a second one that creates the copy and needs authorization to allow the SScopy creation in the user's own drive + a couple of links.(runs as the user accessing the app)
Code below (in 2 distinct projects of course) :
// APP 1 :
function doGet(){
var app = UiApp.createApplication().setTitle('Demo-App');
var link = app.createAnchor('Click this link to create your own copy <br>of my spreadsheet.<br>You will be asked for authorizations<br>tocreate a spreadsheet in your drive',true,'https://script.google.com/macros/s/AKfycbwQ5s_WWrsWXx_umZ1v91XGnm3RaO2Z7UQSXNiWFiaTwGuXIXqq/exec');
app.add(app.createVerticalPanel().setStyleAttribute('padding','50px').add(link));
return app;
}
// APP 2
function doGet(){
var ss = SpreadsheetApp.openById('0AnqSFd3iikE3dGNEUDdoLWhUZl9sZ3Z2Zm5XbjZzTkE');
var copy = ss.copy(ss.getName()); / the SS is shared to "anyone with the link can view"
var app = UiApp.createApplication().setTitle('SSCreate');
var panel = app.createVerticalPanel().setStyleAttribute('padding','50px');
panel.add(app.createHTML('A new spreadsheet has been created in your drive with name '+ss.getName()));
panel.add(app.createAnchor('Open it from <b>here</b>',true,copy.getUrl()));
panel.add(app.createAnchor('or from your own Drive','https://drive.google.com/?authuser=0#all'));
return app.add(panel);
}

Using a Custom Function in a Google Spreadsheet?

I'm trying to figure out how I can write and run a custom function in a Google spreadsheet and I've been following this google tutorial.
However at the time of this posting, I fear that this tutorial is out of date. I followed the steps, but see no way to access my in2mm function from within the spreadsheet that I started at. The tutorial suggests the following to make it show up
You can manually start the scan by going to Tools > Script Manager... and clicking the Reload button.
However, no such menu item exists.
Just cut off in that screenshot is a "Script Center Menu", which has just one option for "Read Data". It's unclear what that does. It's also unclear how the "Script Editor" ends up tying back into the existing spreadsheet to become available...
Does anyone know the current steps required to write a simple google script function and then access it from within a Google spreadsheet?
I had the same problem, and while the tutorial and Sum Ting Wong's answer actually do work, it didn't help in my case.
The sheet I was trying to use the custom function from was in the old format. So I converted it to the new format,created a custom function, and now I can use it the sheet.
Here's how you see if it's an old format sheet Check out the new Google Sheets
You can tell that a spreadsheet has been created in, or upgraded to, the new Google Sheets if it has a green checkmark at the bottom.
and here's how to convert it to the new format:
Moving spreadsheets to the new Google Sheets
you can manually move spreadsheet contents into the new version of Sheets to take advantage of new functionality, following any of these steps:
Copy and paste content from a spreadsheet created in the old version to a spreadsheet created in the new version.
In a spreadsheet created in the old version, click the down arrow next to a sheet tab and click Copy to…, and copy the sheet (and its contents) to a spreadsheet created in the new version.
Export the contents from the old version and import them into a spreadsheet created in the new version.
forget the reload button hint.
if you have in the first step write your function in the script editor and save it.
function in2mm(inNum) { // Function to convert from INCHES to MILLIMETERS
var outNum = 0; // this will hold the answer
var factor = 25.4; // multiply input by this factor to get output
if (typeof inNum != "number") { // check to make sure input is a number
throw "input must be a number"; // throw an exception with the error message
}
outNum = inNum * factor; // calculate the answer
return outNum; // return the answer to the cell which has the formula
}
for your second step write e.g. in cell A1 of your sheet, to call the function
=in2mm(10)
important is that you call your function-name started with the equal sign =
if you do a type-mismatch by your second step you get the message
#NAME?
there is no mystic and no out of date ;-) btw i imagine they talk from the browser reload button
Custom Function still work in google sheets.
function GETKWEEKDAYFROMNBR(weekdayNbr) {
var weekdays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
return weekdays[weekdayNbr];
}
usage example:
=GETKWEEKDAYFROMNBR(WEEKDAY(A2,2))
I've got the same problem. I've had a spreadsheet open for a few days and under Tools there are three script options, those being Script Gallery, Script Manager and Script Editor.
I started a new sheet and went to the script editor, and there's only two options available, just like in your image. If I select Script Gallery I get this message;
Script gallery is now the add-on store
In the new Google Sheets, the script gallery has been replaced with the add-on store. Click the new Add-ons menu to get started. Learn more
The only solution I can see to get the script to work is by running it from within the script editor itself.