[JAVA] Créez une carte du métro de Tokyo à partir du fichier CSV de la station data.jp

introduction

C'est un petit article ancien, mais j'ai lu "Comment obtenir les données de base des stations et des routes - Qiita" et j'ai appris qu'il existe des données CSV des routes. C'était. Créons une carte du métro de Tokyo en utilisant le fichier CSV dans "Station data.jp" présenté dans cet article. La version de Java utilisée est la 14. Utilisez yEd --Graph Editor pour afficher le graphique. Tout le code source peut être trouvé ici [https://gist.github.com/saka1029/7d08fef8744a508b29e1c8206510f21e).

Télécharger

Téléchargez les données d'itinéraire, les données de la station et les données de la station connectée à partir de Ma Page | Téléchargement gratuit de données de station "Station Data.jp".

マイページ _ 駅データ 無料ダウンロード 『駅データ.jp』 - Google Chrome 2020_07_15 8_04_35.png

Vous devez créer un compte gratuit pour télécharger.

Lire le fichier CSV

Créez un programme commun qui lit un fichier CSV et le convertit en List <List <String >>.

static final Charset CHARSET = StandardCharsets.UTF_8;
static final Path DIRECTORY = Paths.get("data", "eki");
static final Path LINE_CSV = DIRECTORY.resolve("line20200619free.csv");
static final Path STATION_CSV = DIRECTORY.resolve("station20200619free.csv");
static final Path JOIN_CSV = DIRECTORY.resolve("join20200619.csv");
static final Path GML = DIRECTORY.resolve("metro.gml");

static List<List<String>> readCSV(Path file) throws IOException {
    return Files.readAllLines(file, CHARSET).stream()
        .map(line -> List.of(line.split(",")))
        .collect(toList());
}

Chaque élément n'est pas entouré de guillemets, il peut donc être facilement lu.

Lecture des données d'itinéraire

Tout d'abord, lisez les données d'itinéraire. Puisque nous allons créer une carte du métro de Tokyo, seuls ceux dont les noms de ligne commencent par "Tokyo Metro" ou "Toei" seront extraits.

//Ligne de métro de Tokyo
List<List<String>> lines = readCSV(LINE_CSV).stream()
    .filter(line -> line.get(2).startsWith("Métro de Tokyo") || line.get(2).startsWith("Toei"))
    .collect(toList());

Lecture des données de la station

Ensuite, les données de la station sont lues, mais une liste de codes d'itinéraire est créée afin d'extraire uniquement ceux qui correspondent aux codes d'itinéraire des données d'itinéraire lues précédemment. (Aurait dû être défini au lieu de List)

//Liste des codes de lignes de métro de Tokyo
List<String> lineCodes = lines.stream()
    .map(line -> line.get(0))
    .collect(toList());

Seules les stations avec les codes d'itinéraire dans cette liste seront extraites.

//Station de métro de Tokyo
List<List<String>> stations = readCSV(STATION_CSV).stream()
    .filter(station -> lineCodes.contains(station.get(5)))
    .collect(toList());

Lecture des données de la station de connexion

Enfin, lisez les données de la station de connexion. Encore une fois, seuls ceux liés au code de ligne du métro de Tokyo sont extraits.

//Connexion à la station de métro de Tokyo
List<List<String>> joins = readCSV(JOIN_CSV).stream()
    .filter(line -> lineCodes.contains(line.get(0)))
    .collect(toList());

Créer un graphique

Créez un graphique à partir des données lues. Les graphiques sont lus à l'aide de yEd --Graph Editor, créez donc des données texte au format GML (Graphic Modeling Language).

//Créer un graphique
try (PrintWriter w = new PrintWriter(Files.newBufferedWriter(GML))) {
    w.println("graph [");
    for (List<String> s : stations) {
        w.println("  node [");
        w.println("    id " + s.get(0));     //Code de la station
        w.println("    label \"" + s.get(2) + "\"");  //Nom de la station
        w.println("  ]");
    }
    for (List<String> j : joins) {
        w.println("  edge [");
        w.println("    source " + j.get(1));    //Code station de connexion 1
        w.println("    target " + j.get(2));    //Code de station de connexion 2
        w.println("  ]");
    }
    w.println("]");
}

Créez une station en tant que nœud et une station de connexion en tant que bord.

Premier graphique

Lisez avec yEd et formatez comme suit.

Ensuite, le graphique ressemble à ceci. 13 itinéraires ont été créés séparément. Vous pouvez voir que le coin supérieur gauche est la ligne Oedo car elle comprend la ligne circulaire et la ligne Marunouchi qui comprend la ligne secondaire Honancho car elle est en forme de Y à côté.

metro-最初のプログラム.png

Cependant, ce n'est pas une carte d'itinéraire. La raison en est que la même station est enregistrée séparément pour chaque ligne.

Agrégé par le même nom de station

Les codes de station sont agrégés par ceux qui ont le même nom de station. Le résultat est une carte de la liste, la clé étant le nom de la station et la valeur étant la liste des codes de station avec ce nom de station. Par exemple, Shinjuku = [2800218, 9930128, 9930401].

//Code de station groupé par nom de station(ex.Shinjuku=[2800218, 9930128, 9930401])
Map<String, List<String>> stationNameMap = stations.stream()
    .collect(groupingBy(e -> e.get(2),
        mapping(e -> e.get(0), toList())));

Afin de combiner les codes représentant Shinjuku en un seul, nous allons créer une carte pour convertir le code de station en code de station représentatif. Le code de station qui apparaît en haut de la liste des codes de station est le code de station représentatif. Dans le cas de Shinjuku, ce sera «2800218 = 2800218, 9930128 = 2800218, 9930401 = 2800218».

//Carte du code de station au code de station représentatif(ex. 2800218=2800218, 9930128=2800218, 9930401=2800218)
Map<String, String> stationCodeMap = stationNameMap.values().stream()
    .flatMap(codes -> codes.stream().map(code -> Map.entry(code, codes.get(0))))
    .collect(toMap(Entry::getKey, Entry::getValue));

Créer un graphique qui regroupe les mêmes noms de stations

Créez un graphique qui résume les mêmes noms de stations.


//Créer un graphique
try (PrintWriter w = new PrintWriter(Files.newBufferedWriter(GML))) {
    w.println("graph [");
    for (Entry<String, List<String>> e : stationNameMap.entrySet()) {   //Utilise des données agrégées par nom de station
        w.println("  node [");
        w.println("    id " + e.getValue().get(0));     //Code de la station représentative
        w.println("    label \"" + e.getKey() + "\"");  //Nom de la station
        w.println("  ]");
    }
    for (List<String> j : joins) {
        w.println("  edge [");
        w.println("    source " + stationCodeMap.get(j.get(1)));  //Convertir en code de station représentatif
        w.println("    target " + stationCodeMap.get(j.get(2)));  //Convertir en code de station représentatif
        w.println("  ]");
    }
    w.println("]");
}

Quand je le lis avec yEd et le formate, cela ressemble à ceci.

metro-市ケ谷問題あり.png

Intégration d'Ichigaya et d'Ichigaya

Cela ressemble à une carte d'itinéraire, mais il y a deux Ichigaya.

metro-市ケ谷問題あり-拡大.png

Si vous regardez attentivement, vous pouvez voir qu'il y a deux stations Ichigaya en raison de la différence entre "ke" et "ga". Si vous recherchez Ichigaya Station sur Wikipedia, C'est écrit.

Les stations de métro JR East et Tokyo sont appelées «Ichigaya» et les stations de métro Toei sont appelées «Ichigaya».

Dans le graphique

Comme c'est le cas, vous pouvez voir que la station data.jp exprime avec précision cette différence. Pour absorber cette différence, modifiez la lecture des données de station décrites ci-dessus comme suit.

//Station de métro de Tokyo
List<List<String>> stations = readCSV(STATION_CSV).stream()
    .filter(station -> lineCodes.contains(station.get(5)))
    .map(station -> station.stream()
        .map(item -> item.replace('Mois', 'Ke')).collect(toList())) // 市Mois谷と市Ke谷を統一
    .collect(toList());

Ici, j'ai décidé de l'unifier au style du métro de Tokyo.

Graphique terminé

La forme finale du graphique ressemble à ceci.

metro.png

Résumé

«Otemachi» est près du centre, mais si vous regardez de près, vous trouverez «Nishifunabashi» à l'extrémité gauche, «Ogikubo» à l'extrémité droite, «Nishimagome» à l'extrémité supérieure et «Nishitakashimadaira» à l'extrémité inférieure. On a l'impression que l'est et l'ouest et le nord et le sud sont inversés. Cela est inévitable car le graphique ne donne que des informations géométriques de phase, mais comme les données de la station comprennent également des informations sur la latitude et la longitude de la station, créez une carte d'itinéraire géographiquement précise. Pourront. Le nœud GML a également un attribut de couleur, vous pouvez donc coder en couleur chaque route. yEd est disponible dans une variété de mises en page, il est donc intéressant de les expérimenter. La plupart des programmes que j'ai créés cette fois utilisent l'API Stream. Je l'ai trouvé très pratique car la plupart d'entre eux peuvent être décrits de manière concise avec "une doublure".

Recommended Posts

Créez une carte du métro de Tokyo à partir du fichier CSV de la station data.jp
J'ai créé un outil pour afficher la différence du fichier CSV
Créez un fichier jar avec la commande
Trouvez la différence à partir d'un multiple de 10
Créer une carte multi-touches avec une bibliothèque standard
Essayez de créer un modèle tridimensionnel (format PLY) à partir de la carte topographique numérique DSM de toute la préfecture de Hyogo
3. Créez une base de données à laquelle accéder à partir du module Web
Créez un fichier Jar avec deux lignes de commande
Extraire un élément spécifique de la liste des objets
21 Lire et exécuter le script à partir du fichier
Un record d'étude du Spring Framework à partir de zéro
Comment créer un formulaire pour sélectionner une date dans le calendrier
Scraping de la page de campagne GoToEat Osaka dans un fichier csv
À propos du comportement lors de la création d'un mappage de fichiers avec Java
Pourquoi insérer un saut de ligne à la fin du fichier
Créez un grand nombre d'enregistrements avec une seule commande à l'aide du fichier seeds.rb Ruby on Rails
[Java] Créer un fichier temporaire
Comment créer un fichier jar et un fichier war à l'aide de la commande jar
Obtenez l'URL publique du fichier privé de Flickr en Java
Créons une application TODO en Java 5 Changer l'affichage de TODO
[chown] Comment changer le propriétaire d'un fichier ou d'un répertoire
Créez un calendrier à partir de la classe Calendar en spécifiant l'année et le mois