visualization Object Type in Project Metadata
The project metadata was upgraded on March 10, 2018 (see the Release Notes).
What has changed?
- All project metadata objects of the
visualizationtype were migrated to thevisualizationObjecttype. Thevisualizationtype is no longer available for use, and any code still using it does not work. Project metadata objects of thevisualizationObjecttype keep information about insights. Insights are created in Analytical Designer (see Analytical Designer) and can be then either used in Analytical Designer directly or added to KPI dashboards (see Dashboards). - A new property,
visualizationClass, was introduced.visualizationClassdefines the type of avisualizationObjectobject (pie chart, line chart, and so on). You can query forvisualizationClassusing the following API:/gdc/md/{workspace_id}/query/visualizationclasses`` /gdc/md/{workspace_id}/objects/query?category=visualizationClass&limit=50
Comparing visualization and visualizationObject
Root element name
The root element name changed from visualization to visualizationObject.
| visualization | visualizationObject |
|---|---|
{ “visualization”: {...} } | { “visualizationObject”: {...} } |
Insight type
The insight type changed from a fixed enumeration to a reference to a particular visualizationClass instance corresponding to the right type of the insight.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { “type”: “table”, ... } ... } } | { “visualizationObject”: { “content”: { “visualizationClass”: { “content”: { “url”: “local:table”, “icon”: “local:table”, "iconSelected": "local:table.selected", “orderIndex”: 0, “checksum”: “local” }, “meta”: { ... } } } } } |
Buckets
Buckets changed from a key-value map to an array, which allows you to have an arbitrary number of buckets. Filters are now placed outside of the buckets.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { “buckets”: { "categories": [...] "measures": [...] "filters": [...] } } } } | { “visualizationObject”: { “content”: { “buckets”: [...], “filters”: [...] } } } |
Each bucket was enriched with a localIdentifier to uniquely locate the bucket in an object. The measures bucket items were moved to a newly created bucket with a localIdentifier set to measures. Attribute buckets were created according to the collection property of the items in the categories bucket.
Individual items in buckets (metrics, attributes) were transformed. In the following example, they are denoted by an apostrophe.
| visualization | visualizationObject |
|---|---|
“buckets”: { “measures”: [M1, M2], “categories”: [{ …A1, collection: “view” }, { …A2, collection: “view” }, { …A3, collection: “stack” }] } | “buckets”: [ { “localIdentifier”: “measures”, “items”: [M1’, M2’] }, { “localIdentifier”: “view”, “items”: [A1’, A2’] }, { “localIdentifier”: “stack”, “items”: [A3’] } ] |
Attributes
Only displayForm and alias are now part of an attribute. Other keys now reside in different parts of the visualizationObject metadata. For more information about sorting and styles, see sort and styles.
collection is used to place the item to the correct bucket. type was made redundant.
localIdentifier that you create must be unique within a whole metadata object.
| visualization | visualizationObject |
|---|---|
{ “category”: { “type”: ‘attribute’, “collection”: “view”, “displayForm”: DF, “attribute”: AT, “sort”: SD, “styles”: ST, “alias”: AL } } | { “visualizationAttribute”: { “localIdentifier”: <unique_identifier> “displayForm”: { “uri”: DF }, “alias”: AL } } |
Metrics
The structure of metrics in the buckets changed in the following way:
- A metric has a
localIdentifier(which is a string used to refer to a metric and must be unique within the whole metadata object) andmeasureDefinition. - The remaining properties are moved under
measureDefinition. - The following properties were renamed:
objectUri–>itemmeasureFilters–>filtersshowInPercent–>computeRatio,aggregation
The properties format, title and alias did not change.
| visualization | visualizationObject |
|---|---|
{ “measure”: { “showPoP”: false, “aggregation”: AG “type”: ..., “objectUri”: URI, “showInPercent”: SIP, “measureFilters”: ... “title”: TI, “format”: FO, “sort”: ..., “styles”: ..., “alias”: AL, “filters”: FI } } | { “measure”: { “localIdentifier”: <unique_identifier>, “title”: TI, “format”: FO, “alias”: AL, “definition”: { “measureDefinition”: { “item”: { “uri”: URI }, “aggregation”: AG, “filters”: FI’, “computeRatio”: SIP } } } } |
The property showPoP was replaced with a period-over-period (PoP) metric and is represented as two metrics:
- the original metric
- another metric that defines the PoP and references the original metric via its
localIdentifier.
| visualization | visualizationObject |
|---|---|
{ “measure”: { “showPoP”: true, M1 } } | { M1’PoP }, { M1’ } |
| visualization | visualizationObject |
|---|---|
{ “measure”: { “showPoP”: true, “aggregation”: AG “type”: ..., “objectUri”: URI, “showInPercent”: SIP, “measureFilters”:... “title”: TI, “format”: FO, “sort”: ..., “styles”: ..., “alias”: AL, “filters”: FI } } | { “measure”: { “localIdentifier”: <unique_identifier>, “title”: TI, “format”: FO, “alias”: AL, “definition”: { “PoPMeasureDefinition”: { “measureIdentifier”: U1, “popAttribute”: { “uri”: ... } } } } }, { “measure”: { “localIdentifier”: U1, “title”: TI, “format”: FO, “alias”: AL, “definition”: { “measureDefinition”: { “item”: { “uri”: URI }, “aggregation”: AG, “filters”: FI’, “computeRatio”: SIP } } } } |
The popAttribute property in PoPMeasureDefinition is a URI of the date attribute in the original metadata object.
In the visualization object, the date could have been located either in buckets (as one of the items in categories) or in filters.
| visualization: date filters in categories | visualizationObject: attribute for PoP metric bucket item |
|---|---|
“measures”: [ “measure”: { “showPoP”: true, M1 } ], “categories”: [ “category”: { “type”: “date”, “attribute”: ATR, ... } ] | { “measure”: { “localIdentifier”: <unique_identifier>, ... “definition”: { “PoPMeasureDefinition”: { “measureIdentifier”: U1, “popAttribute”: { “uri”: ATR } } } } }, { M1’ } |
| visualization: date attribute in global filters | visualizationObject: attribute for PoP metric bucket item |
|---|---|
“measures”: [ “measure”: { “showPoP”: true, M1 } ], “filters”: [ “dateFilter”: { ... “attribute”: ATR, ... } ] | { “measure”: { “localIdentifier”: <unique_identifier>, ... “definition”: { “PoPMeasureDefinition”: { “measureIdentifier”: U1, “popAttribute”: { “uri”: ATR } } } } }, { M1’ } |
Metric filters were transformed the same way the global filters were, see the previous example.
The sort and styles properties were moved to under properties. For more information, see properties.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { “buckets”: { “measures”: [{ “measure”: { sort: SO styles: ST } }] } } } } | { “visualizationObject”: { “content”: { ..., “properties”: SO’ + ST’ } } } |
Filters
Filters were moved from under buckets and now are at the same level as buckets.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { “buckets”: { “filters”: F } } } } | { “visualizationObject”: { “content”: { “buckets”: ..., “filters”: F’ } } } |
The following types of filters exist:
- Date filters
- Relative date filters
- Absolute date filters
- Attribute filters
- Negative attribute filters
- Positive attribute filters
Date filters
In a date filter, dataSet.uri is inherited from the dataset property. If dataset is not present but dimension is, dimension is used instead.
| visualization: relative date filter | visualizationObject relative date filter |
|---|---|
dateFilter: { “type”: 'relative', “from”: F, “to”: T, “granularity”: G, “attribute”: A, “dataset”: D, “dimension”: DIM } | "relativeDateFilter”: { “dataSet”: { “uri”: D |
| visualization: absolute date filter | visualizationObject: absolute date filter |
|---|---|
dateFilter: { “type”: 'absolute', “from”: F, “to”: T, “granularity”: G, “attribute”: A, “dataset”: D, “dimension”: DIM } | “absoluteDateFilter”: { “dataSet”: { “uri”: D |
Attribute filters
In an attribute filter, the property attribute is no longer present.
| visualization: negative attribute filter | visualizationObject: negative attribute filter |
|---|---|
“listAttributeFilter”: { “attribute”: A, “displayForm”: DF, “default”: { “negativeSelection”: true, “attributeElements”: [EL1, EL2] } } | “negativeAttributeFilter”: { “displayForm”: { “uri”: DF }, notIn: [EL1, EL2] } |
| visualization: positive attribute filter | visualizationObject: positive attribute filter |
|---|---|
“listAttributeFilter”: { “attribute”: A, “displayForm”: DF, “default”: { “negativeSelection”: false, “attributeElements”: [EL1, EL2] } } | “positiveAttributeFilter”: { “displayForm”: { “uri”: DF }, in: [EL1, EL2] } |
Properties
sort and styles were moved to under properties.
properties is now a JSON stored in a string, which is accompanied by a references property containing references so that project export/import work correctly. Therefore, when using a URI within the properties string, extract that to references.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { ... } } } | { “visualizationObject”: { “content”: { “properties”: “{...: PROP1, ...: PROP2 }” “references”: { PROP1: “/gdc/md/abc/1”, PROP2: “/gdc/md/abc/2” } } } } |
sort
sort was moved from the original buckets to under properties that now has sortItems.
| visualization | visualizationObject |
|---|---|
{ “visualization”: { “content”: { “buckets”: { “measures”: [{ ..., sort: S }] } } } } | { “visualizationObject”: { “content”: { “properties”: JSON.stringify({ sortItems: S’ }) “references”: { ... } } } } |
The following is an example of sorting defined for an attribute in the bucket:
| visualization | visualizationObject |
|---|---|
{ ...A1 sort: DIR } | “sortItems”: [{ “attributeSortItem”: { “attributeIdentifier”: <localIdentifier_of_A1>, “direction”: DIR } }] |
The following is an example of sorting defined for a metric. The sortItems structure is more complex and contains locators.
| visualization | visualizationObject |
|---|---|
{ ...M1 sort: DIR } | “sortItems”: [{ “measureSortItem”: { “direction”: DIR, “locators”: [ “measureLocatorItem”: { “measureIdentifier”: <localIdentifier_of_M1> } ] } }] |
The following is an example of sorting for a PoP (period-over-period) metric:
| visualization | visualizationObject |
|---|---|
{ ...M1 showPoP: true, sort: DIR } | “sortItems”: [{ “measureSortItem”: { “direction”: DIR, “locators”: [ “measureLocatorItem”: { “measureIdentifier”: <localIdentifier_of_PopM1> } ] } }] |
styles
styles was transformed as follows:
| visualization | visualizationObject |
|---|---|
{ “measure”: { “styles”: [ “visualizationStyle”: { “type”: “bar”, “colorPalette”: { “measure”: { color: C, periodOverPeriod: false }, “stack”: ST } } ] } } | “properties”: JSON.stringify({ “styles”: [ { “colorPalete”: { “measures”: [ { “measureIdentifier”: <M1’_localIdentifier>, “color”: C } ], “stack”: ST, } } ], ... }) |
{ “measure”: { “styles”: [ “visualizationStyle”: { “type”: “bar”, “colorPalette”: { “measure”: { color: C, periodOverPeriod: true }, “stack”: ST } } ] } } | “properties”: JSON.stringify({ “styles”: [ { “colorPalete”: { “measures”: [ { “measureIdentifier”: <M1PoP’_localIdentifier>, “color”: C } ], “stack”: ST, } } ], ... }) |
Upgrade examples
No sorting defined
| visualization | visualizationObject |
|---|---|
"visualization": { "meta": META, "content": { "type": "column", "buckets": { "filters": [ { "dateFilter": { "granularity": "GDC.time.year", "dataset": "/gdc/md/<project_id>/obj/<dataset_id>", "attribute": "/gdc/md/<project_id>/obj/<attribute_id>", "type": "relative", "from": 1, "to" : 2 } } ], "measures": [ { "measure": { "measureFilters": [], "showInPercent": true, "showPoP": true, "objectUri": "/gdc/md/<project_id>/obj/<metric_id>", "type": "metric", "title": "%_Sales" } } ], "categories": [ { "category": { "displayForm": "/gdc/md/<project_id>/obj/<displayForm_id>", "attribute": "/gdc/md/<project_id>/obj/<attribute_id>", "type": "date", "collection": "view" } } ] } } } | "visualizationObject": { "meta": META, "content": { "visualizationClass": { "uri": ""/gdc/md/<project_id>/obj/<visualizationClass_id>"}, "buckets": [ { "localIdentifier": "measures", "items": [ { "measure": { "definition" : { "popMeasureDefinition": { "measureIdentifier": “m1”, "popAttribute": { "uri": "/gdc/md/<project_id>/obj/<attribute_id>" } } }, "localIdentifier": “m2” } }, { "measure": { "definition": { "measureDefinition": { "computeRatio": true, "item": { "uri": "/gdc/md/<project_id>/obj/<metric_id>" } } }, "localIdentifier": “m1”, "title": "%_Sales" } } ] }, { "localIdentifier": "view", "items": [ { "visualizationAttribute": { "displayForm": { "uri": "/gdc/md/<project_id>/obj/<displayForm_id>" }, "localIdentifier": “a1” } } ] } ], "filters": [ { "relativeDateFilter": { "dataset": { "uri": "/gdc/md/<project_id>/obj/<dataset_id>" }, "granularity": "GDC.time.year", "from": 1, "to": 2 } } ] } } |
Sorting defined
| visualization | visualizationObject |
|---|---|
{ "visualization":{ "content":{ "buckets":{ "categories":[ { "category":{ "attribute":"/gdc/md/<project_id>/obj/<attribute_id>", "collection":"attribute", "displayForm":"/gdc/md/<project_id>/obj/<displayForm_id>", "type":"attribute" } } ], "filters":[ { "listAttributeFilter":{ "attribute":"/gdc/md/<project_id>/obj/<attribute_id>", "default":{ "attributeElements":[ ], "negativeSelection":true }, "displayForm":"/gdc/md/<project_id>/obj/<displayForm_id>" } } ], "measures":[ { "measure":{ "measureFilters":[ ], "objectUri":"/gdc/md/<project_id>/obj/<metric_id>", "showInPercent":false, "showPoP":false, "title":"_Close [BOP]", "type":"metric" } }, { "measure":{ "measureFilters":[ ], "objectUri":"/gdc/md/<project_id>/obj/<metric_id>", "showInPercent":false, "showPoP":false, "sort":{ "direction":"desc", "sortByPoP":false }, "title":"_Close [EOP]", "type":"metric" } } ] }, "type":"table" }, "meta":{ "author":"/gdc/account/profile/<profile_id>", "category":"visualization", "contributor":"/gdc/account/profile/<profile_id>", "deprecated":"0", "identifier":"<visualization_identifier>", "isProduction":1, "tags":"", "title":"Table metric sort", "uri":"/gdc/md/<project_id>/obj/<visualization_id>" } } } | { "visualizationObject":{ "content":{ "buckets":[ { "items":[ { "measure":{ "definition":{ "measureDefinition":{ "filters":[ ], "item":{ "uri":"/gdc/md/<project_id>/obj/<metric_id>" } } }, "localIdentifier":"<unique_localIdentifier>", "title":"_Close [BOP]" } }, { "measure":{ "definition":{ "measureDefinition":{ "filters":[ ], "item":{ "uri":"/gdc/md/<project_id>/obj/<metric_id>" } } }, "localIdentifier":"<unique_localIdentifier>", "title":"_Close [EOP]" } } ], "localIdentifier":"measures" }, { "items":[ { "visualizationAttribute":{ "displayForm":{ "uri":"/gdc/md/<project_id>/obj/<displayForm_id>" }, "localIdentifier":"<unique_localIdentifier>" } } ], "localIdentifier":"attribute" } ], "filters":[ { "negativeAttributeFilter":{ "displayForm":{ "uri":"/gdc/md/<project_id>/obj/<displayForm_id>" }, "notIn":[ ] } } ], "properties":"{\"sortItems\":[{\"measureSortItem\":{\"direction\":\"desc\",\"locators\":[{\"measureLocatorItem\":{\"measureIdentifier\":\"<unique_localIdentifier>\"}}]}}]}", "references":{ }, "visualizationClass":{ "uri":"/gdc/md/<project_id>/obj/<visualizationClass_id>" } }, "meta":{ "author":"/gdc/account/profile/<profile_id>", "category":"visualizationObject", "contributor":"/gdc/account/profile/<profile_id>", "deprecated":"0", "identifier":"<visualization_identifier>", "isProduction":1, "tags":"", "title":"Table metric sort", "uri":"/gdc/md/<project_id>/obj/<visualization_id>" } } } |
Update your code to meet the new metadata structure
If you are using the GoodData SDKs
Upgrade to the latest version of the SDK to adjust your code to the structural changes in the project metadata. For more information, see GoodData SDK.
If you are using project metadata objects directly
Use visualizationObject in your code instead of visualization, and use a new API to query for visualizationObject instances.
Stop using: /gdc/md/{workspace_id}/query/visualizations /gdc/md/{workspace_id}/objects/query?category=visualization
Use instead: /gdc/md/{workspace_id}/query/visualizationobjects /gdc/md/{workspace_id}/objects/query?category=visualizationObject