In this 2nd part, I introduce code on how to project 3D lines using the Line Layer of the Map Object.

3D Generated Earth

Continuing on the journey from my previous article about visualising a flattened globe back into 3D, in this article, I will explain how to add more 3d layers on the map object, such as line and area layers. In my previous article, I was only using the point layer of the map object and I was also calculating everything in the script.

In this article, you will see that the calculations can also be done as expressions in the objects and the great advantages it gives.

To get get started, we first need to break the two formulas from my previous article into smaller parts:

Set ReCalcLat = 'EYE_X + SCREEN_DEPTH*tan(atan((($(EARTH_RADIUS) * cos($1*Pi()/180)*cos($2*Pi()/180))-EYE_X) / (($(EARTH_RADIUS) * sin($1*Pi()/180))+SCREEN_DEPTH)))';

Set ReCalcLong= 'EYE_Y + SCREEN_DEPTH*tan(atan((($(EARTH_RADIUS) * cos($1*Pi()/180)*sin($2*Pi()/180))-EYE_Y) / (($(EARTH_RADIUS) * sin($1*Pi()/180))+SCREEN_DEPTH)))';

These functions are doing two things:

  1. Converting Long/Lat data to X, Y & Z coordinates.
  2. Projecting X,Y & Z coordinates on a 2 dimensional Cartesian system X & Y (where Qlik Map object still will call this long/lat).

I will now split these up into two steps.

To convert long / lat directly to x, y and z coordinates, we declare the following 3 functions:

Set x_latlong = '($3) * cos(($1)*Pi()/180)*cos(($2)*Pi()/180)';
Set y_latlong = '($3) * cos(($1)*Pi()/180)*sin(($2)*Pi()/180)';	

Where $1  = Latitude and $2 = Longitude and $3 = EARTH_RADIUS = 6378.137 (in km)
And this

Set z_latlong = '($2) * sin(($1)*Pi()/180)';

Where $1  = Latitude and $2 = EARTH_RADIUS = 6378.137 (in km)

Using this formula we can convert any longitude/latitude coordinate into x, y and z coordinates.

As an example; the long/lat of Stockholm, Sweden is:

Latitude Longitude
59.3294 18.0686

Using the functions above, we can convert that into the following x, y and z coordinates:

x y z
3093.054633 1009.090237 5485.925767

Calculation for this in Qlik Sense will look like below:

Let x = $(x_latlong(59.3294,18.0686,6378.137));
Let y = $(y_latlong(59.3294,18.0686,6378.137));
Let z = $(z_latlong(59.3294,6378.137));

Alright, so we now have a function to convert long/lat to x, y, z.

For the last part, to project x, y, z coordinates back to 2D, we define these two functions:

Set xz2x = '$(EYE_Y) + $(SCREEN_DEPTH) * tan(atan((($1) - $(EYE_Y)) / (($2) + $(SCREEN_DEPTH))))';

where $1=x and $2=z

and

Set yz2y = '$(EYE_X) + $(SCREEN_DEPTH) * tan(atan((($1) - $(EYE_X)) / (($2) + $(SCREEN_DEPTH))))';

where $1=y and $2=z

For both of these functions, we have constants for where we are and how “deep” our field of vision is when we are looking at this 3D Object. I won’t go too much in details on this now, but the values of SCREEN_DEPTH need to be in the same kind of range as your 3D object data points, and EYE_X, EYE_Y can be remained as zero for now. So if we are looking at the Earth I will use the following values:

Let SCREEN_DEPTH = EARTH_RADIUS*2;
Let EYE_X = 0; 
Let EYE_Y = 0;

You will see later that these 3 constants are something you can use with success to visualise your objects just the way you want.

If we use the functions on the previous coordinates for the location of Stockholm we get this:

newLat newLong
705.6293491 2162.888955

Calculating this in Qlik Sense code:

Let newLat = $(yz2y(1009.090237,5485.925767));
Let newLong = $(xz2x(3093.054633,5485.925767));

Heads up – the values we get for our newLat and newLong should not be the same as the original lat/long values we started with, because they are not the traditional latitudes and longitudes anymore. They are now rather just X and Y coordinates projected on your screen.

Also, it may not be certain that you want the function yz2y to be your “latitude” and the xz2x to be your longitude. If you switch them around it is like rotating your monitor 90 degrees, which sometimes is exactly what you want. It all depends on your data and how that was generated.

The beauty of using functions like this is that you can also use them as expressions in your application. This means that you can use the last two functions directly in the layers of the map object.


Let’s build a quick example.

I am using the same data from my previous post, with cities around the world with longitude and latitude (See link to data source at the end of this article.).

I load this data into my application using the following load script:

Cities: 
LOAD   
    RecNo() as UniqueId,
    capital,
    country,
    city,
    population,
    lat,
    lng,

    $(x_latlong(lat,lng,$(EARTH_RADIUS))) 	as x,
    $(y_latlong(lat,lng,$(EARTH_RADIUS))) 	as y,
    $(z_latlong(lat,$(EARTH_RADIUS))) 		as z,
    
    $(x_latlong(lat,lng,$(EARTH_RADIUS)+population/1000)) 	as x2,
    $(y_latlong(lat,lng,$(EARTH_RADIUS)+population/1000)) 	as y2,
    $(z_latlong(lat,$(EARTH_RADIUS)+population/1000)) 		as z2
FROM [lib://Data/worldcities.csv] 
(txt, utf8, embedded labels, delimiter is ',', msq)

where population>0;

Adding the field UniqueId to make sure every city for every country has a unique ID.

As you see here, we are calculating x,y and z based on the EARTH_RADIUS, and then we calculate x2,y2 and z2 based on EARTH_RADIUS + population/1000. This is because we want to draw a line from the surface of the earth and “out”, so what we are doing here for x2, y2 and z2 is to pretend that the earth radius is larger, but we use the same calculation principle (same function) as for x,y and z.

 

Then we add a new map object, just like in the first article. Most important changes to note are:

  • Removing the background map so that you only have a blank background
  • Changing “Projection” to “user defined (meters)”

Then you add a Point Layer to your map, where you choose UniqueId as Dimension.

For the location of the “Point“, you have two options: Latitude/Longitude fields or Location Field.

In my experience, these are exactly the same except that the Location Field requires you to input one field, while Latitude/Longitude wants you to place two fields.

In this example, I am using the “location field”, because later on, when we are using the area layer we don’t have the choice to use Latitude/Longitude fields anymore, so we can just as well start to learn about how the location field is constructed and we will carry on using those from now on.

In the location field you enter the following expression:

'[' & text($(yz2y(y,z))) & ',' & text($(xz2x(x,z))) & ']'

or, if you prefer an even more simpler approach, why not use the built in Qlik function GeoMakePoint:

GeoMakePoint($(yz2y(y,z)),$(xz2x(x,z)))

which will do the same thing (even thought this now has nothing to to with traditional lat/long calculations anymore).

Now, at this point we have not done anything more advanced than what we achieved in my previous article, but we have done this in a way so that we now can take any kind of 3D point system and project it in 3D on the Qlik Sense Map object using the Point Layer.

“The Global View”

From what point of view are we looking at the Earth?

Can you see that? It is not super easy to get that understanding because continents are not super clear when we only plot cities…. but if you make some country selections you will start to understand how the globe is presented.

We are looking at the globe from the complete North, like we are hovering above the North Pole.

What if you want to see the Globe from another perspective?

Then we need to “rotate” the x,yz coordinates, which means more calculations  – and I will write about that in a later blog post.

For now you just have to accept the limitation of just looking at the Globe from the North.

More useful info!

Where do you think on the Globe is the point where x=0, y=0 and z=0?

The answer is: In the exact center of the sphere!

This is going to be important to know when we want to start rotating the Globe and when we want to color/shade the globe so that points “further away” get darker or hidden completely.

 


Time to introduce the Line Layer – in 3D.

This is the how it looks with the concept of lines going “out” from the Earth:

From every city on the globe, we want to draw a line, away from the surface of the earth towards the “sky”. In the script we choose the line length to be the population of the city. The higher the population, the longer line will be.

Line Layer

  1. Create a new “Line” layer on your map.
  2. Add UniqueId as the “Line” dimension
  3. In the “location” tab – add GeoMakePoint($(yz2y(y,z)),$(xz2x(x,z))) as start point (same code as for the Point layer)
  4. In the “location” tab – add GeoMakePoint($(yz2y(y2,z2)),$(xz2x(x2,z2))) as end point (same code as for the Point layer, but with the other fields)

You see that first 3 steps are same as the Point Layer.

The only difference is that we are drawing a line from the same point as the “city point”, to a the location calculated with a fictive EARTH RADIUS based on the city population.

We can continue to make this chart pop more. I recommend changing line width to as thin as possible, and I also recommend adding some transparency to the color of the line.

Speaking of line color, in my data I also have a field called “capital” which has three values, “primary“, “minor” or “admin“. I want the line colour to reflect which of those types it is. So in my line layer I go to “Colour” and select “colour by dimension” and add “capital” as field.

Perhaps you have more relevant data, e.g., average family size, GDP, carbon footprint, mortality rate, etc. Just use your imagination and pick and chose among the following ways to customize this chart further. You can add several line layers like this and make them show depending on selections in the app.

I also recommend to add the set expression {1} to all your expressions in the map-object. That way the globe is always represented as a globe, even if the user is selecting a country, and instead it shows by color what country is selected.

More features you can play with:

Point Layer

  • Point Colour (Hue, Saturation, Luminosity)
  • Point Outline Color
  • Point Size
  • Point Shape
  • Point Image / and rotation

Line Layer

  • Line Length
  • Line Thickness
  • Line Curtvature
  • Line Colour (Hue, Saturation, Luminosity)

So, all in all, with this single chart we are now able to visualize more than 10 different dimensions for each city. And possible more if you just add several line layers!

In the app that you can try or download below, I am using the map object with a black background. This is done by using a Background layer (Add Layer / Background Layer) and then you need to have access to a small picture that has just black pixels. You can use two methods, either a Tiled image (TMS), or a complete black image that is not Tiled (Image). I am using a 100×100 small image called ‘black.png‘ that I have uploaded to the Content library on our server so I just use the direct https link to explain to Qlik Sense where the image is located.

If you want a black background, your link to the picture should be something like this: =’https://{your qlik sense server}/content/default/black.png’

 

In my example app I have also added a normal flat 2D map of the cities, using the long and lat values that was included in the data file. Since this is linked to the x,y,z points, selections on the flat map will be reflected on the 3D globe and vice versa.

I also added three variable sliders (using Vizlib because they look nicer than the standard slider) so that you can try to adjust which x,y and z values you want to show on the 3D Globe.

I added this because if you play around with them you can get a better understanding on what is x,y,z representing on the map. For instance, here is the same globe where I only show positive x,y z values:

The “further away” a point is, perhaps you want to color it darker, and perhaps also if a point is located “behind” the horizon, you do not want to plot it all. Take some time to play around with the x,y and z sliders to get a good understanding on what they do. When we get to areas and rotation, this will be very important.

 

You can try the app here as embedded in this blog post. Our Qlik Server is the smallest possible that exists so be patient as it takes time to load the data.

For best performance, download the app from GitHub (see links below) and run it directly in your environment.


Next articles in this series will be about

  • Part 3: How to import Country KML files and project them to the 3D Globe using the Area Layer.
  • Part 4: How to rotate 3D objects in Qlik Sense.
  • Part 5: How to import 3D objects (.obj files) directly in Qlik Sense.
  • Part 6: How to 3D scan a real world object with your phone and import that into Qlik Sense.
  • Part 7: Next Level 3D Analytics

Article Resources

Try the app online here (be patient, ,server is weak)

If you are interested in downloading the example app, you can get it from our GitHub here: