Did you know that you can automatically create dynamic charts (Pie / Column / Bar) using data in Excel by using Office Scripts and Power Automate? These charts can be created and returned as images to Power Automate and then used in any document of your choice. Send the chart via Teams. Send the chart(s) to external users via email. Embed the charts into Word, HTML, or permanent PDF files using Premium or regular actions.
The Office Script
I have a couple of videos (at the bottom of the page) demonstrating the creation of Charts from Excel using Office Scripts. The script below assumes that data is already in the sheet and the range is fixed BUT you can dynamically identify the column & row range in use for the creation of Charts. Equally, you can apply a filter on the data and run the addchart() function on the filtered data. Below, we assume that our worksheet is called June. We then create both a line chart and a pie chart on two different data sets. Note these data sets do not have to be defined as tables. Using the getImage() function we can create a base64 representation of the Chart. You’ll note that both images are returned to the Flow as an array.
function main(workbook: ExcelScript.Workbook ) { let selectedSheet = workbook.getWorksheet("June"); // Insert line chart on sheet selectedSheet let linechart = selectedSheet.addChart(ExcelScript.ChartType.line, selectedSheet.getRange('A1:B31')); // Insert pie chart on sheet selectedSheet let piechart = selectedSheet.addChart(ExcelScript.ChartType.pieExploded, selectedSheet.getRange('D4:E9')); piechart.getTitle().setText('Favourite PowerPlatform Tool'); linechart.getTitle().setText('Total Solutions in June 2021'); // set image variables let linechartimage = linechart.getImage(); let piechartimage = piechart.getImage(); //Delete charts from sheet linechart.delete(); piechart.delete(); // return linechart and piechart images return [linechartimage, piechartimage] }
Whilst the script can be tested and called from within Excel Online, it can be triggered from a Flow. The automate tab of Excel is only available Online, don’t go looking for it on the Desktop client. Here you can record a script or start from scratch if you are confident with TypeScript. I often start by recording the steps I am looking to automate and then repurpose the code to suit my exact requirements.
The Flow
Calling the Excel Office Script from Power Automate is done from the “Run Script” action. Here you must select the excel file you wish to run the script on and the script you wish to run. If you have defined parameters as part of your Office Script, the action will dynamically display them. In my example, I do not have any parameters only response, in the form of a results array.
You will see above that I have used a compose action to create an image object. The expression includes the first result from the array. I also have an Image2 compose action, not shown above. The expression used here for the second image is outputs(‘Run_script’)?[‘body/result’]?[1]. This object is required by the Populate Word Template action but for HTML, Teams, and Email methods, you will use an expression for the first or second result. Your HTML will need to look something like the following:
Note that you must include img src=”data:image/png;base64 when displaying the image as the office script will return it as a base64 string.
Charts Via Email
Using the “send an email” action, ensure the body is in the HTML editor and simply use the img src HTML per above. Depending on the number of charts that you have created, your body should look something like the following:
Email Action
Charts via Teams
Very much like sending an email, you use the same expression as before. I’ve used the flow bot and an adaptive card. You can build your own adaptive card here.
Charts in HTML and converted to PDF
This is the non-premium method for creating a read-only document in Power Automate. You can create an HTML file on OneDrive and then convert the file to PDF using the OneDrive convert file action. Getting the HTML file formatted is trial and error but it can be achieved using div to define page sizes and therefore page breaks. This also takes a lot of patience. Below I have included my sample HTML as used in my video.
<!DOCTYPE html> <html> <body style="background-color:white;"> <div style="background-color:white; width: 539px; height: 200px; text-align:center"><img src="data:image/png;base64, @{outputs('Get_file_content')?['body']?['$content']}" width="100%" height=100%"/></div> <div style="background-color:white; width: 539px; height: 590px; text-align:center"> <h1>Welcome to your PDF DOC</h1> <br> <h1>Created by DamoBird365</h1> <p style="color:red; font-size:50px;">Subscribe to my YouTube!</p> <p style="color:red; font-size:50px;">YouTube.com/c/DamoBird365</p> <p style="color:red; font-size:50px;">Comment with your ideas</p> <br><br> </div> <div style="background-color:white; width: 539px; height: 790px; text-align:center"> <h1>Here is your line chart</h1> <img src="data:image/png;base64,@{outputs('Run_script')?['body/result']?[0]}" width="75%" height="75%"/> <br> <h1>Here is your pie chart</h1> <img src="data:image/png;base64,@{outputs('Run_script')?['body/result']?[1]}" width="75%" height="75%"/> </div> </body> </html>
Below are the actions required to create these files. Note that OneDrive supports the file conversion, SharePoint does not. Therefore you convert the HTML file on OneDrive and then save the file contents to a file on SharePoint. Don’t forget to include your file extensions in the filename when creating files.
Charts in Word (Premium)
Using the “Word populate a Microsoft word template” action, you can insert the above images. Make sure you use the image object created in the earlier compose action. You must build the word template in Word Desktop, note that Word Online does not support editing of these features.
Using the developer tab (which you might need to add), you can insert various controls for dynamic content. I have inserted both text and image controls. You must specify a tag that will be used to identify the control from within the Word Action in your Flow. When you pass the image object to this control, the image is displayed dynamically.
The word action requires that you specify the template file you are going to populate the data on. Note that this will not overwrite your template. You then need to ensure that the output from this action is saved to a file. Make sure you include that file extension.
The video demos
Want to see how to create charts using data collected from Microsoft Forms and then dynamically filtered, all from Power Automate and Office Scripts? In this video, I send the Charts to Teams and Email.
If you are looking to see static data (without tables) converted to charts and then saved to a file (Word, HTML, Or PDF) all from Power Automate, watch below. Remember your data can be collected from Power Automate and passed to Excel. I have examples of how to pass data to excel using Office Scripts here.
I want to email images of charts that are already existing in my workbook. how would I code this? I cant find out how to select the existing charts.
Hi Daniel, sounds like an interesting use case. It looks like charts get a name.
* m_name: “Chart 2” *
I ran the following and was able to see that my pie chart was called ‘Chart 2’ and then by using that name, I was able to select the chart and get the image.
function main(workbook: ExcelScript.Workbook) {
let selectedSheet = workbook.getActiveWorksheet();
let charts = selectedSheet.getCharts();
//output to console window – charts array
console.log(charts)
let pie = selectedSheet.getChart(‘Chart 2’);
let pieimage = pie.getImage();
//output image base64
console.log(pieimage)
}
Hi, I have the same requirement as Daniel. I tried your script. It doesn’t give me any array of chart name, further if I try to just consol.log(pieimage) it give a huge alphanumeric string
I understood the problem – get array of images in last line of office script. Then in flow HTML code need to refer to array items using the above output(….). Thanks aton! for sharing all your knowledge.
Glad you cracked it Saba and thanks for keeping me posted 👍
Hey Damo ,
How to filter a table and move the filtered values to the next sheet.
After moving I have to sum all the values of the column.I used range function but it was summing up the values which are not filtered.
Kindly help
Hi Vingeshbabu, have you tried the recording tool? If you do the steps you have described to me, with the tool recording, you will have the foundation for a script.
how to view chart in gmail ?
I’m not sure I follow you. Can you expand on your question? You can email this to a gmail address?
Hey Damo, love what you do with Power Automate.
I need to do exactly what you’ve done here, but I can’t get the image sent by email. The email just appears blank with the text, do you know what could it be? I’m running this Office Script
function main(workbook: ExcelScript.Workbook
) {
let selectedSheet = workbook.getWorksheet(“Porcentaje_Aprob_SOD”);
// Insert pie chart on sheet selectedSheet
let piechart = selectedSheet.addChart(ExcelScript.ChartType.pieExploded, selectedSheet.getRange(‘d2:e4’));
piechart.getTitle().setText(‘Porcentaje de Estado de Aprbación’);
piechart.setPosition(“k10”);
piechart.getSeries()[0].getDataLabels().setShowLegendKey(true);
piechart.getSeries()[0].getDataLabels().setPosition(ExcelScript.ChartDataLabelPosition.outsideEnd);
// set image variables
let piechartimage = piechart.getImage();
//Delete charts from sheet
piechart.delete();
// return linechart and piechart images
return [piechartimage]
}
And the following in the Power Automate;
outputs(‘Run_script’)?[‘body/result’]?[0]
And for the email:
Here is your pie chart
for the email the following;
Here is your pie chart
Cheers Daniel. Check the flow history and see what the output of the run script action looks like. If you can’t see anything, If you comment out piechart.delete(); and run again do you see the chart in excel after the script has run?
Hi Damo,
Love all of your stuff. This does exactly what I need but for some reason I’m getting a “Picture can’t be displayed” error when I open my word template after triggering my flow. Any idea why this could be happening?
Thanks
Owen
Are you using the word premium connector? What does your action look like for the image?
Hi Damo,
I have sorted the issue, I was referencing an output that didn’t exist in my outputs(‘Run_script’)?[‘body/result’]?[…] function.
Hi Damo,
Is there a way to format the image before passing it into a word template? I’m finding the image quality and scaling isn’t great for larger graphs. It would be good if I could adjust the width/height/pixels as part of my compose action.
Nice one Owen, thanks for letting me know.
Hi Damo,
Thanks for this blog!
Did you maybe find a solution to have better image quality when exported?
You are the man! I opened up my file, automation tab (Online), New Script, Pasted your script, updated name from “June” to “Sheet1”, updated the range, ran it! Opened Power Automate, manual trigger to test, added run script, selected it, tested it, Phase 1 done.
Thank you!
Cheers Rick 👍
I’m trying to populate a word document, but keep getting the error:
“The image is not of type PNG or JPG. Please provide an image of type PNG or JPG.”
I’ve ensured, that the object gets passed as an object and not an array, but the error remains.
Do you know how to do that?
Is this from the script? Are you passing the object from image1? Try pasting the base64 into a base64 to image converter online.
Thank you for your reply. Yes, the object is passed from the script and an image converter correctly returns the original image.
It is only in the power automate workflow, that the base64 image is not recognized by the “populate word” section.
I’m struggling to think of an idea to be honest. Word premium? Recreate the action for the image object? Check the image object in the history? Does it show the base64 under content and not null?
I found a workaround -> saving the file as a html, converting it via OneDrive and inserting it in the word document.
Thank you for your help!
Thank you for this, however when running this flow to send an adpative card with response or post in chat or channel i am receiving an error message telling me the “payload” is too big and needs to be below 28kb
Assuming you are embedded the base64, you could save the image and use the url? https://adaptivecards.io/explorer/ImageSet.html
Is there any way to adapt this to avoid using office scripts? I have an existing flow that has various integer variables, and then sends a summary email with these integer variables as a list. Is there any way to email these in a bar or pie chart rather than just as a list of values?
I guess the aim is to do this within standard connectors? Graph API can do charts too https://learn.microsoft.com/en-us/graph/api/resources/excel?view=graph-rest-1.0#add-a-chart and can be accessed via SharePoint HTTP connector.
Hey , I followed your guide and it’s generating base64 from an office script, but the base64 is not of the correct chart.. when i run the script in excel it creates the right chart, but when the Run_script action from flow runs it the base64 that’s generated is for a completely wrong chart. Not sure why.
function main(workbook: ExcelScript.Workbook) {
let selectedSheet = workbook.getActiveWorksheet();
// Insert chart on sheet selectedSheet
let chart_62 = selectedSheet.addChart(ExcelScript.ChartType.radarFilled, selectedSheet.getRange(“A1:B13”));
// Resize and move chart
chart_62.setLeft(629.03564453125);
chart_62.setTop(293.142822265625);
chart_62.setWidth(623.678588867188);
chart_62.setHeight(466.607177734375);
// Capture the chart as a Base64 image
let base64Image = chart_62.getImage();
//Return chart image
return [base64Image];
}
I am not sure to be honest. You could to get the image before moving it but unlikely to be the cause. Do you have lots of charts? Could they have the same name? Maybe try the MS forum and let me know how you get on.
Hello Damo,
Thank you for this tutorial. I would have a question: is there anyway in the script to get the images of already existing graphs.
What I mean is that in my case I have several existing graphs obtained either with pivot tables and some in the traditional way. It would be very difficult for me to create all of them with code and therefore, I would like to ask you if there is any way of getting those graphs (or the images of those graphs) with the script and use them in the subsequent steps of the power automate worflow as you explain in this page (in particular to paste them in Word template).
I tried myself (I’m amateur at coding), but whenever I use getImage property in existing graphs (not created with code), it doesn’t seem to work out.
Thank you for any help.
Julian
I haven’t tried myself but it would be worth exploring on a forum where someone can dedicate the time to explore. I do offer 1-1 but at cost. I can add to video requests but I have many on my list.
Thank you Damo for your answer,
I think I have found a way. However for the “Compose action” I have a message that says “The expression is invalid” when I try to enter the expression: “outputs(‘Run_script’)?[‘body/result’]?[1]”
I tried to paste a screenshot here but I couldn’t. I just pasted your expression in the fx space dedicated for this, but may be I am missing something logical not shown in the video. Could you please explain where I might be doing things wrong when trying to create and insert the expression in the compose action ?
Thanks
Julian
It might be that the single quotes need retyped by you as sometimes copy/paste doesn’t work.
Hi Damo,
Thanks for your answer. It was indeed that. I typed it and it wored out, but unfortunately I could not delete the message I have already sent you 🙂
When I tried to run the new script I told you about (the solution I found) with your power automate workflow I got the following error:
“The API ‘excelonlinebusiness’ returned an invalid response for workflow operation ‘Run_script’ of type ‘OpenApiConnection’. Error details: ‘The API operation ‘RunScriptProd’ requires the property ‘body/result’ to be of type ‘String’ but is of type ‘Array’.”
The script I am using is this one (obtained from Microsofts page for illustrating the property getImage). I just adjusted the code to account for a second graph and changed some names:
function main(workbook: ExcelScript.Workbook): string {
// Get the first chart in the first worksheet.
const firstSheet = workbook.getFirstWorksheet();
const firstChart = firstSheet.getCharts()[0];
//Get the second chart in the first worksheet.
const secondChart = firstSheet.getCharts()[1];
// Get an image of the chart as a base64-encoded string.
const firstimage = firstChart.getImage(
600, /* Width */
400, /* Height */
ExcelScript.ImageFittingMode.fill /* Fill to match the dimensions. */
);
//get image of the second chart
const secondimage = secondChart.getImage(600, /* Width */
400, /* Height */
ExcelScript.ImageFittingMode.fill /* Fill to match the dimensions. */);
return [firstimage,secondimage]
}
I know the solution for the error in my particular case must be either in the final part of the script “return” or in the expression for the compose action “outputs(‘Run_script’)?[‘body/result’]?[0]”.
Do you think you can help me one last time. I’m not very good at coding, but it seems in my case the problem is mixing strings and array in the script and compose action steps, but I am not able to adapt either of them to make the whole process to work for my case.
Thank you,
Julian
Hi Damo,
I wondered if you’d come across this issue before, I’m creating a doughnut chart via office script and and returning the base64 to Power Automate to insert into a word document.
What I’m finding is the image returned to Power Automate is different to what is shown in Excel, this is usually a missing column/section of the chart.
When I use the base64 that is passed to Power Automate in a decoder it shows the image (missing column/section) so somehow the base64 being passed from the script into Power Automate is corrupt somehow – any suggestions would be more than welcome.
Im trying to post that image in teams’ group but image is not displaying.
i observed power automate encoding the request properly, for some reason I’m unable to view that image in the teams post