Shortest flight path

  1. Import the airports.ttl dataset, which contains airports and flights.

  2. Display the airports on a map using the latitude and longitude properties.

  3. Find the shortest path between airports in terms of number of flights.

<html>
<body>
<!-- Include the library -->
<script src="../lib/ogma.min.js"></script>
<script src="../lib/jquery-3.2.0.min.js"></script>
<script src="commons.js"></script>
<script src="../lib/lodash.js"></script>

  <style>
    #graph-container { top: 0; bottom: 0; left: 0; right: 0; position: absolute; margin: 0; overflow: hidden; }
    .info {
      position: absolute;
      color: #fff;
      background: #141229;
      font-size: 12px;
      font-family: monospace;
      padding: 5px;
    }
    .info.n { top: 0; left: 0; }
  </style>

<!-- This div is the DOM element containing the graph. The style ensures that it takes the whole screen. -->
<div id="graph-container"></div>
<div id="n" class="info n">loading a large graph, it can take a few seconds...</div>

<script>

// The query to visualize
var airportsQuery = `
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
construct {
    ?source <http://openflights.org/resource/route/hasFlightTo> ?dest.
    ?dest rdf:type ?dtype .
    ?dest rdfs:label ?destLabel .
    ?source rdf:type ?stype .
    ?source rdfs:label ?sLabel .
    ?source <http://openflights.org/resource/airport/latitide> ?sourceLat .
    ?dest <http://openflights.org/resource/airport/latitide> ?destLat .
    ?source <http://openflights.org/resource/airport/longtitude> ?sourceLong .
    ?dest <http://openflights.org/resource/airport/longtitude> ?destLong .
} where {
    ?flight <http://openflights.org/resource/route/destinationId> ?dest .
    ?flight <http://openflights.org/resource/route/sourceId> ?source .
    ?flight rdf:type ?ftype .
    ?dest rdf:type ?dtype .
    ?dest rdfs:label ?destLabel .
    ?source rdf:type ?stype .
    ?source rdfs:label ?sLabel .
    ?source <http://openflights.org/resource/airport/latitide> ?sourceLat .
    ?dest <http://openflights.org/resource/airport/latitide> ?destLat .
    ?source <http://openflights.org/resource/airport/longtitude> ?sourceLong .
    ?dest <http://openflights.org/resource/airport/longtitude> ?destLong .
}
`;

var typePredicate = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
var labelPredicate = "http://www.w3.org/2000/01/rdf-schema#label";
var latitudePredicate = "http://openflights.org/resource/airport/latitide";
var longtitudePredicate = "http://openflights.org/resource/airport/longtitude";


var postData = {
	query: airportsQuery,
	infer: true,
	sameAs: true,
	// limit: 10000
}

var startNode = 'http://openflights.org/resource/airport/id/1194';
var endNode = 'http://openflights.org/resource/airport/id/4061';


$.ajax({
	url: 'http://localhost:8082/repositories/airroutes',
	type: 'POST',
	data: postData,
	headers: {
		'Accept': 'application/rdf+json'
	},
	success: function (data) {

		var triples = convertData(data);

		// Get all nodes uris
		var linkTriples = _.filter(triples, function (triple) {
			return triple[1] !== typePredicate && triple[1] !== labelPredicate && triple[1] != latitudePredicate && triple[1] != longtitudePredicate
		});
		var nodesUris = _.uniq(_.union(_.map(linkTriples, function (t) {
			return t[0]
		}), _.map(linkTriples, function (t) {
			return t[2]
		})));

		// Get triples for types
		var typeTriples = _.filter(triples, function (triple) {
			return triple[1] === typePredicate
		});
		var labelTriples = _.filter(triples, function (triple) {
			return triple[1] === labelPredicate
		});
		var latitudeTriples = _.filter(triples, function (triple) {
			return triple[1] === latitudePredicate
		});
		var longtitudeTriples = _.filter(triples, function (triple) {
			return triple[1] === longtitudePredicate
		});

		// Create node objects
		var nodes = _.map(nodesUris, function (nUri) {
			var type = _.find(typeTriples, function (typeTriple) {
				return typeTriple[0] === nUri && typeTriple[1] === typePredicate
			});
			var label = _.find(labelTriples, function (labelTriple) {
				return labelTriple[0] === nUri && labelTriple[1] === labelPredicate
			});
			var latitude = _.find(latitudeTriples, function (latTriple) {
				return latTriple[0] === nUri && latTriple[1] === latitudePredicate
			});
			var longtitude = _.find(longtitudeTriples, function (longTriple) {
				return longTriple[0] === nUri && longTriple[1] === longtitudePredicate
			});
			return {
				id: nUri,
				text: (label != undefined) ? (label[2] + "(" + getLocalName(nUri) + ")") : getLocalName(nUri),
				size: 0.5,
				color: ((type != undefined) ? stringToColour(type[2]) : "#eceeef"),
				latitude: (latitude != undefined) ? parseFloat(latitude[2]) : 0,
				longitude: (longtitude != undefined) ? parseFloat(longtitude[2]) : 0,
			}
		});

		// Create edge objects
		var edges = _.map(linkTriples, function (triple, index) {
			return {
				id: index,
				source: triple[0],
				target: triple[2],
				text: getLocalName(triple[1]),
				shape: 'arrow',
				size: 0.5
			}
		});

		var url = Ogma.utils.pixelRatio() === 2 ? // retina displays
			'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}@2x.png' :
			'https://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png';

		// Initialize ogma with the data
		var ogma = new Ogma({
			container: 'graph-container',
			settings: {
				geo: {
					tileUrlTemplate: url, // indicates from which server the tiles must be retrieved
					sizeZoomReferential: 5, // Paris will be displayed with a radius of 8 pixels on the screen if the geographical zoom is 5
					attribution: '<div class="attribution">Map data © <a target="_blank" href="http://osm.org/copyright">OpenStreetMap contributors</a></div>'
				},
				texts: {
					nodeFontSize: 20,
					edgeFontSize: 15,
					nodeBackgroundColor: '#fff',
				}
			},
			graph: {
				nodes: nodes,
				edges: edges
			}
		});

		ogma.geo.enable();

		var pathNodes = ogma.pathfinding.dijkstra(startNode, endNode);
		if (pathNodes) {
			var ids = pathNodes.map(function (node) {
				return node.id
			});

			// Color the path
			for (var i = 0; i < pathNodes.length; i++) {
				pathNodes[i].color = '#86315b';
				pathNodes[i].size = 2;

				ogma.topology.getAdjacentEdges(pathNodes[i]).forEach(function (edge) {
					if (ids.indexOf(edge.source) != -1 && ids.indexOf(edge.target) != -1 && ids.indexOf(edge.source) < ids.indexOf(edge.target)) {
						edge.color = '#86315b';
						edge.size = 0.4
					}
				});
			}
		}

		document.getElementById('n').textContent = 'nodes: ' + ogma.graph.nodes.length + '; edges: ' + ogma.graph.edges.length;
	}
})

</script>
</body>
</html>

Which produces the following graph:

../_images/map.png