Glyphs and edges of the London Underground#

Station passenger volume change 2017 - 2018 Line segment running time and percentage change (slow down) at peak times 2011 data.

Powered by TfL Open Data Contains OS data © Crown copyright and database rights 2016’ and Geomni UK Map data © and database rights [2019]

Nick Holliman, @binocularity, September 2023

[ ]:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import numpy as np
from PIL import ImageColor
from vizent import create_plot, add_glyphs, add_lines

# Flag to draw station name labels on the plot.
drawStationLabels = True

# Circle line RGB colour from the TfL hexcode.
# Calculate a derived three colour scale for the line speed.
rgbColraw = (ImageColor.getcolor("#FFD300", "RGB"))
rgbCol = tuple(ti/255 for ti in rgbColraw)
centralLineCol = tuple(ti/255 for ti in rgbColraw)
cmapPlain = ListedColormap([ tuple(np.clip(ti*2,0.0,1.0) for ti in centralLineCol),
                            centralLineCol,
                            tuple(ti/2 for ti in centralLineCol) ])

# Read in csv table holding the node locations and data
# Use the UK national grid Eastings and Northings location data.
dfNodes = pd.read_csv ('sample-data/circle-line-tubeNodesZ1L3PsgrCnghPcnt1718GB.csv')
N_Vals = dfNodes["northing"]
E_Vals = dfNodes["easting"]
pcntVals = dfNodes["AnnEntExPcnt2017"]
pcntChng1718Vals = dfNodes["AnnEntExChngPcnt1718"]
passngrNum2018 = dfNodes["AnnEntEx2018"]
passngrNum2018_M = dfNodes["AnnEntEx2018"]/1000000

# Load the edge connectivity table with the edge data on journey times.
dfEdges = pd.read_csv ('sample-data/circle-line-edgesZ1L3_withTime.csv')
startPts = []
endPts = []
for i, edge in dfEdges.iterrows() :
    startPts.append([E_Vals[edge["s1"]-1], N_Vals[edge["s1"]-1] ])
    endPts.append([E_Vals[edge["s2"]-1], N_Vals[edge["s2"]-1] ])

# Create a Vizent plot
vizent_fig = create_plot(use_glyphs=True,
                         use_lines=True,
                         show_legend=True,
                         show_axes=True,
                         use_cartopy=False,
                         scale_x=20,
                         scale_y=11.25)

# Add glyphs to the plot (graph nodes)
add_glyphs( ax=vizent_fig,
            x_values=E_Vals,
            y_values=N_Vals,
            colormap = "cool",
            color_values=passngrNum2018_M,
            color_min = 0.0,
            color_max = 100.0,
            shape_values=pcntChng1718Vals,
            shape_min = -30,
            shape_max = 30.0,
            shape_neg = "saw",
            shape_n = 4,
            size_values=[14 for i in range(27)],
            legend_title = "Station",
            color_label = "Annual\nPassengers\n(M)",
            shape_label = "Change\nYr on Yr\n(%)",
            label_fontsize=10
)

# Add edges to the plot.
add_lines(
    ax = vizent_fig,

    x_starts=[i[0] for i in startPts],
    y_starts=[i[1] for i in startPts],

    x_ends=[i[0] for i in endPts],
    y_ends=[i[1] for i in endPts],

    freq_values=dfEdges["slowerPcnt"],
    width_values=[3 for i in range(27)],
    freq_min = 0.0,
    freq_max = 40.0,
    freq_n = 3,

    color_values=dfEdges["Inter peak (1000 - 1600) Running time (mins)"],
    colormap=cmapPlain,
    color_min=1.0,
    color_max=4.0,
    style = "set_length",
    length_type = 'pixels',
    striped_length =20,
    # length_type = 'units',
    # striped_length =200,

    legend_title = "Line",
    color_label = "Daytime Running\ntime (min)",
    frequency_label = "Peak\ndelay (%)",

    label_fontsize=10
)

# Select correct subfigure to overplot with station names
fig = vizent_fig[0]
ax = vizent_fig[1]

# CUSP London location (at Bush House)
ECUSP = 530736
NCUSP = 181042
ax.plot(ECUSP, NCUSP, 'o',markerfacecolor="w",markeredgecolor="w")
ax.text(ECUSP-100.00, NCUSP+125.00, 'CUSP\nLondon', color='w', fontsize = 10,
                 horizontalalignment='right',
                 bbox={'facecolor': (0.3,0.5,0.3),'edgecolor':(0.3,0.5,0.3),  'pad': 3})

#Draw the station names if flag for text is True
if drawStationLabels :
    dfNames = pd.read_csv ('sample-data/circle-line-tubeNodesZ1L3NamesLocsGB.csv')
    for i,row in dfNames.iterrows() :
        lonNm = row["easting"] + row["adjEast"]
        latNm = row["northing"] + row["adjNorth"]
        curName = row["name"]
        curName = curName.replace(r'\n', '\n')
        ax.text(lonNm, latNm, curName, color='w', fontsize = 10, alpha=0.6,
                        horizontalalignment=row["ha"])

# Adjust the plot aesthetics.
fig.axes[2].set_facecolor((0.35,0.35,0.55))
fig.axes[1].set_facecolor('0.6')
fig.axes[0].set_facecolor('0.6')

plt.suptitle("London Tube, Circle Line, Annual Performance.\n"+
             "Total passenger numbers 2018, and % change from 2017,"+" normal line running time (min) and % peak delay, 2011",
               fontsize=16)


# When saving this image, a DPI of 192 generates a file of 3,840 x 2,160 pixels (i.e. UHD quality).
# This can be done with the following lines:
# fileDPI = 192
# plt.savefig( fileName, dpi=fileDPI )

C:\Users\k2364528\Code\vizent\vizent\scales.py:230: UserWarning: Specified minimum and maximum shape scale values or specified shape scale spread exclude some data
  warnings.warn("Specified minimum and maximum shape scale values "
Text(0.5, 0.98, 'London Tube, Circle Line, Annual Performance.\nTotal passenger numbers 2018, and % change from 2017, normal line running time (min) and % peak delay, 2011')
_images/gallery-circle-line_1_2.png

Link to image