Skip to main content

Proportional symbols in three dimensions

Since I'm making my own Thematic Mapping Engine, I need to understand the math behind proportional symbol calculations. Originally, I thought I would need different equations for different geometric shapes, and my book in cartography gave me the same impression. But after reading this article, I realised that life was not that complicated.

This tutorial is a summary of a discussion on the CartoTalk forum. I especially want to thank Dominik Mikiewicz (mika) for his valuable comments and figures. The CartoTalk forum is highly recommended!

Equations for 1D, 2D and 3D proportional symbols:

1-dimensional symbols (height)
This is how the height of bars or prisms is calculated in TME.

Equation: symbolSize = (value / maxValue) * maxSize
PHP: $symbolSize = ($value / $maxValue) * $maxSize
JavaScript: symbolSize = (value / maxValue) * maxSize

Bars or prisms show “real” values scaled down to fit on a map, and you can easily see the relations and which is higher than the other. I’m not considering the problems caused by perspective and the curvature of the earth.

2-dimensional symbols (area)
This is how proportional images and regular polygons (e.g. circle, square) are scaled in TME.

Equation: symbolSize = power(value/maxValue; 1/2) * maxSize
PHP: $symbolSize = pow($value/$maxValue, 1/2) * $maxSize
JavaScript: symbolSize = Math.pow(value/maxValue, 1/2) * maxSize

2D symbols use areas as mean of expression and therefore you're dealing with a square root of a showed value. This makes it relatively difficult to assess a value.

3-dimensional symbols (volume)
This is how 3D Collada objects (e.g. cube, sphere) are scaled in TME.

Equation: symbolSize = power(value/maxValue; 1/3) * maxSize
PHP: $symbolSize = pow($value/$maxValue, 1/3) * $maxSize
JavaScript: symbolSize = Math.pow(value/maxValue, 1/3) * maxSize

3D objects use volumes as mean of expression so you’re showing a cube root of the value. This makes it difficult to assess a value.


It’s important to know that it’s one degree harder for the viewer to assess the relative size of 3-dimensional symbols compared to 3-dimensional, which again is harder to compare to 1-dimensional. This is clearly visualised on this figure (credit: Dominik Mikiewicz):

The figure compares the circle and sphere radius for the same values.

These three images shows GDP per capita (2006, UNdata) using bars (1D), circles (2D) and spheres (3D).



A colour scale and legend helps the user in assessing and comparing symbols.

The visual appearance of 2D and 3D symbols can also be improved by using a perceptual or logarithmic scale.

Comments

Popular posts from this blog

Creating a WebGL Earth with three.js

This blog post will show you how to create a WebGL Earth with three.js , a great JavaScript library which helps you to go 3D in the browser. I was surprised how easy it seemed when reading a blog post  by Jerome Etienne . So I decided to give it a try using earth textures  from one of my favourite cartographers, Tom Patterson . WebGL is a JavaScript API for rendering interactive 3D graphics in modern web browsers without the use of plug-ins. Three.js is built on top of WebGL, and allows you to create complex 3D scenes with a few lines of JavaScript. If your browser supports WebGL you should see a rotating Earth below: [ Fullscreen ] To be able to display something with three.js, you need three things: a scene, a camera and a renderer. var width  = window.innerWidth,     height = window.innerHeight; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000); camera.position.z = 1.5; var rende...

Creating 3D terrains with Cesium

Previously, I’ve used three.js to create 3D terrain maps in the browser ( 1 , 2 , 3 , 4 , 5 , 6 ). It worked great for smaller areas, but three.js doesn’t have built-in support for tiling and advanced LOD algorithms needed to render large terrains. So I decided to take Cesium for a spin. Cesium is a JavaScript library for creating 3D globes and 2D maps in the browser without a plugin. Like three.js, it uses WebGL for hardware-accelerated graphics. Cesium allows you to add your own terrain data, and this blog post will show you how. Impressed by the terrain rendering in @CesiumJS - with a 10m elevation model for Norway! Farewell Google Earth. pic.twitter.com/RQKvfu2hBb — Bjørn Sandvik (@thematicmapping) October 4, 2014 Compared to  the dying Google Earth plugin , it's quite complicated to get started with Cesium. The source code is well documented and the live coding Sandcastle is great, but there is a lack of tutorials  and my development slows down when ...

Terrain building with three.js

In my last blog post , we converted a digital elevation model (DEM) to a WebGL-friendly format ( i.e. easy to transfer and parse by JavaScript in the browser). In this blog post, we'll use the elevation data to build a terrain mesh with three.js .  First we need to transfer the terrain data to the browser. The elevation values are stored in a binary file as 16-bit unsigned integers. This page explains how you can send and receive binary data using JavaScript typed arrays. I've created a TerrainLoader by adapting the  XHRLoader . You can also use this function: function loadTerrain(file, callback) {   var xhr = new XMLHttpRequest();   xhr.responseType = 'arraybuffer';   xhr.open('GET', file, true);   xhr.onload = function(evt) {         if (xhr.response) {       callback(new Uint16Array(xhr.response));     }   };     xhr.send(null); } Loading elevation data with the Terrai...