I have a Google Slides presentation with charts that are linked to a specific Google Sheets Spreadsheet.
As there are many charts in the presentation, I'm looking for a way to update all these linked charts automatically, or at least all of them at once.
What is the best way to do this?
You can add a custom function to a dropdown menu in the Slides UI with the following script. This gets the slides from the current presentation, loops through them, gets any charts in each slides and refreshes (updates) them.
function onOpen() {
var ui = SlidesApp.getUi();
ui.createMenu('Custom Menu')
.addItem('Batch Update Charts', 'batchUpdate')
.addToUi();
}
function batchUpdate(){
var gotSlides = SlidesApp.getActivePresentation().getSlides();
for (var i = 0; i < gotSlides.length; i++) {
var slide = gotSlides[i];
var sheetsCharts = slide.getSheetsCharts();
for (var k = 0; k < sheetsCharts.length; k++) {
var shChart = sheetsCharts[k];
shChart.refresh();
}
}
}
Note: The functionality to update/refresh linked Slides doesn't appear to exist at the time of this response.
You can find it in official documentation about API (for different lang).
https://developers.google.com/slides/how-tos/add-chart#refreshing_a_chart
You need to write a script for this and run it by schedule or manually.
I have found my own code that worked great.
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/slides.googleapis.com-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/drive'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Google Slides API Python Quickstart'
def get_credentials():
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'slides.googleapis.com-python-quickstart.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
"""Shows basic usage of the Slides API.
Creates a Slides API service object and prints the number of slides and
elements in a sample presentation:
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('slides', 'v1', http=http)
# Here past your presentation id
presentationId = '1Owma9l9Z0Xjm1OPp-fcchdcxc1ImBPY2j9QH1LBDxtk'
presentation = service.presentations().get(
presentationId=presentationId).execute()
slides = presentation.get('slides')
print ('The presentation contains {} slides:'.format(len(slides)))
for slide in slides:
for element in slide['pageElements']:
presentation_chart_id = element['objectId']
# Execute the request.
try:
requests = [{'refreshSheetsChart': {'objectId': presentation_chart_id}}]
body = {'requests': requests}
#print(element)
requests = service.presentations().batchUpdate(
presentationId=presentationId, body=body).execute()
print('Refreshed a linked Sheets chart with ID: {0}'.format(presentation_chart_id))
except Exception:
pass
if __name__ == '__main__':
main()
Latest update: There is now an option in Slides's Tools drop-down menu to see all Linked Objects; the menu that appears has the option at the bottom to "Update all".
Related
In Smartsheet I have downloaded Published Items list from user management. Using this list I need to change the Access control (Public/Organization) value through api. Please help. Thanks
Depending on the type of object you're updating (Sheet, Report, or Dashboard), the operations you'll use are as follows:
Set Sheet Publish Status
Set Report Publish Status
Set Dashboad (Sight) Publish Status
I've included some code examples below (taken nearly verbatim from those you'll find in the docs I've linked to above.)
One additional note: You'll notice that the values written to the Published Items list that you manually export from Smartsheet differ from the values used by the API. For example, the Access Control column of exported data contains values like Organization and Public -- where as the corresponding values used by the API are ORG and ALL.
Example #1: SHEET --> Set ReadOnlyFullAccessibleBy to ALL, ReadWriteAccessibleBy to ORG
SheetPublish sheetPublish = new SheetPublish();
sheetPublish.ReadOnlyLiteEnabled = false;
sheetPublish.ReadOnlyFullEnabled = true;
sheetPublish.ReadOnlyFullAccessibleBy = "ALL";
sheetPublish.ReadWriteEnabled = true;
sheetPublish.ReadWriteAccessibleBy = "ORG";
sheetPublish.IcalEnabled = false;
smartsheet.SheetResources.UpdatePublishStatus(
4583614634583940, // sheetId
sheetPublish
);
Example #2: Report --> Set ReadOnlyFullAccessibleBy to ORG
ReportPublish reportPublish = new ReportPublish();
reportPublish.ReadOnlyFullEnabled = true;
reportPublish.ReadOnlyFullAccessibleBy = "ORG";
smartsheet.ReportResources.UpdatePublishStatus(
1653087851556740, // reportId
reportPublish
);
Example #3: Dashboard (Sight) --> Set ReadOnlyFullAccessibleBy to ALL
SightPublish publish = new SightPublish();
publish.ReadOnlyFullEnabled = true;
publish.ReadOnlyFullAccessibleBy = "ALL";
smartsheet.SightResources.SetPublishStatus(
5363568917931908, // sightId
publish
);
I have a bunch of Flex pages I need to convert to get rid of the flash player and have been unable to see how to replicate this code just using the javascript.
The Flex code gathers up data and sends it in a POST to a Cold Fusion page in another frame (named FrameData). Cold Fusion accesses the data from a FORM variable (FORM.mydata1, FORM.mydata2, etc.).
var RequestSite:URLRequest;
OutputPageValues.OutputType = 5;
OutputPageValues.mydata1 = "2";
OutputPageValues.mydata2 = "test";
RequestSite = new URLRequest("pageurl.cfm"));
RequestSite.data = OutputPageValues;
RequestSite.method = URLRequestMethod.POST;
navigateToURL(RequestSite, 'FrameData');
How do I emulate this construct in Royale? Is there another way to do this?
equivalente code for URLRequest:
var u:URLRequest = new URLRequest("http://domain.foo");
navigateToURL(u,"_blank");
in Apache Royale is BrowserWindow:
import org.apache.royale.core.BrowserWindow;
var u:String = "http://domain.foo";
BrowserWindow.open(u, "_blank");
To pass variables you need to do via GETmethod: "http://domain.foo?variable=" + key.
To use POST method use HTTPService class from Network SWC instead:
import org.apache.royale.net.HTTPConstants;
import org.apache.royale.net.HTTPService;
import org.apache.royale.net.URLVariables;
// add the variables to send
var urlVars:URLVariables = new URLVariables();
urlVars.set("variable", key);
// create the httpservice instance
var service:HTTPService = new HTTPService();
service.url = "http://domain.foo";
service.method = HTTPConstants.POST;
service.addEventListener("complete", resultCallback);
service.addEventListener("ioError", faultCallback);
// add the variables
service.contentData = urlVars;
// trigger the service
service.send();
Optionally in case you need to deal with CORS you can add CORSCredentialsBead bead to the HTTPService:
service.addBead(new CORSCredentialsBead(true));
(Note: code is untested, please report if all is ok so we can improve this response and code snippet, thanks)
I'm looking for a REST API for generating PowerPoint slides... does anyone have any suggestions?
Realize this wouldn't be too difficult to implement, but we're trying to avoid building noncore functionality we could get from a third party.
Basically, we want to send a JSON blob and get back the generated slide.
Think this is a related question:
Is there an API to make a MS Office 365 Powerpoint presentation programmatically?
Thanks for your help!
You can try using Aspose.Slides Cloud for your purposes. This product provides REST-based APIs for many programming languages (C#, Java, PHP, Ruby, Python, Node.js, C++, Go, Perl, Swift), platforms and environments. With this product, you can use both Aspose file storages and third-party storages. Docker containers can also be used for working with Aspose.Slides Cloud.
This product does not support adding contents to presentations from JSON files but it provides many features for generating contents. It also provides features to add contents to presentations from HTML and PDF documents. The following Python sample code shows you how to add a WordArt object to a new presentation, for example.
import asposeslidescloud
from asposeslidescloud.apis.slides_api import SlidesApi
from asposeslidescloud.models.slide_export_format import SlideExportFormat
from asposeslidescloud.models.shape import Shape
from asposeslidescloud.models.fill_format import FillFormat
from asposeslidescloud.models.line_format import LineFormat
from asposeslidescloud.models.text_frame_format import TextFrameFormat
from asposeslidescloud.models.three_d_format import ThreeDFormat
from asposeslidescloud.models.shape_bevel import ShapeBevel
from asposeslidescloud.models.light_rig import LightRig
from asposeslidescloud.models.camera import Camera
slides_api = SlidesApi(None, "my_client_id", "my_client_secret")
file_name = "example.pptx"
slide_index = 1
dto = Shape()
dto.shape_type = "Rectangle"
dto.x = 100
dto.y = 100
dto.height = 100
dto.width = 200
dto.text = "Sample text"
dto.fill_format = FillFormat()
dto.fill_format.type = "NoFill"
dto.line_format = LineFormat()
dto.line_format.fill_format = FillFormat()
dto.line_format.fill_format.type = "NoFill"
text_frame_format = TextFrameFormat()
text_frame_format.transform = "ArchUpPour"
three_d_format = ThreeDFormat()
bevel_bottom = ShapeBevel()
bevel_bottom.bevel_type = "Circle"
bevel_bottom.height = 3.5
bevel_bottom.width = 3.5
three_d_format.bevel_bottom = bevel_bottom
bevel_top = ShapeBevel()
bevel_top.bevel_type = "Circle"
bevel_top.height = 4
bevel_top.width = 4
three_d_format.bevel_top = bevel_top
three_d_format.extrusion_color = "#FF008000"
three_d_format.extrusion_height = 6
three_d_format.contour_color = "#FF25353D"
three_d_format.contour_width = 1.5
three_d_format.depth = 3
three_d_format.material = "Plastic"
light_rig = LightRig()
light_rig.light_type = "Balanced"
light_rig.direction = "Top"
light_rig.x_rotation = 0
light_rig.y_rotation = 0
light_rig.z_rotation = 40
three_d_format.light_rig = light_rig
camera = Camera()
camera.camera_type = "PerspectiveContrastingRightFacing"
three_d_format.camera = camera
text_frame_format.three_d_format = three_d_format
dto.text_frame_format = text_frame_format
# Create the WordArt object and download the presentation.
slides_api.create_presentation(file_name)
slides_api.create_shape(file_name, slide_index, dto)
file_path = slides_api.download_file(file_name)
The WordArt object in the output presentation:
This is a paid product but you can make 150 free API calls per month for API learning and presentation processing.
I work as a Support Developer at Aspose.
Situation description:
Python 3.7, GTK 3.0, PyGObjects 3.34.0 Webkit2 4.0
I have a dialog window, with GtkNotebook containing 2 tabs.
1. tab contains editable Webkit webview, the 2. tab contains textview. One of the arguments provided in class consrtructor is valid HTML snippet as string variable
What I would like to get as a result, is that any changes made in any window, are automatically reflected in other.
Current problem:
Using solution provided here, any previous changes that were made in webview are discarded upon switching the notepad tabs. Debugging shows that html obtained with aforementioned call, does not contain changes.
Any ideas what might be missing in the logic or handling itself?
For reference, the code for the dialog is as follows:
# -*- coding: utf-8 -*-
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2
class DescriptionDialog:
def __init__(self, *args):
# GTK Builder
self._builder = args[0]
self._builder.add_from_file("UI/GUI/description.glade")
self.dialog = self._builder.get_object("descriptionDialog")
self._textView = self._builder.get_object("textview1")
self.webViewContainer = self._builder.get_object("WebViewContainer")
self.browserHolder = WebKit2.WebView()
self.browserHolder.set_editable(True)
self.webViewContainer.add(self.browserHolder)
self.browserHolder.show()
# valid html snippet, held as string
self.__buffer_orig__ = args[2]
self.buffer = args[2]
self.browserHolder.load_html(self.buffer)
self._builder.connect_signals(
{
"onDialogClose": self.onDialogClose,
"pageChangeNotebook": self.onPageChange
})
self.dialog.set_transient_for(self._builder.get_object("MainWindow"))
self.textBuffer = self._builder.get_object("textbuffer1")
self.textBuffer.set_text(self.buffer)
self.dialog.show()
def onDialogClose(self, handler):
self.dialog.hide()
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
self.browserHolder.get_main_resource().get_data(None, self.getDataFromResource, None)
def getDataFromResource(self, resource, result, userData=None):
# Changed html is not returned here
self.buffer = str(resource.get_data_finish(result).decode("utf-8"))
self.textBuffer.set_text(self.buffer)
For other internet users finding this thread.
Currently, at the given versions, this is the working result that I have come up with.
Main idea with this implementation is following - use the WebView enabled Javascript engine to obtain the contents of a <body> tag. Then, parse the Javascript result to use this value later on.
def onPageChange(self, notebook=None, scrolledWindow=None, pageNumber=0):
if pageNumber == 0:
self.buffer = self.textBuffer.get_text(self.textBuffer.get_start_iter(), self.textBuffer.get_end_iter(), True)
self.browserHolder.load_html(self.buffer)
if pageNumber == 1:
# use JavaScript to get the html contained in rendered body tag
script = "document.body.innerHTML;"
# Execute JavasScript via WebKit2.WebView bindings.
# Result can be obtained asynchronously, via callback method
self.browserHolder.run_javascript(script, None, self.getJSStatus, None)
def getJSStatus(self, resource, result, userData=None):
# Sample adapted and simplified from here:
# https://lazka.github.io/pgi-docs/#WebKit2-4.0/classes/WebView.html#WebKit2.WebView.run_javascript_finish
# Get the JavaScript result
data = self.browserHolder.run_javascript_finish(result)
# Get value from result, and convert it to string
self.buffer = data.get_js_value().to_string()
self.textBuffer.set_text(self.buffer)
I have the following python script (reduced, but the rest of it performs similar actions):
from Spotfire.Dxp.Application.Visuals import *
from Spotfire.Dxp.Data import *
#assign default values for prompts if needed
if Document.Properties['cannedKPISelected'].isspace():
Document.Properties['cannedKPISelected'] = 'GS'
if Document.Properties['cannedTimeSelected'].isspace():
Document.Properties['cannedTimeSelected'] = 'Month'
#determine which type of viz needs displayed based on a flag in the data
tableName='PrimaryDataTable'
columnToFetch='displayPercentageFlag'
activeTable=Document.Data.Tables[tableName]
rowCount = activeTable.RowCount
rowsToInclude = IndexSet(rowCount,True)
cursor1 = DataValueCursor.CreateFormatted(activeTable.Columns[columnToFetch])
for row in activeTable.GetRows(rowsToInclude,cursor1):
rowIndex = row.Index
percentageNeeded = cursor1.CurrentValue
break
#create consumer report
for page in Document.Pages:
for viz in page.Visuals:
if str(viz.Id) == 'a7f5b4ec-f545-4d5f-a967-adec4c9fec79':
if Document.Properties['coffeeReportSelected'] == 'Brand Category by Market':
if Document.Properties['cannedKPISelected'] == 'GS' and Document.Properties['cannedTimeSelected'] == 'Month' and percentageNeeded == 'Y':
visualContentObject = viz.As[VisualContent]()
visualContentObject.MeasureAxis.Expression = 'Sum([GS Month]) as [GS Mnth]'
visualContentObject.RowAxis.Expression = '<[BRAND] as [Brand Category] NEST [MARKET] as [Market]>'
visualContentObject.ColumnAxis.Expression = '<[Axis.Default.Names] as [Measure Names]>'
visualContentObject.ShowColumnGrandTotal = True
visualContentObject.ShowColumnSubtotals = True
visualContentObject.ShowRowGrandTotal = False
visualContentObject.Title = 'Monthly GS by Brand, Market'
visualContentObject.Data.WhereClauseExpression = '[NAME] = "CANADA"'
visualContentObject.CellWidth = 125
Document.Properties['cannedReportHideRows'] = 'Sum(Abs(SN([GS Month],0)))'
elif Document.Properties['cannedKPISelected'] == 'GS' and Document.Properties['cannedTimeSelected'] == 'Quarter' and percentageNeeded == 'Y':
visualContentObject = viz.As[VisualContent]()
visualContentObject.MeasureAxis.Expression = 'Sum([GS Quarter]) as [GS Qtr]'
visualContentObject.RowAxis.Expression = '<[BRAND] as [Brand] NEST [MARKET] as [Market]>'
visualContentObject.ColumnAxis.Expression = '<[Axis.Default.Names] as [Measure Names]>'
visualContentObject.ShowColumnGrandTotal = True
visualContentObject.ShowColumnSubtotals = True
visualContentObject.ShowRowGrandTotal = False
visualContentObject.Title = 'Quarterly GS by Brand, Market'
visualContentObject.Data.WhereClauseExpression = '[NAME] = "CANADA"'
visualContentObject.CellWidth = 125
Document.Properties['cannedReportHideRows'] = 'Sum(Abs(SN([GS Quarter],0)))'
So on and so forth.
This script (and others) run perfectly fine in the client. It does not run in the web. The web will say processing, then say ready (in the bottom left corner), all while doing nothing (no error, nothing). A few other scripts that I have in the same analysis run perfectly fine.
I know there are some limitations on IPython scripts on the web for security reasons, but I am only building a table. This cant be restricted can it? Web server logs are not capturing anything out of the ordinary.
We are on Spotfire 7.6
UPDATE: It seems to be due to this: if str(viz.Id) == 'a7f5b4ec-f545-4d5f-a967-adec4c9fec79':. This is because IDs are different between Web and Client unfortunately. Knowing my title changes as well, any ideas on what I could reference a visualization by that stays the same between client and web?
Because Spotfire changes IDs of a vis depending on whether it is on the web player vs the client, the script was not working as intended. I simply added the vis as a parameter instead of relying on the script to go and locate the correct vis. When the name of the vis changes, the parameter is updated correctly so it is still dynamic.
Could you just figure out what the index is on the current visual and refer to it that way?
Try something like:
Replace this line:
if str(viz.Id) == 'a7f5b4ec-f545-4d5f-a967-adec4c9fec79':
With:
if viz[0] (or whatever the index is)
Not sure if this is what you had in mind, but I believe this will give you a way to refer to the visualization without having to use an ID.