2

I'm looking for a way to embed a Charts.Chart to a Google Sheet (but not only, I also want to be able to insert it to other supports such as userform, Google Doc, etc.)

function generateChart(data) {
  
  var chartBuilder = Charts.newBarChart();
    // Miscellaneous such as titles, dimensions and data
    // ..
    ;
  
  var chart = chartBuilder.build();
  
  return chart;
}

Also, I don't want to directly use the chart values from the spreadsheet range (there will be some data manipulation..), but used if from data where is a struct of array.

data = {
  field1: [..],
  field2: ..
}

So, basically I want to avoid something like as it creates a dependency to the Sheet.

var sheet = SpreadsheetApp.getActiveSheet();
var chartBuilder = sheet.newChart()
  // ..
  ;

If I write sheet.insertChart(generateChart(data)), I get the following error. Which makes sense because I'm not dealing with same kind of Chart, but is there a workaroud?

Exception: The parameters (Charts.Chart) don't match the method signature for SpreadsheetApp.Sheet.insertChart.

I'm wondering if I shouldn't convert it as blob in order to make it compatible with Google Sheet Chart format, but I'm sure there are more straightforward ways to achieve it.

Thanks for any insights!

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Ludovic Wagner
  • 115
  • 2
  • 8
  • You could insert it as a image, otherwise I don't think converting ``Chart`` => ``EmbeddedChart`` class is possible. – TheMaster Oct 26 '20 at 09:22
  • Well, I also found this possibility, but I'm afraid it will be far too limited... So, basically the `Chart` class is completely useless (apart of given imagines?) I also have some thought about creating a custom `Sheet` class where I can abstract it a little bit, but I'm only know the very basics of JavaScript. – Ludovic Wagner Oct 26 '20 at 10:28
  • Yes. `Chart` class is pretty useless. It's a surviving solo remnant of now deprecated `UiApp`. – TheMaster Oct 26 '20 at 11:44
  • ... so, it there no other way to generate charts which are not directly using the ranges? I mean with array or collection (not sure whether it exists in JavaScript or not, but in VBA collection have to be converted to array in order to populate chart series) of values (string, int, etc.)? Otherwise, I found an excellent way the generate awesome charts with chart.js, but I'm afraid it won't be possible to insert them directly in Sheets (or other Google applications), right? – Ludovic Wagner Oct 26 '20 at 11:49
  • I am not completely sure as I haven't tried hacking and looking into `EmbeddedChart` objects(which requires original research/time and real possibility of complete waste of my time). Based on my experience so far, Directly creating Embedded charts without ranges is not possible. If I'm interested, I would start by looking into `.setOption()` and the [chart html source](https://stackoverflow.com/questions/13594839). A better/easier way is to employ the sidebar html and use google- charts directly in the browser, where you could add arrays as you see fit. – TheMaster Oct 26 '20 at 11:58
  • Could anyone confirmed that using the `Chart` is not applicable to represent graph where the data continually changes (let's say every second). I'm ready basics of Google Visualization, but I'm getting confused.. – Ludovic Wagner Oct 28 '20 at 21:02

1 Answers1

1

EmbeddedChart is not part of the Class Charts

As per the documentation for Charts says creates a basic data table, populates an area chart with the data, and adds it into a web page as an image. You can get the image URL and the Blob as well.

As a Workaround

By using Sheets

I'd use the insertImage function making use of the URL provided by Charts.

function myFunction() {
  var data = Charts.newDataTable()
    .addColumn(Charts.ColumnType.STRING, "Year")
    .addColumn(Charts.ColumnType.NUMBER, "Sales")
    .addColumn(Charts.ColumnType.NUMBER, "Expenses")
    .addRow(["2004", 1000, 400])
    .addRow(["2005", 1170, 460])
    .addRow(["2006", 660, 1120])
    .addRow(["2007", 1030, 540])
    .addRow(["2008", 800, 600])
    .addRow(["2009", 943, 678])
    .addRow(["2010", 1020, 550])
    .addRow(["2011", 910, 700])
    .addRow(["2012", 1230, 840])
    .build();

  var chart = Charts.newColumnChart()
    .setTitle('Sales & Expenses')
    .setXAxisTitle('Year')
    .setYAxisTitle('Amount (USD)')
    .setDimensions(600, 500)
    .setDataTable(data)
    .build();

  var htmlOutput = HtmlService.createHtmlOutput().setTitle('My Chart');
  var imageData = Utilities.base64Encode(chart.getAs('image/png').getBytes());
  var imageUrl = "data:image/png;base64," + encodeURI(imageData);

  // Insert the image in the A1
  SpreadsheetApp.getActiveSheet().insertImage(imageUrl, 1, 1);
}

By using Docs

I'd use the insertInlineImage

function myFunction() {
  var data = Charts.newDataTable()
    .addColumn(Charts.ColumnType.STRING, "Year")
    .addColumn(Charts.ColumnType.NUMBER, "Sales")
    .addColumn(Charts.ColumnType.NUMBER, "Expenses")
    .addRow(["2004", 1000, 400])
    .addRow(["2005", 1170, 460])
    .addRow(["2006", 660, 1120])
    .addRow(["2007", 1030, 540])
    .addRow(["2008", 800, 600])
    .addRow(["2009", 943, 678])
    .addRow(["2010", 1020, 550])
    .addRow(["2011", 910, 700])
    .addRow(["2012", 1230, 840])
    .build();

  var chart = Charts.newColumnChart()
    .setTitle('Sales & Expenses')
    .setXAxisTitle('Year')
    .setYAxisTitle('Amount (USD)')
    .setDimensions(600, 500)
    .setDataTable(data)
    .build();

  var image = chart.getAs('image/png')
  
  // Insert an image chart
  var doc = DocumentApp.getActiveDocument();

  var cursor = doc.getCursor();
  if (cursor) {
    cursor.insertInlineImage(image);
  } else {
    doc.getBody().insertImage(0, image);
  }
}

Reference

Google Apps Script > Charts

Jose Vasquez
  • 1,678
  • 1
  • 6
  • 14
  • OK, thanks for your help. I manage it to my example (which is also a `BarChart`), but I get the bars horizontally and it seems that I can't permutes the column and the rows in the `DataTable`). How is it possible to achieve it? – Ludovic Wagner Oct 26 '20 at 13:37
  • Okay, that's not an issue at all, I edited my code in order to use the `Charts.newColumnChart()` that's the chart you want to use. – Jose Vasquez Oct 26 '20 at 15:40
  • OK, it makes sense. I wasn't a `BarChart`, but rather a `ColumnChart` to use. I still have to transpose my object which populates the rows, but that shouldn't be an issue. Still concerned to render it as an image because it prevents manual editing to the graph... – Ludovic Wagner Oct 26 '20 at 16:35