Category Archives: Visualization

Quick Sense App in a Page

Summary: Learn an easy method to deliver a Qlik Sense app as an embedded web page. Yes, the spelling of this post’s title is intentional¬†ūüėČ

I just came off a week of Qlik Sense API & Integration training with Nick Webster of Websy. ¬†I’ve been nothing short of impressed with the integration and reuse options of Qlik Sense.

I was intrigued today by a question on Qlik Community asking if there was a way to disallow the application Edit mode in Qlik Sense Desktop. ¬†The poster wanted his students to just “use” an app and not poke around in the design until a later time. ¬†Kind of like the “distraction free” mode ¬†in text editors.

The challenge I gave myself was how quickly¬†could I knock out a solution to this problem? ¬†I’ll detail my solution below and I’ll tell you it is taking me longer to write this blog post than it took to build¬†the solution.

Rather than working at disabling or removing function I didn’t want, I approached the problem as including only what I wanted. My first thought was to create a mashup that represented the entire application. ¬†Then I struck on an even easier approach — use the Qlik Sense “Single Integration API” with a bit of Bootstrap. ¬† The Single Integration API does not require writing any code. ¬†It’s just a URL that displays a single Visualization or complete Sheet. ¬†You can create URLs and experiment with options in the Dev Hub Single Configuration Tool.

Bootstrap is a popular web design toolkit that makes it easier to create responsive and interactive web pages. ¬†Thanks to Nick’s class I understood how Qlik utilizes¬†bootstrap.

A basic URL to display a sheet looks like this:


Appid is a qvf filename on QS Desktop, or the GUID if using QS Server.  Options allow you to control  things like allowing selections.  A complete list is in the API doc.

With 50 lines of html I created a web page that delivers the full associative experience across seven sheets, including Current selections, Smart search and the Selections tool.

Here’s a screenshot showing my sheet navigation buttons across the top and the Sheet content, including Current selections, immediately below the buttons.

The html file is available for download here. ¬†I used the “Sales Discovery” sample app but it is¬†easy to adapt the file to any application.

There is a single iframe nested in a responsive Bootstrap container.  The buttons simply change the src attibute of the iframe to load a specific sheet .

If you want to try the file yourself you ¬†only need to change the “var appid=” string to point to the app path on your machine. ¬†No web server is required, just double click the html file to launch. ¬†Your server or QS Desktop must be active. ¬†Yes, this file works as is with QS Server.

Nick and I will be showcasing a variety of QS integrations at the Masters Summit for Qlik in Boston Oct 23-25. ¬† Nick will also be presenting¬† a half day “Qlik Sense Integration” session at the summit that will teach you how to create a basic web page with bootstrap and explore more advanced¬†QS integration options.




QV12 Variables with Alt State Fixed

Summary:  QV11 contained an inconsistency in how variables with equal signs were evaluated when using Alternate States.  This has been fixed in QV12.10.  Read on if you want the details. 

QlikView V12.10 includes an important fix to variable evaluation when using alternate states. A quote from the Release Notes:

In QV11.20 the variable was expanded in the first state encountered and this resulted in a random behavior when more than one alternate state was being used. Whereas in version 12 and up, the variable always belongs to a specific alternate state and this results in different behavior.

The random behavior described in QV11.20 has generated several interesting posts to QlikCommunity with responses¬†of “I can reproduce” / “I can’t reproduce” and¬†few clear answers.

I find the problem confusing and interesting enough to warrant an explanation and example beyond the Release Note.

What I am describing¬†in this post only affects variables with a leading “=” in the definition, e.g. “=Sum(Sales)”. ¬†These variables are calculated once in the context of the entire document. They are not calculated per row in a chart.

Let’s consider a variable named “vSumX” with a definition of “=Sum(X)”. ¬†The expression simply sums all selected values of X. ¬† Suppose we have two States in our document — “Default” and “State1”. ¬†There could be two different selections for “X”. ¬†Which set of X should the variable sum?

If we consider the variable definition in isolation, the answer is “Default set” ¬†as there is no set identifier in the expression. ¬†But what if the variable is referenced in an object in State1. ¬†Should the State1 values of X be used?

No matter what you think the rules should be, here’s what was happening in QV11.20. ¬†The variable was expanded (evaluated)¬†in the first state encountered. ¬†First state encountered means first state in the calculation chain, not something the developer directly controls.

Let’s look at some examples. ¬† I’ve created a sample app (you can download here) with three States — Default, ¬†State1 and State2. ¬†The variable “vSumX” is defined as “=Sum(X)”.

With all objects on sheet in the Default state, selections in X would yield results like this. ¬†(Note “$” indicates default state).

The first text box contains the expression “Sum(X)”. ¬†The second text object contains the reference to variable vSumX. ¬†The two values are what we might expect, summing the selected values of X in this state.

Let’s switch to a sheet that contains objects in the state named “State1”.

No selections in X and the first text object shows the expected result. ¬†The second object shows the value of vSumX as previously calculated from the default state. ¬†If we make selections on this State1 sheet, that will cause vSumX to be recalculated and both State1 and the Default sheet will reflect the State 1 number. ¬†Is that correct? ¬†Is it useful? ¬†It’s at least consistent and comprehensible.

My next example is where the aforementioned “random” comes into play. ¬†Let’s put objects from three states on the same sheet.

I’ve selected some values in the Default state of X and the results are what I might expect. ¬†The value of vSumX is calculated from my last selections and the variable value is consistent across objects — there is only ever one value for a variable at a given point in time.

Now I select some X values in State1 and expect to see a new value (19) for vSumX.  But no change! The variable was expanded (evaluated) in the first state encountered which happened to be Default ($).

Now I select some X values in State2.  If the vSumX calc used my last selection I would expect to see 7.  But no, I see 19.  The State1 values were used.  If I repeat the exercise, it may use a different state to calc vSumX.  If you test you may get different results.  In this last example, State1 was used because it was the first state encountered in the calculation chain.  The order is not consistent.  It will be influenced by factors such as number of available processors and the order in which the objects were created.

Now that we’ve established that QV11,20 is broken in this regard, how was it fixed in QV12.10? ¬†Simple. ¬†QV12 uses ¬†set identifiers as specified in the expression, without inheritance.


will use the Default State as there is no identifier.   If you want to Sum from a specific state, use it in the expression:

=Sum({State1} X)

Variables do not belong to any State. ¬†Aggregation functions used in a variable may specify a Statename, just as chart expression do. ¬†The difference is that the absence of a set identifier in a chart expression means “inherit the state from the containing object”. ¬†In a “=” variable, no set identifier means “use the default state”.

A reminder that end of standard support for QV11 comes on Dec 8, 2017. ¬†If you haven’t yet upgraded to QV12.10, I encourage you to do so. ¬†Download my¬†¬†QV12 Upgrade Considerations Doc as part of your planning process. ¬†Feel free to contact me if you want some assistance with your upgrade.


Update:  Qlik has extended support for QV11.20 to March 31, 2018. 


Web Dev for Qlik Devs Course in San Francisco

In January I attended¬†(review) Nick Webster’s ¬†“Web Development for Qlik Developers” course. ¬†I found the course extremely valuable so I’m bringing Nick ¬†to San Francisco September 19-22 for a four day fast track course.

Are you a Qlik Sense Developer that wants to understand how to use the various QS APIs to create your own mashups,  portal integrations or custom content pages that leverage data from Qlik Sense?  Do you want to create your own QS Visualization Extensions or modify existing extensions?

In this four day hands on course you’ll learn:

  • The fundamentals of HTML/Javascript/CSS as they apply to QS Development and how to get¬†started with some ¬†popular frameworks and libraries.
  • Creating Visualization Extensions.
  • The differences and application of the various QS APIs e.g. Capability, Visualization, Engine.
  • Important QS core concepts such as the generic object model.
  • Connecting to the QIX engine to retrieve existing content or generate associative aggregations (hypercubes) on the fly.
  • Visualizing data using third party libraries.

You’ll come away with example code and your own completed exercises giving you the confidence to move ahead on your own.

No prior experience with web programming is required as the course will provide an intro to those technologies and how they are used in Qlik Sense Web Development.

Course fee, location and registration here. ¬† Don’t wait, as the class is limited to 10 students!




Vizlib: Innovation and Agility

Summary:  As a provider of Qlik Sense visualization extensions Vizlib promises to blend the innovation and agility of open source with the reliability of commercial software.. 

The pace of delivery for visualization in Qlik Sense has been disappointing to some.  Thanks to rich open APIs in QS, much of the slack has been taken up by the community in the form of open source visualizations as seen on   There you can see some remarkable innovation and responsiveness to community requests.

Should you use open source visualizations?  An open source extension may provide just what you need in your project.  But you should consider the unsupported nature of open source and evaluate the risk and consequences of the visualization possibly failing at some point.

When I worked as  a Java developer  my team used the open source Eclipse IDE as our main tool.  We also used a dozen or more open source plugins.  As our plugin library grew, we found that testing and updating plugins between releases was taking an inordinate amount of time, sometimes making us afraid to upgrade the base Eclipse product.   We  turned to a vendor and purchased a bundled version of Eclipse with dozens of plugins tested, supported and verified. Problem solved.

Vizlib is a new company is promising to blend the innovation and agility of open source with the commercial support that many customers demand.  Vizlib is partnering with the best extension authors to produce a library of fully supported high function visualization extensions. Check out some of what they have published so far:

  • A Table object that delivers the functionality of ¬†a QlikView table and much more.
    • Rich Formatting Options just like in Excel/QlikView
    • Conditional show & hide of columns
    • Dynamic Labels
    • Minicharts & Progress Bars

  • An Advanced Text Object that provides the full functionality of the classic QlikView text object ¬†(including actions!) plus additional¬†functionalities like HTML code and icons.¬†

To date Vizlib has released five visualizations with more on the way. Check out what’s available on the Vizlib download page. ¬†A free trial license is offered that allows you to try any of the extensions in your own installation. ¬†Take a look!



Alt States Merged Selections Tip

Summary: I suggest a simpler syntax for merging selections from multiple states. 

You may be¬†familiar with the “Product Grouping” example from the “What’s new in QlikView 11.qvw” sample. ¬†It’s a great ¬†beginner demo of using¬†Alternate States¬†for comparative analysis.

In this visualization, a user can select two sets of values from the [Product Sub Group] field. The two different sets are represented by two states, [Group 1] and [Group 2].  The blue [Group 1] bar is plotted on the bar chart using this expression:

sum({[Group 1]<Region = $::Region, [Sales Rep] = $::[Sales Rep], Path = $::Path, Year = $::Year, Quarter = $::Quarter, Month = $::Month>} Sales)

[Group 1] ¬†as the Set Identifier indicates we want to start with the selections in [Group 1]. We then modify, or add, selections from the default state by referencing each field with the “$::fieldname” syntax.

The green [Group 2] bar is created with a similar expression, the only difference being [Group 2] as the Set Identifier.

The “$::fieldname” syntax works, but it forces us to list every field. Listing every field can get difficult. Is there an easier, more generic method? ¬†Yes, if we redefine the problem as: ¬†All selections from the Default state except for [Product Sub Group].

sum({[Group 1] * $<[Product Sub Group]=>} Sales)

Breaking the Set Expression down:

[Group 1]    // Group 1 selections
*    // Intersected with
$<[Product Sub Group]=>   // All selections from Default except [Product Sub Group]

I’m not suggesting ¬†the sample is wrong. The “$::” syntax is useful to know and is required when you want to reference only specific fields. ¬†I’m posting this alternative because I see people¬†copying this more complex $:: ¬†syntax when the simpler syntax would suit their application.


Join me at an upcoming Masters Summit for Qlik event in Johannesburg (6-8 Sept) or Austin (10-12 Oct). ¬†Oleg Troyansky’s¬†Set Analysis and Advanced Aggregation session provides ¬†more useful tips and advanced techniques in using Alternate States.




QV12 Timestamp Parsing

Have you noticed something new in QlikView12 and Qlik Sense timestamp parsing? UTC timestamps are automatically understood.

(Note: the output displayed below utilizes¬†the US Date format set in the script as: ¬†SET TimestampFormat=’M/D/YYYY h:mm:ss[.fff] TT’;)

For example, the expression:



5/4/2016 7:25:23 PM

That is, the UTC offset of “-0500” is detected and the returned value is the UTC time, not the local time of 2:25:23 PM.

I can’t find anything in the help beyond an example ¬†for Timestamp# that demonstrates¬†this but provides no¬†detail.

This parsing functionality is particularly useful now that the QlikView Server logfiles use the UTC format for times.

I’m not sure yet if I like the automatic conversion to UTC time. ¬†For example, apps like the QlikView Governance Dashboard now report Session Start or Event times in UTC time, not local time.

It’s nice that the “T” character is understood. If you want local time, it’s easy enough to drop the offset (“-0500”) as

=Timestamp(left('20160504T142523.487-0500', 19))

which returns

5/4/2016 2:25:23 PM




Scaling Numbers and DSE Tips

Summary: I demonstrate a simple reusable expression to auto scale numbers in QlikView. This leads to an exploration of some of the finer details of dollar sign expansion.

A QVW example to accompany this post is available for download at

The QlikView auto-scaling feature selects¬†an appropriate unit – billion, million, thousands — based on the magnitude of the ¬†Y-axis values. ¬†It’s a nice feature ¬†available in Line and Bar charts. ¬†How can we create¬†the same functionality in¬†Text Objects or Straight Tables?

It’s easy enough to use an if() function that tests the magnitude, does any necessary division, and formats appropriately. For example:

if(Sum(Sales)>1E6, num(Sum(Sales)/1E6,'$#,##0.000M')
 ,if(Sum(Sales)>1E3, num(Sum(Sales)/1E3,'$#,##0.000K')

(The 1E6 is an easier way to write 1000000).

To avoid repeated coding of “Sum(Sales)” I create a reusable variable with parameters in the script like this:

SET vScaleNumber=if($1>1E6, num($1/1E6,'$#,##0.000M')
 ,if($1>1E3, num($1/1E3,'$#,##0.000K')

Now I can use the variable vScaleNumber in a Text Object as:


The string “Sum(Sales)” will get substituted in ¬†every occurrence of “$1”. ¬†I ‘ll get an appropriately formatted number like:

If I use¬†“$(vScaleNumber(Sum(Sales)))” in a Straight Table expression without label, hovering over the column heading will show me the full substitution in ¬†a tooltip.

I ¬†can see that the “$1” substitution occurs before the expression is evaluated, and the substituted expression looks like:

if(Sum(Sales)>1E6, num(Sum(Sales)/1E6,'$#,##0.000M')
 ,if(Sum(Sales)>1E3, num(Sum(Sales)/1E3,'$#,##0.000K')

I’ve avoided re-typing “Sum(Sales)”.¬†But I may have a concern about the performance implications of repeated execution of “Sum(Sales)”. ¬†And what about more complex expressions such as “Round(Sum(Sales),10)”? ¬†The comma in that expression will break the syntax as variable parameters always treat commas as parameter separators.

I can fix the comma/performance problem by using Dollar Sign Expansion (DSE) with an “=”. ¬†The “=” will cause the expression to evaluate and pass the numerical result to vScaleNumber.


Checking the expansion in a Straight Table shows:

if(1783150>1E6, num(1783150/1E6,'$#,##0.000M')
,if(1783150>1E3, num(1783150/1E3,'$#,##0.000K')

I ¬†see the value of “round(Sum(Sales),10)” has been calculated as “1783150”, ¬†yielding an efficient and syntactically correct expression.

Next¬†¬†I’ll add a Dimension to the Straight Table. ¬†The row results are incorrect!

The “=” in the DSE caused the¬†Sum¬†expression ¬†to be evaluated¬†only once for the entire chart, yielding the same value for every row. ¬†How to fix?

I will calculate the sum() expression in a n Expression n column, and then hide this column on the Presentation tab. I can then refer to the hidden column:


Once again, the expansion yields an efficient and syntactically correct expression.

if(Column(1)>1E6, num(Column(1)/1E6,'$#,##0.000M')
 ,if(Column(1)>1E3, num(Column(1)/1E3,'$#,##0.000K')

I started this post by demonstrating a simple expression to format scaled numbers. It’s a function I frequently use.

For more on DSE, see Henric’s post at¬†

A QVW example to accompany this post is available for download at



Yoke Dashboard

I was chatting with a colleague recently about trends in BI and I brought up what I call the “commoditization of metrics” . ¬†Google Analytics is¬†an early example of this — your data crunched¬†and delivered at the KPI level.

I recently ran across a great example of the commodity metrics idea:

Yoke let’s you build your own dashboard using metrics gleaned from cloud services such as¬†Gmail, Twitter and Github. Here’s a portion of my¬†Yoke dashboard. It’s all built with a few clicks and no coding.

Yoke Image

Give a try, it’s free!


Join me at the upcoming “Masters Summit for Qlik” in Milan on 5-7 April. In addition to learning about all things Qlik, we’ll be talking about trends in Dashboarding and BI.¬†


Scoping Selections with Aggr()

Summary: Selections can be made in Calculated Dimensions, although the result may not always be what is expected or desired.   The Aggr() function can be used to control what field(s) get selected.

The technique discussed in this post applies to both QlikView and Qlik Sense.  The screenshots shown are from QlikView.  Some of the visuals are a bit different in Qlik Sense, but the idea and expressions demonstrated are the same.

A downloadable example to accompany this post is available here.

Consider a listbox created with an <Expression> value of:

=Customer & ' -- ' & Country

A listbox constructed this way is useful for providing additional context or an  additional search.

Selections made in that listbox will make underlying selections in both Customer and Country.

The user is probably  expecting a selection in Customer only.  To limit the selection to Customer, add an Aggr() function to the expression:

 Customer & ' -- ' & Country

Only the Customer field is listed in the Aggr() dimension, so selections will be made only in Customer.

A side effect of adding Aggr() is that gray (unassociated) rows no longer display.  We can fix that with a bit of Set Analysis.

 only({1<Customer={"*"}>} Customer & ' -- ' & Country)

Now the listbox looks and behaves as expected.


Another place you may need Aggr() to control selection intent is chart Calculated Dimensions.

Hovering over a Salesrep value in the chart below gives a contextual popup that identifies Manager and Hire Date associated with the Rep.

The column was created as a Calculated Dimension:

& chr(10) & 'Reports to ' & [Sales Manager]
& chr(10) & 'Hire Date ' & date(HireDate,'YYYY-MMM-DD')

Clicking Michelle in the chart correctly selects her name as SalesPerson, but makes unexpected selections in HireDate and SalesManager.

I’m going to say¬†that the dimension is “improperly scoped” and correct it by adding Aggr() to the Calculated Dimension.

 & chr(10) & 'Reports to ' & [Sales Manager]
 & chr(10) & 'Hire Date ' & date(HireDate,'YYYY-MMM-DD')

Selections will now be correctly limited to the “SalesPerson” field.


We’ve seen that Aggr() can¬†narrow selections. We can widen selections as well. ¬†This listbox will make selections in Customer, Country, SalesPerson and Year, even though only Customer is displayed in the listbox.

 ,Customer, Country, SalesPerson, Year)


We don’t have¬†to include the display field in the selections. ¬†In¬†what I’ll call a¬†¬†“backdoor associative search” , this expression will display Customer, but selects¬†only¬†the OrderID values associated with the Customer.

only({1}Customer )

It’s usually a best practice to pre-create Calculated Dimensions in the script, when possible, for performance reasons. Returning to our first example, we might create a new field in the script as:

Customer & ' -- ' & Country AS CustomerAndCountry

We can use the new field as a display value, but we want selections to be made in Customer.

 only({1}  CustomerAndCountry)


As a last example, ¬†we can create ¬†“bookmark” like alternatives;¬†either new fields linked in the data model or advanced search at run time.

Here I’ve linked a hidden field named “Bookmark” into specific OrderIDs in the script. ¬†I want selections to be reflected in the OrderID field.

=aggr(only({1}Bookmark), Bookmark,OrderID)

Here is an advanced search that presents a listbox of Customers who have placed at least one order with a value >50K.

only({1<OrderID={"=sum({1}OrderAmount)>50000"}>}Customer )

Aggr() can be a “heavy resource consumer” and has the potential to slow down your application. Use only when required and avoid using or benchmark the impact in large applications. ¬†Calculated Dimensions can also be a source of slow performance, precalculate fields in the script when possible.

Download the  example qvw for this post .





A Better Show Frequency

I like using¬†“Show Frequency” in a Listbox, but the feature¬†suffers two drawbacks.

  1. If the Field is in a Dimension table, the frequency — usually 1 — is not particularly¬†useful to the user.
  2. Excluded (gray) rows show a blank frequency value.

As an alternative to “Show Frequency”, we can use the Expression pane of the Listbox to provide a more meaningful number, such as count of orders.

 count(DISTINCT OrderID)

Listbox Expressions don’t provide for a heading. ¬† We can fake one by adding it the Listbox Title with enough spaces to align the heading.

The excluded values show zero. We can fix that by adding a Set to the expression. The Set should honor selections in other fields such as Product or Year, so we only need to ignore the selection in this field.

 count({<Customer=>} DISTINCT OrderID)

Optionally, we can use the same expression as a Sort Expression if we want to sort by Order count.

There you have it.   A more useful Frequency for the QlikView Listbox.

The Qlik Sense Filter Pane does not provide an Expression property, but you can achieve a similar result in Qlik Sense by creating the Field as an expression,

    & repeat(chr(160),8)
    count({<Customer=>}DISTINCT OrderID)



The “repeat(chr(160),8)” is a trick to insert 8 “non-breaking” spaces. A string of multiple regular ‘ ¬†‘ spaces will¬†display¬†as only a single space¬†when displayed in the browser.

You may want to place the numbers on the left side to make the numbers clearer.

And yes, you could dynamically calculate the number of spaces required to get multiple digits right-aligned.

Using ¬†aggr() to create a Filter Box is a much “heavier calculation” than just using the Field. If you have a large application, test this technique for performance before deciding to use it there.