Allowing login to multiple instances

When using multiple IBM Planning Analytics instances with the same credentials in your Canvas application, you will now be able to authenticate to all your instances by entering the credentials only once.

A property named loginInstances has been added into an instance’s configuration via the instances.json file. This is an array containing a string of instance name for which this will try to log into. For example,

  “loginInstances”:[“dev2”, “dev3”]

For flexibility, the following broadcast events has also been added so you can check for when the other instances have logged in:

  • login.instance.start

  • login.instance.status

  • login.instance.success

  • login.instance.failure

And on each broadcast, the name of the instance is also included along with other information depending on the stage of the process.

Sending TM1 REST API calls directly into TM1

A new API has been added that will allow a consultant or developer to send REST API calls directly into TM1 while leveraging on Canvas session handling. These REST API calls can be called through /api/rest

The allowedRestPaths property has been added into the settings.json file which will contain the API calls allowed to pass through.

An example entry would be:


The path property is a Regex string that be matched against calls made into the /api/rest/<instance> calls.

And to get the configuration from TM1, your HTTP Request would be:

GET /api/rest/<instance>/Configuration

This API works by whitelisting TM1 API calls that you will use. Place into the list only those APIs that you will use. <instance> refers to the name as define in the instances.json file.

Using the Trace Calculation

Being able to trace calculation from any cell is a very popular IBM TM1 and Planning Analytics feature. This is now available in Canvas v3.2.0.

Prerequisites: TM1 should be at least PA 2.0.3 (TM1

To access the Trace calculation feature, clicks the context button from any cells containing a dbr function and you will find the Calculations option (as shown below):

A new window will pop-up showing the intersection of the cell. If the intersection contains a consolidation, you will be able to drilldown until the leaf levels to find the rule:

Disabling the Calculations button

A new parameter tm1-hide-trace-calculation has been added to the tm1-ui-dbr directive in order to hide the Trace Calculations option if required.

Trace caluations through the $tm1UI services

The Trace Calculation feature can also be accessible from the $tm1Ui services. The new service is called cellTraceCalculations(instance, cube, element1, element2, elementN, options). More information in your application Help page (http://<serverName>:<portNumber>/<applicationName>/#/help).

Setting up Open ID with Canvas

Canvas v3.2.0 can now connect to IBM Planning Analytics instances configured with Open ID authentication.

Open ID authentication with Planning Analytics can be configured in two ways. It can either connect straight to your OpenID provider or by connecting to Cognos Analytics (the Cognos server will then authenticate you to your Open ID provider).

In the case where you are using Open ID with CAM Security, configuring Canvas is not different than setting up SSO with CAM and Canvas, as Canvas will only authenticate you with the Cognos server.

If you are using OpenID authentication without CAM security, the configuration on the Canvas side is quite straightforward.

But before going through these steps, you will need to make sure that you can connect to TM1 using OpenID.

Once the TM1 setup with OpenID is configured, open your instances.json file from the application WEB-INF folder (<canvasInstallationDirectory>\webapps\<applicationName>\WEB-INF), add the following property to the TM1 instance that was configured to connect with OpenID:

  • “useSSOWithOIDC”: true

Next, create a JSON file within WEB-INF/config/oidc folder. The name of the file should match the name of the instance (defined in instances.json) which will be configured for OpenID.

Path should be located in <Canvas Application>/WEB-INF/config/oidc/<instance-name>.json. For dev instance for example, it would be: <Canvas Application>/WEB-INF/config/oidc/dev.json

Sample content of the JSON file would be:

    “clientID”: “XXXX123456789ZZ”,
    “discoveryEndpoint”: “http://<OpenID Provider’s Well Known Configuration>”

That should be it!

Restart your Canvas Application Server. Go to your page’s Configuration page for example to trigger the OpenID Connect mechanism.

What to Expect

When you open up a page in Canvas that has TM1 data on it, Canvas will check first if the session is valid. If not, it will redirect the current page to the Open ID Provider’s Login page to ask the user to login. Once successful, the OpenID Provider will then redirect the user back to the Canvas page that triggers it.

Canvas will now try to login to TM1, given the new set of information present in the URL (the code parameter in particular). If valid, it will proceed as per normal with the page, and all TM1 operations should work based off the user that was retrieved from OpenID:

Getting Started


TM1 version 10.2.2 FP5 minimum

Minimum 3 port number available on the server:

  • Canvas Server (default 8080)

  • Canvas_sample port number (default 32343)

  • Canvas_sample HTTPPortNumber (default value 8882)

  • Then one port number per TM1 instances in order to enable the TM1 REST API.

Canvas system requirements:

Installation Guide

  1. Download the latest Canvas version

  2. Unzip the folder

  3. Follow the installation guide

Canvas System Requirements

Server Requirements

  • Windows 2008 or later

  • Min 700Mb of disk space (1.2Gb if Samples Application with the Canvas Sample TM1 server is included)

  • CPU: < 1% during normal operations

  • RAM: Min 4 GB (Min 500 MB per application)

  • IBM TM1 10.2 Fix Pack 6 as minimum.

Web Browser

  • Internet Explorer 10+

  • Any other modern browser: Firefox, Chrome, Safari, etc.

Data Storage and Retention

  • Minimum 2GB free space on the disk.

  • No data stored. Only configurations in JSON files for TM1 Connectivity, Canvas Scheduler Tasks, etc.

Using SSL with Canvas

Create your own keystore and SSL certificate

  1. Open a Command Line Window using Run As Administrator
  2. Use the cd command to change the directory to the conf directory where Canvas is installed:

    cd C:\CWAS\conf
  3. Create your own keystore and generate a Certificate Signing Request:

    ..\jre\bin\keytool -genkey -alias tomcat -keyalg RSA -keystore canvas.keystore -keysize 2048
  4. Enter a password and write it down so you can use it later:

    Enter keystore password: 
  5. Enter the details for the certificate: 
    • First and last name (Common Name (CN)): Enter the domain of you are going to use for Canvas (i.e. in the "first- and lastname" field.. It looks like "" or "". NOTE: The Common Name above must match the URL people are going to use to access Canvas
    • Organizational Unit (OU): This field is optional; but can be used to help identify certificates registered to an organization, i.e. the name of the department making the request.
    • Organization (O): If your company or department, exclude any special characters such as & or @ from the name.
    • Locality or City (L): The locality field is the city or town name, for example: New York. 
    • State or Province (S): Spell out the state completely; do not abbreviate the state or province name, for example: Florida
    • Country Name (C): Use the two-letter code for the country, for example: US, AU, UK, etc.
  6. Confirm that the details are correct, type 'y' and press <Enter>:

    Is, OU=Unknown, O=Cubewise, L=North Sydney, ST=New South Wales, C=AU correct? 
    [no]: y
  7. Press <Enter> and use the same password as entered in Step 4

    Enter key password for <canvas>
    (RETURN if same as keystore password): [Enter]
  8. Generate a Certificate Signing Request (CSR) to be used by a certificate Authority (Symantec, Thawte, DigiCert, GeoTrust, Go Daddy, etc)

    ..\jre\bin\keytool -certreq -alias tomcat -file canvas.csr -keystore canvas.keystore
  9. Enter the password your created in step 4:

    Enter keystore password: 
  10. Follow the steps of your Certificate Authority to purchase a new certificate using the canvas.csr file that was created in the previous step.

    NOTE: The canvas.csr file will be in the conf directory where Canvas is installed
  11. At this point you should make a copy of the canvas.keystore file so you have a backup if you encounter problems when importing certificates

Import Your X.509 Certificate into the Key Store

  1. Open a Command Line Window using Run As Administrator
  2. Use the cd command to change the directory to the conf directory where Canvas is installed

    cd C:\CWAS\conf
  3. First import any root/intermediate certificate(s) as instructed by your Certificate Authority, these need to be imported BEFORE your certificate is imported:
    1. Save any root/intermediate certificates to the conf directory, i.e. root.cer
    2. Execute, replacing -alias and -file options for each certificate:

      ..\jre\bin\keytool -import -trustcacerts -alias root -keystore canvas.keystore -file root.cer
    3. Enter the password from above and press enter
  4. Import your actual certificate into the key store:
    1. Save the certificate to the conf directory, i.e. canvas.cer.
    2. Execute, the alias needs to be canvas: 

      ..\jre\bin\keytool -import -trustcacerts -alias tomcat -keystore canvas.keystore -file canvas.cer
    3. Enter the password from above and press enter
  5. If you get: Certificate reply was installed in keystore. The certificate has been successfully installed in the keystore

    If you receive this error, keytool error: java.lang.Exception: Failed to establish chain from reply, you need to install the appropriate intermediate certificates

Update the Connector Settings for the New Key Store

  1. Open conf/server.xml (in the Canvas install directory)

You will need to add the following code between <Service and <Engine section:

     <!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
           port="8443" maxThreads="200"
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="C:/CWAS/conf/canvas.keystore" keystorePass="password"
           clientAuth="false" sslProtocol="TLS"

You can choose a different port number, in this example we are using 8443.

The server.xml file should look like this:

Finally restart the Cubewise Application Server service and you should now be able to access Canvas through the new port in this example 8443:

  • https://localhost:8443/samples

Using the Canvas subset editor

Like the cube viewer, the Canvas subset editor (introduced in v3.0.1), is built to generate MDX set expressions. Most of the functionality should be familiar to what you have experienced in Architect or Perspectives: all elements, filtering, ordering, etc.

Use the subset editor to your Canvas page

To use the subset editor in your Canvas page, you will need to use the new directive tm1-ui-subset-editor


This new directive contains as the minimum parameters - instance name and the dimension name. To open a specific subset, you will need to add the subset name using the parameter tm1-subset. The tm1-ui-subset-editor has lots of other options, more information can be found in the Help section <Canvas Application URL>/#/help.

Open the subset editor from the cube viewer

From any hierarchy either on rows, columns or titles of the cube view, you can open the cube viewer:

MDX record expression

There is no Record Expression option as the Arc subset editor is always recording the MDX expression. You can edit the MDX expression manually.

The subset editor tests the MDX expressions by executing a query against the }ElementAttributes cube of the dimension. This means that any dimension that you want to use the subset editor against must have at least one attribute. Arc will prompt you to create one if it doesn’t exist.

Using the Canvas cube viewer

Canvas v3.0.1 introduces a new cube viewer to explore your cubes. The new cube viewer supports both native and MDX views.

Native view vs MDX view

A native view is the name of the standard view you have been using in TM1 for many years. These views do not support the new multiple hierarchies and are essentially deprecated. Canvas supports reading native views but you cannot save a native view unless all dimensions are using a subset. This also applies to dimensions involving default hierarchies only. 

MDX views were added to TM1 to support multiple hierarchies where these views contain a single MDX statement. The cube viewer is based on MDX. Each time you drag/drop a hierarchy or select a set of elements, the MDX is updated and executed against the TM1 model.

You can save these MDX views through Canvas. These views can be viewed in the newer TM1 interfaces such as PAX and PAW.

Open an existing cubeview

To add a Cube Viewer into your HTML page, you just need to use the new directive, tm1-ui-cube-viewer:

                    tm1-cube="General Ledger">

Refresh your page and you should see the cube view:

Canvas cube viewer options

The Canvas Cube Viewer has lots of options, mainly to turn on/off features:

These options can be set by using the tm1-options parameter of the tm1-ui-cube-viewer directive. Motre information in the Help section of your application <Canvas  Application URL>/#/help.

Default member of a dimension

You do not need to drag and drop all dimensions in the view to be able to see data. You just need at least one dimension on row and one on column. For all other dimensions which are not part of the view definition, Canvas is going to use their default member. To learn how to define a default member for your dimensions, you should look at the following article:

Save/Save as view

If you are using Planning Analytics, saving a view will always create an MDX view. If you are using TM1 10.2 FP5, FP6 or FP7, you will have the option to save as a Native View:

When saving an MDX view, Canvas also saves the “view definition” as part of the view. If the MDX is updated outside of Canvas (or Arc), you will need to update / edit the MDX manually. Clear the MDX statement to revert to the drag/drop interface.

See the MDX

To access the MDX behind the view, just click the MDX button. Note that you cannot override manually the MDX. To update the MDX query, make some changes in the view and then click again to the MDX button to see the changes:

Using Sandbox with Canvas

A sandbox is your personal workspace where you can write data without interferring the base data. Canvas v3.0.1 introduces support to TM1 and Planning Analytics sandbox. All sandbox's operation are now available in Canvas such as Create, Publish, Discard or Delete:

Values in the sandbox but not published to the base data will be shown in blue:

Using Sandbox in DBR

The tm1-ui-dbr directive supports sandboxes. A new component has been added to the samples application to show you how to use sandboxes:

  • http://<CanvasServerName>:8080/samples/#/sample/component/dbr-sandbox

To use sandbox in dbr, you will need to use the parameter tm1-sandbox and specifies the sandbox name:

<tm1-ui-dbr tm1-instance="dev" 
            tm1-elements="Actual,2011/12,Local,England,{{item.key}},Standard Cost" 

Sandbox comparaison

To compare two sandboxes, you just need to compare two DBRs pointing to two different sandboxes.

Sandbox with $tm1Ui

Sandbox is also supported by the $tm1Ui services such as CellPut, CellGet, CellSetPut and CellSetGet. To use sandbox, you just need to add the sandbox name using the configuration parameter, more information in the Help section <Canvas Application URL>/#/help.

Set Printer Version to Use mode 2

Canvas v3 introduced a new printer version. By default, Canvas will now use this new printer version but if you prefer to go back to the first version of the printing you can change the printer version in your application Admin section:

Printer version mode 1 is the native printing version (Canvas v2 and previous versions) and Printer version 2 is the new printer.

This new printer is much faster and support better Canvas charts. It uses in the backend Headless Chromium. This printer version comes with a set of new parameters which you can find in the WEB-INF\config\settings.json file:

  • printerPath – location of the Chromium executables.

  • printerOnPageNavigationWaitForKeyword – keyword it waits from the printer engine to indicate completion of rendering of a web page. Default is ‘networkIdle‘.

  • printerPauseBeforePrint – timeout before issuing the request to generate the PDF.

  • printerPauseBeforeShutdown - On closing down the printer engine, sometimes it will need a longer wait time to wrap up and execute other clean up tasks. Default for this is 500ms.

  • printerPollerInterval – interval in millisecond to check for incoming messages from Chromium.

  • printerPollerIntervalMaxRetry – number of times the poller will try to check for incoming messages assuming a certain keyword has not been received yet.

  • printerScale – as per Chrome Print PDF settings, this is 50. But you can change it up to 200.

  • printerStartingPort – the starting port where Chromium can listen too. The number of instances that will be launch needs to have a unique port.

  • printerMaxInstance – the port that will be used will be incremented until this count has been reached. If you have port 9000 as set in printerStartingPort for example and you have in here a value of 10, then it means first instance will have 9000 as port, then 9001, and so on. What this is also means is that there can only be this printerMaxInstance value running at a time.

  • printerMaxPageSizeInMB – Maximum size, in MB, which helps the printer engine in allocating memory on the expected PDF output.

  • printerBaseUrl – if provided, this will be used to get the protocol and the host to use for accessing Chromium. Default is localhost.

Introduction to Load Balancing with Canvas

The following article explains the concept of load balancing and how it can be implemented with Canvas.

What is Load Balancing?

Load balancing is very common in the computing world, lots of companies such as Netflix which have lots of users logging in to their application are using it to optimize the use of their servers. To avoid all users logging to the same server, the load balancer can be configured to split users into different servers. A good definition of load balancing can be found in the following link:

Load balancing with Canvas

Canvas uses an Apachet Tomcat server, there are lots of documentation online which explains how the load balancing can be set up with Apache Tomcat:

Keep in sync the CWAS folder

One important thing to consider before setting up load balancing with Canvas is that you will have to install Canvas on each server. It means that you will have one CWAS folder per server. The CWAS contains the Canvas application (HTML, JS files..) so you will need to keep this folder in sync to make sure that all your users have access to the same Canvas application.

Transform your cell set into a structured format

Canvas comes with lots of directives which are ready to use. For example with tm1-ui-dbr you can quickly request a data from TM1 and display it in your page. With these directives you can already achieve a lot but in certain case where you want to do more customization, you can use Canvas services such as cubeExecuteMdx to request data from TM1 and then transform it into your controller:

  1. Request data to TM1 from a MDX query.
  2. TM1 will send you back an object with OData structure.
  3. Transform this object so it can match your HTML component structure.
  4. Finally display this object into your HTML page.

The tricky part in this process is the data transformation. Good thing Canvas comes with a service named resultsetTransform which takes your OData object and then restructure it and add more properties such as pagination which you can then use in your table.

An example of this service can be found in the samples application (/sample/component/mdx-chart). This article explains in details how this sample works.

1. Create MDX Statement

The first step to request data from TM1 server is to use an MDX statement. On this example we used the following query:

NON EMPTY {[Period].[Jan], [Period].[Feb], [Period].[Mar]} ON COLUMNS, 
NON EMPTY {[Account].AllMembers} ON ROWS 
FROM [General Ledger] 
WHERE([Version].[Actual], [General Ledger Measure].[Amount], [Currency].[Local], [Region].[1], [Department].[1], [Year].[2012])

This query will give us a set of data coming from the General Ledger cube with three columns (Jan, Feb and Mar) for all accounts ([Account].AllMembers) on rows.

2. Retrieve the value from TM1

To retrieve the cell set from TM1, we use the Canvas service cubeExecuteMdx, in the controller (mdx-chart.js), you can see the following code:

$tm1Ui.cubeExecuteMdx($scope.values.instance, $scope.mdxQuery).then(function(data){

The cell set coming back from TM1 is then stored in an object called data This data object follows the OData structure:

You do not have to know the OData structure to be able to use Canvas but if you are curious, you can find out more about OData in this article:

3. Restructure this object using resultsetTransform

from mdx to display data.png

Instead of manipulating this object, you can transform it using the Canvas service resultsetTransform into a new object and store it to let us say $scope.values.table:

This service transfoms a cell set from TM1 into an object which you can easily manipulate to create a table. You can find more information about all Canvas services into the Canvas Help page (application/#/help):


This new object $scope.values.table has much more properties than the previous data object and it is easier to access:

Now that our object is ready, we can now build the table in our HTML page.

4. Display these properties in the view

The new object created by the service resultsetTransfrom has been structure in a way that it is much easier to access the most important properties of a table such as headers and values:

Create the header row

The headers can be found in the elements property of any row, in this example we choose the first one (rows[0]):


The HTML code to display the row header is:

 <th ng-repeat="rowDimension in values.table.rows[0].elements" class="text-center">

Create the column headers

The column headers are in the key properties of every cells of a row.

Again in this example we pick the first row to get all column headers:

<th ng-repeat="cellHeader in values.table.rows[0].cells" class="text-center">
    {{cellHeader.key.split(',').join(' - ')}}

Get the element on rows

The elements on rows are in the elements properties, we use the alias property to show the alias value:

The HTML code to display the element on rows is:

<tr ng-repeat="row in values.table.rows">
    <td ng-repeat="rowDimension in row.elements" class="text-center">

Get the values

The values are stored in the cells property of the rows:

The HTML code is:

<tr ng-repeat="row in values.table.rows">
        <td ng-repeat="cellHeader in row.cells" class="text-right">
                {{cellHeader.value | formatNumber: 2}}

You are now ready to build your own table based on an MDX query!

How to build your own service

What is a service?

In AngularJS, a service is a function, or an object, that is available for, and limited to, your application. AngularJS has about 30 built-in services. If you are updating the URL in your application, it is likely that you have already used the $location service.

Differences between a service and a directive?

A service is mainly a way to communicate between controllers. A service does not contain any HTML components. Whereas a directive is used to build widgets, it can contain a view (HTML file) and a controller (JS file).

Why build your own service?

  • Avoid duplicating the same code on multiple pages.
  • Reduce the maintenance into one file.
  • Create a reusable function for all your future projects.
  • Build a function that you can share with the Canvas community.

Building a service is very easy, just follow these steps and you will be able to build your first service in 5 minutes.

Structure of a service

A service is a JS file the following structure:

app.service('serviceName', ['$tm1Ui', '$location', function($tm1Ui, $location) {
    //Do something

A service can use other services. To enable other services, you will need to add these services as arguments of your service. In the example above the new service called serviceName will be able to use the $tm1Ui and $location service.

How to build your first service?

Building a service is very easy, you just need to copy the code from your controller into a new file. First let's create this new file. Canvas is going to load all files from the JS folder so you can put it anywhere inside the JS folder. In this example we put it inside js/controllers folder.

For example, let's say in our controller we use the function to update the settings. Instead of using the same code in every controllers, we can copy this function:

$scope.updateSettings = function (parameter, options) {
    //Get user settings value from Settings cube

And paste it into a new file called globals.js and replace $scope. with this.:

app.service('globals', ['$tm1Ui', '$location', function($tm1Ui, $location) {
    this.updateSettings = function (values, defaults, selections, parameter, options) {
    //Get user settings value from Settings cube

When this function was in our controller, we were using $scope to get the values of the variables defaults and selections. To be able to use the defaults and selections variables inside our service, we need to pass them as argument of the function in the service.

You can download the all code here:

How to call your service from a controller?

To be able to use a service in a controller, you need first to declare it at the top of the controller:

Then you just need to prefix the function with the service name. In the example below, the function initializeVariables is going to call the function updateSettings from the service globals:

$scope.initializeVariables = function(){
            $scope.values.user = data;
            globals.updateSettings($scope.values, $scope.defaults, $scope.selections, "Year", {"tm1Dimension":"Year", "tm1Alias":"Financial Year"});
            globals.updateSettings($scope.values, $scope.defaults, $scope.selections, "Version", {"tm1Dimension":"Version", "tm1Alias":"Description"});

How to call your service from a view?

From the view (HTML page), you can access only functions which are defined in the controller. To call a function from a service, you will have to create a link between the controller and the service using:

$scope.globals = globals; 

By doing so all functions defined in the globals service are now available from the view by using globals.functionName. In our example we trigger the function globals.updateSettings from the SUBNM when the value change using tm1-change:

  tm1-change='globals.updateSettings(values, defaults, selections, "Version", {"tm1Dimension":"Version", "tm1Alias":"Description", "value":data})'>     </tm1-ui-subnm>

You can download the example here (it includes the view, the controller and the service):

How to build your own directive

Canvas for TM1 comes with 30 directives (tm1-ui-dbr, tm1-ui-subnm...) which will help you to build quickly a page. If you combine these Canvas directives with the AngularJS Directives such as ng-repeat and ng-if, you can already achieve a lot. By combining these existing directives, you can build more sophisticated components. When you start replicating the same component in different pages, this is where you need to start thinking about bulding your own directive.

What is a directive?

A directive can be anything, it could be just an HTML component or a part of it that you want to reuse in multiple pages.

Why building your own directive?

  • Avoid duplicating the same code on multiple pages.
  • Reduce the maintenance into one file.
  • Create a reusable component for all your future projects.
  • Build a component that you can share with the Canvas community.

Building a directive is very easy, just follow these steps and you will be able to build your first directive in 5 minutes.

Directive structure

A directive can just be a JS file or with an HTML file combined. In this example we are going to build a directive which is going to show all attributes of an element. For this directive we will need a view (an HTML file) and a controller (JS file) to where we will define our directive:

Create the HTML components

The HTML page used in the directives is very similar to an HTML page you use on your main page except that you do not need to specify a controller:

The link between the view (display-attributes.html) and the directive itself (display-attributes.js) will be defined in our JS file.

For our view, let us just start with a simple row from which we will then define the contents we want to show:

<div class="row">
    View contents

You can download the full example here:

Create the directive definition:

If this is your first directive, the structure will be slightly different at the beginning. The structure of the "controller" used in a directive is going to be slightly different than the one used for a main view:

You can download the code here:

The Canvas server is going to load all the files in the JS folder. So you just need to put your new directive (JS file) in the JS folder and you will be able to use your directive in your page.

How to use the directive in a new page

To use the directive, you just need to call the HTML tag with the name of your directive. If your directive is called myDirective, the HTML tag will be <my-directive></my-directive>, in our example, we use the following code to call our directive:

<display-attributes tm1-instance="dev" 

Display data from an Excel file and then send it to TM1 via REST API

With Canvas, you can upload an Excel file into your browser, validate the data and then send the data into TM1 using the REST API. A sample showcasing has been introduced in Canvas 2.0:

  • http://localhost:8080/samples/#/sample/sample-sheetjs

This article explains in details how this sample work.

Enable SheetJS library

The first step is to enable the optional libray sheet JS, the steps are described in the following article:

Upload Excel File

1. Create upload button in the view

To upload an Excel file into your browser, you need to create an upload button that will handle and help us process the Excel file, within the client's browser. To do that you just need to add and to utilize the js-xls directive as follows:

When you upload an Excel file, the read function is triggered and if there is an error, the error function is triggered.

2. Create 'read' function in the controller

You then need to define the read function. This function takes the processed workbook by SheetJS as an argument, initializes the variables. We will then call our parseWorksheet function which will help us extract the data from the Excel file and show it into our Canvas page:

3. Get values from the cells

The parseWorksheet function loops through all rows and associate the cell values, to an object we will name as record:

For example: for every row, we know that the product name is in Excel sheet's column A. To then access the name for each row (A1, A2, A3, etc.):

var product = sht["A" +(r + 1)].v;

SheetJS creates an object and make the cells accessible via properties. A cell in Excel has different properties such as: the formula used, the actual display value, etc. But where we are interested in is in the property named 'v', which contains the value. 

We will then associate all values for a row to a record. Each record will have one Boolean property indicating if it was selected, the product name on that row, one value for each month on that row and an error message.:

var record = {
      row: r - startRow + 1,
      selected: true,
      product: product,
      m01: m01,m02: m02,m03: m03,m04: m04,m05: m05,m06: m06,
      m07: m07,m08: m08,m09: m09,m10: m10,m11: m11,m12: m12,
      error: error

Each record will then gets pushed into an array stored within the lists.records object:


Near the end of this function, the lists.records should contain a list of record objects. Lastly, the validate function is then called to check these records for any errors or missing information.

4. Validate the set of records

The validate function loops through all the records we have created and check if the product is in the Product dimension. If it is not, it updates the error message and set its Boolean property to indicate selection, to false (this will make the record be not selected on the front end):


5. Display the data into the browser

To display the records in the view, we use the ng-repeat directive in a table and iterate through the list of records we have prepared previously:

Send data into TM1 via REST API

Now that we have displayed the data in the browser, the last step is to allow the users to send this data to the right intersection of the TM1 cube:

1. Store all information in an object

We create first an array of CellPut request objects with the following properties:

  • [{value:'Test', instance:'dev', cube:'System Info', cubeElements:['Server Time', 'String']}]

We need one request per month:

2. Use CellSetPut

Once the array is populated, we just need to use one of the available Canvas scripting service for sending data into TM1 - $tm1Ui's service cellsetPut:

This service should then send a batch of cells into TM1 for update. In the case above, this should batch and send the cells within the row all at the same time into TM1 for updating.

If you prefer to send data into TM1 line per cell, use cellPut instead of cellsetPut:

  • cellPut(value, instance, cube, element1, element2, elementN)

Alternate Hierarchies in Canvas

Probably the most exiting feature in IBM Planning Analytics is alternate hierarchies. Using alternate hierarchies will enable you to potentially reduce the number of dimensions in your cube and therefore improve cube size and performance.

For example you could merge the Year and the Month dimension into one Time dimension:

Enabling Alternate Hierarchies

Alternate hierarchies are available since IBM Planning Analytics. To turn on alternate hierarchy, you need to add the new parameter EnableNewHierarchyCreation=T into the tm1s.cfg file and restart the TM1 instance.


Support for alternate hierarchies has been added from Canvas 2.0 with tm1-ui-dbr. To get values using alternate hierarchies, you can now use the following syntax within the tm1-elements:

  • "Hierarchy1::Element1 && Hierarchy2::Element2"

For example, to get the value from 2009 Jan on the Time dimension, you will need to use the following when referring to the intersection of these hierarchies:

  • "Year::2009 && Month::Jan"

An example of DBR with alternate hierarchies can be found in the Components page of the samples application:

  • http://localhost:8080/samples/#/sample/component/dbr-hierarchy


Another way to get data using alternate hierarchies is to use an MDX query. To specify an element on another hierarchy within the same dimension, use the following format:

  • [Dimension].[Hierarchy].[Element]

For example to get the element All Months which is in the Month hierarchy of the Time dimension:

  • [Time].[Month].[All Months]

One of the ways to show data from an MDX query within Canvas is using a Named MDX. For more advance scripting, you can also create your own MDX query and pass it on one of the Canvas scripting service - cubeExecuteMdx(). Additional information on this and other available Canvas scripting services can be found on you application's Help pages. 

Different Sources for Bursting Reports

This article details the different bursting methodology you can use to send and to generate different PDFs and/or Emails.


To enable Report bursting on your reports, select the following option on your Report action:


An option to burst these reports is provided via the 3rd tab:


From which the following options is shown when you click the plus icon on the right side:


Most types of bursting methodology allows you to define a placeholder or variable, which you can then use on your Emails or the URLs of your attachments which will then generate the PDFs.

For example, if we have defined a dimension subset as follows:


This means that the elements of the subset 'Burst' in dimension 'Region' will be available for each 'burst'. If for example the Burst subset has the following elements:


When the task runs, it will generate Emails and PDFs depending on how many iterations is available on your burst tab. On this case, since there are only two elements on the Burst subset, it will run two times. These elements are available and can be accessed by typing the following:


For example, in the subject of your email you can type like:


The effect of this will then be, for each burst, the placeholder {{region}} will then be replaced with the iteration value - first is with 'Finland', second is with 'England'.

You can do this on the various parts of the email and also in the URLs if you have an attachment.

Here are the other source you can use for your report bursting:

Dimension Subset

Selecting this burst type means being able to utilize the elements in a subset, into your emails or reports. 

Dimension MDX

This option provides you the option to retrieve the elements by executing an MDX against a dimension.

Cube View


As you have noticed, there is no input for placeholder. What it actually uses as placeholders are the names of the dimensions on the row of your Cube View! And this is how the cube view looks like:


With this, you can manage the bursting even via Cube View.


Using comma separated values as a starting point can also be used. This method allows you to use adhoc data. You can start by uploading a CSV into the provided box or create your own table of information:


Similar to Cube View, the placeholder name will be the header of the CSV, or the first row.

CSV Path

Instead of starting with a CSV file, you can provide a CSV path accessible in the server which will then get parsed when the task runs. This allows you to update the file prior to running the actual task, or have a TI for example, to re-generate the file prior to running this Report action. Note that you can also schedule a TI to run as part of this task (the others being Chores, and Wait times).

This is the options you will be provided with:


The files in here should then be accessible within the current Canvas' applications file directory as defined in the Settings. These are further separated by the instance name. So in the case above, the location will be at:

 <Canvas Application>\files\<instance>

Or as an example for our samples application that is for example installed in drive C,


And that is it!

Lastly, also note that you can mix and merge different bursting sources!

Burst PDF reports with the Task Scheduler

From Canvas 2.0 and up, there is now a Task Scheduler which you can use to schedule tasks. These tasks can contain TM1 processes, TM1 chores or Canvas pages. This article describes the steps to follow to set up a new task which is going to send by email one dashboard per region.

SMTP Configuration

Before scheduling a task, you should check if the SMTP configuration has been configured correctly. Canvas allows you to send emails, which it does by accessing an SMTP server. For most corporate networks, the SMTP server can accept any requests to send an email from servers within the same network.

This is an example of settings with an Office 365 accounts, you can test your settings with the paper plane button at the top right:

For more information about SMTP configurations, you can check the following Help article: Email settings.

Open Task Scheduler

There is one Task Scheduler per application, you can access it from the admin section:

  • http://<server name>:8080/<application name>/admin#/task-scheduler

For example, to access the Task Manager of the samples application:

Create a new task

In this page you will see the list of tasks. Click the Add New Task button at the top right: 

Add name and instance settings:

The name is the task name which will appear in the main page. There is a status button which is active by default. You then need to add the login information of the TM1 instance that will be used on this task:

  • Instance: TM1 instance name defines in the instances.json
  • User Name: TM1 user
  • Password: TM1 Password
  • Use CAM: Yes if you are using CAM Security
  • CAM Namespace: CAM Namespace

Add Schedule (optional)

The next step is to schedule the task, add a name for the schedule and then click the schedule button:

A pop-up window will appear with different options to choose from for scheduling your task such as every month, week, day, etc.:

Click the Check Schedule button to see when its next runs. Finally click Apply Schedule.

Add an action

There are different action that you can add such as run TM1 process, TM1 Chore, add a wait and run a report. In this example we will add a Report:

Then click on the icon to update the information about the report:

Email information

For each report you need to specify the email information. The description is used only in the Task Scheduler. If you burst multiple reports, you can choose between sending one Email for all reports or one email per attachment:

Report information

Attachments are the URL path to the Canvas pages. Canvas uses the URL to create PDF reports. If you want to send the report with the filter region, you have to make sure that the filter is in the URL, if not it will always print the report with the default filters. To learn how to dynamically update the URL, you can check the following help article: Update the URL before printing.

In this example, the bursting will be based on the regions. In the attachment name and in the url we use {{region}} to get the value of the region we are bursting:

Burst information

There are different ways to drive your bursting. You can either drive the bursting based on a Dimension Subset, Dimension MDX, Cubeview, CSV file or a path to a CSV file. You can mix and match these. You can also use these in the three special markups. Combining these can potentially help you manage the recipients by Region for example.

In this example we drive the bursting based on the Default subset of the Region dimension:

Each type of burst item presents you a placeholder variable which you can then use in the Email or Report tab. The placeholder name is the name of the variable you can then use in either Report or Email tab.

Click Save button

The last step is to save the task:

Burst report 12.png

Tasks list

Once save you will than see the new task in the Task List, you can then disable or enable them from this page:


Just click the execute button if you want to test your new task. In this example we receive one email with one report per region in the Default substet:

To send one email per report, in the Email tab click An Email per Attachment Burst, in the email subject you can use {{region}} to add the region name:

You can even customize the email body with some information about the region such as attributes or key KPIs. To bring this information you can either use DBRA or DBR with the following syntax:

  • [[ dbr:<instance>:<cube>:<elements> ]]

    o   i.e. [[dbr : dev: Product :Actual, 2012, Local, Finland, All Products by Category, Standard Cost]]

  • [[ dbra:<instance>:<dimension>:<element>:<attribute> ]]

    o   i.e. [[dbra : dev: Region :Finland: Currency]]

  •  [[ rundate:<date format> ]]

    o   i.e. [[ rundate: yyyy.MM.dd]]

For example in the example below, the email body will contain the Currency attribute, the Standard Cost and List Price value:

Tasks folder

All Tasks can be found in the \CWAS\webapps\<application name>\WEB-INF\config\tasks folder:

For the samples application:

  • C:\CWAS\webapps\samples\WEB-INF\config\tasks

The Task ID is found in the URL when a task is opened in the Task Scheduler:

This should help you find the file within the config/tasks folder if it needs to be moved into a different server, or for backing up purposes. 

To learn more about the different sources for bursting reports you should check the following article:


Refresh DBRs by Groups

By default when you input a value in a cell containing DBRs in Canvas, all the DBRs will refresh. From Canvas 2.0 and up, you can now group the DBRs so that when you input a value, only the DBRs of the same group as that input will be refreshed. This could greatly improve the responsiveness of your page.

For example if the table contains data from two different cubes, you could split the DBRs into two groups.

To group DBRs, you will need to add to the tm1-ui-dbr directive, the new attribute tm1-refresh-group="<group name>". For example if you want to call the group Group 1, it will look like this:

  • tm1-refresh-group="Group 1"

An example of the tm1-refresh-group button can be found in the components of the samples application.

  • http://localhost:8080/samples/#/sample/component/dbr-group-update

This page contains the DBRs which get the same value in TM1, if you input a value in the first DBR, all DBRs will refresh:

The DBR in the No Group block does not have any group defined:

   tm1-cube="General Ledger"
   tm1-elements='Actual,2011/12,Mar,Local,England,Sales and Marketing,Employee Benefits,Amount'>

When you write a value to this DBR it will update every other DBRs, even the one which are in a specific group.

However if you input a value in the first group DBR, you will see that it will only update the DBRs within that panel (all the these were given the same group for sample purposes). And in connection to this, the DBRs in Group 2 panel will not refresh:

If we have a look at the code, we can see that both DBR are in different groups:

This grouping also applies to the other DBRs within that panel, per group.


This feature should allow you to localize your inputs and updates, giving you further control on how to update your page.

When you input a value to a DBR and if it is part of a group, only the DBRs within the same group will be refreshed. If the DBR is not part of any group, as per normal cases, then all DBRs will be refreshed even the ones which are parts of a group.