13
Cartographic Data

13.1. Cartographic application: using cartographic libraries

A cartographic application is of a level of complexity greater than a simple graphic plot, as we have described earlier. We will not try to code it ourselves, even if, for most of the libraries (open source or proprietary), they just draw on a <canvas>. There are various methods for drawing lines or polygons or pixel matrices, for computing topological relations such as sharing a vertex, being included or intersecting each other, and also for computing distances, transforming geographical coordinates between map projections, etc.

It is not our intention to detail any of these numerous features. We will merely present the basic use of one library, open source, which is complete enough to sample all of the most useful features, in a way similar to those of proprietary libraries such as Google, Bing and Yahoo. That library is OpenLayers, code licensed under the “2-Clause BSD”, with a very active community (2006–2017): at the time of writing this book, the latest version is v4.6.5 (March 18, 2018).

The requirements are the library, the basic styles, and a simple <div> element (or a <canvas>) that will be used by the library:

 <link rel="stylesheet" href=
 "https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.css">
 <body>
 <div id="olmap" class="olmap"></div>
 <script src=
 "https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.4/ol.js">
 </script>

In this application, we use data from four sources:

  • – a list of French universities, schools of engineering, management, fine arts, etc. as well as large French research institutions, public ones, such as CNRS, Inra, Inria, Inserm, and some private laboratories. Their geographical coordinates are extracted from their Wikipedia pages (they all have one);
  • – a list of universities from Quebec, the CEGEPS of Quebec and a few laboratories as well. The coordinates have also been extracted from Wikipedia (see section 13.3);
  • – a list of partnerships between higher education institutions or research laboratories from Quebec and France. Such partnerships can be extracted from lists provided by the universities, from the Federation des CEGEPS and from the lists of joint projects funded by the France-Quebec official partnerships (Samuel de Champlain program, CFQCU, etc.);
  • – the cartographic source used by the openlayers library: we use OpenStreetMap®, which is open data licensed under the Open Data Commons Open Database License (ODbL) by the OpenStreetMap Foundation (OSMF).

The three lists are JSON files. We must make a join, in a way similar to the electoral application, between the list of partnerships and the list of institutions of Quebec (respectively, France). The common key is a normalized label of the institution (the process of normalizing is not described). The first join links the partnerships data with the coordinates of the single point associated with each institution. We can define an activity index whose value is the number of partnerships of each institution.

What is really specific in this application is the second join, between the coordinates of the points representing the institutions and the points actually displayed on the canvas by the OpenLayers library. That cartographic join allows us to transform the activity of each institution into a marker on the map, displaying that activity: the marker is a circle whose center is the point representing the institution and whose radius is proportional to the activity index.

Here is an example of what we can display on the map of Québec. One similar map can be drawn to display the same activity on the France side.

image

Figure 13.1. Cartographic application: full display of all data

In this chapter, we will focus on the cartographic join. There are two main operations: the preparation of the map and the display of the markers.

13.1.1. Preparation of the map

The sequence of operations to be performed is pretty much the same with every available cartographic library. This code details the sequence with OpenLayers:

function prepareMap(latlon, zoom) {
   const sourceUnivs = new ol.source.Vector({});    // empty source
   const layerUnivs = new ol.layer.Vector({ // markers's layer
             title: 'Universities',
             source: sourceUnivs
   });
   const center = ol.proj.fromLonLat([latlon[1],latlon[0]]);
   const map = new ol.Map({
       target: canvasName,
       layers: [new ol.layer.Tile({source: new ol.source.OSM()})],
       view: new ol.View({center, zoom})
   });
   map.on('singleclick', function(e){/* handler: click on map */});
 }

The construction map object requires several predefined objects:

  • – target: the drawing surface, the <canvas> element in the HTML DOM;
  • – layers: there is generally one basic layer as the background on top of which to draw other specific layers. The basic layer is the “tiled” version of OpenStreetMaps, referred to as the ol.source.OSM(), a given feature of the openlayers library. Moreover, the specific layer for the markers that we will compute later as circles, must be set as an ol.layer.Vector() feature: we name it Universities and we attach its source (see below);
  • – sources: OSM is the first source. The specific Vector layer requires a new source, which we set as ol.source.Vector({}) and leave empty ({}) at first;
  • – view: the map is a representation of the real world on a flat surface and we need to define which part of the world is to be displayed, using a center location and a zoom factor;
  • – controls: this is optional. Default values controls the ± signs for interactively modifying the zoom, the scale rule, or other features, which we may optionally modify;
  • – overlay: an optional special kind of layer which we can use, for instance, with click popups, displaying information linked to a marker.

For short, we can say that, for making a map, we need one or several sources to be displayed in as many layers, transposed within a view, displayed onto a target, and we can add specific controls and display some additional overlays.

13.1.2. Creating a layer of markers

For each university, we want to compute a marker representing its activity in terms of its number of partnerships. The marker is, a circle, that is, a geometric feature in the vector source, defined by a center and a radius. In the code below, the object univMark = new ol.Feature({geometry, name, properties}) is that feature, initialized with an ol.geom.Circle() geometry, with an identified name, and some additional properties: {id,np,content}, which can be used for a popup overlay.

Here is a sample code for the creation of these circles:

const fill = new ol.style.Fill({color:'rgba(255,0,0,0.4)'}),
const stroke = new ol.style.Stroke({color:'rgb(0,0,0,1), width:1})
function makeMarker(x, y, np, content, id, fill, stroke) {
   let rad = np * 150 + 2500; // @np: number of partners
   let cen = ol.proj.fromLonLat([y, x]); // @x, @y: point
   const univMark = new ol.Feature({
     "geometry": new ol.geom.Circle(cen, rad, 'XY'),
     "name": id,
     "properties": {id, np, content}
   });
   univMark.setId(id);
   univMark.setStyle(new ol.style.Style({fill, stroke}));
   sourceUnivs.addFeature(univMark);
   return univMark;
 }

Each marker is pushed into an array and we use its index in that array as its id (used in several places above), which we can relate uniquely to the institution, of which it is the marker. We attach a style (stroke and fill) to each marker. In this case, the style is constant, but it could be computed (e.g. a varying color). The variable content is defined elsewhere.

In Figure 13.1, the markers are created with the full list of partnerships of every institution. It is interesting to allow the user to make a selection, according to one or several filters. After each selection, we start with erasing the previous markers, then we compute the new markers: some universities are filtered out, the radius is recomputed according to the filtered partnerships.

Finally, the map must be “refreshed”. Here is the code:

const newMarkers = [];       // start with empty
// partnerships: set by JSON reading
// selectedUnivs: from the handler of the selection form
clearMarkers(newMarkers); newMarkers.length = 0;
selectedUnivs.forEach(function(u) { // reset markers
   let np = u.parts.length;
   let content = makePopupToDisplay(u.parts, partnerships);
   newMarkers.push( makeMarker(u.x, u.y, np, content, u.u) );
 }
layerUnivs.setMap(map); // refresh the map

13.1.3. Interacting and selecting features

Here are the results of selecting the partnerships with the interface form on the left: only major topics in engineering or biology are selected. The next map shows the selection over the keyword image (and displays topics on the right).

image

Figure 13.2. Partnerships selected by major scientific domain

image

Figure 13.3. Partnerships selected by keyword and associated topics

13.2. SVG-based cartography

We have learnt some bases of the SVG language, which can be:

  • – autonomous: an SVG document can be directly rendered in a web page;
  • – embedded: the SVG code can be inserted into an HTML document, providing the associated DTD declaration (xmlns attribute), hence benefiting from DOM access and CSS rules mechanisms.

This application has been used already as illustration in Part 2.

13.2.1. Description of the application

Many SVG data are available on the Internet, and especially geographic maps, by country, region or continent. Once selected, the data file can be read by a simple AJAX request, in plain text mode.

We use an SVG file, from WikiMedia commons, of the borders of the countries of the European continent and the Mediterranean rim. It is several megabytes in size, which is voluminous for text data, meant to be processed initially as a string. Therefore, we have first used a preprocessing that degrades gently the precision of the coordinates and the total number of points used for representing the borders. We can easily find online such “svg-optimizers”: the result is a 340 kB file.

The main element in that file is the <path> element, with its two attributes:

  • – identifier: id=number (supposedly unique);
  • – path descriptor: d= "M83.6619 151.193c-0.2476,0.0627 …z", which generally starts with M and ends with z, which indicates a polygon in the coordinates that complies with the chosen viewport.

Each country is represented by one <path> (simplest case), or several <path>, wrapped into a graphic group <g id=num></g>, and sometimes nested groups. The United Kingdom is in that most complex category (mainland, NI, Gibraltar and a nested group for islands). Each group can be individually selected. Disputed territories, such as Crimea, or the Golan Heights, are represented that same way.

There is a second source, a JSON file containing information about each country:

 {
   "countries": [
     {
       "name": "Germany",
       "capitale": "Berlin",
       "EUmember": "1958",
       "money": "euro",
       "Shengen": "Shengen", "population": "81.5",
       "gdp": "3874.5"
     },
     {}
 ]}

The goal is twofold:

  • – to display the map, therefore, to embed the SVG data into the HTML;
  • – to access each individual element (path or g), to modify their CSS rules and to use the screen coordinates as a selector of the country information linked to the graphic element. Therefore, the join between the two sources must establish that bidirectional link.

13.2.2. Embedding the whole SVG document by direct copy

In Chapter 8, we have described the construction of HTML elements from JavaScript using the “lazy approach”. We can do something similar with the SVG document. It is very simple, perfect for the lazy among us (I often use it):

 <div class="svgExt"><!-- here: the SVG code --></div>
 <script>
// const textSVG = … in the callback of a file request document.querySelector(".svgExt").innerHTML = textSVG;
 </script>

the entire SVG text, from <svg> to </svg>, is copied into the <div>; for instance, if the file has been limited to Monaco, we get:

 <div class="svgExt">
 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 230 192.5">
   <g class="maing" transform="translate(-9,-9)">
     <rect x="10" y="10.15" width="228.02" height="189.85">
     <g class="pays memberstate" id="mc">
       <path class="p0" d="M83.6619 151.193c-0.2476,0.0627 -
 0.5932,0.1566 -0.9258,0.2615l0 0 0.0691 -0.4229c0.2099,-0.203
 0.4828,-0.1426 0.7337,-0.1075 0.0318,0.0044 0.0933,0.259
 0.123,0.2689l0 0z" />
     </g>
   </g>
 </svg></div>

13.2.3. Embedding the SVG code, element by element

This is the second, constructive, approach, where the SVG document is read from file, parsed and each element is added to the HTML DOM, one by one. We must use a special createElement method:

const NSuri = "http://www.w3.org/2000/svg"; // namespace svg2000
const svg = document.createElementNS(NSuri, 'svg');
        // document.createElement('svg') doesn't work

There is a namespace specification for every SVG element in svg2000: <g>, <rect>, <path>, etc This constructive approach is not difficult to code but takes more time. However, we can control every step, and add as many appropriate handlers as we may need.

Once the embedding is done, by either approach, the HTML layout engine takes care of the display using CSS rules: it fills in a blue <rect> for the ocean because of: rect {fill:"light blue"}; draws each country with a white background and a black border, because of: path {stroke:"black"; fill:"white"}; etc.

13.2.4. Joining relational data and SVG data

The identifier chosen for a <g> group representing a country is the standard “a_code”, the Internet domain code of that country. Therefore, we need to join that code with the name of the country, as used in the JSON data file. We use a new JSON file for that purpose, containing couples:

 {"a_code":"de", "name":"Germany"
 {"a_code":"mc", "name":"Monaco"}

The a_code is the value chosen for the id attribute of the <g> elements:

<g id="mc"><path class="pays" d=" … " /></g>

We know how to handle such multiple joins.

13.2.5. Processing the combined information

Here is a simple example: let us select the countries whose money is the euro. The name of the country is joined with the acode and that acode gives access to the right <g> group. Given the list of these <g>, we can “mark” them, for instance by attributing an additional class name: “euro”. Then we can retrieve them and have access to all the concerned <path> elements, and we can change an attribute of their style, for instance the fill color.

Array.from(document.querySeletorAll("g.euro")) // select <g>
 .forEach(function(g){
     Array.from(g.querySelectorAll("path")) // select <path> in g
     .forEach(function(p){p.path.style.fill = 'yellow';});// color
 });
image

Figure 13.4. Join between relational and SVG cartographic data

13.3. Getting coordinates from Wikipedia pages

Here is a very useful feature which we can easily implement: obtaining the coordinates attached to an entry of the Wikipedia encyclopedia.

We can use a direct access to the data through the Wikipedia API1:

   https://en.wikipedia.org/w/api.php?data

followed by the appropriate parameters in the data fields:

action=query         the action type;
prop=coordinates     the property to select;
format=json          the ouput format;
titles= …            name(s) of the page(s) to browse.

For example:

https://en.wikipedia.org/w/api.php?action=query&prop=coordinates&format=json&titles=McGill_University

The result is:

 {"query":{
    "normalized":[{"from":"McGill_University","to":"McGill_University"}],
    "pages":{ "7954643":{
       "pageid":7954643, "ns":0,
       "title":"McGill University",
       "coordinates":[{"lat":45.504166,"lon":-73.574722,"globe":"earth"}]
      }}
 }}

Then we can parse the result, and join the institutionʼs coordinates with extra information on the same institution.

EXERCISE.– use Fetch and what you have learned so far, to plot the capital cities of a few European countries (with a radius proportional to population size).

It is possible to group several pages in the same request (pipe sign):

https://en.wikipedia.org/w/api.php?action=query&prop=coordinates&format=json&titles=McGill_University|Universite_Laval
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.249.42