Map Of Test Cricket Grounds Of The World

5 minute read

A Map of Test Cricket Grounds of the World

A look at visualisations using maps in Python. I’ll use a data set I’ve collated of coordinates of all the main current test match cricket grounds and over the next few posts I’ll plot them in different map based packages, making use of those packages specific functionality where possible.

Basemap Package

Firstly I’m going to use Basemap to create a simple visualisation of the location of all the grounds, linked to every other ground using great circles. We will hopefully end up with a visualisation that looks something along the lines of a route map of a major airline that travels all round the world.

Purpose?

This is just going to be a static visualisation and on its own will hold minimal insight. On a general level knowing the distance between venues in sports may provide a line of insight into performance, though for test cricket purposes this factor is probably negligible as teams tend to travel well in advance of matches.

For example, if a London based Premier League football team like Arsenal plays a European game in Moscow on a Thursday evening followed by an away league game in Newcastle on Sunday afternoon, how far have they travelled in the last 4 days? How much further have they travelled than Newcastle in the time period? Should we expect an adverse effect on performance? Can we quantify that effect in terms of expected goals scored/conceded if so?

What about a tennis player who makes the final of a tournament in France on a Sunday and whos next match is in China on a Tuesday? Should we expect that players performance level on Tuesday to be significantly worse than Sundays? Does it drop off more than if they had to go from Germany to the UK in the same length of time?

I’m not going to be able to answer those questions here, but collating the data of distance a player/team travelled would be involved in such an analysis. In that case knowing the distance between venues would be useful.

The Data

Lets start by importing our data, which is in a csv file.

#Import relevant packages
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from itertools import combinations

#Load our dataset as a DataFrame
all_grounds_df = pd.read_csv('https://eddiesport.github.io/projects/test_grounds.csv', header=0, index_col=0)
                             
#Check data
print(all_grounds_df.head(10))
print(all_grounds_df.info())
          ground        lat         lng     location       team
0          Lords  51.529603   -0.172906       London    England
1       The Oval  51.483816   -0.115138       London    England
2   Old Trafford  53.456806   -2.287469   Manchester    England
3   Trent Bridge  52.936857   -1.132165   Nottingham    England
4     Headingley  53.817661   -1.581978        Leeds    England
5      Edgbaston  52.455658   -1.902610   Birmingham    England
6      Rose Bowl  50.924125   -1.321760  Southampton    England
7            MCG -37.820000  144.983333    Melbourne  Australia
8            SCG -33.891667  151.224722       Sydney  Australia
9  Adelaide Oval -34.915556  138.596111     Adelaide  Australia
<class 'pandas.core.frame.DataFrame'>
Int64Index: 59 entries, 0 to 58
Data columns (total 5 columns):
ground      59 non-null object
lat         59 non-null float64
lng         59 non-null float64
location    59 non-null object
team        59 non-null object
dtypes: float64(2), object(3)
memory usage: 2.8+ KB
None

We have coordinate data for 59 grounds. To draw our great circles we are going to need coordinate combinations for all possible pairs of grounds. Firstly I’ll extract from the DataFrame a tuple of coordinate pairs for each ground.

#Create a list of tuples of all grounds coordinates
#%%timeit - 1.66 ms ± 84.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

#Set up our empty list
ground_tuples = []

#Iterate over our dataframe to create our required variables
for row in all_grounds_df.itertuples():
    ground_lat = row.lat
    ground_lng = row.lng
    #Append new sets of tuples to our list
    ground_tuple = ground_lat, ground_lng
    ground_tuples.append(ground_tuple)

#Check an element of our list    
print(ground_tuples[0])
(51.529603, -0.172906)

Note: I’ve commented out a timeit command in that code cell. In testing the timeit result shown for this cell (minus the print call) was obtained and was as displayed, 1.66 ms ± 84.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each).

I mention this as virtually the same for loop method using for i, row in all_grounds_df.iterrows(): would have returned the desired ouput in the form of a list of lists of coordinate pairs, but was computationally much slower, returning a timeit of 7.34 ms ± 137 µs per loop (mean ± std. dev. of 7 runs, 100 loops each).

This is an expected result and a reminder that iterating using itertuples() is preferable to using iterrows() where suitable.

Now lets find every combination of pairs of grounds, using the combinations function of itertools.

#Get all 2-combinations of tuples
#Generate a combinations object
ground_pairs_obj = combinations(ground_tuples, 2)

#Convert our combinations object to a list by unpacking
ground_pairs = [*ground_pairs_obj]

#Check our output
print(ground_pairs[0])
print(len(ground_pairs))
((51.529603, -0.172906), (51.483816, -0.115138))
1711

We now have 1711 tuple pair combinations to be drawn as great circles, thats quite a lot and something to think about when choosing the linewidth of a displayed great circle, we dont want to colour in our whole map!

Designing Our Map

Now lets create and display our map using Basemap. I’ve decided to use the Mercator Projection of the earth, with the shadedrelief image background for a more appealing look. Using shadedrelief does impact loading time of the map, especially if the ‘scale=’ arg is not reduced from its default.

the .drawgreatcircle() function requires the longitude and latitude of both destinations, which we have in our ground pairs list.

#Create a world map
plt.figure(figsize=(12, 9), dpi = 100)

#Define our map type and parameters
m = Basemap(projection='merc',llcrnrlat=-60,urcrnrlat=65,\
            llcrnrlon=-180,urcrnrlon=180,lat_ts=20,resolution=None)

#Add shadedrelief image to the map
m.shadedrelief(scale=0.4)

#Draw our great circles by unpacking our tuple pairs
for ground_pair in ground_pairs:
    
    #Create coord variables for drawgreatcircle, note lat/lng order reversed
    lng1 = ground_pair[0][1]
    lat1 = ground_pair[0][0]
    lng2 = ground_pair[1][1]
    lat2 = ground_pair[1][0]
    
    #Draw our great circles
    m.drawgreatcircle(lng1, lat1, lng2, lat2, linewidth=0.1, color='b')

#Highlight the grounds locations
for ground in ground_tuples:
    xlng = ground[1]
    ylat = ground[0]
    
    m.plot(xlng, ylat, latlon='True', color='#FFFF00', marker='.', markersize=2)

#Show
plt.title("Linking Test Cricket Grounds of the World")
plt.show()

png

There we have it, a map of all test grounds linked. It has an appealing global network look, but lacks functionality. Labelling grounds would look messy as on a global scale they are located in bunched up groups. In a future post I’ll use a different map package where we can zoom in and out, clicking on venues to display their names and any extra data.

Leave a Comment