visualization Object Type in Project Metadata

The project metadata was upgraded on March 10, 2018 (see the Release Notes).

Contents:

What has changed?

  • All project metadata objects of the visualization type were migrated to the visualizationObject type. The visualization type is no longer available for use, and any code still using it does not work.
    Project metadata objects of the visualizationObject 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 a visualizationObject object (pie chart, line chart, and so on).
    You can query for visualizationClass using the following API:
    /gdc/md/{project_id}/query/visualizationclasses

    /gdc/md/{project_id}/objects/query?category=visualizationClass&limit=50

Comparing visualization and visualizationObject

Root element name

The root element name changed from visualization to visualizationObject.

visualizationvisualizationObject

{
  “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.

visualizationvisualizationObject

{
  “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.

visualizationvisualizationObject

{
  “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. 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 (measures, attributes) were transformed. In the following example, they are denoted by an apostrophe.

visualizationvisualizationObject

“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.

visualizationvisualizationObject

{
  “category”: {
    “type”: ‘attribute’,
    “collection”: “view”,
    “displayForm”: DF,
    “attribute”: AT,
    “sort”: SD,
    “styles”: ST,
    “alias”: AL
  }
}

{
  “visualizationAttribute”: {
    “localIdentifier”: <unique_identifier>
    “displayForm”: {
      “uri”: DF
    },
    “alias”: AL
  }
}

Measures

The structure of measures in the buckets changed in the following way:

  • A measure has a localIdentifier (which is a string used to refer to a measure and must be unique within the whole metadata object) and measureDefinition.
  • The remaining properties are moved under the measure definition.
  • The following properties were renamed:
    • objectUri --> item
    • measureFilters --> filters
    • showInPercent --> computeRatio, aggregation

The properties format, title and alias did not change.

visualizationvisualizationObject

{
  “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) measure and is represented as two measures:

  • the original measure
  • another measure that defines the PoP and references the original measure via its localIdentifier.
visualizationvisualizationObject

{
  “measure”: {
    “showPoP”: true,
    M1
  }
}

{
  M1’PoP
},
{
  M1’
}

visualizationvisualizationObject

{
  “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 measure 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 measure bucket item

“measures”: [
  “measure”: {
    “showPoP”: true,
    M1
  }
],
“filters”: [
  “dateFilter”: {
    ...
    “attribute”: ATR,
    ...
  }
]

{
  “measure”: {
    “localIdentifier”: <unique_identifier>,
    ...
    “definition”: {
      “PoPMeasureDefinition”: {
        “measureIdentifier”: U1,
        “popAttribute”: {
          “uri”: ATR
        }
      }
    }
  }
},
{
  M1’
}

Measure 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.

visualizationvisualizationObject

{
  “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.

visualizationvisualizationObject

{
  “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      // (or DIM if D missing)
  },
  “granularity”: G,
  “from”: F,
  “to”: T
}

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      // (or DIM if D missing)
  },
  “granularity”: G,
  “from”: F,
  “to”: T
}

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.

visualizationvisualizationObject

{
  “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.

visualizationvisualizationObject

{
  “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:

visualizationvisualizationObject

{
  ...A1
  sort: DIR
}

“sortItems”: [{
   “attributeSortItem”: {
     “attributeIdentifier”: <localIdentifier_of_A1>,
     “direction”: DIR
   }
}]


The following is an example of sorting defined a measure. The sortItems structure is more complex and contains locators.

visualizationvisualizationObject

{
  ...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:

visualizationvisualizationObject

{
  ...M1
  showPoP: true,
  sort: DIR
}

“sortItems”: [{
   “measureSortItem”: {
     “direction”: DIR,
     “locators”: [
       “measureLocatorItem”: {
         “measureIdentifier”: <localIdentifier_of_PopM1>
       }
     ]
   }
}]

styles

styles was transformed as follows:

visualizationvisualizationObject

{
  “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

visualizationvisualizationObject

"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/<measure_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/<measure_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

visualizationvisualizationObject

{
  "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/<measure_id>",
       
    "showInPercent":false,
       
    "showPoP":false,
       
    "title":"_Close [BOP]",
       
    "type":"metric"
     
    }
   
    },
   
    {
      
    "measure":{
        
   "measureFilters":[
        
    ],
       
    "objectUri":"/gdc/md/<project_id>/obj/<measure_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 measure sort",
   
  "uri":"/gdc/md/<project_id>/obj/<visualization_id>"
   
}
  }
}

{
  "visualizationObject":{
   
"content":{
 
   "buckets":[
  
   {
       
"items":[
         
{
        
   "measure":{
          
   "definition":{
            
   "measureDefinition":{
                 
"filters":[
              
   ],
              
   "item":{
                   
"uri":"/gdc/md/<project_id>/obj/<measure_id>"
              
   }
            
   }
          
   },
          
   "localIdentifier":"<unique_localIdentifier>",
          
   "title":"_Close [BOP]"
        
   }
      
   },
      
    {
       
    "measure":{
         
    "definition":{
           
    "measureDefinition":{
             
    "filters":[
             
    ],
             
    "item":{
               
    "uri":"/gdc/md/<project_id>/obj/<measure_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 measure 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/{project_id}/query/visualizations
/gdc/md/{project_id}/objects/query?category=visualization

Use instead:
/gdc/md/{project_id}/query/visualizationobjects
/gdc/md/{project_id}/objects/query?category=visualizationObject