Having made this visualisation from scratch twice over I thought it deserved its own blog. Hopefully it goes some way into understanding how I created it, my thought process, as well as things to consider along the way.

This blog post is going to be a walkthrough of how I created my Grand Slam Tennis visualisation (#VOTD Makeover version). It actually follows different calculations to the original #VOTD from December 2020 but aesthetically looks quite similar.

You can find a copy of the original VOTD here, and can see my new cleaned up version here.

There’s a few reasons why this is a run-through and not a template.

1. This works for my data and probably only my data. I hope this blog helps you understand how it works rather than just to refresh my workbook with your own data. This will become apparent the further you read.

2. Through understanding the calculations you will then be able to improve it! I am excited to see anyone that takes learnings from the blog, and implements them for their own unique visualisation.

3. User cases are far and few between. I was lucky the three tennis players I chose are so good, and win a lot! I’m not sure it would look as appealing with lots of start points (Players / Winner)

4. Covering my own back a little…. I made minor calculations for aesthetics to calculations that aren’t the same as if you learn the theory; I wouldn’t want to pass this on to others. There are also many different ways you could approach building this visualisation!

I think that is enough disclaimers out the way now. Outlined below is a step-by-step guide with explanations if you think you have a good user case for it.

Data Prep.

You will see I have two sheet tabs in the original excel. You can clone your own copy from my Github at the top of the page.

The first sheet is “Main Data”

Runner-Up, Score, Tournament These fields aren’t actually necessary – I just use them within the tooltips.
Winner This is an important field. This is my starting points. I will create a case statement to mark the starting X and Y co-ordinate for my winners.
Year The year is important because this is where my end points will be. I want the most recent competition (2020) to be the first marker, going clockwise radially to the furthest point in 2000.
Rank Based on the year, therefore I assign each a rank number. You could do this in Tableau but I did it in excel for convenience. The rank is because my circle will start at 1 and increase as we move around the circle’s edge.

The second sheet contains our T Values for data densification

T Values from 0 to 100. To produce our curves to become curved.

Load the data and inner join Main Data to T sheet on a new calculation of 1 = 1.


1a. Start X


Explanation.  Where on the X-axis you want your starting point. Visually I know I need my starting co-ordinates to be on a straight line going up. Therefore whatever this number they will all reside on the same X co-ordinate. Do note, I went back and forth amending some of these values to find what was appropriate.

1b. Start Y

When ‘Novak Djokovic’ then 2
when ‘Rafael Nadal’ then 0.75
when ‘Dominic Thiem’ then -0.5
when ‘Roger Federer’ then  -3
else -1.8

Explanation: I am manually creating the starting Y co-ordinates for my winner. Again these were amended at the end to align to my bump chart. Theoretically I started with Djokovic as 1 Nadal as 0 and Federer as -1. (That’s because that’s the order I wanted them listed in, as Novak is currently the best player in the world, followed by Nadal & Federer) If this is hard to visualise check out the photo below.

You will also realise you will want to adjust these in relation to the final circle points to sit roughly within the middle. Let’s revisit this later….

1c. Max Points

// Maximum number of points in our densification data (T going from 1 to 100)
{FIXED: MAX ([T])}

Explanation: this is the maximum amount of points in our T, e.g. 100. I saw Ken Flerlage use this calculation so have kept it for safe-keeping ever since. If I were lazy I would just hard code the number 100.

2a. Angle


Explanation: Speaking of lazy… I know there are 83 distinct tournament outcomes (outer points) I want to create. Therefore I want to space these evenly and create the angle between them as dividing 360 degrees of a full circle by 83.

2b. Rank Angle

([Rank]* [2a. Angle])/2

Explanation: Lazy part two. We have made life easier by moving the rank into our excel document. We times the Rank by the Angle to find where each of the 83 points will sit along the 360 degree.

Why have I divided by 2? At the moment we have calculated the marks for a full circle…. I want to make them into a semi-circle so I divided by 2.

3a. End X

((sin(radians([2b. Rank Angle]))*10)) +10

Explanation: We know that when we wrap the rank angle in radians and SIN it makes it the circle we want. So why have I multiplied and added 10?

The times 10 is going to be the from one side of the circle to the other (2 Radius lengths, or 2 times the distance from the edge to the centre point) E.g how big is the circle.

The plus ten amounts: The ten shifts the graph to the right by ten. The original centre of the chart would be at X = 0. Knowing where I have my start points of the winners, I want to make sure my end markers are to the right. Again, you can move this as far or close, as you’d like. Check the below to see what this looks like:


3b. End Y

(COS(radians([2b. Rank Angle]))*10)

Explanation: We know that when we wrap the rank angle in radians and COS it makes it the circle we want. So why have I multiplied by 10? Same as above. We want the circle to be bigger we must keep the multiplied size in our End X as the same as our End Y or we will get an oval shape not circular one!

I haven’t added 10 to this calculation because we don’t want our end points to be any higher up.

4a. Sigmoid X


Explanation: This isn’t the exact correct sigmoid function. Please check out my dashboards showing the true calculations of data densification and sigmoid functions here. It has been adjusted for aesthetics slightly.

The original calculation, and one I would recommend starting with is:

(T-1)*(12/([Max Points]-1))-6

4b. Sigmoid Y

1/(1 + EXP(-[4a. Sigmoid X]))

Explanation: Again if you’d like to understand more about the theory of sigmoid curves please check out the above. This is another use of Ken Flerlage’s blog that I constantly refer to.

5a. Curve X

IF [T] = 1 then
[1a. Start X]
[T] > 1 and [T] < 100
[1a. Start X] + ([3a. End X] – [1a. Start X]) * [4b. Sigmoid Y]
ELSEIF [T] = 100
then [3a. End X]

Explanation:Where we have densified our data (100 points for each actual row) We set T = 1 for the start, T = 100 as our end point. For anything in between those values is the chord shape and style that we have just calculated in step 4a and 4b. Take the start position, the difference of each X co-ordinate multiplied by our curved adjustment.

5b. Curve Y

IF [T] = 1 then
[1b. Start Y]
[T] > 1 and [T] < 100
[1b. Start Y] + ([T]-1) * ([3b. End Y] – [1b. Start Y]) / ([1c. Max Points]-1)
ELSEIF [T] = 100
then [3b. End Y]

Explanation: We want the exact same for Y.  The good news is, if you give this tutorial a go, you won’t need to amend Curve X and Curve Y.

6a. Curve X

IF [T] = 1 then
[1a. Start X]
ELSEIF [T] = 100
then [3a. End X]

Explanation: I create a separate calculation for the start and end points as I wanted to make them circle. Probably quite old fashioned now but I used the dual axis. Therefore I’ll make the start (T = 1 ) a circle , as well as  (T = 100)


Drag 5a. Curve X onto Columns and make it a dimension.

Drag 5b. Curve Y onto Rows and make it a dimension.

I like to make my axis fixed to fit the feel and shape. For my work this was, -11 to 11 for curve Y.  This was -5 to 21.5 for X. Logically you just need to look at what works best. It’ll also depend on where you moved your start points from and how big you decided to make your semi-circle.

Drag 6a. Curve X onto Columns and make it a dimension and change the mark card to a circle.

Make the axis dual axis, and synchronise the axis.

(If measure names goes onto the colour mark remove this from ALL)

Change the Marks to a Line and Drag T onto curve.

Drag Winner, Tournament, Score, and Runner-up onto detail.

We need to do this for the LOD of the lines! Otherwise you get a hot mess of thick lines all over the place.

Finally, It is a case of cosmetics.

  • Remove gridlines, background colour, and hide axis.
  • Add some colour.
  • Add some sizing to your circles.

I created a colour calculation:

7a. Colour

When ‘Novak Djokovic’ then ‘Novak Djokovic’
when ‘Rafael Nadal’ then ‘Rafael Nadal’
when ‘Dominic Thiem’ then ‘Dominic Thiem’
when ‘Roger Federer’ then ‘Roger Federer’
else ‘Other’

Explanation: I’d encourage individuals to amend the opacity on their line marks curve. I also sorted the colours manually this was preference.

8a Size

IF [T]= 1 and [Winner] =
‘Novak Djokovic’ then 17
ELSEIF [T]= 1 and [Winner] = ‘Rafael Nadal’ then 20
ELSEIF [T]= 1 and [Winner] = ‘Dominic Thiem’ then 1
ELSEIF [T]= 1 and [Winner] = ‘Roger Federer’ then 20
else 10

Explanation: Dragging size onto the circle marks card allows for some reshaping. I want the start points to be the number of Grand Slam wins, and then each of the outer points I made just a relative size, this probably isn’t best practice.

To end, Let’s revisit a few calculations for explanation.

Start X.

Now we’ve finished the build it may be more apparent why I set X to zero, and shifted the circle to the right. Theoretically you could approach this in a different way and move the start point to the left of the build of your semi-circle.

Start Y.

You can see that the centre point of the circle sits at zero of the Y-axis.  As the top and bottom of my circle sit at -10 and 10, I want my start points to sit within those points. For me I liked the feel of having them distributed only slightly above and below zero.

& That’s a wrap. Hopefully somewhat useful. I really enjoyed making this visualisation. It’s actually may favourite one I’ve made so far. I won’t expect to see many of these made in the future but hope it offers a small insight into my brains approach! As always any questions please do note hesitate to message me on Twitter @_CJMayes.