How to build a multi-layered Radial Chart in Tableau Software

Two weeks have passed since IronViz. Many of you are still wondering what magic lies behind the design of the « weather memories » radial chart. Without any black magic, let’s build together, step by step, the multi-layered circular visualization performed on stage.

 

2018-10-18_18h19_50.png
weather memories

 

Data

The IronViz data set was meteorological measures of the Tableau Conference attendee’s cities, for the last 3 years.

The seasonality of weather events is no longer to be proven. By choosing a year, it becomes interesting to visualize time and weather on a cyclical visualization. The circular visualization, or « radial chart », is ideal for that! Several types exist: radial histogram, radial bar chart, radial heatmap or even radial convergences.

 

giphy (2)
« Radial Chart, I choose you! »

 

I selected six measures for ironviz:

  • Average precipitation per day
  • Maximum precipitation per day
  • Average wind speed per day
  • Maximum wind gust per day
  • Average temperature of the night per day
  • Average temperature of the day per da

The main challenge was to be able to represent all these indicators on the chosen visualization, the radial chart. One of the possible solutions was then to build several radial charts, stacked on top of each other.

The data being confidential, we will work on a false dataset created for the occasion.

2018-11-04_19h24_42
« data » sheet

The data is available for download on this link.

Layers

To build this superposition of radial charts, we need to include the notion of layers.

 

WeirdCaringAmurstarfish-size_restricted
Not these layers, but almost.

 

Two solutions :

  • Duplicate input data (our choice here)
  • Rotate input data measures (from columns to rows)

I first heard about « layers » on the datablick blog and the awesome Chris de Martini article on small multiple flows.

A Cartesian product is performed between the initial data and a second sheet. This second data set is made of as many lines as there will be layer in my visualization. As much information as necessary can be included in this table (unit, description, title, …)

2018-11-04_19h47_19
« model » sheet
2018-11-06_11h51_41.png
the very famous cartesian product in Tableau performed on « link » field.

 

Four main layers will be implemented:

  • The precipitation layer
  • The wind layer
  • The temperature layer
  • The axis and references layer

 

Visualization

I advise you to follow this tutorial by also downloading the dashboard on Tableau Public:

https://public.tableau.com/views/greatified_com-Multi-LayeredRadialChart/multi-layeredradialchart?:embed=y&:display_count=yes&publish=yes

Basics : The circle

The starting point of a circular visualization is to be able to build a basic circle. We have to convert our information in angle, then in coordinates thanks to the usual formulas of trigonometry.

Please, please, take a look at Ken Flerlage  tutorial about trigonometry. A lot of my work is based on this, Thanks Ken!

Here we go for basic trigonometry calculations!

@angle : For each day of the year, we want to calculate the corresponding angle.

DATEPART(‘dayofyear’,[Date])*360/365

@cos : For each day of the year, we want to calculate the corresponding ordinate.

cos(RADIANS([@angle]))

@sin : For each day of the year, we want to calculate the corresponding abscissa.

sin(RADIANS([@angle]))

To make sure of the result, I advise you to visualize the calculated coordinates by dragging the sines and cosines  in columns and lines.

2018-11-06_09h58_49.png
The coordinates are displayed for each date and form a circle.

All future calculations are variations of these first two components.

Layer 1 : the precipitation radial

The radial chart of precipitation is actually a double radial bar chart:

  • the average precipitation, a bar towards the inside of the circle
  • the maximum precipitation, a bar to the outside of the circle

we therefore need to calculate the coordinates of these two positions, the average and the maximum precipitation. A single bar connecting these two points will be drawn, instead of two separate bars. This choice is purely aesthetic, and each bar can be drawn independently if you want to.

Below, the calculations of these coordinates. Hold on, we get into the subject!

value_prec : value to calculate according to the lower position (position = 0) or higher (position = 1) on the bar. If there is no precipitation, I don’t want to display anything. The bar is built around a circle of a specific radius, [radius_prec], a parameter that we want to be able to vary.

IF [Precipitation Avg]>0 THEN
IF [position]=0 then [radius_prec]-[Precipitation Avg]
ELSEIF [position]=1 then [radius_prec]+[Precipitation Max] END
END

x_prec : point abscissa.

[value_prec]*[@sin]

y_prec : point ordinate.

[value_prec]*[@cos]

For each day of the year, we now have two points. A low point for average precipitation, a high point for maximum precipitation. These two points must be connected to form a bar. Just drag and drop the x and y in columns and rows and choose the mark type « line ». Finally, we must set the path for this line, a line by date, between the low and high position. The line finally looks like a bar!

2018-11-06_11h51_59

The first layer is up! You can filter on layer = 1, this does not change the result for now but minimizes the number of rows returned.

You can also vary the radius_prec parameter to change the radius of the circle.

Layer 2 : the wind radial

The radial chart of wind is a radar/line, embellished with bubbles:

  • the average wind speed is the position of the line on the radar
  • the speed of the maximum gust is the size of the bubble on the day concerned

Once again, we need to calculate the coordinates of these two measures. You must also find a way to display two different types of visualization, the line and the bubble, on the same graph. Hint: double axes are my friends!

Let’s start with the wind:

value_wind : value to be calculated according to the wind speed. The radar / line is built around a circle of specific radius, [radius_wind], which we want to be able to vary. The amplitude, [amplitude_wind] is also a parameter which must be variable.

[radius_wind]+[Wind Speed Avg]/[amplitude_wind]

x_wind : abscissa of the point.

[value_wind]*[@sin]

y_wind : ordinate of the point.

[value_wind]*[@cos]

On the same graph, we want to display an additional visualization for the gust, the bubbles. We will use double axes, so we need to recalculate the position for these new axes. Here it’s simple, the position is the same for wind and gust. Only the size of the bubble is specific and must be calculated.

value_gust : point size, depending on the maximum of the gust.

max([Gust Speed Avg])

x_wind_2 : abscissa of the point. I do not want any points if no gust is recorded for the day.

IF [Gust Speed Avg]>0 THEN
[value_wind]*[@sin]
END

y_wind_2 : ordinate of the point.

IF [Gust Speed Avg]>0 THEN
[value_wind]*[@cos]
END

For each day of the year, we have the position of the line for the wind speed and the positions and sizes of the bubbles for gusts. By using double axis coordinates in columns and rows, I can display these two different representations. The path setting of the line is different from the precipitation one. Only one line is drawn around the circle. We use the field « position » (single value) by default in detail, then the path on each date value. The mark type must be changed for the second axis to a bubble.

2018-11-06_11h52_09

The second layer is up. You can also vary the radius and amplitude parameters.

 

Layer 3 : the temperature radial

The temperature radial chart looks like the precipitation radial:

  • the average temperature of the night is the low position of the bar
  • the average temperature of the day is the high position of the bar

The calculation of the coordinates is quite similar to the first layer.

value_temp : value to be calculated according to the low or high position. Variable position around a circle of radius [radius_temperature]. Variable amplitude thanks to the parameter [amplitude_temp].

[radius_temperature]+
IF [position]=0 then [Temperature Night Avg]
ELSEIF [position]=1 then [Temperature Day Avg] END
/[amplitude_temp]

x_temp : point abscissa.

[value_temp]*[@sin]

y_temp : point ordinate.

[value_temp]*[@cos]

The visualization configuration is identical to the layer 1. We want a bar (actually a line), for each date, between the low position and the high position.

2018-11-06_11h52_26

 

Layer 4 : the axis and references radial

Layer 4 will be our generic layer for information, reference lines and scale:

  • a bubble in the center for textual information
  • a line at 0 for precipitation that will visually separate the two bars (average and maximum precipitation)
  • grid lines for each day for wind speed
  • a 0 degree reference line for temperatures
  • a 30 degrees reference line for the temperatures

What?? Yes,  the layer 4 is made of sub-layers!

4.gif
a layer into a layer…

If you remember the model sheet, we have six different positions for layer = 4.

2018-11-04_19h47_19

We gonna use the layers for the first time. Let’s go!

value_init : value of points for each position.

IF [position]=1 THEN [radius_wind]
ELSEIF [position]=2 THEN [radius_wind]+10/[amplitude_wind]
ELSEIF [position]=3 THEN [radius_temperature]+32/[amplitude_temp]
ELSEIF [position]=4 THEN [radius_temperature]+86/[amplitude_temp]
ELSEIF [position]=5 THEN [radius_prec]
END

x_init :point abscissa.

[value_init]*[@sin]

y_init : point ordinate

[value_init]*[@cos]

Several lines are now to be drawn, at different levels and with different paths. Three have to be drawn around the circle, like the wind. One is to be plotted for each date, such as rainfall and temperature. We must therefore have specific detail and path fields for each layers.

details_init : field to use in detail. Here @angle is used instead of date, to use the same datatype as the position field.

IF [position]=1 THEN [@angle]
ELSEIF [position]=2 THEN [@angle]
ELSEIF [position]=3 THEN [position]
ELSEIF [position]=4 THEN [position]
ELSEIF [position]=5 THEN [position]
END

path_init : field to place in path for the line layout to perform.

IF [position]=1 THEN [position]
ELSEIF [position]=2 THEN [position]
ELSEIF [position]=3 THEN [@angle]
ELSEIF [position]=4 THEN [@angle]
ELSEIF [position]=5 THEN [@angle]
END

The central bubble will be created thanks to a double axis. New coordinates must be recalculated.

x_init_2 : abscissa of the central bubble at 0. single point.

IF [@angle]=360 and [position]=0 then 0.0 END

y_init_2 : ordinate of the central bubble at 0. single point.

IF [@angle]=360 and [position]=0 then 0.0 END

Finally, in the same way as before, we will drag our fields x and y in columns and rows to display the points, filter on layer = 0. details_init and path_init must be used in detail and path. The double axis must also be set.

2018-11-06_11h52_40

The last layer is up!

 

Final Layering

If you have understood the last layer tutorial, you now have an idea of how we will stack all these layers. Let’s begin!

x_radial : specific abscissa for each layers.

IF [Layer]=0 THEN [x_init]
ELSEIF [Layer]=1 THEN [x_prec]
ELSEIF [Layer]=2 THEN [x_wind]
ELSEIF [Layer]=3 THEN [x_temp]
END

y_radial : specific ordinate for each layers.

IF [Layer]=0 THEN [y_init]
ELSEIF [Layer]=1 THEN [y_prec]
ELSEIF [Layer]=2 THEN [y_wind]
ELSEIF [Layer]=3 THEN [y_temp]
END

x_radial_2 : specific abscissa for each layers. double axis.

IF [Layer]=0 THEN
[x_init_2]
ELSEIF [Layer]=2 THEN
[x_wind_2]
END

y_radial_2 : specific ordinate for each layers. double axis.

IF [Layer]=0 THEN
[y_init_2]
ELSEIF [Layer]=2 THEN
[y_wind_2]
END

For each layer, we had different information in detail and path depending on the type of visualization to display: circle or bar.

detail : field to use in detail. Here @angle is used instead of date, to use the same datatype as the position field.

IF [Layer]=0 THEN [details_init]
ELSEIF [Layer]=1 THEN [@angle]
ELSEIF [Layer]=2 THEN [position]
ELSEIF [Layer]=3 THEN [@angle]
END

path : field to place in path for the line layout to perform.

IF [Layer]=0 THEN [path_init]
ELSEIF [Layer]=1 THEN [position]
ELSEIF [Layer]=2 THEN [@angle]
ELSEIF [Layer]=3 THEN [position]
END

size : Line thicknesses can be configured according to the layers for the aesthetic side.

IF [Layer]=1 THEN 10
ELSEIF [Layer]=2 THEN 1
ELSEIF [Layer]=3 THEN 30
END

size_2 : bubble size according to the layers.

IF [Layer]=0 THEN 2000
ELSEIF [Layer]=2 THEN [Gust Speed Avg]
END

The setting of the visualization is relatively simple. You no longer need the layer field in filter. The layer field can be used to configure colors. The order field of the « model » sheet can be used the conifgure depth of the different layers. The values of the parameters can be changed to find the optimal configuration.

2018-11-06_11h52_53

 

If you read these words, congratulations for your perseverance, I know you would have been brave enough (or crazy) to follow this tutorial to the end! If you have questions or difficulties about this method, do not hesitate to contact me through traditional channels, twitter or LinkedIn.