When using Enigma.js to communicate with the Qlik Associative Engine to build visualizations for instance or simply to get access to data from Qlik Sense, you will certainly come across the concept of Generic Objects, which are structures for storing and interacting with data in an application. They are considered generic because of they are flexible structures that can represent many different app components such as sheets, bookmarks, hypercubes, lists etc..In this blog post, we will go over Hypercubes and List Objects providing a brief explanation of the concepts and how to use them with enigma.jsHypercubesIn Qlik Sense, a Hypercube is an interface for defining a set of data to extract. It is the definition provided to the Qlik Data Engine, which holds all information on which data is queried and how it’s calculated. If selections are applied to a Hypercube, only the selected values will be returned.For example, this can represent data needed to display some type of visualization such as a bar chart that shows “Sum of Sales” by “Salesperson”. At its simplest form, you can think of it as a table comprised of rows and columns. In that sense, our Hypercube that would power our barchart, would consist of a table with “Salesperson” as a column, and the evaluated “Sum(Sales)” expression as the other column. The engine will fill the cells of this table and extract all the information.In order to use a Hypercube, we need to define it through the “qHyperCubeDef” object which is passed on to the Qlik Engine API to create a query for processing the data.A very simple definition of a Hypercube looks like this:qHyperCubeDef: {
qDimensions: [],
qMeasures: [],
qInitialDataFetch: [{
qWidth: 2,
qHeight: 50
}]
} But since it is a very flexible tool of extracting data, that means that there is a huge amount of settings available for it. You can view the full definition of the structure here.Let’s go over the most important ones:qDimensions: defines the array of dimensions that will be used in the HyperCube. You can have multiple dimensions depending on the results you want.There is a number of settings within the dimension that you can set. More about these here.For instance, qNullSuppression: which removes null values in the dimensionqShowAll, which if set to true, displays all dimension values, regardless of whether they are selected or not.etc...qMeasures: similar to how qDimensions are defined, but used to define measures, i.e: calculations performed for each distinct value of dimensions.qInitialDataFetch: defines how many data cells are initially retrieved from the calculated HyperCube.qSuppressZero: if set to true, removes rows that have zero values across the entrie HyperCube rowqMode: defines the structure of the HyperCube that will be returned. By default, the data is returned as a straight table representation. But more advanced modes are available, such as:Pivot table representation (qMode -> P)Stacked table representation (qMode -> K)Tree representation (qMode -> T)Below is an example of a Hypercube where we define 1 dimension (ID) and 1 measure (=Sum(Value)), Notice that we define qWidth and qHeight properties within qInitialDataFetch as 2 and 5 respectively, since we have 2 columns and would like to get 5 rows of data for a total of 10 cells.P.S: The maximum number of cells (qWidth*qHeight) allowed in an initial data fetch is 10,000.const properties = {
qInfo: {
qType: 'my-straight-hypercube',
},
qHyperCubeDef: {
qDimensions: [
{
qDef: { qFieldDefs: ['ID'] },
},
],
qMeasures: [
{
qDef: { qDef: '=Sum(Value)' },
},
],
qInitialDataFetch: [
{
qHeight: 5,
qWidth: 2,
},
],
},
};So how does the implementation look like in enigma.js?For the purposes of this example, we are creating a Session App (i.e: have an inline script and create an app on the fly).const qlikScript = `
TempTable:
Load
RecNo() as ID,
Rand() as Value
AutoGenerate 100
`;
const properties = {
qInfo: {
qType: 'my-straight-hypercube',
},
qHyperCubeDef: {
qDimensions: [
{
qDef: { qFieldDefs: ['ID'] },
},
],
qMeasures: [
{
qDef: { qDef: '=Sum(Value)' },
},
],
qInitialDataFetch: [
{
qHeight: 5,
qWidth: 2,
},
],
},
};
const session = createSession();
// Open the session and create a session document:
session.open()
.then((global) => global.getActiveDoc())
.then((doc) => doc.setScript(qlikScript)
.then(() => doc.doReload())
// Create a generic object with a hypercube definition containing one dimension and one measure
.then(() => doc.createObject(properties))
// Get hypercube layout
.then((object) => object.getLayout()
.then((layout) => console.log('Hypercube data pages:', JSON.stringify(layout.qHyperCube.qDataPages, null, ' ')))
// Select cells at position 0, 2 and 4 in the dimension.
.then(() => object.selectHyperCubeCells('/qHyperCubeDef', [0, 2, 4], [0], false))
// Get layout and view the selected values
.then(() => console.log('\n### After selection (notice the `qState` values):\n'))
.then(() => object.getLayout().then((layout) => console.log('Hypercube data pages after selection:', JSON.stringify(layout.qHyperCube.qDataPages, null, ' '))))))
// Close the session
.then(() => session.close())
.catch((error) => {
console.log('Session: Failed to open socket:', error);
process.exit(1);
});Notice that after opening the enigma session, and calling the necessary methods for our session app, we call “createObject” to create a Generic Object with our Hypercube definition containing 1 dimension and 1 measure, then get the Hypercube Layout which returns a bunch of results including our data.We’re mostly interested in “qDataPages” which holds our calculated data. Below is how the typical response looks like:Going back to our code, the full qDataPages results are as follows from our first console.log:Hypercube data pages: [
{
"qMatrix": [
[
{
"qText": "1",
"qNum": 1,
"qElemNumber": 0,
"qState": "O"
},
{
"qText": "0.73213545326144",
"qNum": 0.732135453261435,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "2",
"qNum": 2,
"qElemNumber": 1,
"qState": "O"
},
{
"qText": "0.66564685385674",
"qNum": 0.6656468538567424,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "3",
"qNum": 3,
"qElemNumber": 2,
"qState": "O"
},
{
"qText": "0.66189019801095",
"qNum": 0.6618901980109513,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "4",
"qNum": 4,
"qElemNumber": 3,
"qState": "O"
},
{
"qText": "0.98009621817619",
"qNum": 0.9800962181761861,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "5",
"qNum": 5,
"qElemNumber": 4,
"qState": "O"
},
{
"qText": "0.48425585823134",
"qNum": 0.4842558582313359,
"qElemNumber": 0,
"qState": "L"
}
]
],
"qTails": [
{
"qUp": 0,
"qDown": 0
}
],
"qArea": {
"qLeft": 0,
"qTop": 0,
"qWidth": 2,
"qHeight": 5
}
}
]Notice that we have additionally called the “selectHyperCubeCells” method in order to make a selection on the cells at positions 0, 2, and 4 in the Dimension. Here is how the results of qDataPages looks like after the selection:### After selection (notice the `qState` values):
Hypercube data pages after selection: [
{
"qMatrix": [
[
{
"qText": "1",
"qNum": 1,
"qElemNumber": 0,
"qState": "S"
},
{
"qText": "0.73213545326144",
"qNum": 0.732135453261435,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "3",
"qNum": 3,
"qElemNumber": 2,
"qState": "S"
},
{
"qText": "0.66189019801095",
"qNum": 0.6618901980109513,
"qElemNumber": 0,
"qState": "L"
}
],
[
{
"qText": "5",
"qNum": 5,
"qElemNumber": 4,
"qState": "S"
},
{
"qText": "0.48425585823134",
"qNum": 0.4842558582313359,
"qElemNumber": 0,
"qState": "L"
}
]
],
"qTails": [
{
"qUp": 0,
"qDown": 0
}
],
"qArea": {
"qLeft": 0,
"qTop": 0,
"qWidth": 2,
"qHeight": 3
}
}
]List ObjectsAlongsideqHyperCube, the family of Generic Objects provides us with another structure called qListObject.Unlike a Hypercube, a List Object better serves the purposes of displaying one single dimensionwithoutany required calculation, meaning no metrics are required to be defined.As such, it is fairly straightforward to work the list objects, and their definition is very similar to theqHyperCubeobject, with some added extra properties minus measures.I usually use List Objects when I want to build a list of values to be used for selections.The following code is an example of creating aqListObjectDefand writing the resulting list object into the console:List object data: [
[
{
"qText": "0.063513102941215",
"qNum": 0.06351310294121504,
"qElemNumber": 0,
"qState": "O"
}
],
[
{
"qText": "0.15987460175529",
"qNum": 0.15987460175529122,
"qElemNumber": 1,
"qState": "O"
}
],
[
{
"qText": "0.50091209867969",
"qNum": 0.5009120986796916,
"qElemNumber": 2,
"qState": "O"
}
]
]After selection of the first value, the qDataPages response looks like the following:(Notice that with a qListObject, all values are rendered, regardless of whether they have been excluded or not.If selections are applied to a list object, the selected values are displayed along with the excluded and the optional values. We do however hava access to the qState property which lets us know if the value is selected (S), alternate (A), etc..)List object data: [
[
{
"qText": "0.063513102941215",
"qNum": 0.06351310294121504,
"qElemNumber": 0,
"qState": "S"
}
],
[
{
"qText": "0.15987460175529",
"qNum": 0.15987460175529122,
"qElemNumber": 1,
"qState": "A"
}
],
[
{
"qText": "0.50091209867969",
"qNum": 0.5009120986796916,
"qElemNumber": 2,
"qState": "A"
}
]
]Attached is a zip file containing example code that shows how a default Hypercube, Pivot Hypercube, Stacked Hypercube, and a List Object are used in enigma.js.To run the code:first run “npm install”change the .env file with your tenant and API key (learn how to get an API key here).then, run “node filename.js” for each file and check the console logs.To see how Hypercube can be used as part of creating visualizations with Nebula.js, checkout my previous blog post: https://community.qlik.com/t5/Qlik-Design-Blog/Create-a-Slope-chart-with-tooltips-and-brushing-using-Nebula-js/ba-p/1827168
...View More
Soon we will introduce a new machine learning and predictive analytics capability to Qlik Cloud, Qlik AutoML. If you are interested in learning more, take a look at this quick video before getting started.
Based on extensive user feedback, there will be an update to the default sheet behavior on private sheets to enable a new and improved visualization creation experience. All tenants will receive this change August 9th. If you don't want to wait, a Qlik Cloud Tenant Administrator can enable this change for all users on your tenant now using a switch in the tenant setting feature configuration of the Management Console. Note that the changes will take effect immediately and cannot be reverted. However, users can toggle to the old create experience if they want to.You can learn more by watching the video below and read about the change here.
Want to learn what it's like using the Qlik Cloud Platform as a "user"? Check out this webinar recording to learn more and experience the art of the possible using the Qlik Cloud Platform.
A few months ago, I blogged about KPI color and Map label enhancements that are available in Qlik Sense SaaS. Today, I will add to the list of visualization enhancements and discuss the bar chart. The bar chart now has additional styling options that allow the developer to style the title, subtitle, and footnote as well as the bars. Below is a horizontal bar chart with the default styling and bars that are colored based on the sales value.In the bar chart properties window under Presentation, the Styling section can be expanded to view the properties that can be changed.On the General tab, the font family and font size of the title, subtitle, and footnote can be changed. Developers can also make the text bold, italic or underlined. There is a “reset all” option to undo all changes made and return to the defaults or individual text (title, subtitle or footnote) can be reset. This is nice if you would like to play with various settings to see how it will look and opt to return to the default.On the Chart tab, there are styling options for the bars. Developers can add an outline – small, medium, or large – and they can adjust the width of the bars. Like the General tab, there are reset options on this tab as well.Below is the same bar chart with styling changes. The font family was changed to Tahoma for the title, subtitle and footnote and the color of the title was changed to a reddish color. On the Charts tab, the width of the bars was increased, and a small outline was added to the bars. When making these styling changes, keep in mind that the data is the most important part of the visualization, and you want that to stand out and not be overshadowed by distracting color titles, subtitles, or footnotes.The new bar chart styling options gives developers more ways to customize their visualizations. Check out the styling properties the next time you are building an app. You can also learn more about the bar chart properties in Qlik Help.Thanks,Jennell
...View More
I’m always on the lookout for a tool that would make my life easier as a developer. Qlik-cli is a great asset to have in your toolbox when working with Qlik Sense SaaS. As its name suggests, it is a command line interface that lets you tap into Qlik’s published APIs and take advantage of the full power and possibilities of Qlik Cloud.Being able to perform any administrative task from the command line can be very attractive for developers or system administrators who, for one, are used to dealing with cloud platforms via a cli, but also just want to access certain tools quickly without going through the management console graphical interface especially when trying to execute tasks in bulk or automate certain workflows.So whether you are looking to run tasks or reloads, check on those reloads, move apps between environments, manage user access, or make updates at a large scale, qlik-cli is the right tool for that.You can check out this recent blog post for a great introduction to the qlik-cli to learn about what it is and walk through the installation process to get up and running quickly: https://community.qlik.com/t5/Qlik-Design-Blog/Using-Qlik-cli-to-automate-workflows/ba-p/1943319How does it works:Once you’ve installed qlik-cli on your machine, you will need to grab your API Key from the Qlik Cloud tenant and create and configure a context from the command line to authenticate to Qlik Sense SaaS.You can always view contexts if you happen to have multiple tenants or users via the "qlik context ls" command, and switch between them using "qlik context use <context-name>"With qlik-cli’s built-in documentation, it’s very intuitive to see see which commands and flags you can use by adding --help to any command.For instance qlik app --help will return the following:What are some of the things you can use qlik-cli for:A quick and easy example to show how easy it is to perform certain tasks with qlik-cli is to create an app, add a script and reload it:qlik app create --attributes-name cli-testapp -q
qlik app script set <path-to-script> --app <appid>
qlik reload create --appId <appid>That’s it! Running just 3 lines is all it takes to have an app ready for use.But what if we wanted to create 10 apps instead of one?Easy, all we got to do is wrap that same command we used above (qlik app create —attributes-name <name>) in a shell script “for” loop.$appIds = @()
function appExists {
param([String] $appName)
$result = qlik item ls --resourceType app --name $appName | ConvertFrom-Json
return $result[0].resourceId
}
For ($i=0; i -lt 10; $i++) {
$name = "qlik-cli-app-$i"
$app = appExists -appName $name
if(!$app) {
$app = qlik app create --attributes-name $name -q | Out-String
}
$appIds += $app
}
return $appIdsYou can view a more detailed tutorial on qlik.dev:https://qlik.dev/tutorials/creating-and-deleting-apps-in-bulk-with-qlik-cliA good idea then is to maybe create a space and move all these apps to it with a few commands such as: “qlik space create” and “qlik app space update”You can also do some basic task chaining by using a function that runs against a JSON object containing task name, app id and status. This process can be especially helpful when wanting to execute a reload upon the completion status of a preceding reload.Here is a tutorial that walks you through doing just that:https://qlik.dev/tutorials/task-chaining-with-qlik-cliAnother great application of the qlik-cli for folks who are moving away from Qlik Sense Enterprise Client-Managed to Qlik Cloud, is to use it for migration. By leveraging basic PowerShell scripts and qlik-cli commands, you can facilitate and speed up a process that would otherwise be tedious. You can find more information about the whole process here. Take a look at the PowerShell scripts (download and extract the “Qlik Cloud migration tools” zip file) to see qlik-cli commands in action for inspiration.I hope this post helped you get a sense of how powerful yet simple qlik-cli can be when it’s used alongside shell scripting to access and unlock the full potential of Qlik Cloud APIs.
...View More