Tuesday, October 6, 2020

Evaluating the Availability and Relative Speed of Public Transport

6 October 2020

I've spent the whole day yesterday looking into an interesting problem brought to my attention by Wayne Purcell after he read an article by Simon Behar. I took Simon's code, signed up for Google Maps API key, got the relation ids for a few cities from OpenStreetMap.org, and the poly files from Polygons.OpenStreetMap.fr, updated my Visual Studio Code and Python installations and ended up with this code:

Note: if you are reading this on a phone, the horizontal view may be better.

import googlemaps
import random
import csv
import time
from shapely import geometry as geo
from datetime import datetime, timedelta

MODES = ["driving""transit"]

CITIES = {"Gold Coast""GoldCoast""Warsaw""Warsaw", \
    "Brisbane""Brisbane""Berlin":"Berlin"}

# utc offset may change on daylight saving time (DST) change
GMT = {"Gold Coast": +10,  "Warsaw": +2, \
    "Brisbane": +10"Berlin": +2
POLYS = {}

gmaps = googlemaps.Client(key = "your api key goes here")

def get_directions(_from_to_mode_time):
    return gmaps.directions(_from,_to, mode=_mode, \
        departure_time=_time)

def get_travel_time(_dir):
    "In minutes"
    return round(_dir[0]['legs'][0]['duration']['value'] / 602)

def get_travel_distance(_dir):
    "In kilometers"
    return _dir[0]['legs'][0]['distance']['value'] / 1000

def get_poly(_city):
    poly_name = CITIES[_city]
    if poly_name in POLYS:
        return POLYS[poly_name]
    else:
        POLYS[poly_name] = create_polygon_from_file(poly_name)
        return POLYS[poly_name]

def create_polygon_from_file(_file_name):
    poly_points = []
    with open ("polys\\" + _file_name + \
         ".poly.txt""r"as raw_poly:
        
        raw_poly.readline()
        next_line = raw_poly.readline()
        
        while next_line[0] != "E":
            next_line = raw_poly.readline()
            
            while next_line[0] != "E":
                pair = next_line.split("\t")[1:]
                pair[1] = pair[1][:-1]
                poly_points.append([float(p) for p in pair])
                next_line = raw_poly.readline()
            next_line = raw_poly.readline()
    return geo.Polygon(poly_points)

def generate_random_point(polygon):
    minx, miny, maxx, maxy = polygon.bounds
    pnt = geo.Point(random.uniform(minx, maxx), \
        random.uniform(miny, maxy))
    
    while not polygon.contains(pnt):
        pnt = geo.Point(random.uniform(minx, maxx), \
            random.uniform(miny, maxy))
    return pnt

def point_to_dict(point):
    return {"lat": point.y, "lng": point.x}

def dict_to_string(_dict):
    return str(_dict['lat']) + " " + str(_dict['lng'])

def get_test_point(poly):
    return point_to_dict(generate_random_point(poly))

def route(_citylocalTimeattempt):
    poly = get_poly(_city)
    _from = get_test_point(poly)
    _to = get_test_point(poly)
    out = [_city, dict_to_string(_from), dict_to_string(_to)]
    
    for mode in MODES:
        departure_time = localTime - timedelta(hours = GMT[_city])
        print(mode + " directions in " + _city + " from " + \
            dict_to_string(_from) + " to " + dict_to_string(_to) +\
                " at " + str(departure_time))
        res = get_directions(_from, _to, mode, departure_time)

        if not res:
            time.sleep(1)
            if mode == 'transit':
                print ("Route failed at " + mode + ", retrying...")                
                return []
            return route(_city, localTime, attempt)    
        out.extend([get_travel_time(res), \
            get_travel_distance(res)])
    
    return out

def run(citiesroutesoutputFilelocalTime):
    with open(outputFile, 'a'newline=''as out:
        writer = csv.writer(out, dialect='excel')
        writer.writerow(['city''start''end''driving_time[m]',\
            'driving_dist[km]''transit_time[m]', \
            'transit_dist[km]''attempts''ratio'])
        
        for city in cities:            
            for i in range(routes):
                attempt = 1
                print ("Progress: " + str(i) + "/" + str(routes))
                time.sleep(1)
                res = route(city, localTime, attempt)
                while not res:
                    attempt += 1                    
                    res = route(city, localTime, attempt)
                res.extend([str(attempt), \
                    round(res[5] / res[3], 2) ])
                
                writer.writerow(res)

run(CITIES.keys(), routes=10outputFile="4cities.csv", \
    localTime= datetime.fromisoformat("2020-10-07T08:00:00"))

Which, I think allows to measure the availability and relative speed of public transport at 8am local time on a particular work day.

Here are the results for Berlin, Warsaw, Brisbane and Gold Coast:


What was missing in Simon's article and data was a number of failed attempts at routing by public transport between points A and B. The results for Brisbane and Gold Coast may be skewed by their boundaries including large national parks without any public transport nearby. Warsaw and Berlin also have large forests within city boundaries, but they seem to be more available. Still, in Brisbane and Gold Coast you CAN get there by car - driving is checked first, so the data as the measure of availability of public transport stands.

The code picks 10 random routes and asks Google Maps for a route at 8am local time when driving and when using public transit, and then compares the times. The longer it takes to get from A to B using public transport, the less attractive it is for people to use. A ratio of 2 means that it takes twice as much time to get from A to B using public transport than driving. The ratio of 2 is not bad.

I will do more testing, but from yesterday’s runs, the state of public transport availability is:

1. Warsaw: 0 failed attempts, speed ratio of 2.9

2. Berlin: 1 failed attempt, speed ratio of 2.1

3. Brisbane: 14 failed attempts, speed ratio of 7.4 

4. Gold Coast: 54 failed attempts, speed ratio of 4.2

The availability of public transport for Warsaw and Berlin is close to 100% (need to run 100 routes, instead of 10 to get more accurate percentages, but my guess Berlin is closer to 100% than 90%).

The availability of public transport for Brisbane is 42% and for Gold Coast only 16%.

The next step will be to to include more cities and check for correlations with public transport mode share.

Sunday, May 24, 2020

Tokyo, Japan - December 2019 - Part 2 - Trains

Greater Tokyo is the biggest metropolis in the world with about 38 million residents, 1000 train and metro stations, over 2500 km of tracks, 30 operators, and about 40 million trips on trains and metro every day. The main operators are the Japanese Railways East (JR East) - Tokyo is in the eastern part of Japan, Keikyū, Keisei, Keiō, Odakyū, Seibu, Tōbu, Tōkyū, and the two subway networks: Tokyo Metro and Toei. Many travellers arrive in Tokyo from the Narita Airport by this train:

N'EX - Narita Express by JR East
How did the rail transport in Japan get to that point? It all started with a visit by an American.

Japan self-restricted contact with the outside world for over 200 years, until 1853, when the American Navy, lead by Matthew C. Perry forced opening up of the country. The photo of him was one of the only two foreigners that I noticed in the JR East Railway Museum in Saitama. The other one, was an Englishman, the inventor of card tickets used for over 150 years around the world - Thomas Edmondson.

Matthew C. Perry

First locomotives were imported from the UK and the US and were used among other things to build railway lines and transport timber.
Vulcan Foundry, England, 1871 
H.K. Porter Locomotive Works, the USA, 1880
Look how convenient the Paddington Station in London was for travellers:
you could step off from the horse carriage right onto the platform and the railway carriage.






There was a short period when, in some places, human powered railways were in operation:


A peculiarity of the Japanese electrical system, that extends to the railways, is that Eastern Japan (including Tokyo) runs at the frequency of 50 Hz; Western Japan (including Osaka) runs at 60 Hz. This originates from the first purchases of generators from the German AEG (50 Hz) for Tokyo in 1895 and from the American General Electric (60 Hz) for Osaka in 1896.

In 1914 the Tokyo Station was opened. Its front section looked almost the same in 2019:

After 1920 you could go from Tokyo to Paris on a single ticket, in 15 days:

On day 13 you reached Warsaw by Polish State Railways, and on day 14 Berlin:

The subways in Tokyo are usually elevated. They look more like Berlin's S-Bahn in the photo above than London's underground.

Have you noticed that there are no English-language descriptions in the photos above? That's how it is at the Railway Museum in Saitama. The Google Translate app with the image scanning option comes handy. The other railway museum I visited, Tokyo Metro Museum in Kasai, has descriptions in English, although the quality of translations could be better:


The Tokyo Metro founder, Noritsugu Hayakawa travelled to the UK and the US to learn, buy and licence equipment. More recently, the Chinese got the railway technology for their high speed trains from Japan and Europe - the US is out.

The first metro in the Orient was based on the New York Subway technology:
Subway car 1001 

Subway car 301



 The first 2.2 km section of the metro opened in 1927, and the passengers could not be more excited:


The metro was needed because the trams did not have enough capacity. This photo from 1938 shows both the trams and the new elevated metro:

Today, the Tokyo Metro network is quite extensive:

Tokyo Metro is ready for passengers getting stuck at stations (because of earthquakes):

 In the elevators:

 In case of flooding:

The company is also gradually installing platform edge doors to prevent accidents and suicides. The half-height type looks like this: 






Did you know there were elephants in Japan as recently as 24 thousand years ago?

I thought, the rail was the rail, but nope, there are different sizes/weights:



Back to the JR East museum. This is an amazing photo of the first Shinkansen train, 0 series, with max speed of 210 km/h that started operating between Tokyo and Osaka in 1964:


Shinkansen run on dedicated tracks, standard gauge, mild curves, low gradient, few stops, many overpasses and tunnels, 25 kV AC power.


Shinkansen have wider bodies, the catenary tension is higher, and compensating for thermal expansion of rails is done like this:

Japan was making some futuristic looking trains already before the Shinkansen. The predecessor of Series 181, looked very similar and was already made in 1958. The 181 was a narrow gauge train with max speed of 110 km/h:



The 200 series, 210 km/h:

The 400 series "mini" Shinkansen, max speed 240 km/h. The "mini" part is about the body being narrower (2.947 m) than in the standard Shinkansen (3.385 m). You can see it clearly in the economy (2nd class) seating configuration: 3-2 per row in Shinkansen and 2-2 in mini Shinkansen. Funnily enough, some (most?) European high speed trains are even narrower without the "mini" in their name. The New Pendolino is only 2.83 m wide, ICE 4 is 2.852 m wide, Frecciarossa 1000 is 2.924 m wide. Only the wide gauge (Russian) Siemens Velaro is 3.265 m wide.



The even wider at 3.43 m, double-deck, 1235-passenger, E1 series, no longer in service, max speed 240 km/h:


And finally, the E5 series, 320 km/h:







 The turntable at the JR East museum:


The railway infrastructure is very visible in Tokyo:
Tokyo cityscape with a train station
Lot's of concrete here

Double-deck station

 
Double deck tracks next to high-rises


Road under train tracks

Trains going into a tunnel

Double-deck train station over a river

A very common E216 series
Tokyo subway operators use a standard gauge (1435 mm) track on the original underground lines with 3rd rail, and a narrow gauge (1067 mm) track on other lines. Tokyo railways (JR East) use a narrow gauge on all lines except Shinkansen. Can you recognise the gauge in these cab videos?