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
visualization
type were migrated to thevisualizationObject
type. Thevisualization
type is no longer available for use, and any code still using it does not work. Project metadata objects of thevisualizationObject
type 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 KPI Dashboards). - A new property,
visualizationClass
, was introduced.visualizationClass
defines the type of avisualizationObject
object (pie chart, line chart, and so on). You can query forvisualizationClass
using 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
–>item
measureFilters
–>filters
showInPercent
–>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