[JAVA] Lassen Sie uns Force-Graph des Eisenbahnnetzes aus dem öffentlichen Verkehr von Tokio Daten öffnen

Open Data Challenge für öffentliche Verkehrsmittel in Tokio

In der Open Data Challenge für öffentliche Verkehrsmittel in Tokio werden wichtige Daten zu öffentlichen Verkehrsmitteln in der Metropolregion als Open Data veröffentlicht und die "3. Open Data Challenge für öffentliche Verkehrsmittel in Tokio". Wenn Sie eingeben, wird ein Zugriffstoken ausgestellt und Sie können die API verwenden. Ich habe die Seite während GW kennengelernt und vorerst versucht einzutreten.

Überblick

Da ich in einer ländlichen Gegend lebe, weiß ich nicht viel über das Eisenbahnnetz in der Metropolregion. Aus diesem Grund die Metropolitan Area Railway, die Informationsorganisation und Studie der API Tokyo Open Data Challenge und D3.js kombiniert. Ich habe ein Netto-Force-Diagramm erstellt.

Inhalt / Verfahren

1. Organisieren Sie Daten mit der ODPT Train API

Wir haben Routen- und Stationsinformationen mit "ODPT Train API" gesammelt und die Daten mit Java organisiert. Der Quellcode wird unten angezeigt. Der http-Client verwendet OkHttp und die JSON-Verarbeitung verwendet Gson. Eine Railline-Instanz wird generiert, indem der "Routenname", die "eindeutige Kennung" und die "Routenstation" der Route aus der Antwort (JSON) der "ODPT Train API" sowie der "Stationsname" und die "eindeutige Kennung" der Station in der Route extrahiert werden. , "Stationsinstanz wird aus" zugehöriger Routenkennung "generiert. Stationen scheinen für jede Leitung eindeutige Kennungen zugewiesen zu haben, daher werden Informationen nach "Stationsname (japanischer Name)" zusammengefasst.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class Test {
	private static final String URL_TOKYO_CH="https://api-tokyochallenge.odpt.org/api/v4/";
	private static final String KEY_TOKYO_CH="Zugangstoken";

	@SuppressWarnings({ "unused", "rawtypes", "unchecked" })
	public static void main(String[] args){
        OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
        okHttpBuilder.connectTimeout(20, TimeUnit.SECONDS);
        okHttpBuilder.readTimeout(20, TimeUnit.SECONDS);
        okHttpBuilder.writeTimeout(20, TimeUnit.SECONDS);
        OkHttpClient client=okHttpBuilder.build();
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        List<Map> list=trainAPI(client,gson,"odpt:Railway");
        Map<String,Station> stations=new HashMap<String,Station>();
        List<RailLine> raillines=new ArrayList<RailLine>();
    	for(Map map : list){
    		RailLine line=new RailLine();
    		line.name_ja=((Map)map.get("odpt:railwayTitle")).get("ja").toString();
    		line.name_en=((Map)map.get("odpt:railwayTitle")).get("en").toString();
    		line.sameAs=map.get("owl:sameAs").toString();
    		line.operator=map.get("odpt:operator").toString();
    		List<Map> ll=(List<Map>)map.get("odpt:stationOrder");
    		for(Map o : ll){
    			String st=((Map)o.get("odpt:stationTitle")).get("ja").toString();
    			line.stations.add(st);
    			if(stations.containsKey(st)){
    				Station s=stations.get(st);
    				s.lines.add(line.name_ja);
    			}else{
    				Station s=new Station();
    				s.sameAs=o.get("owl:sameAs").toString();
    				s.name_ja=((Map)o.get("odpt:stationTitle")).get("ja").toString();
    				s.name_en=((Map)o.get("odpt:stationTitle")).get("en").toString();
    				s.lines.add(line.sameAs);
    				stations.put(s.name_ja, s);
    			}
    		}
    		raillines.add(line);
    	}
    	Map<String,Object> ret=new HashMap<String,Object>();
    	ret.put("stations", stations);
    	ret.put("raillines", raillines);
        File f=new File("railway.json");
        BufferedWriter bw=null;
        try{
        	bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f),"UTF-8"));
        	bw.write(gson.toJson(ret));
        	bw.flush();
        	bw.close();
        	bw=null;
        }catch(Exception e){
        	e.printStackTrace();
        }finally{
        	if(bw!=null){
        		try{bw.close();}catch(Exception e){}
        	}
        }
	}

	@SuppressWarnings("unchecked")
	private static List<Map> trainAPI(OkHttpClient client,Gson gson,String odpc){
		String url=URL_TOKYO_CH+odpc+"?acl:consumerKey="+KEY_TOKYO_CH;
		System.out.println(url);
        try{
    		Request request = new Request.Builder()
                    .url(url)
                    .get()
                    .build();
            Response response = client.newCall(request).execute();
    		return gson.fromJson(response.body().string(), List.class);
        }catch(Exception e){
        	e.printStackTrace();
        	return null;
        }
	}

	static class Station{
		public String name_ja;
		public String name_en;
		public String sameAs;
		public List<String> lines=new ArrayList<String>();
	}
	static class RailLine{
		public String name_ja;
		public String name_en;
		public String sameAs;
		public String operator;
		public List<String> stations=new ArrayList<String>();
	}
}

2. JSON ausgeben

Wenn Sie den obigen Code ausführen, wird die folgende JSON-Datei ausgegeben. Wenn ich das betrachte, habe ich das Gefühl, dass mein Verständnis des Eisenbahnnetzes in der Metropolregion Tokio gestiegen ist und sagt: "Es gibt solche Linien und es gibt Stationen wie diese."

{
  "raillines": [
    {
      "name_ja": "Tokyo Sakura Tram (Toden Arakawa Linie)",
      "name_en": "Tokyo Sakura Tram (Arakawa Line)",
      "sameAs": "odpt.Railway:Toei.Arakawa",
      "operator": "odpt.Operator:Toei",
      "stations": [
        "Minowa-Brücke",
        "Arakawa Ichichu Mae",
        "Vor dem Büro der Gemeinde Arakawa",
        "Arakawa 2-chome",
        "Arakawa 7-chome",
        "Vor dem Bahnhof Machiya",
        "Machiya 2-chome",
        "Higashio Hisa 3-chome",
        "Vor Kumano",
        "Miyano-mae",
        "Kleiner Stand",
        "Vor dem Vergnügungspark Arakawa",
        "Vor der Arakawa Garage",
        "Kajiwara",
        "Sakaemachi",
        "Vor der Oji Station",
        "Asukayama",
        "Takinogawa 1-chome",
        "Nishigahara 4-chome",
        "Shinko Shinzuka",
        "Koshinzuka",
        "Negamo Nitta",
        "Vor der Otsuka Station",
        "Mukaihara",
        "Higashi Ikebukuro 4-chome",
        "Toden Verschiedenes Shigaya",
        "Kishimojinmae",
        "Unter dem Studienzentrum",
        "Omokage-Brücke",
        "Waseda"
      ]
    },
/*****Kürzung*******/
  "stations": {
    "Serada": {
      "name_ja": "Serada",
      "name_en": "Serada",
      "sameAs": "Serada",
      "lines": [
        "odpt.Railway:Tobu.Isesaki"
      ]
    },
    "Higashi Toshozawa": {
      "name_ja": "Higashi Toshozawa",
      "name_en": "Higashi-Tokorozawa",
      "sameAs": "Higashi Toshozawa",
      "lines": [
        "odpt.Railway:JR-East.Musashino"
      ]
    },
/*****Kürzung*******/

3. Zeigen Sie Force-Graph in D3.js an

Ich habe die Routen- / Stationsinformationen in D3.js geladen und Force-Graph generiert. Ich habe Force-Graph zum ersten Mal mit D3.js erstellt, war aber überrascht, dass es viel einfacher zu erstellen war als beim Schreiben von GraphLayout mit Java. D3.js ist unglaublich.

<!DOCTYPE html>
<html>
<head>
    <title>tokyo-challenge-test</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"></script>
</head>
<body>
<svg></svg>
<script type="text/javascript">
    let width = 1200;
    let height = 800;
    const loadData = () => {
        d3.json("railway.json").then(function(json) {
            createMap(json);
        });
    };
    const createMap=(json)=>{
        const rail=json.raillines;
        const station=json.stations;
        let nodes=[];
        let links=[];
        let check={};
        let idv=0;
        for(let i=0;i<rail.length;i++){
            let sts=rail[i].stations;
            let tmp=[];
            for(let j=0;j<sts.length;j++){
                if(!check[sts[j]]){
                    let p={id:idv++,label:station[sts[j]].name_ja,val:1};
                    tmp.push(p);
                    nodes.push(p);
                    check[sts[j]]=p;
                }else{
                    check[sts[j]].val=check[sts[j]].val+1;
                    tmp.push(check[sts[j]]);
                }
            }
            for(let i=1;i<tmp.length;i++){
                let l={source:tmp[i-1].id,target:tmp[i].id};
                links.push(l);
            }
        }
        const svg = d3.select("svg").attr("width",width).attr("height",height);
        const link = d3.select("svg")
            .selectAll("line")
            .data(links)
            .enter()
            .append("line")
            .attr("stroke-width", 1)
            .attr("stroke", "#ccc");
        const node = d3.select("svg")
            .selectAll("g")
            .data(nodes)
            .enter()
            .append("circle")
            .attr("r",function(d){return d.val*5;})
            .attr("fill", "orange")
            .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));
        const label = d3.select("svg")
            .selectAll("g")
            .data(nodes)
            .enter()
            .append("text")
            .attr("text-anchor", "middle")
            .attr("dominant-baseline", "middle")
            .style("fill", "steelblue")
            .style("font-size", "9px")
            .text(function(d){return d.label;});
        const simulation = d3.forceSimulation()
            .force("link", d3.forceLink())
            .force("center", d3.forceCenter(600, 450))
            .force("charge", d3.forceManyBody().strength(-8))
            .force("x", d3.forceX().strength(0.05).x(width / 2))
            .force("y", d3.forceY().strength(0.05).y(height / 2));

        simulation.nodes(nodes).on("tick", ticked);
        simulation.force("link").links(links);
        function ticked() {
            link.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
            node.attr("cx", function(d) { return d.x; })
                .attr("cy", function(d) { return d.y; });
            label.attr("x", function(d) { return d.x; })
                .attr("y", function(d) { return d.y; });
        }
        function dragstarted(d) {
            if(!d3.event.active) simulation.alphaTarget(0.3).restart();
            d.fx = d.x;
            d.fy = d.y;
        }
         function dragged(d) {
            d.fx = d3.event.x;
            d.fy = d3.event.y;
        }
        function dragended(d) {
            if(!d3.event.active) simulation.alphaTarget(0);
            d.fx = null;
            d.fy = null;
        }
        const zoom = d3.zoom()
            .scaleExtent([1/4,4])
            .on('zoom', function(){
                node.attr("transform", d3.event.transform);
                link.attr("transform", d3.event.transform);
                label.attr("transform", d3.event.transform);
            });
        svg.call(zoom);
    }
    loadData();
</script>
</body>
</html>

Schließlich

Es gibt zu viele Stationen und Routen, daher ist die Grafik nicht klar, aber es war überraschend, dass es an der Shinjuku Station und der Shibuya Station mehr Routen gibt als an der Ueno Station. Ich möchte etwas mehr Anzeige entwickeln und Daten wie die Entfernung zwischen jeder Station und dem zu spielenden Tarif hinzufügen.

Recommended Posts

Lassen Sie uns Force-Graph des Eisenbahnnetzes aus dem öffentlichen Verkehr von Tokio Daten öffnen
Lassen Sie uns ein Pseudomodell mit active_hash ~ Präfekturdaten ~ erstellen
Lass uns einen Roboter bauen! "Eine einfache Demo von Java AWT Robot"