South Korean public transit isochrones

This thread is just for me to document my journey in using this tool.

To start I use this configuration.

graphhopper:
  datareader.file: south-korea.osm.pbf
  gtfs.file: south-korea-gtfs.zip
  graph.location: graph-cache/sk-transit

  profiles:
    - name: foot
      custom_model_files:
        - foot.json
      # optionally add
      #  - foot_elevation.json

  import.osm.ignored_highways: motorway,trunk
  graph.encoded_values: foot_access, foot_average_speed, hike_rating, foot_priority

server:
  application_connectors:
    - type: http
      port: 8989
      bind_host: localhost
  admin_connectors:
    - type: http
      port: 8990
      bind_host: localhost

The GTFS data comes from the 국가교통DB (National Transportation DB) of South Korea. I had to modify the agency so that the timezone is correct.

Next I run this command to start it up (Yes the heap needs 14GB):

java -Xmx14g -Ddw.graphhopper.datareader.file=south-korea.osm.pbf -jar web/target/graphhopper-web-*.jar server config-sk.yml

Someone may also find this flake to be useful.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    systems.url = "github:nix-systems/default";
    devenv.url = "github:cachix/devenv";
  };

  outputs = {
    self,
    nixpkgs,
    devenv,
    systems,
  } @ inputs: let
    forEachSystem = nixpkgs.lib.genAttrs (import systems);
  in {
    devShells = forEachSystem (system: let
      pkgs = import nixpkgs {inherit system;};
    in {
      default = devenv.lib.mkShell {
        inherit inputs pkgs;
        modules = [
          ({
            pkgs,
            lib,
            ...
          }: let
          in {
            # https://devenv.sh/languages/
            languages.java.enable = true;
            languages.java.maven.enable = true;
            languages.java.gradle.enable = true;
            languages.java.jdk.package = pkgs.jdk21;
          })
        ];
      };
    });
  };
}

Here’s an example request that seemed to work after it was all configured:

http://localhost:8989/isochrone?point=37.5479729%2C127.0735641&time_limit=2700&profile=pt&pt.earliest_departure_time=2024-04-26T09%3A00%3A00.821104%2B09%3A00&arrive_by=true&reverse_flow=true

I used this python to query it. I expect the result to show me all the points I can start from such that I arrive at the point specified by the time in pt.earliest_departure_time (possibly a misnomer as I’ve set arrive_by and reverse_flow to true).

import requests
import datetime

# Gets GeoJSON data
def get_data_from_graphhopper_instance(start, travel_duration):
    api_url = "http://localhost:8989/isochrone"
    
    now = datetime.datetime.now(tz=datetime.timezone(datetime.timedelta(hours=9)))
    if now.time() < datetime.time(9, 0, 0):
        #It's before 9 so give me today at nine
        nine_oclock = now.replace(hour=9, minute=0, second=0, microsecond=0)
    else:
        #It's after 9 so give me tomorrow at nine
        nine_oclock = now.replace(day=(now + datetime.timedelta(days=1)).day, 
                                  hour=9, 
                                  minute=0, 
                                  second=0)
    if now.date().weekday() >= 4:
        days_until_monday = (7 - nine_oclock.date().weekday()) % 7
        nine_oclock = nine_oclock + datetime.timedelta(days=days_until_monday)
    
    query_params = {
        'point': f'{start[0]},{start[1]}',
        #'time': nine_oclock.isoformat(),
        'time_limit': travel_duration,
        'profile': "pt",
        'pt.earliest_departure_time': nine_oclock.isoformat(),
        'arrive_by': 'true',
        'reverse_flow': 'true',
    }
    
    response = requests.get(api_url, params=query_params).json()
    #print(response)
    return response

In any case, here’s a nice screenshot of what I have so far. This an isochrone map in 5 minute intervals showing travel time 45 minutes to my university in Seoul.

1 Like