C'est déjà le dernier jour du
#30DayMapChallenge
pour lequel je réaliserai une carte, aujourd'hui sur le thème "Mes données"
(My Data). Ma seule manière de collecter des données au quotidien, c'est de
prendre des photos, et ce d'à peu près tout. A l'heure où j'écris ces lignes,
mon téléphone atteint le nombre inquiétant de 14874 photos, pour un total de
presque 39 Go de stockage (dont un bon tiers sont sans doute des photos de mon
chien, je dois l'admettre).
Évidemment, nos photos en disent très long sur nous. Et parmi les mille et une
manières d'en apprendre plus sur quelqu'un à travers ses photos, en voilà une
que j'aime bien : afficher les endroits où les photos ont été prises sur une
carte, comme par exemple dans
cette application
réalisée avec l'API JavaScript d'ArcGIS (pour plus de confort visuel,
n'hésitez pas à cliquer sur le lien pour la voir en plein écran).
Comme vous le voyez, je ne me suis pas contentée d'afficher les points, mais
ai créé une carte d'élévation fictive en fonction de la densité de points à
chaque endroit.
Dans cet article, je vous propose de suivre le cheminement de création de
l'application, de la préparation des données jusqu'au code (qui est très
abordable, promis). De quoi recréer la même chose avec vos propres données
!
Préparation des données
Dans un premier temps, j'ai créé ma propre boîte à outil via un script Python
en utilisant
arcpy
dans
ArcGIS Pro, qui me permet de parcourir tous les fichiers photos de mon téléphone, et de
récupérer les coordonnées XY de chacune des photos via leur
fichier EXIF
(des métadonnées associées à votre photo lors de la prise de vue) afin de les
placer sur une carte. ArcGIS Pro possède déjà un outil
Photos géolocalisées vers points
qui fonctionne très bien pour faire cela, mais il peut rencontrer des
problèmes lorsque les formats de votre jeu de donnée d'entrée ne sont pas
lisibles par l'outil (qui prend en charge des jpeg et des tiff), ce qui est
souvent le cas sur nos portables où nous pouvons par exemple collecter des
gif, des mp4 etc. Dans un article très prochain, nous reviendrons en détail
sur la création d'une Toolbox ArcGIS Pro en utilisant arcpy à travers cet
exemple. En attendant,
vous retrouverez ici un Notebook que vous pouvez utiliser sur vos données
pour créer vos propres cartes.
Voici le résultat une fois les photos affichées sur la carte :
En lisant cette carte, je vois énormément de choses : où j'habite et je
travaille, où mes parents habitent, où j'ai fait mes études, où je pars en
vacances, etc. Elle me permet même de faire revivre des souvenirs, comme une
rapide journée en Belgique il y a quelques années que j'avais complètement
oubliée.
Bon, est-ce qu'on peut faire mieux ? Je pense que oui ! En me baladant sur le
Github de la géniale
Raluca Nicola,
je suis tombée
une application
représentant des densités de points avec des isohypses en 3D. J'étais curieuse
de voir ce que cela pouvait donner sur mes photos.
C'est parti ! Je choisis dans un premier temps de me concentrer sur une zone
géographique restreinte, par exemple le Sud-Ouest de Paris dans lequel je
travaille actuellement et je fais pas mal d'activités. J'ai donc extrait les
points correspondant à cette zone puis ai suivi
cet article
pour préparer mes données dans ArcGIS Pro : en appliquant l'outil
Densité de Noyau, j'ai obtenu un raster contenant des valeurs plus ou moins élevées selon la
densité de points. Pour paramétrer l'outil sur mes propres données, je dois
avouer avoir opté pour l'approche très scientifique d'y aller à tâtons jusqu'à
obtenir un résultat que je trouvais suffisamment détaillé. Il n'y a de toute
façon rien de scientifique à cette application, c'est avant tout pour la
beauté de la chose.
Ma densité étant globalement très basse, mon raster était composé uniquement
de valeurs décimales. Je suis passée par la
calculatrice raster
pour le multiplier (dans mon cas par 1000000) obtenir un nouveau raster
valeurs comprises entre environ 0 et 455, qui ressemblent plus à des valeurs
"d'élévation" desquelles on pourra tirer quelque chose.
Enfin, l'outil
Isolignes
permet de transformer ce raster en isolignes, c'est à dire des lignes d'égales
valeurs. J'ai édité les entités afin de refermer chacune des isolignes (encore
une fois, rien de scientifique, tout pour le style). Voici le résultat final :
J'ai ensuite publié la carte contenant les isolignes ainsi que les points
représentant chacune des données et les cartes sur mon portail ArcGIS (ArcGIS
Online ou Enterprise).
Il est temps de passer au code ✨
Le code
Ici, nous sommes sur une application très basique qui utilise
l'API JavaScript d'ArcGIS, pour laquelle j'ai simplement modifié les rendus des couches. Si vous êtes
totalement débutant avec l'API, vous pouvez essayer de suivre ce tuto, mais si
vous voyez que certaines notions sont expliquées trop rapidement, rendez-vous
sur
cette série de prise en main de l'API
où tout est expliqué pas à pas. Vous pouvez également retrouver le code
complet sur
mon Github
ou le modifier interactivement dans
ce CodePen. Cette application n'étant qu'un remaniement de celle de
Raluca, vous
pouvez aussi consulter directement
son code
si vous le souhaitez.
Comme d'habitude, nous commençons avec un HTML très simple, avec un appel à
l'API JavaScript
https://js.arcgis.com/4.30/
ainsi qu'à son style
https://js.arcgis.com/4.30/esri/themes/dark/main.css
, que nous
allons utiliser ici en mode sombre (dark). Je référence également ma propre
feuille de style et mon propre script que j'ai séparés du HTML. Dans le corps
du HTML, j'insère une unique balise <viewDiv>
qui
contiendra la vue de ma carte.
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>
France | Élévation
</title>
<link rel="stylesheet" href="style/style.css" />
<link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/dark/main.css" />
<script src="https://js.arcgis.com/4.30/"></script>
<script src="app/main.js"></script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Côté CSS, je m'assure simplement que la taille de la
<viewDiv>
prendra l'entièreté de l'écran.html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
position: absolute;
}
Il est maintenant temps de faire appel à l'API JavaScript pour insérer notre
carte !
Il est maintenant temps de faire appel à l'API JavaScript pour insérer
notre carte !
Comme d'habitude, je commence par appeler les classes qui me seront utiles
dans le require (ici,
WebMap,
SceneView, FeatureLayer, PointSymbol3D et
IconSymbol3DLayer), puis je déclare la fonction qui contiendra toutes les
instructions utiles à l'affichage de ma carte et je lui passe en arguments
chacune de ces classes dans le même ordre que dans le require.
require([
"esri/WebMap",
"esri/views/SceneView",
"esri/layers/FeatureLayer",
"esri/renderers/SimpleRenderer",
"esri/symbols/PointSymbol3D",
"esri/symbols/IconSymbol3DLayer"
], function (WebMap, SceneView, FeatureLayer, SimpleRenderer,PointSymbol3D,IconSymbol3DLayer) {
//le reste du code ira ici
});
Je vais commencer par appeler ma carte publiée sur mon portail avec la
classe
WebMap. A la place de construire la carte de zéro avec la classe
Map, la classe WebMap me permet d'appeler directement une carte publiée sur le
portail, en conservant les configurations en termes de couches, symbologie
(si supportée), géosignets, projection, etc.). J'ajoute donc simplement
cette WebMap à mon code en indiquant son id, que vous pouvez retrouver
facilement dans l'url de la page de l'item. (exemple ici :
https://esrifrance.maps.arcgis.com/home/item.html?id=ecab473029a94c9f90904997dd7836d0).
Vous pouvez directement utiliser la même carte que moi, car je l'ai partagée
en public, mais si vous suivez le tutoriel avec vos propres données, pensez
à modifier la valeur d'id.
const map = new WebMap({
portalItem: {
id: "ecab473029a94c9f90904997dd7836d0"
}
});
Je crée ensuite une instance de
SceneView, qui va me permettre de créer une vue 3D sur une carte.
const view = new SceneView({
container: "viewDiv",
map: map,
camera: {
position: {
longitude: 2.219092028824691,
latitude: 48.78941188838513,
z: 2771.364869683981
},
heading: 17.062531917143495,
tilt: 60.592038831044185
},
viewingMode: "local",
environment: {
background: {
type: "color",
color: "#212526"
},
atmosphereEnabled: false,
starsEnabled: false
}
});
Je commence par indiquer le
container
, la balise de mon HTML dans laquelle la carte sera affichée, ici
"viewDiv"
comme nous l'avons défini au tout début du
tutoriel. J'indique également que la carte (map
) sur laquelle je génère la vue est la carte créée juste ci-dessus.
Je dois ensuite placer la
camera
, qui donnera l'angle initial avec lequel je dois virtuellement filmer ma
carte. Pour cela, je définis une orientation par rapport au Nord (heading
), une inclinaison (tilt
), la
position
constituée de la longitude
, de la latitude
et de
l'élévation (z
) ainsi qu'une référence spatiale
(spatialReference
).
Je peux également déterminer qu'il s'agit d'une scène locale grâce au
viewingMode
, et modifier l'environment en choisissant une
couleur d'arrière-plan (background
) ainsi qu'en supprimant
l'atmosphère et les étoiles présentes par défaut.
Je retire également les widgets de l'interface utilisateurs présents par
défaut afin d'épurer l'application au maximum.
view.ui.remove([ "compass", "zoom","navigation-toggle"]);
Pour la suite, je veux m'assurer que la carte et ses couches soient
entièrement chargées avant de les manipuler. J'utilise pour cela une
instruction map.when(() => { ... })
à l'intérieur de
laquelle je placerai toute la suite de mon code.
J'accède ensuite à la couche contenant les isolignes. Le calque étant en
2ème position de la carte, je le retrouve à l'index 1 en accédant aux
layers
de la map et je le stocke à l'intérieur de la variable
isohypses
. const isohypses = map.layers.items[1];
Attention, votre couche n'est peut-être pas dans la même position à
l'intérieur de votre carte, pensez à vérifier et à adapter l'index en
fonction.
Afin de décaler ces isolignes sur l'axe Z, j'accède à la propriété
elevationInfo
de la couche. Le mode
d'élévation choisi est
"relative-to-ground", c'est-à-dire que la hauteur d'affichage sera
calculée en prenant le sol comme référence pour le zéro. Pour choisir la
valeur de Z affichée, nous utilisons la propriété
featureExpressionInfo
et indiquons que celle-ci sera calculée
à partir de l'attribut Contour de chacune des entités. Lors de la création
des isolignes dans ArcGIS Pro, l'outil a automatiquement créé ce champ
Contour dans lequel il a stocké les valeurs de chacune des isolignes.
const isohypses = map.layers.items[1];
(isohypses.elevationInfo = {
mode: "relative-to-ground",
featureExpressionInfo: {
expression: "$feature.Contour"
}
}),
Vous devirez maintenant voir vos lignes décoller du sol. Cependant pour
l'instant, elles ne sont pas très sexys. Nous allons maintenant appliquer
un gradient de couleur, pour partir d'un rose foncé pour les lignes les
plus basses en allant d'un rose foncé pour les lignes de faible altitude
jusqu'à un rose très clair pour les lignes les plus hautes. Nous allons
pour cela accéder au
renderer
de la couche. Ici, nous allons utiliser un rendu simple (SimpleRenderer
) associé à des variables visuelles (visualVariables
).
(isohypses.renderer = new SimpleRenderer({
symbol: {
type: "line-3d",
symbolLayers: [
{
type: "line",
size: 1
}
]
},
visualVariables: [
{
type: "color",
field: "Contour",
stops: [
{
value: 25,
color: "#7A0177"
},
{
value: 200,
color: "#F768A1"
},
{
value: 400,
color: "#FDE0DD"
}
]
}
]
}));
Nous construisons un SimpleRenderer
, pour lequel nous
commençons par définir le
symbole
utilisé. Puisque je travaille en 3D sur une donnée linéaire, le
type
de symbole est "line-3d
". Je peux ensuite indiquer le
symbolLayers
, permettant de définir la manière dont les objets seront visualisés.
Ici, nous définirons le
type
sur "line"
nous pouvons également jouer sur sa taille avec
le paramètre
size
.
Enfin, pour faire varier la couleur "l'altitude" moyenne de l'hexagone,
nous allons tirer parti des
visualVariables
. Ici, une
ColorVariable
pour faire varier la couleur. Indiquons cela en paramétrant le
type
sur "color"
, puis définissons le champ (field
) selon lequel la couleur devra varier, ici "Contour. Nous pouvons
ensuite indiquer les
stops
, qui sont un array contenant des valeurs clés auxquelles nous
attribuons des valeurs précises. Ici par exemple, nous définissons 3
valeurs de contour qui prendront une couleur particulière que nous
passons avec sa valeur hexadécimale (il est également possible
d'utiliser du rgb). Entre ces valeurs, l'API va déterminer
automatiquement une rampe de couleurs pour attribuer des couleurs à
chacune des lignes.N'hésitez pas à tester d'autres couleurs si vous le
souhaitez.
Pour compléter l'application, nous allons afficher au sol les points de
collecte des photos. Nous accédons à la couche, puis indiquons que le
mode d'élévation sera sur le sol.
const photos = map.layers.items[2];
(photos.elevationInfo = {
mode: "on-the-ground"
}),
Enfin, nous allons également modifier le rendu de la couche. A nouveau,
nous allons construire un un SimpleRenderer
, pour
lequel nous commençons toujours par définir le
symbole
utilisé. Cette fois-ci, puisque nous travaillons sur des points, nous
allons utiliser des
PointSymbol3
D
. Nous allons renseigner sa propriété
symbolLayers
, en utilisant un
IconSymbol3DLayer
pour avoir un rendu plat plutôt que volumétrique. Nous indiquons ensuite
quelle ressource (resource
) est utilisée pour cette icone, ici nous utiliserons une forme de type
cercle, quel matériel (material
) de rendu nous souhaitons utiliser, ici un simple aplat de
couleur, ainsi que la taille (size
) des points. (photos.renderer = new SimpleRenderer({
symbol: new PointSymbol3D({
symbolLayers: [
new IconSymbol3DLayer({
resource: {
primitive: "circle"
},
material: {
color: "#DD3497"
},
size: 3
})
]
})
}));
Voilà, la partie cartographique de l'application est prête ! Vous pouvez
désormais enrichir l'UI avec par exemple un titre, des crédits, un
loader, etc. Pour cela, vous pouvez prendre inspiration sur mon code
(dans Github ou CodePen), ou alors vous amuser par vous-même ! Pour ma
part, j'utilise très souvent
Calcite
pour cela.
Si cet article vous a plus, n'hésitez pas à retrouver les tutoriels de
mes deux autres créations cartographiques pour ce challenge :
la carte d'élévation de la France en hexagones, et
une animation sur les variations d'étendues de l'Arctique.
Aucun commentaire:
Enregistrer un commentaire