User:Defuneste/Les alignements d'arbres de Lyon Métropole
Cette page a pour vocation de présenter :
- les alignements d'arbres de Lyon Métropole ;
- les opérations effectuées pour préparer l'import ;
- les imports effectués.
Les alignements d'arbres de Lyon Métropole
Les données ont été téléchargées, le 8 janvier 2019, sur le site Data Grand Lyon à cette adresse. Elles ont été téléchargées sous format shape(.shp) (les autres formats ne semblaient pas accessibles) avec l'EPSG 4326 comme système de projection.
Les opérations effectuées pour préparer l'import
L'exploration et le "nettoyage" des données est fait sur R avec en package : sp, sf, dplyr et ggplot2 (il est possible de publier les scripts au besoin). C'est un fichier shape de points qui regroupe 94435 arbres caractérisés par 25 champs. Je me suis concentré sur les champs indiqués comme souhaitable dans le wiki.
Genre / Key:genus et Espèce / Key:species
Genre
La variable genre
comprend trois valeurs étranges :
- "Emplacement libre" : 3447 lignes
- "souche" : 1615 lignes
- "Non défini" : 12 lignes
"Emplacement libre" comprend une très grande majorité de valeurs nulles (0) qui devraient être considérées comme NA et quelques valeurs positives (une absence d'arbre avec une hauteur) qui sont probablement des artefacts. Cela semble correspondre à des endroits où des arbres peuvent être plantés mais ne le sont pas encore. "Souche" doit correspondre à des arbres morts. Seul deux d'entre eux ont une circonférence et trois une hauteur. Je ne pense pas que cela soit important. "Non défini" est étrange car tous possèdent une circonférence, il est donc possible que cela soit des arbres non identifiés mais qui existent bien.
Dans le cadre d'OSM je pense qu'il ne faut pas garder ces lignes ("on cartographie le terrain"). Il faut ensuite renommer la variable en genus
arbres_lyon.shp$filtre <- 0
arbres_lyon.shp$filtre[arbres_lyon.shp$genre == "Emplacement libre"] <- 1
arbres_lyon.shp$filtre[arbres_lyon.shp$genre == "souche"] <- 1
arbres_lyon.shp$filtre[arbres_lyon.shp$genre == "Souche"] <- 1
arbres_lyon.shp$filtre[arbres_lyon.shp$genre == "Non défini"] <- 1
arbres_lyon.shp <-arbres_lyon.shp %>% filter(filtre == 0)
Il y a également deux valeurs manquantes (NA) pour genre. Ce sont deux Hibiscus.
arbres_lyon.shp[is.na(arbres_lyon.shp$genre),] # ici on vérifie les NA
#genre est un facteur, je le garde comme tel mais on pourrait aussi s'en passer
levels(arbres_lyon.shp$genre) <- c(levels(arbres_lyon.shp$genre), "Hibiscus")
arbres_lyon.shp$genre[is.na(arbres_lyon.shp$genre)] <- "Hibiscus"
Espèce
Espèce ne comprend presque que des noms latins uniques (campestre par ex). On aurait pu attendre qu'elle corresponde comme dans OSM au nom latin de l'espèce (Acer campestre). En plus, cette variable comprend trois termes posant questions :
- "hybride" : 2148 lignes
- "hybride turneri" : 1 lignes
- "x zoeschense" : 17 lignes
Il est possible que ces trois termes soient tous liés à la façon dont la base a codé les hybrides (et Espèce). Les hybrides sont un cas particulier du nom latin (constitué majoritairement de deux noms) constitué alors de trois mots. Ici le champs espèce est probablement une extraction automatique du second nom. L'extraction n'aurait prévue le cas des hybrides.
Utiliser "hybride" plutôt que × qui est un caractère particulier n'est pas une mauvaise idée et éviterait des tas de problèmes d'encodage (on utilise souvent x pour aller plus vite). Il semble cependant que × est plus rigoureux et valide dans toute les langues.
Voici les modifications :
arbres_lyon.shp$espece <- recode(arbres_lyon.shp$espece, hybride = "×" )
arbres_lyon.shp$variete[arbres_lyon.shp$espece == "hybride turneri"] <- "turneri"
arbres_lyon.shp$espece[arbres_lyon.shp$espece == "hybride turneri"] <- "×"
arbres_lyon.shp$variete[arbres_lyon.shp$espece == "x zoeschense"] <- "zoeschense"
arbres_lyon.shp$espece[arbres_lyon.shp$espece == "x zoeschense"] <- "×"
sort(unique(arbres_lyon.shp$espece)) #une verif pas indispensable
Et ici la composition d'un nom d'espèce pour les hybrides puis pour les arbres "normaux". Si paste comporte une valeur manquante il retourne NA ce qui me convient.
arbres_lyon.shp$species <- ifelse(arbres_lyon.shp$espece == "×" ,
paste(arbres_lyon.shp$genre, arbres_lyon.shp$espece, arbres_lyon.shp$variete),
paste(arbres_lyon.shp$genre, arbres_lyon.shp$espece))
La circonférence : Key:circumference
La circonférence est difficile à visualiser (le diamètre est plus parlant), à titre d’exemple : un arbre de 1 m de DHP (diamètre à hauteur de poitrine) a une circonférence de 3,14 m et 2 m donne 6,28 m (ce sont de très gros arbres).
circonfere est le champs qui semble correspondre à la circonférence. OSM recommande l'usage du m et circonfere doit être plus en m. La mediane serait donc de 0,49 m et non pas 49 m soit 0.1559718 m de DHP.
summary(arbres_lyon.shp$circonfere)
Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. | NA's |
---|---|---|---|---|---|---|
0.00 | 25.00 | 49.00 | 67.55 | 93.00 | 12210.00 | 9 |
La circonférence minimale de 0 concerne 8618 arbres. C’est, soit une absence de donnée mal codée (devrait être NA dans le cas des "emplacement libre" et "souche"), ou alors on est face à des arbustes qui n’ont pas encore de circonférence à 1,30. Est-ce possible ?
Si elle est bien en cm il est peu probable que l’on ait des arbres de plus de 628 cm de circonférence (des arbres de 2 m de DHP sont très rares).
table(arbres_lyon.shp$circonfere[arbres_lyon.shp$circonfere >= 628])
Circonférence (cm) | 800 | 997 | 999 | 1069 | 1114 | 12210 |
---|---|---|---|---|---|---|
Nb d'arbres | 29 | 1 | 43 | 1 | 1 | 1 |
Le plus évident est l’arbre de 12210 cm de circonférence (prés de 39 m de rayon) qui doit correspondre à une erreur de frappe. Vient ensuite les "999" qui sont souvent utilisés pour indiquer des valeurs manquantes, le fait qu’ils aient tous été plantés après 2005 renforce cette idée. Les 29 arbres ayant une valeur 800 de circonfere ont tous été plantés le même jour (2018-06-25) et sont sur la même avenue (avenue Bataillon Carmognole Liberté, Vaulx-en-Velin). On peut éliminer l’hypothèse de gros arbres. S'ils ont tous le même diamètre et qu’ils ont bien été tous plantés la même date, il est possible que de jeunes arbres aient 0,08 m (8cm de circonférence). Dans un premier temps il me semble cependant plus sage de leur attribuer une valeur manquante. Pour les dernières valeurs (997, 1069 et 1114) il est probable que l’on soit aussi dans une erreur d’encodage et donc en attendant ils prendront également NA.
arbres_lyon.shp$circumference <- arbres_lyon.shp$circonfere/100 # passage en m
# gros arbres en NA
arbres_lyon.shp$circumference[arbres_lyon.shp$circumference >= 6.28] <- NA
# valeurs nulles en NA
arbres_lyon.shp$circumference[arbres_lyon.shp$circumference == 0] <- NA
La hauteur Key:height
Je pense que c'est un des critères les plus difficiles à estimer et qui héberge souvent une proportion un peu plus forte de valeurs "rondes" (ici par exemple 30). Dans la base c'est hauteurtot
qui correspond à la hauteur (hauteur totale). La hauteur de fût est également renseignée mais je ne pense pas que cela soit une bonne idée de la garder dans OSM.
Il y a 5047 arbres avec une hauteur nulle (`0`). Il est probable que ce 0 corresponde à des valeurs manquantes. Une partie correspond aux "Emplacement libre". L'unité semble bien être le m.
Il est très peu probable d'avoir des arbres de plus de 50 m (j'ai aussi des doutes pour ceux de plus de 40 m).
table(arbres_lyon.shp$hauteurtot[arbres_lyon.shp$hauteurtot >= 50])
50 | 61 | 64 | 66 | 67 | 90 | 2020 | |
---|---|---|---|---|---|---|---|
nb d'arbres | 1 | 1 | 1 | 2 | 2 | 1 | 1 |
2020 est probablement une faute de frappes (20 et 20 ?). 50 m est une option possible (50 m c'est une piscine olympique et c'est presque impossible pour un feuillus, ici un platane). Les autres hauteurs sont donc aussi des erreurs.
arbres_lyon.shp$hauteurtot[arbres_lyon.shp$hauteurtot >= 50] <- NA
arbres_lyon.shp$hauteurtot[arbres_lyon.shp$hauteurtot == 0] <- NA
Rayon de la couronne : diameter_crown=*
rayoncouro
correspond au rayon de la couronne du houppier. C'est un paramètre (diameter_crown=*) pas bien décrit dans le wiki OSM. Partons du principe que l'on a un rayon en m correspondant à un demi diamètre.
Il y a 5070 valeurs nulles. Il est préférable d'attribuer NA. Dans les valeurs extrêmes seulement 25 et 29 sortent du lot et devraient être passer comme NA.
arbres_lyon.shp$rayoncouro[arbres_lyon.shp$rayoncouro == 0] <- NA
arbres_lyon.shp$rayoncouro[arbres_lyon.shp$rayoncouro >= 25] <- NA
Dateplanta et anneeplant
summary(arbres_lyon.shp$dateplanta)
summary(arbres_lyon.shp$anneeplant)
Ce ne sont pas des critères présents dans le wiki. On les retrouve cependant relativement renseigné dans les arbres isolés de la métropole. Faut-il les garder ?
dateplanta
correspond à des dates de plantation au format YYYY-MM-DD et anneeplant
correspond à l'année. Ils correspondent bien, donc autant ne garder que le premier. Le format est celui de start_date:FR:plantation dans OSM.
Une rapide vérification indique des arbres plantés en 1616 et 1664 avec de petites diamètres. Les deux arbres plantés en 1861 et celui en 1894 ont de gros diamètres et sont plus crédibles. Beaucoup d'arbres plantés en 1900 sont douteux mais il serait nécessaire d'en savoir plus avant de leur attribuer NA. A l’opposé l'arbre planté en 2025 et celui en 2019 semblent être des fautes de frappes et vont devoir également prendre NA pour valeur.
arbres_lyon.shp$rayoncouro[arbres_lyon.shp$dateplanta <= 1850] <- NA
arbres_lyon.shp$rayoncouro[arbres_lyon.shp$dateplanta >= 2019] <- NA
Mise en forme pour OSM
Ici l'objectif est de mettre en forme et de ne garder que les variables utiles dans OSM.
leaf_type et Leaf_cycle
Un import du tableau du wiki des correspondances entre des genres, des types de feuillages et sa persistance.
leaf <- read.csv2("leaft_type.csv", sep = "\t")
On compare ce tableau avec la liste des genres de la base Lyonnaise :
sort(unique(arbres_lyon_final.shp$genus)[unique(arbres_lyon_final.shp$genus) %in% leaf$Genus]) # liste des genres présents
sort(unique(arbres_lyon_final.shp$genus)[!(unique(arbres_lyon_final.shp$genus) %in% leaf$Genus)]) # liste des genres absents
Seulement 23 genres sont présents. Vérifier ces genres avec Wikipédia (cf. tableau plus bas) permet de trouver trois orthographes de genres pouvant être corrigé : Pirus, Thuya et Evodia. Passer dans TNRS pour confirmer Pirus est bien Pyrus et Thuya est bien Thuja par contre les deux versions Evodia et Euodia sont possibles (je n'ai gardé qu'Euodia en suivant le wiki mais c'est discutable).
levels(arbres_lyon_final.shp$genus)[levels(arbres_lyon_final.shp$genus) == "Thuya"] <- "Thuja"
levels(arbres_lyon_final.shp$genus)[levels(arbres_lyon_final.shp$genus) == "Pirus"] <- "Pyrus"
levels(arbres_lyon_final.shp$genus)[levels(arbres_lyon_final.shp$genus) == "Evodia"] <- "Euodia"
Genus | leaf_cycle | leaf_type |
---|---|---|
Acacia | deciduous | broadleaved |
Acer | deciduous and evergreen | broadleaved |
Aesculus | deciduous | broadleaved |
Ailanthus | deciduous | broadleaved |
Albizia | deciduous | broadleaved |
Alnus | deciduous | broadleaved |
Amelanchier | deciduous | broadleaved |
Betula | deciduous | broadleaved |
Broussonetia | deciduous | broadleaved |
Buxus | evergreen | broadleaved |
Carpinus | deciduous | broadleaved |
Castanea | deciduous | broadleaved |
Catalpa | deciduous and evergreen | broadleaved |
Cedrela | deciduous and evergreen | broadleaved |
Celtis | deciduous | broadleaved |
Cercidiphyllum | deciduous | broadleaved |
Cercis | deciduous | broadleaved |
Chimonanthus | deciduous and evergreen | broadleaved |
Cladrastis | deciduous | broadleaved |
Cornus | deciduous and evergreen | broadleaved |
Corylus | deciduous | broadleaved |
Crataegus | deciduous | broadleaved |
Davidia | deciduous | broadleaved |
Diospyros | deciduous | broadleaved |
Elaeagnus | deciduous and evergreen | broadleaved |
Eucalyptus | deciduous and evergreen | broadleaved |
Euodia | deciduous | broadleaved |
Fagus | deciduous | broadleaved |
Firmiana | deciduous | broadleaved |
Fraxinus | deciduous and evergreen | broadleaved |
Gleditsia | deciduous | broadleaved |
Gymnocladus | deciduous | broadleaved |
Hibiscus | deciduous and evergreen | broadleaved |
Idesia | deciduous | broadleaved |
Juglans | deciduous | broadleaved |
Koelreuteria | deciduous | broadleaved |
Lagerstroemia | deciduous and evergreen | broadleaved |
Ligustrum | deciduous and evergreen | broadleaved |
Liquidambar | deciduous | broadleaved |
Liriodendron | deciduous | broadleaved |
Maclura | deciduous | broadleaved |
Magnolia | deciduous and evergreen | broadleaved |
Malus | deciduous | broadleaved |
Melia | deciduous | broadleaved |
Mespilus | deciduous | broadleaved |
Morus | deciduous | broadleaved |
Nyssa | deciduous | broadleaved |
Olea | evergreen | broadleaved |
Ostrya | deciduous | broadleaved |
Parrotia | deciduous | broadleaved |
Paulownia | deciduous | broadleaved |
Phellodendron | deciduous | broadleaved |
Pyrus | deciduous and evergreen | broadleaved |
Platanus | deciduous | broadleaved |
Populus | deciduous | broadleaved |
Prunus | deciduous and evergreen | broadleaved |
Ptelea | deciduous | broadleaved |
Pterocarya | deciduous | broadleaved |
Rhus | deciduous | broadleaved |
Robinia | deciduous | broadleaved |
Salix | deciduous | broadleaved |
Sambucus | deciduous | broadleaved |
Sassafras | deciduous | broadleaved |
Semiarundinaria | deciduous | broadleaved |
Sophora | deciduous | broadleaved |
Sorbus | deciduous | broadleaved |
Syringa | deciduous | broadleaved |
Ulmus | deciduous | broadleaved |
Zelkova | deciduous | broadleaved |
arbres_lyon_final.shp <- arbres_lyon.shp %>%
rename(genus = genre, ## ici on renome
"species:fr" = essencefra,
height = hauteurtot,
`start_date:FR:plantation` = dateplanta,
taxon = essence) %>%
mutate(diameter_crown = rayoncouro * 2,
"source:name" = "Arbres d'alignement de la métropole de Lyon",
"source:addr" = "https://data.grandlyon.com/") ## puis on supprime %>%
select(-hauteurfut, -diametreco, -rayoncouro, -circonfere, -anneeplant, -architectu, -localisati, -naturereve, -surfacecad,
-mobilierur, -commune, -codefuv, -nomvoie, -identifian, -numero, -codegenre, -filtre, -espece)
names(arbres_lyon_final.shp)
Une fois que l'on a un fichier avec une correspondance entre genus et leaf_type et leaf_cycle une jointure fait le travail.
# ouverture du fichier complémentaire
leaf2 <- read.csv2("leaf_type_ajout.csv", sep = "\t", stringsAsFactors = FALSE)
leaf_tot <- rbind(leaf,leaf2) # rajout au fichier tiré du CSV
arbres_lyon_final.shp <- arbres_lyon_final.shp %>% # une jointure
left_join(leaf_tot, by = c("genus" = "Genus"))
Production de petits fichiers pour faire plusieurs imports
Il semble difficile de faire un gros import tout en contrôlant visuellement que l'on ne supprime pas des données terrain / d'utilisateurs ou n'ajoute pas de la données de mauvaise qualité. Diviser le travail en plusieurs fichiers semble une meilleur solution.
outlist <- list() # initialisation d'un liste
longueur <- length(unique(arbres_lyon_final.shp$codeinsee)) # le nombre de fichier souhaité
for(i in 1:longueur) {
# on passe par une liste, c'est pas indispensable mais je voulais vérifier un peu avant d'écrire des fichiers
outlist⟦i⟧ <- arbres_lyon_final.shp %>%
filter(codeinsee == unique(arbres_lyon_final.shp$codeinsee)[i])
# on écrit des tas de fichiers
st_write(outlist⟦i⟧, dsn = paste0(unique(arbres_lyon_final.shp$codeinsee)[i], ".geojson"))}
geojson semble bien passer avec JOSM, ce format présente l'avantage de prendre plus de 9 caractères dans le nom de variables et d’accepter les ":" souvent utilisés. Lors de ce travail la structure d'un tableau a été utilisée et mon export (la commande st_write) la reproduit dans les geojson. Cette méthode va utiliser plus d'espace que nécessaire : en absence d'information la clef est renseignée avec un "null". Il y a une amélioration possible mais je ne connais pas bien les outils pour le faire.
La suite est ici.