Specify Result Structure
The structure of the result data is defined by resultSpec
. You can add dimensionality (pivoting), totals, and sorting.
See the type definition.
Dimensions
Structure of dimensions
// Type: IResultSpec
{
// Optional; Defaults to two dimensions – first with attributes, second with 'measureGroup'
dimensions: [
{
itemIdentifiers: [ '<attribute-local-identifier>' ], // array of localIdentifiers or 'measureGroup' string
totals: [] // Optional; Defaults to []
}
],
sorts: [] // Optional; Defaults to []
}
The dimensions
field communicates the executor how the data is organized into arrays. Imagine an attribute in columns vs. rows. Each dimension requires the itemIdentifiers
property, which is an array of items. These items could be attributes' localIdentifier
s from the AFM or a special measureGroup
string.
NOTES:
- Currently, you can define either one or two dimensions, with one dimension being empty. The default value for the first dimension is all attributes. The default value for the second dimension is
measureGroup
.- AFM components fill
resultSpec
with an appropriate definition depending on the type of the visualization.
Each item consists of several elements. For example, the attribute 'Year' would have 2016, 2017, and so on. The same applies to measureGroup
: its elements are the individual measures from the AFM. All these elements are sent in the headerItems
property.
Examples of dimensions
AFM with one measure (Revenue) and one attribute (Year)
Data is needed in one dimension: a simple array.
resultSpec.dimensions = [
{ itemIdentifiers: [ '<Year local id>', 'measureGroup' ] }
]
// `executionResult` is returned by years (that is, 2016, 2017, 2018):
{
data: [ 32000, 41000, 77000 ]
}
AFM with two measures (Revenue and Clicks) and one attribute (Year)
A typical layout of a viewBy chart is to have the attribute elements (2016, 2017, ...) in rows and the two measures in columns. The rows mean the first dimension of the returned array, and columns mean the second array.
resultSpec.dimensions = [ { itemIdentifiers: [ '<Year local id>' ] }, { itemIdentifiers: [ 'measureGroup' ] } ] // `executionResult` is returned with measures in the second dimension: { data: [ [ 32000, 300 ], [ 41000, 345 ], [ 77000, 590 ] ] }
What happens when we switch the dimensions?
resultSpec.dimensions = [ { itemIdentifiers: [ 'measureGroup' ] }, { itemIdentifiers: [ '<Year local id>' ] } ] // `executionResult` is returned with measures in the first dimension: { data: [ [ 32000, 41000, 77000 ], [ 300, 345, 590 ] ] }
AFM with one measure (Revenue) and two attributes (Year, Country)
This layout is often used for a stackBy chart. It has one attribute in rows and the other in columns.
resultSpec.dimensions = [
{ itemIdentifiers: [ '<Year local id>' ] },
{ itemIdentifiers: [ '<Country local id>', 'measureGroup' ] }
]
// `executionResult` is returned with two columns (for example, Czechia and USA):
{
data: [
[ 13000, 19000 ], // year 2016 - gives original sum of 32000
[ 15000, 26000 ], // year 2017 - gives original sum of 41000
[ 31000, 36000 ] // year 2018 - gives original sum of 77000
]
}
Cartesian product with two measures (Revenue and Clicks) and one attribute (Year)
In the previous example, measureGroup
contains only one element. If two items in one dimension have more than one element, a Cartesian product is returned.
The Cartesian product works in the following way:
A,B × 1,2 = A1, A2, B1, B2
- The following code sample gets revenues in years, followed by clicks in years:
resultSpec.dimensions = [ { itemIdentifiers: [ 'measureGroup', '<Year local id>' ] } ] // `executionResult`: { data: [ 32000, 41000, 77000, 300, 345, 590 ] }
- The following code sample gets revenues in years, followed by clicks in years:
resultSpec.dimensions = [ { itemIdentifiers: [ '<Year local id>', 'measureGroup' ] } ] // `executionResult`: { data: [ 32000, 300, 41000, 345, 77000, 590 ] }
headerItems
Every item in dimensions has its own elements. The labels for each element are sent in the executionResult.headerItems
property, which is a three-dimensional array.
Array levels:
dimensions: one or two records, one for each respective dimension in
resultSpec.dimensions
items: one record for each item in the dimension's
itemIdentifiers
elements: one record for each element in an item (an attribute or
measureGroup
)The type of this record is one of the following:
IResultAttributeHeaderItem
,IResultMeasureHeaderItem
,IResultTotalHeaderItem
. See the type definition file.
For example:
resultSpec.dimensions = [
{ itemIdentifiers: [ '<Year local id>', 'measureGroup' ] }
]
// `executionResult`:
{
data: [ 32000, 41000, 77000 ]
headerItems: [ // first dimension (we have not specified any other)
[
// first item (Year attribute)
[
// elements of the attribute
{ attributeHeaderItem: { name: "2016", ... } },
{ attributeHeaderItem: { name: "2017", ... } },
{ attributeHeaderItem: { name: "2018", ... } }
],
// second item (measureGroup)
[
// elements of measureGroup = the names of the measures. In this case, it is just one name.
{ measureHeaderItem: { name: "Revenue", ... } }
]
]
]
}
For more examples, sign up to the Live Examples and watch the Network tab in your browser's Developer console. You may also experiment by sending your own resultSpec
s: for example, use the Postman application.
Totals
Optionally, you can define totals for each dimension. Totals are used to get aggregated data over several rows or columns of measure data.
Definition of totals
totals: [
{
measureIdentifier: String, // measure local identifier, on which total is defined
type: String, // total type. Possible values are: [sum, max, min, avg, med, nat]
attributeIdentifier: String // attribute local identifier in dimension defining total placement
},
...
]
See the type definition.
Order of totals
The order of total items is [sum, max, min, avg, med, nat]
and cannot be changed.
Limitations
Currently, the following limitations are supported:
- Table visualizations
- First dimension with
attributes
andtotals
- Second dimension with
measureGroup
- First dimension with
- Grand totals in the first dimension
total.attributeIdentifier
contains the firstattribute-local-identifier
fromitemIdentifiers
.
If you want to define a nat
(native) total, make sure that it is in sync with the AFM.nativeTotals
definition (see Native totals).
Defining table totals
See Table Totals in ExecutionObject.
Example of totals
{
dimensions: [
{
itemIdentifiers: ['<attribute-local-identifier-1>', '<attribute-local-identifier-2>']
totals: [
{
measureIdentifier: '<measure-local-identifier-1>',
type: 'avg',
attributeIdentifier: '<attribute-local-identifier-1>'
},
{
measureIdentifier: '<measure-local-identifier-2>',
type: 'nat',
attributeIdentifier: '<attribute-local-identifier-1>'
}
...
]
},
{
itemIdentifiers: ['measureGroup']
}
]
}
Sorting
Sorting is defined by an array of either AttributeSortItems
or MeasureSortItems
.
Multi-level sorting is supported by combining several sortings. For example, sort by date first, then by product name alphabetically.
You can sort specific dimension items by a data line using measureSortItem
.
A data line is uniquely defined by the locators
array. The data line contains a chain of elements (attributeLocatorItem
) and optionally a measure (measureLocatorItem
) matching the selected dimension items. For example, you can sort your data by a specific data column (sorting your product sales only by sales of a certain product).
If the selected attributes, attribute values or measures are not available (for example, by being filtered out), measureSortItems
are omitted.
Measures are always listed in the same order in which they were defined in the AFM. Sorting measures based on their value is currently not supported.
Structure of sorting
{
...
// Type SortItem[]
sorts: [
// Type: IAttributeSortItem
{
attributeSortItem: {
direction: 'asc', // or 'desc',
attributeIdentifier: '<attribute-local-identifier>',
aggregation: 'sum' // Optional;
}
},
// Type: IMeasureSortItem
{
measureSortItem: {
direction: 'asc', // or 'desc',
// Type: LocatorItem[]
locators: [
{
attributeLocatorItem: {
attributeIdentifier: '<attribute-local-identifier>',
element: '<attribute-value-uri>'
}
}
]
}
}
]
...
}
Aggregation
By using aggregation: 'sum'
, all elements of an attribute are sorted based on an aggregation function applied to all valid values belonging to each element. This is extremely useful when sorting stacked visualizations such as stack bars or area charts.
Currently, only sorting by the sum
function is supported.
The following example shows sorting a table with two measures and a 'Year' attribute. You can set sorting based on the Year attribute with:
{
...
aggregation: 'sum',
direction: 'desc'
...
}
Consider the following original data:
Year | 2006 | 2006 | 2007 | 2007 |
---|---|---|---|---|
Measures | M1 | M2 | M1 | M2 |
Values | 1 | 2 | 3 | 4 |
The sorting function (sum
) is applied to all attribute element values for each attribute element (2006 and 2007). Notice that you are summing up values across different measures (M1 and M2):
2006 | 2007 |
---|---|
1 + 2 = 3 | 3 + 4 = 7 |
Attribute values are then sorted by this computed value (3 and 7, respectivelly):
Year | 2007 | 2007 | 2006 | 2006 |
---|---|---|---|---|
Measures | M1 | M2 | M1 | M2 |
Values | 3 | 4 | 1 | 2 |
Quick Reference of Dimensions
AFM | resultSpec.dimensions: |
executionResult: { } |
---|---|---|
1 measure 1 attribute (A) |
[ { itemIdentifiers: [ 'A', 'measureGroup' ] } ] |
|
2 measures (M1, M2) | [ { itemIdentifiers: [ 'measureGroup' ] } ] |
|
2 measures (M1, M2) 1 attribute (A) |
[ { itemIdentifiers: [ 'A', 'measureGroup' ] } ] |
|
empty first dimension + the same as above |
[ |
|
2 measures (M1, M2) 1 attribute (A) // typical for viewBy chart |
[ |
|
2 attributes (A, B) 1 measure (M1) // typical for stackBy chart |
[ |
|