Ce tutoriel s’adresse à mes deux groupes. Les deux premières parties (Python, QGIS2Web) sont pour les étudiant.e.s dans le cours «Informatique appliquée à l’histoire». La dernière partie (Leaflet) s’adresse aux étudiant.e.s dans mon activité de recherche sur le renseignement militaire russe.

Python

Cette semaine, en complément au tutoriel de Joshua sur le web scraping, j’aimerais présenter quelques bribes de code que j’ai été amené à écrire pendant la session, notamment pour l’activité de recherche sur le renseignement militaire russe. L’activité est divisée en deux avec, pendant la première moitié de la session, dépouillement d’un volumineux corpus sur la Perse, puis, au retour de la semaine de lecture, dépouillement d’un non moins grand corpus sur la Turquie. À la fin de chaque dépouillement, la tradition veut que nous jouions à une sorte de partie de Donjons et Dragons. Il s’agit de tirer les dés pour déterminer qui prend la parole et cette personne dit ensuite ce qu’elle ferait pour assurer une invasion russe des Indes britanniques (pour le premier corpus) et une invasion russe des Détroits (pour le second). Exemple: j’ordonne à mes troupes de prendre Hérat et j’en fais mon poste de commandement et le maillon central de ma chaîne de ravitaillement; ou encore je m’empare de la baie d’Asterabad et j’organise d’Astrakhan à Asterabad des convois maritimes de soldats, de vivres et de munitions à travers la Caspienne. Avant, j’utilisais des dés. Maintenant j’utilise le module random dans Python. J’avais l’habitude d’écrire quelques lignes de code dans la console pour obtenir une liste aléatoire des participants.

import random
genshtab = ["Camille", "CEG", "Henri", "Victoria", "Catherine", "David P.", "Marie-Soleil", "CEB", "JCSJ", "David B.", "Thomas"]
random.shuffle(genshtab)
genshtab
['David P.', 'Camille', 'Henri', 'Victoria', 'Thomas', 'Marie-Soleil', 'CEB', 'CEG', 'JCSJ', 'Catherine', 'David B.']

Mais cela enlevait l’effet de surprise, puisqu’on savait déjà qui parlerait et dans quel ordre. Aussi, j’ai écrit un petit programme qui tire un nom au hasard, puis enlève ce nom de la liste et affiche le nombre de participants restant pour que la personne puisse prendre une décision éclairée (genre, s’il reste encore trois tours, il est trop tôt pour annoncer qu’on s’empare de Calcutta).

import random
genshtab = ["Camille", "CEG", "Henri", "Victoria", "Catherine", "David P.", "Marie-Soleil", "CEB", "JCSJ", "David B.", "Thomas"]

while len(genshtab)>0:
    agent=random.choice(list(genshtab))
    print(agent)
    genshtab.remove(agent)
    print(len(genshtab))
    print("continuer[c], arrêter[a]")
    R=input()
    continuer="c"
    if R == continuer:
        continue
    else:
        break
print("game over")

Un autre programme que j’ai été amené à écrire dans cette activité de recherche pourrait vous être utile un jour. En effet, au moment de compresser vers un zip mes dossiers contenant les sources (pour ensuite les déposer dans Moodle pour les étudiant.e.s), l’opération a échoué parce que presque tous les dossiers comprenaient un apostrophe, ce qui s’explique par le fait qu’un des mots utilisés dans l’archivistique russe en contient un (opis’). Or, l’ordinateur a tendance (on l’a vu) à interpréter les apostrophes comme le début d’une chaîne de caractères, d’où ici le message d’erreur. Il me fallait donc enlever l’apostrophe dans plusieurs centaines de fichiers. À la mitaine, ça m’aurait pris des semaines. Avec Python, ça m’a pris quelques minutes écrire le programme, puis quelques secondes pour que l’opération soit complétée. Voici le programme en question:

import os, sys
import glob

root_dir = "D:\Dropbox\Archives historiques\Renseignement 2017\RGVIA\F-450"

for filename in glob.iglob(root_dir + '*\*', recursive=True):
    print(filename)
    os.rename(filename, filename.replace("΄", "_"))

Un dernier programme utile que j’ai écrit cette session, cette fois pour notre cours «Informatique appliquée à l’histoire», permet de convertir en lot des documents word vers des pdf (c’était pour vos fiches de rétroaction). Il tient en 4 lignes!

from docx2pdf import convert

input = "D:\Dropbox\Cours\Corrections"
output = "D:\Dropbox\Cours\Corrections\pdfs"

convert(input, output)

Encore une fois, pour installer des modules tiers (ici docx2pdf), il faut avoir installé l’installateur pip, comme je l’ai expliqué ailleurs. Ce que j’aurais dû ajouté alors, c’est que pour éviter d’avoir à se situer à chaque fois avec l’invite de commande Windows dans le dossier qui contient pip avec la commande appropriée, soit cd suivi du chemin absolu, on peut éditer le chemin (path) de Python. Joshua nous a fait ce tutoriel sur ce sujet.

J’espère que vous avez apprécié dans ce cours cette introduction au monde de la programmation, en général, et à Python, en particulier. Python est maintenant le troisième langage le plus populaire, avec Java et Javascript. Il est simple, clair et vraiment pratique. Je vous encourage à persister dans son étude. Comme pour toute chose (sport, écriture, musique…), le secret est de pratiquer le plus souvent possible. La prochaine fois que vous vous trouverez devant une tâche ennuyeuse (comme renommer des fichiers ou exporter des images), avant de vous transformer en robot, essayez-vous à imaginer un programme! Et n’oubliez pas que j’ai fait acheter par la bibliothèque du Frère-Théode le livre d’Al Sweigart. Donc quand elle rouvrira, n’hésitez pas à l’emprunter. Sinon, la première édition est disponible en ligne.

QGIS2Web

Non seulement nous avons dans le cours «Informatique appliquée à l’histoire» vu la programmation, mais nous avons aussi couvert les systèmes d’information géographique. Comme vous l’aurez compris, l’avantage des SIG sur les anciennes cartes est que l’on peut superposer des couches et ainsi observer les relations qui existent entre les différents types de données.

01 : Le SIG fournit un langage visuel courant | The ArcGIS Book
Crédits: ArcGIS

La carte papier que vous devez réaliser en équipe dans ce cours ne permet pas une telle interaction. Mais il existe une façon simple de publier votre carte en ligne. Ce n’est pas obligatoire, mais vous pourriez ensuite imprimer un hyperlien sur votre carte vers la version électronique de votre carte ou encore (comme l’un d’entre-vous l’a déjà fait) un code QR qui, une fois scanné avec un téléphone intelligent, ouvrirait la page web de votre carte.

On a vu jusqu’à présent plusieurs extensions vraiment cool (comme Timemanager et QGIS2threeJS). En voici une autre méga cool: QGIS2Web. La première chose à faire est d’ouvrir le projet sur lequel vous travaillez depuis le début de la session. Puis, ouvrez les propriétés du projet (Ctrl+maj+P).

Sous l’onglet approprié, ajoutez un titre et un résumé de votre projet.

Cliquer sur OK. Maintenant, il vous faut télécharger l’extension (car, si ma mémoire est bonne, l’extension n’est pas accessible depuis le gestionnaire d’extensions). Ensuite, dans le gestionnaire d’extensions, choisir d’installer depuis un zip et sélectionner (en cliquant sur les trois points) le fichier que vous venez de télécharger.

Puis cliquer sur installer le plugin. Une fois l’installation terminée, fermer le gestionnaire d’extensions, puis, sous l’onglet Internet, créer une nouvelle carte web.

Sous l’onglet Couches et groupes, sélectionner les couches que vous voulez voir apparaître sur votre carte en ligne et assurez-vous de choisir Leaflet en bas de la fenêtre.

Sous l’onglet Apparences, choisir d’afficher le résumé que vous avez rédigé et choisir l’emplacement (en haut à droite ou en bas à gauche…). Vous pouvez aussi ajouter une boîte de recherche, des outils de mesure, choisir d’afficher la liste déployée des couches ou repliée, limiter le minimum et le maximum du zoom… Explorez ça un peu.

Sous l’onglet Exporter, choisir un endroit dans votre ordinateur pour exporter le projet et cliquer sur Exporter.

L’exportation peut prendre un petit moment, dépendamment de la taille de votre projet et de la puissance de votre ordi. Patience.

Une fois l’exportation terminée, la carte devrait s’ouvrir d’elle-même dans votre navigateur par défaut, sinon retrouvez le dossier que vous venez d’exporter et ouvrez le document index.html. Si on inspecte ce dernier dossier, on voit qu’il contient un index html (que le navigateur ouvre par défaut) et des dossiers CSS et JavaScript. Nous reviendrons là-dessus dans la dernière section de ce tutoriel.

On peut ensuite verser le dossier sur un serveur en se servant d’un logiciel FTP (File Transfer Protocol) comme Filezilla, si on dispose d’un espace sur un serveur.

Dans le cadre du cours «IAH», nous vous proposons d’héberger la version électronique de vos cartes sur historiamatica.ca. Dans le futur, vous pourriez vous tourner vers des services peu onéreux, comme AmazonWS, en espérant qu’ils améliorent leur empreinte environnementale. Voir ce tutoriel. Une fois en ligne, la carte ressemble à ceci.

Bien que QGIS2web soit un outil convivial et pratique, il a aussi ses défauts. Pour un projet simple comme celui-ci, impliquant seulement une carte de fond OSM et des points, ça fonctionne très bien. Pour des projets avec des géométries plus complexes, ça peut ne pas fonctionner. Il se pourrait que votre projet ne soit pas exportable avec cette extension et Joshua et moi ne pourrons vraisemblablement pas vous aider. Les options d’exportation sont également assez limitées. Et pour ce qui est d’ajouter des images dans la table des attributs, c’est très compliqué, voire problématique! Si bien qu’il est peut-être préférable de programmer soi-même sa carte avec Leaflet. Le tutoriel s’arrête ici pour les étudiant.e.s dans mon cours «Informatique appliquée à l’histoire». Pour le genshtab, il se poursuit avec la section suivante.

Leaflet

Notre carte avance très bien. Le problème est que les marqueurs, lignes et polygones sont si nombreux qu’il s’en dégage une impression de chaos.

Pour faire un peu de ménage là-dedans, nous allons voir comment créer des groupes d’attributs (Feature Groups) et ajouter un contrôleur de couches. Donc, commençons par définir nos groupes. En raison de la quarantaine (et je ne parle pas de mon âge), nous n’avons pas pu véritablement discuter en groupe de l’organisation de notre carte, mais j’ai tout de même créé un forum Moodle sur la question et les étudiant.e.s se sont majoritairement prononcé.e.s pour une organisation utilisant les «tags» créés par le groupe en html. Je me suis donc servi le plus possible de ces étiquettes, sauf dans le cas où celles-ci n’étaient pas assez précises (ex.: <em>Perse</em>), pour créer mes groupes.

  var economieGroupe = L.featureGroup();
  economieGroupe.addTo(myMap)

  var EnvironnementGroupe = L.featureGroup();
  EnvironnementGroupe.addTo(myMap)

  var colonialismeGroupe = L.featureGroup();
  colonialismeGroupe.addTo(myMap)

  var militaireGroupe = L.featureGroup();
  militaireGroupe.addTo(myMap)

  var DiplomatieGroupe = L.featureGroup();
  DiplomatieGroupe.addTo(myMap)

  var renseignementGroupe = L.featureGroup();
  renseignementGroupe.addTo(myMap)

  var PresseGroupe = L.featureGroup();
  PresseGroupe.addTo(myMap)

  var geopolitiqueGroupe = L.featureGroup();
  geopolitiqueGroupe.addTo(myMap)

  var technologieGroupe = L.featureGroup();
  technologieGroupe.addTo(myMap)

  var topographieGroupe = L.featureGroup();
  topographieGroupe.addTo(myMap)

  var cultureGroupe = L.featureGroup();
  cultureGroupe.addTo(myMap)

  var ethnoGroup = L.featureGroup();
  ethnoGroup.addTo(myMap)

  var logistiqueGroupe = L.featureGroup();
  logistiqueGroupe.addTo(myMap)

  var marineGroupe = L.featureGroup();
  marineGroupe.addTo(myMap)

  var strategieGroupe = L.featureGroup();
  strategieGroupe.addTo(myMap)

  var religionGroupe = L.featureGroup();
  religionGroupe.addTo(myMap)

  var resistanceGroupe = L.featureGroup();
  resistanceGroupe.addTo(myMap)

  var fortificationsGroupe = L.featureGroup();
  fortificationsGroupe.addTo(myMap)

  var cheminsdeferGroupe = L.featureGroup();
  cheminsdeferGroupe.addTo(myMap)

  var cavalerieGroupe = L.featureGroup();
  cavalerieGroupe.addTo(myMap)

J’ai ensuite créé une variable à l’intérieur de laquelle est attribué un nom à chaque couche, tel qu’il apparaîtra dans le contrôleur de couches.

var couches = {
    "Économie": economieGroupe,
    "Environnement": EnvironnementGroupe,
    "Colonialisme": colonialismeGroupe,
    "Militaire": militaireGroupe,
    "Diplomatie": DiplomatieGroupe,
    "Renseignement": renseignementGroupe,
    "Presse": PresseGroupe,
    "Géopolitique": geopolitiqueGroupe,
    "Technologie": technologieGroupe,
    "Topographie": topographieGroupe,
    "Culture": cultureGroupe,
    "Ethnographie": ethnoGroup,
    "Logistique": logistiqueGroupe,
    "Stratégie": strategieGroupe,
    "Religion": religionGroupe,
    "Résistance": resistanceGroupe,
    "Fortifications": fortificationsGroupe,
    "Marine": marineGroupe,
    "Chemins de fer": cheminsdeferGroupe,
    "Cavalerie": cavalerieGroupe
  };

Il s’est ensuite agi d’ajouter chaque marqueur à un groupe avec la commande appropriée:

LomakinBel.addTo(EnvironnementGroupe)

Le contrôleur de couches nous permet aussi de donner le choix à l’internaute entre diverses cartes de fond. Nous allons donc définir des variables pour trois couches de tuiles et une autre qui les contient toutes, en plus de leur nom tel qu’il apparaîtra dans le contrôleur de couches.

var ARCGISBasemap = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}.png',{
    attribution: '© Tuiles de fond <i>temporairement</i> par ESRI.'
  }).addTo(myMap);

var osmBasemap = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png',{
    attribution: '© <a href="http://openstreetmap.org">OpenStreetMap</a>'
  });

  var stamen = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.png',
		{
      attribution: '© <Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.'
    });

var basemaps = {
  "OSM": osmBasemap,
  "Relief": ARCGISBasemap,
  "Aquarelle": stamen
  };

Il ne reste plus qu’à ajouter à la carte le contrôleur de couches lui-même, tout en spécifiant que les couches doivent apparaître en ordre alphabétique.

L.control.layers(basemaps, couches, {
    sortLayers: true,
  }).addTo(myMap);

Le résultat donne ceci:

On aurait aussi pu choisir (comme plus haut dans QGIS2Web) que la liste des couches soit dépliée au départ:

L.control.layers(basemaps, couches, {
    sortLayers: true,
    collapsed: false
  }).addTo(myMap);

Ce qui donne ceci:

Notre carte en ligne ressemble donc maintenant à ceci:

Le contrôleur de couches permet d’organiser les marqueurs et également d’observer de possibles relations entre les différents types d’informations. Ce classement n’est pas définitif et le genshtab pourra, bien sûr, le revoir avant de publier la carte dans historiamatica. Mais ça montre déjà les avantages de travailler avec des groupes.

Tant qu’à faire, ajoutons une échelle:

var scale = L.control.scale();
  scale.addTo(myMap)

Ce qui nous donne ceci:

Mais revenons à QGIS2Web et inspectons dans le dossier exporté le fichier index.html pour nous en inspirer. Nous aimerions avoir pour notre carte du renseignement un titre et un résumé, comme pour la carte produite précédemment avec l’extension. Donc, je repère dans le fichier html le passage qui m’intéresse et fais un copier-coller dans le html de ma carte, en apportant les modifications nécessaires.

     var title = new L.Control();
     title.onAdd = function (map) {
         this._div = L.DomUtil.create('div', 'info');
         this.update();
         return this._div;
     };
     title.update = function () {
         this._div.innerHTML = '<h2>Renseignement militaire russe</h2>';
     };
     title.addTo(myMap);

     var abstract = new L.Control({'position':'topright'});
     abstract.onAdd = function (myMap) {
         this._div = L.DomUtil.create('div',
         'leaflet-control leaflet-bar abstract');
         this._div.id = 'abstract'
             this._div.setAttribute("onmouseenter", "abstract.show()");
             this._div.setAttribute("onmouseleave", "abstract.hide()");
             this.hide();
             return this._div;
         };
         abstract.hide = function () {
             this._div.classList.remove("abstractUncollapsed");
             this._div.classList.add("abstract");
             this._div.innerHTML = 'i'
         }
         abstract.show = function () {
             this._div.classList.remove("abstract");
             this._div.classList.add("abstractUncollapsed");
             this._div.innerHTML = 'Les Archives de la science militaire ont été fondées à Saint-Pétersbourg, suite à un décret de Paul Ier du 8 août 1797. Elles devaient servir de dépôt personnel de Sa Majesté Impériale pour tout ce qui touchait aux affaires militaires. Ces archives ont par la suite plusieurs fois changé d\’appellation, mais l\’esprit était toujours le même : conserver cartes et protocoles historiques, descriptions et autres documents provenant de divers institutions et individus. Tous les dossiers émanant des centres de commandement et des états-majors des armées ont été ainsi archivés à la fin de chacune des guerres menées par la Russie. On y retrouve bien sûr des documents en russe, mais aussi beaucoup de documents en français, soit parce qu\’ils ont été saisis à l\’ennemi, soit parce que rédigés en français par des officiers russes. Ce fonds se trouve aujourd\’hui à Moscou dans les Archives d\’histoire militaire de l\’État de Russie (RGVIA). <br /> Ces archives, avec lesquelles nous travaillerons dans ce cours, apportent un éclairage unique sur une période cruciale dans l\’histoire de la Russie, qui connaît, au XIX<sup>e</sup> siècle, une fulgurante expansion en Asie, à défaut de pouvoir s\’étendre à l\’ouest, où ses frontières ont été fixées depuis le Congrès de Vienne. Cette expansion n\’est pas sans inscrire la Russie en compétition avec les autres puissances occidentales qui se disputent ces marchés nouveaux et ces colonies potentielles, voire avec le Japon, puissance montante en Asie qu\’affrontera sans succès la Russie en 1904-05. Au sein de cette compétition — tantôt pacifique, tantôt belliqueuse — la collecte de renseignement s\’avère cruciale. Or, le renseignement connaît précisément à cette époque une véritable révolution, qui voit ses <i>modus operandi</i> se spécialiser, devenir beaucoup plus analytiques, voire encyclopédiques, dans la mesure où l\’étude de l\’ennemi ne se borne plus aux réalités économiques, militaires et politiques, mais s\’ouvre également à l\’ethnographie. Les documents que nous analyserons sont des rapports d\’espions ou de diplomates (les deux fonctions tendant souvent à se confondre à cette époque), des rapports d\’attachés militaires, de la correspondance entre officiers russes, des cartes, des plans, des croquis… Le travail avec ces archives permettra à l\’étudiant.e de se familiariser avec le système archivistique russe, d\’appliquer à un corpus précis les principes de la critique des sources, de comprendre enfin de l\’intérieur une période captivante dans l\’histoire du renseignement, soit celle de la Question d\’Orient et du Grand Jeu.';
     };
     abstract.addTo(myMap);

Le résumé est temporaire, vous pourrez le remplacer par un texte de votre choix. On ouvre maintenant le fichier qui dans notre dossier QGIS2Web contient les styles CSS et on copie et modifie comme bon nous semble la définition des styles du titre et du résumé.

.abstract {
    font: bold 18px 'Lucida Console', Monaco, monospace;
    text-indent: 1px;
    background-color: #f8f8f8 !important;
    width: 30px !important;
    color: #000000 !important;
    height: 30px !important;
    text-align: center !important;
    line-height: 30px !important;
}
.abstractUncollapsed {
    padding: 6px 8px;
    font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
    background-color:#f8f8f8 !important;
    color: #000000 !important;
    box-shadow: 0 0 15px rgba(0,0,0,0.2);
    border-radius: 5px;
    max-width: 40%;
}

.info {
    padding: 6px 8px;
    font: 14px/16px Arial, Helvetica, sans-serif;
    background: white;
    background: rgba(255,255,255,0.8);
    box-shadow: 0 0 15px rgba(0,0,0,0.2);
    border-radius: 5px;
}
.info h2 {
    margin: 0 0 5px;
    color: #777;
}

Ce qui nous donne ceci:

Et quand on passe le pointeur sur le i, on voit le résumé:

Il est possible de s’inspirer de cartes en ligne et d’aller chercher des bouts de code comme ça avec l’inspecteur du navigateur (F12 dans Chrome).

On peut ainsi inspecter le code de notre propre carte:

La console est pratique pour vérifier s’il y a des erreurs, par exemple ici un fichier manquant.

On peut aussi manipuler la carte avec la console, par exemple faire disparaître ou apparaître l’un des groupes d’attributs que nous avons créés dans ce tutoriel:

Quand vous commencez à taper, le navigateur vous suggère les noms de vos groupes, même chose pour les méthodes, simplement taper sur la touche de tabulation pour accepter la suggestion. On peut ajouter un groupe avec la commande suivante:

economieGroupe.addTo(myMap)

Ça ne change pas notre fichier html d’origine, c’est simplement une façon d’interagir avec lui via javascript.

Depuis le tutoriel qui montrait comment faire ses propres icônes svg, nombre d’entre vous en ont fait et certains sont vraiment très réussis. Voici une autre méthode, plus rapide pour faire des icônes personnalisées avec Leaflet. On crée d’abord une variable évoquant la fonction appropriée dans Leaflet, on lui attribue une classe, puis on crée un marqueur auquel on attribue l’icône.

var iconeCarre = L.divIcon({className: 'carre'});
L.marker([41.6929, 44.7981], {icon: squareIcon}).addTo(myMap)

Il faut ensuite définir l’icône en CSS:

.carre {
  background-color: green;
}

Ce qui nous donne ceci:

Pour obtenir un marqueur complet, on pourrait écrire ce code:

var squareIcon = L.divIcon({className: 'square'});
var Tbilisi = L.marker([41.6929, 44.7981], {icon: squareIcon, title: 'Tbilisi'}).addTo(myMap);
  Tbilisi.bindPopup("<p class='titre'>Mission Gardane</p> <img src='images/gardane.jpg' class='image'</p> <p class='texte'>Le général Gardane au service de la France. Dans une missive, écrite à Téhéran en 1808 et adressée au gouverneur de Tbilissi le Maréchal-Comte Goudovitch (qui devient gouverneur de Tbilissi et de Géorgie en 1807), le général Gardane dévoile des informations importantes sur sa mission en Perse. </p> <p class='archive'>TsGIA. F. 2, op. 1, d. 1284, l. 1-3</p> <p class='auteur'>Frédéric Gosselin</p> ");

C’est un exemple très basique. Mais avec CSS, les possibilités sont infinies. Par exemple, ce code…

.cercle
{
  background:blue;
  border:5px solid rgba(255,255,255,0.5);
  color:blue;
  font-weight:bold;
  text-align:center;
  border-radius:50%;
  line-height:30px;
  line-width:30px;
  height:150px;
  width:150px;
}

…donnera ceci:

C’est ce qui met fin à notre tutoriel. Portez-vous bien et lavez-vous les mains souvent. Je ne pensais jamais écrire ça!

Vitkevitch à l’affût de ses ennemis; ils sont nombreux!