Archives de
Auteur : Francois Keck

Contours and Networks with epimap and rleafmap

Contours and Networks with epimap and rleafmap

In February, I participated in a hackaton organized by Thibaut Jombart at Imperial College, London, to work on visualization tools for outbreak data. This was a great time spent with great people! Thanks again, Thibaut, for organizing. I took part in the development of epimap, an R package for statistical mapping. The aim of epimap is to provide tools to quickly and efficiently visualize spatial data. There is a set of functions designed to do that and you can check out the Github page for a demo.

This package also provides two functions to coerce complex objects to Spatial classes so that they can be easily included in a map.

  • The contour2sp function takes a SpatialGrid object and returns contour lines as a SpatialLinesDataFrame.
  • The graph2sp function takes a graph (from igraph package) with geolocated vertices and returns a list of Spatial objects (points and lines).

Following this post of Arthur Charpentier (who nicely plays with rleafmap!), I decided to include the John Snow’s Cholera dataset in epimap so it can be simply used for tests.

In this post I want to show how epimap and rleafmap can be combined to create fully customizable interactive maps with complex objects. The cholera dataset gives the locations of cholera deaths and the locations of water pumps in London. The maps will show the location of cholera deaths with points, the local density of deaths with colored contour lines and the location of water pumps with icons. Moreover, the pumps will be represented within a network where two pumps are connected if there are close enough.

library(rleafmap)
library(epimap)

data(cholera)

# Create a network of pumps
pump.adj <- as.matrix(dist(sp::coordinates(cholera$pumps)))
pump.graph <- graph.adjacency(pump.adj < 0.003, diag = FALSE)
V(pump.graph)$lat <- coordinates(cholera$pumps)[, 2]
V(pump.graph)$lon <- coordinates(cholera$pumps)[, 1]

# Convert death density SpatialGrid to contour SpatialLines
death.cont <- contour2sp(cholera$deaths.den, nlevels = 10)

# Basemap layer
cdbdark.bm <- basemap("cartodb.darkmatter.nolab")

# Data layers
death.points <- spLayer(cholera$deaths,
                        size = 1,
                        fill.col =  "white",
                        fill.alpha = 0.5,
                        stroke = FALSE)
death.contour <- spLayer(death.cont,
                         stroke.col = heat.colors(12)[cut(death.cont$level, 12)],
                         stroke.lwd = 1.5,
                         stroke.alpha = 1)
pumps.points <- spLayer(graph2sp(pump.graph)[[1]],
                        png = "/home/francois/water.png",
                        png.width=31 ,
                        png.height=31)
pumps.links <- spLayer(graph2sp(pump.graph)[[2]],
                       stroke.lwd = 3,
                       stroke.col = "white")

my.ui <- ui(layers = "topright")

writeMap(cdbdark.bm, death.points, death.contour,
         pumps.links, pumps.points, interface = my.ui)

And here is the map we get:

Facebooktwitter
Introducing rleafmap. An R package for interactive maps with Leaflet.

Introducing rleafmap. An R package for interactive maps with Leaflet.

Obviously, I am late…

I released rleafmap about 1 year ago and I am just writing this blog post today. During this time, I presented the package to the french R-users community at the 3eme Rencontres R in Montpellier and could get some good feedbacks. Now, I would like to communicate better on the project. My idea is to post news about the development and communicate on new features illustrated with examples on this blog. The documentation and tutorials will be published on the project website (http://www.francoiskeck.fr/rleafmap/) if I can save time for that.

Purpose and philosophy

rleafmap is an R package that can be used to generate interactive maps with your data. If you manipulate spatial data in the R environment, at some point you probably want to visualize them. The most common way to visualize spatial data is maps. Like other packages (googleVis, rMaps…) rleafmap is designed to produce maps with interactivity to bring a richer experience to the end user. This is made possible by the use of Leaflet, the amazing open-source javascript library created by Vladimir Agafonkin.

There are two things important to be aware for a good start with rleafmap.

  • First, the package use exclusively input data inheriting from the Spatial class of the sp package. These classes are central and allows to work with many packages. If you don’t know it, a good place to start is the vignette of the sp package on CRAN. If you prefer a good book have look to Bivand et al. 2013 [1].
  • The second point is about how the package works. Data layers are stored in independent R object with their own symbology. The map consists in a compilation of these objects. The idea is to stick to the philosophy of the traditional GIS software.

For a more complete view of the package I strongly recommend that you have a look to the website.

[1] Bivand R.S., Pebesma E.J. & Gómez-Rubio V. (2013) Applied Spatial Data Analysis with R, 2nd edn. Springer, New York.

Facebooktwitter
Notifications planifiées sur Ubuntu

Notifications planifiées sur Ubuntu

Au travail nous sommes à présent tenus de badger quatre fois par jour via une interface web. Je ne reviendrai pas ici sur tout le mal que je pense de la badgeuse. Le problème à présent est de composer avec ce système et de ne pas oublier de badger alors qu’on a mille choses plus intéressantes à l’esprit. D’où l’idée d’utiliser le système de notification d’Ubuntu dans une tache cron, pour s’envoyer des petits messages de rappels.

On commencera par installer le paquet libnotify-bin.
sudo apt-get install libnotify-bin

Pour ajouter une tache planifiées on édite le fichier crontab.
crontab -e

Et on y ajoute autant de tache qu’on veut (exemple d’utilisation ici)
Dans notre cas, pour s’envoyer un petit message chaque jour à 8:30 on peut mettre :
30 8 * * * DISPLAY=:0 notify-send -u critical -i /usr/share/icons/gnome/256x256/emotes/face-wink.png "Salut, as-tu pensé à badger?"

Et voilà !
Sélection_038

Facebooktwitter
RZH, une macro VBA Excel pour la délimitation de zones humides

RZH, une macro VBA Excel pour la délimitation de zones humides

Ce billet est l’occasion de présenter et de relacher dans la nature un petit programme VBA (hemhem…) pour faciliter la saisie et la synthèse de données dans le cadre de la délimitation administrative de zones humides sur critères botaniques. Autant dire tout de suite que ça s’adresse à un public plutôt restreint mais il en faut pour tout les goûts.

Zieg3rman on Flickr (CC BY-NC-SA)
Zieg3rman on Flickr (CC BY-NC-SA)

Le programme en lui même est relativement simple,je recommande néanmoins aux utilisateurs de bien veiller à ce que tout fonctionne bien selon leurs attentes, car je n’ai pas fait 36.000 tests…

RZH est distribué sous licence libre GPL, toutes les sources sont disponibles via l’éditeur VBA de Excel.

>>> Télécharger RZH

Je reproduit ci-dessous l’aide, plutôt réduite j’en conviens, mais qui donne un premier aperçu du programme.

1. A PROPOS DE RZH

RZH est une application intégrée à Microsoft Excel conçue pour faciliter la saisie et la synthèse de données dans le cadre de la délimitation de zones humides sur critères botaniques.

RZH s'appuie sur l'Arrêté du 24 juin 2008 précisant les critères de définition et de délimitation des zones humides en application des articles L. 214-7-1 et R. 211-108 du code de l'environnement français. Cependant RZH n'est pas reconnu par la législation et est fourni sans aucune garantie (Voir Licence).

2. RECOMMANDATIONS RELATIVES A CETTE VERSION

RZH est en développement et des bugs sont susceptibles de survenir. Pour vous en prévenir, il est conseillé d'utiliser uniquement les assistants de RZH pour saisir et supprimer des données.

De manière générale il est recommandé de ne pas modifier manuellement la structure du classeur et de ne pas l'annoter si vous ne comprenez pas le fonctionnement interne de l'application.

Une fois les tableaux générés vous pouvez les copier dans un autre classeur où vous pourrez les modifier à loisir.

3. UTILISATION DE RZH

RZH fonctionne en quatre étapes
- Génération d'un nouveau projet
- Construction d'une base de données espèces
- Saisie des données de terrain
- Synthèse

3.1 INITIALISATION D'UN NOUVEAU PROJET

Un nouveau projet est généré avec le bouton "Initialiser un nouveau projet" disponible dans l'onglet "Start".
Cette action entraîne la perte de tout projet antérieur présent sur ce document.
L'assistant vous permet de saisir le nombre de transect pour ce projet et pour chaque transect le nombre de placettes désiré.
A la fin de cette étape, les onglets résultats (un par transect) sont générés.

3.2 BASE DE DONNEES ESPECES

Avant de saisir les résultats, il convient de compléter la base de données espèces. Cette base doit contenir toutes les espèces recensées sur le projet. Elle peut en contenir plus.
Cliquez sur l'onglet "BD Espèces" pour consulter la base. Utilisez les boutons modifier la base.
Il peut être intéressant de transférer la base d'un projet à l'autre. Pour cela, un simple Copier-Coller suffit.
La base de données n'est pas effacée lors de l'initialisation d'un projet.

3.3 SAISIE DES DONNEES TERRAIN

Les données collectées sur le terrain peuvent être saisies et supprimées sur chaque onglet transect en utilisant les boutons et assistants dédiés.

3.4 SYNTHESE DES DONNEES

L'onglet "Synthèse" permet de générer un tableau de synthèse des résultats et de caractériser la végétation de chaque placette (hygrophile ou non).
La synthèse se met à jour automatiquement si des changements sont faits dans les résultats.

Facebooktwitter
Convertir un tableau R vers Javascript

Convertir un tableau R vers Javascript

Pour un petit projet sur lequel je travaille, j’ai eu besoin de passer des données d’un dataframe de R vers Javascript. Les données en Javascript peuvent être chargées au format JSON que R exporte avec le package RJSON. Mais pour ce projet particulier, dans un souci de simplicité et parce que je débute en Javascript, je voulais importer mes données dans le format traditionnel des arrays de Javascript.

Un array en JS ça marche comme ça :

var montableau = [1, 2, 3, 4];

Ce qui équivaut grosso modo à un vecteur sous R :

montableau <- c(1, 2, 3, 4)

On peut aussi faire de la pseudo-2D :

var montableau = [[1, 2], [3, 4]];

Ce qui donnerai une matrice sous R :

montableau <- matrix(c(1, 2, 3, 4), ncol=2, byrow=TRUE)

Bref voici une petite fonction R pour passer un dataframe (ou un truc ressemblant) de R vers Javascipt :

toJSarray <- function(df){

  if (!is.data.frame(df)){
    df <- as.data.frame(df)
  }
  
  df.nbli <- dim(df)[1]
  df.nbco <- dim(df)[2]
  temp <- vector()
  a.1 <- vector()
  
  for (i in 1:df.nbli){
      for (j in 1:df.nbco){
          if (is.numeric(df[,j])){
            a.1[j] <- df[i,j]
          } else {
            a.1[j] <- paste("\"", df[i,j], "\"", sep="")   
          }
      }
      a.2 <- paste(a.1, collapse=", ")
      temp[i] <- paste ("[", a.2, "]", sep="")
  }
  
  temp.2 <- paste(temp, collapse=", ")
  if (df.nbli == 1){
    jsarr <- temp.2
  } else {
    jsarr <- paste ("[", temp.2, "]", sep="")
  }
  invisible(jsarr)
}

Après quoi on peut rapidement écrire un fichier JS contenant nos données.

write(paste("var montableau = ", toJSarray(mondf), sep=""), "monfichier.js")

Facebooktwitter
POC devient POK

POC devient POK

La première des bonnes résolutions qui vient à l’esprit d’un bloggeur à l’aube d’une nouvelle année c’est surement d’écrire plus d’article. Mais je sais que je ne pourrai jamais tenir une telle promesse car les mois à venir vont être bien chargés.

Pour me mettre un peu de pression je vient de faire l’acquisition du nom de domaine pieceofk.fr et j’ai mis à jour le header dans la foulée. En avant pour 2013 !

Facebooktwitter
Google au hasard

Google au hasard

Il m’arrive parfois, dans de grand moments de solitude, de me trouver béat à l’adresse www.google.fr, perdu et sans trop savoir ce que je fais là. Je m’étonne alors de voir comment mon esprit pense à la manière de trouver une réponse avant même que je n’ai formulé ma question. Mais c’est une évolution de mon comportement qui est somme toute assez logique puisque quelque soit la question, 9 fois sur 10 c’est bien par google que j’obtiens la réponse.

C’est comme ça que j’explique que je puisse échouer sur google sans avoir rien à lui demander. Et parfois face au curseur qui clignote j’ai ce réflexe (simiesque ?) de taper des touches au hasard.

Mykl Roventine on Flickr (CC BY-NC-SA)

Même si quand on y réfléchit on est surement assez loin du hasard, je suis toujours impressionné par la capacité du moteur à renvoyer des résultats. Par exemple la recherche sdbxce renvoie 612000 résultats (65 si on recherche le terme exact). On constate néanmoins et c’est d’ailleurs assez évident, que le nombre de résultat diminue à chaque nouvelle lettre ajoutée.

La petite expérience du jour consiste donc à sonder un peu la monstruosité de l’index de Google en déterminant jusqu’à combien de lettre frappées au hasard le bestiau nous renvoie des résultats.
On peut bien sur faire ça à la main mais R a quelques avantages décisifs :

  • Il est plus fort que nous pour simuler le hasard
  • Il peut faire les recherches Google à notre place ce qui n’est pas sans intérêt sachant qu’on en a plusieurs centaines au programme…

Commençons donc par générer nos termes de recherche. Une matrice 100×15 : 100 réplications de mots de 1 à 15 caractères tirés au hasard.

nb.letters <- 15
nb.samp <- 100

req <- data.frame()
for (i in 1:nb.letters){
  for(j in 1:nb.samp){
    samp <- sample(letters, i, replace=T)
    req[j, i] <- paste(samp, collapse="")
  }
}

Maintenant voici une fonction qui lance une recherche Google à partir d’une chaîne de caractères et retourne le nombre de résultats renvoyés par le moteur. J’ai choisi de rechercher les termes exacts (recherche entre guillemets) car je trouvais ça plus parlant.

library (XML)
library(RCurl)

goonum <- function(q){
  Sys.sleep(runif(1))
  url <- paste("http://www.google.fr/search?aq=f&gcx=w&sourceid=chrome&ie=UTF-8&q=\"", q, "\"", sep="")
  gpage <- getURL(url)
  gpage <- htmlParse(gpage)
  nbres <- xpathApply(gpage, "//div[@id='resultStats']", xmlValue)
  nbres.num <- unlist(gregexpr("[0-9]", nbres))
  nbres.val <- vector()
  for(i in 1:length(nbres.num)) 
    {nbres.val[i] <- substr(nbres, nbres.num[i], nbres.num[i])}
  nbres.val <- as.numeric(paste(nbres.val, collapse=""))
  nbres.val <- ifelse(is.na(nbres.val), 0, nbres.val)
  return(nbres.val)
}

Il ne reste qu’à faire tourner la fonction en boucle sur notre matrice de requêtes. Et faire deux petit graphiques qui sont assez parlant.

g.ans <- apply(req, FUN=goonum, MARGIN=c(1,2))
plot(apply(log(g.ans+1), 2,mean), type="b", ylab="Nombre de résultats (log+1)", xlab="Nombre de lettres")
plot(apply(g.ans==0, 2, sum), type="b", ylab="% de résultats nuls", xlab="Nombre de lettres")

Hum, ça pour être parlant… Quand on vient du monde de la biologie (et pire encore, de l’écologie) on hallucine toujours un peu face à ce genre de données ! C’est doux comme de la soie !

Comme on pouvait s’y attendre, le nombre de réponses décroit de manière exponentielle avec l’augmentation du nombre de lettre… jusqu’à 7 lettres. A 8 lettres 90% des requêtes ne renvoient plus aucun résultat. A partir de 9, plus rien, en tout cas dans cet échantillon. M’enfin 7 lettres c’est déjà pas mal, des combinaisons à 7 lettres il y en a 26^7 soit plus de 8 milliards…

Facebooktwitter
Quelques réflexions sur le permis de conduire

Quelques réflexions sur le permis de conduire

J’ai eu mon permis de conduire il y a quelques semaines et je n’ai même pas fêté ça. Si j’avais eu quelques potes sous la main, nul doute que nous nous serions emparés du prétexte mais doit on se réjouir d’avoir englouti une énergie considérable et des flots d’euros pour avoir le droit de devenir un pollueur actif et de jouir d’une illusion de liberté que l’on paye cher à l’industrie pétrolière ? Comme je n’était pas un élève très doué la petite blague m’aura en tout coûté plus de 2000 euros. Voici quelques enseignements que j’ai pu tirer de cette expérience dont je me serais volontiers passé. Je les partage avec vous, souhaitant bonne chance à ceux qui devront en passer par là…

Martin Gommel on Flickr (CC BY-NC-ND)

Ne comptez par sur votre banquier (surtout à la Banque Postale)

Tout le monde le sait, le permis ça coûte un bras. Certains s’en tirent pas trop mal et puis il y a les boulets de mon espèce qui ratent l’examen et à qui il faut quinze heures de leçon pour arriver à passer les rapports… Dans tout les cas arrive le moment douloureux où il faut sortir le chéquier. Comme la plupart des candidats sont des jeunes souvent désargentés, l’État a mis en place le « Permis à 1 euro ». Ça ne veut pas dire qu’on va vous faire le permis à un euro faut pas déconner quand même ! Ça veut juste dire qu’une banque vous fait un prêt que vous remboursez 1 euro/jour et l’État paye les intérêts à la banque. Le principe est pas mal, voyons la pratique.

Je suis à la Banque Postale, je me pointe la gueule enfarinée au guichet. La fille ne comprends rien, elle n’a jamais vu le document que je lui tends. Finalement un responsable m’explique que je dois prendre rendez vous avec mon conseiller financier. Deux jour plus tard je me pointe au rendez-vous, ça dure plus de deux heures pendant lesquels le type me ré-explique toute la procédure puis fait le tour de mes comptes, puis demande des documents sur mon garant. A la fin il me dit que naturellement ce n’est pas lui qui va prendre la décision de m’accorder le prêt. Il téléphone à Paris, et me passe une fille qui à nouveau me repose 50 questions… Je sors du bureau, dubitatif. C’était comme si je leur demandais un prêt de 250000 euros. Au bout d’une semaine la grosse blague, je reçois un courrier me notifiant qu’après simulation et examen de mon dossier la banque me refuse ma demande de prêt. Mon conseiller m’explique qu’il en est désolé mais qu’il ne peut rien pour moi. Tout ça se décide à Paris dans des conditions pour le moins opaque.

C’est juste un scandale, ces abrutis de banquiers me refuse un prêt de 1200 euros alors qu’il font joujou avec des millions sur les marchés financiers. Précisons que j’étais leur client depuis plus de cinq ans et que durant tout ce temps je n’ai pas été dans le rouge plus de cinq fois. Mon garant était fonctionnaire de catégorie A avec un revenu fixe et largement suffisant pour un tel prêt. Autrement dit un paquet de gens doivent se pointer avec un moins bon dossier et se faire gentiment remballer. Ironique quand on sait que ces mesures ont été prises pour aider ceux qui ont le moins de moyens…

Jouer à GTA ou à Need for Speed ne vous servira à rien

C’est bien malheureux mais les heures que j’ai pu passer au volant dans les rues de Liberty City et les tournois endiablés à bord de monstrueuses caisses couvertes de néons n’ont pas fait de moi un as de la route. En fait ces jeux ont même plutôt tendance à donner de mauvais réflexes car écraser une mamie est éliminatoire le jour de l’examen. Mais que cela ne vous dissuade pas de vous amuser ! J’ai remarqué qu’après une leçon épuisante de conduite, une petite course sur NFS atteint un niveau de fun record.

Misez sur vos facultés intellectuelles à défaut de savoir conduire

Le permis est avant tout une question de maîtrise technique que l’on acquiert au fur et à mesure des leçons. Comme partout, certain sont plus doués et apprennent plus vite. D’autres (comme moi) galèrent beaucoup ! A ceux là je conseille de ne pas se décourager et d’envisager la conduite accompagnée (voir point suivant) mais aussi de compenser avec leur neurones. Car dans le permis aussi il y a de la théorie. L’examen du code par exemple est uniquement basé sur la connaissance du code de la route et l’interprétation de situations. Il y a des gens qui mettent des années à avoir leur code en enchaînant les échecs à l’examen et les auto-école en profitent à fond avec plein de petites lignes glissées dans le contrat, qui à la fin, coûtent beaucoup d’argent. La solution que j’ai adoptée est simple : travail intensif ! Je me suis mangé leur bouquin immonde et tout leurs cours vidéo en 2 semaines, puis pendant une semaine j’ai enchainé les tests (attention de veiller à ce que l’auto-école donne accès à une banque de tests en ligne). Y a que ça qui marche, au bout de 400 questions on voit venir tout les pièges. J’ai donc eu mon code en 3 semaines au tarif minimum.

Pour l’épreuve pratique de conduite les choses se corsent mais là aussi un peu de travail à la maison permet de gratter quelques points. Connaitre les commandes, effectuer les vérifications et s’installer correctement dans le véhicule, ça peut rapporter jusqu’à 9 points (sur 30). Au passage je vous conseille ce site bien foutu pour réviser.

Tablez sur la conduite accompagnée et restez vous-même (i.e. un gros geek)

La conduite accompagnée permet de prendre confiance au volant et de terroriser son accompagnateur. Il serait donc dommage de s’en priver. En plus pour les majeurs, il existe une formule light : la conduite supervisée.

En ouvrant mon livret d’apprentissage je constate que je dois relever chaque trajet avec la date et la distance parcourue. Hahaha je vais te faire ça avec Excel ça va être rigolo en plus d’être joli. Mais je me rends vite compte que ça me soule d’aller chercher les distances sur google map. R peut nous faire tout ça tout seul et ça va être très rigolo en plus d’être très joli. Maintenant vous savez comment j’en suis arrivé à développer les fonctions présentées dans mon dernier billet. Pour les exploiter dans le cadre de la conduite accompagnée, il suffit de remplir un tableau comme ça :

DATE FROMCITY FROMDEP TOCITY TODEP AR
24/03/2012 LYON 69 GRENOBLE 38 NO

On précise le n° de département pour lever les ambiguïtés lors de la résolution d’adresse. La colonne AR est utilisée pour préciser si le trajet est un aller-retour.

source("script_mapquest.R")
tab <- read.table("conduite.txt", h=T)
tab$FROMDEP <- sprintf("%02.0f", tab$FROMDEP)
tab$TODEP <- sprintf("%02.0f", tab$TODEP)

from.cont <- paste(tab$FROMCITY, tab$FROMDEP, sep="+")
to.cont <- paste(tab$TOCITY, tab$TODEP, sep="+")

DIST <- mapq.distance(from.cont, to.cont, print=FALSE)
DIST <- DIST*ifelse(tab$AR=="NO", 1, 2)
sum(DIST)

DATE <- strptime(tab$DATE, format="%d/%m/%Y")
plot(DATE,cumsum(DIST), type="b", pch=20, ylab="Distance Cumulée (Km)", xlab="Date")
abline(h=c(1000), lty="dashed")

La commande source sert à charger les fonctions que l’on trouve ici. On utilise sprintf pour formater les chiffres car R à la fâcheuse habitude de supprimer les 0 qui précèdent les nombres. La ligne 11 renvoie le nombre total de km parcourus et on peut faire un petit graphique de son expérience, qui va croissante.

Distance cumulée en fonction du temps. Ojectif 1000 km atteint :p

En guise de conclusion : réformez moi ce système à la con

Voilà ma conclusion. Le permis de conduire en France a grand besoin d’être réformé en profondeur. Et ça beaucoup de gens le disent sans que ça bouge pour autant. Pourtant je suis d’avis qu’il ne faut pas y aller avec le dos de la cuillère. Je rêve d’une nationalisation des auto-écoles que l’on intégrerait aux lycées. Mon immersion au sein de la mafia des auto-écoles et mes mésaventures à la banque ne m’ont pas transformé en communiste… mais presque ! L’apprentissage de la conduite pourrait être une option facultative (mais fortement conseillée), pour laquelle des créneaux serait réservés dans l’emploi du temps. Le prix de la formation serait fixe, indexé sur le QF et l’évaluation serait continue. Ce ne sont que quelques idées lancées en l’air et ça peut sonner un peu extrême mais si on maintient que le permis de conduire est un facteur important pour l’accès à l’emploi, il serait temps de remettre un peu d’égalité dans ce bazar.

Facebooktwitter
Distances routières avec R et l’API Mapquest

Distances routières avec R et l’API Mapquest

Voilà un petit bout de code que j’avais écrit pour obtenir rapidement la distance par la route entre deux lieux géographiques avec R. On utilise les librairies RCurl et XML pour interroger l’API Mapquest basée elle même sur les données d’OSM. Le code est constitué de trois fonctions :

  • mapq.loc() renvoie un certain nombre d’infos sur un lieu (y compris ses coordonnées géographiques)
  • mapq.dist() renvoie la distance entre deux points géographiques spécifiés par leurs coordonnées
  • mapq.distance() : renvoie la distance routière entre deux points géographiques spécifiés par leurs noms. Choix de l’unité possible (« k » pour km ou « m » pour miles)

Une petite application de ces fonction est prévue pour le prochain billet 😉
On peut noter qu’une fonction équivalente est désormais fournie avec le package ggmap, basée elle sur le service Google Maps.

library (RCurl)
library (XML)

mapq.loc &lt;- function(query, format=&quot;xml&quot;, limit=1, details=1)
  {
  urlroot &lt;- &quot;http://open.mapquestapi.com/nominatim/v1/search?&quot;
  url &lt;- paste(urlroot, &quot;format=&quot;, format, &quot;&amp;q=&quot;, query, &quot;&amp;addressdetails=&quot;, details, &quot;&amp;limit=&quot;, limit, sep=&quot;&quot;)

  xmllocinfo &lt;- getURL(url)
  xmllocinfo &lt;- htmlParse(xmllocinfo)
  xmllocinfo &lt;- xmlRoot(xmllocinfo)
   
  verif &lt;- function(express) tryCatch(express, error=function(e) NULL)
  locinfo &lt;- list()
  locinfo$lat &lt;- verif(as.numeric(unlist(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/@lat&quot;))))
  locinfo$lon &lt;- verif(as.numeric(unlist(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/@lon&quot;))))
  locinfo$city &lt;- verif(as.character(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/city&quot;, xmlValue)))
  locinfo$county &lt;- verif(as.character(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/county&quot;, xmlValue)))
  locinfo$state &lt;- verif(as.character(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/state&quot;, xmlValue)))
  locinfo$country &lt;- verif(as.character(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/country&quot;, xmlValue)))
  locinfo$countrycode &lt;- verif(as.character(xpathApply(xmllocinfo, &quot;/html/body/searchresults/place/country_code&quot;, xmlValue)))
  return(locinfo)
  }


mapq.dist &lt;- function(Alat, Alon, Blat, Blon, format=&quot;xml&quot;, unit=&quot;k&quot;)
  {
  urlroot &lt;- &quot;http://open.mapquestapi.com/directions/v0/route?&quot;
  url &lt;- paste(urlroot, &quot;outFormat=&quot;, format, &quot;&amp;unit=&quot;, unit, &quot;&amp;from=&quot;, Alat, &quot;,&quot;, Alon, &quot;&amp;to=&quot;, Blat, &quot;,&quot;, Blon, sep=&quot;&quot;)
  
  xmldistinfo &lt;- getURL(url)
  xmldistinfo &lt;- htmlParse(xmldistinfo)
  xmldistinfo &lt;- xmlRoot(xmldistinfo)
  
  verif &lt;- function(express) tryCatch(express, error=function(e) NULL)
  distance &lt;- verif(as.numeric(xpathApply(xmldistinfo, &quot;/html/body/response/route/distance&quot;, xmlValue)))
  return(distance)
  }

mapq.distance &lt;- function(from, to, unit=&quot;k&quot;, print=TRUE)
  {
  from.f &lt;- chartr(&quot; &quot;,&quot;+&quot;, from)
  to.f &lt;- chartr(&quot; &quot;,&quot;+&quot;, to)
  from.info &lt;- mapq.loc(from.f)
  to.info &lt;- mapq.loc(to.f)
  distance &lt;- mapq.dist(from.info$lat, from.info$lon, to.info$lat, to.info$lon, unit=unit)
  if(unit==&quot;k&quot;) unit.print &lt;- &quot;Km&quot;
  if(unit==&quot;m&quot;) unit.print &lt;- &quot;Miles&quot;
  if (print==TRUE){
    cat(&quot;Distance between&quot;, &quot;\n&quot;)
    cat(from, &quot;,&quot;, from.info$state, &quot;,&quot;, toupper(from.info$countrycode), &quot;and&quot;, to, &quot;,&quot;, to.info$state, &quot;,&quot;, toupper(to.info$countrycode), &quot;\n&quot;)
    cat(distance, unit.print, &quot;\n&quot;)
  } else {
    invisible(distance)
  }
  }
Facebooktwitter
Une carte des stations Vélo’V avec R (Partie 3 : Participer à OpenStreetMap)

Une carte des stations Vélo’V avec R (Partie 3 : Participer à OpenStreetMap)

OpenStreetMap est un formidable projet de cartographie collaborative en ligne. Dans deux précédents billets (ici et ) nous avons vu comment importer des données en provenance d’OSM dans R et un exemple (parmi une infinité) de traitement et de rendu cartographique. Mais les données que nous avons utilisées n’étaient pas vraiment complètes. Là où réside tout l’intérêt d’OSM c’est que tout le monde peut intervenir en complétant la base de donnée sur la base de ses propres connaissances, d’une sortie terrain ou encore avec l’imagerie satellite fournie par Bing.

Dans notre cas toutes les stations Vélo’V de la ville de Lyon ont déjà été localisé par les cartographes d’OSM mais pour un certain nombre d’entre elles les tags associés ne sont pas assez informatifs. On s’est par exemple intéressé à la capacité des stations (i.e. le nombre de vélos que l’on peut y garer) qui est renseignée dans la base de données avec le tag capacity. A l’heure où j’écris ces lignes – et cette précision est importante car les choses vont très vite sur OSM – la capacité est indisponible pour 87 stations. Il pourrait alors être intéressant de produire une carte de ces stations « incomplètes » pour optimiser le travail de terrain. Une carte statique comme on en a produit jusqu’à présent n’est pas idéale. L’idée ici est d’utiliser l’outil Google Maps qui permet d’une part d’accéder à une carte interactive mais aussi d’ajouter des points d’intérêts définis par l’utilisateur et accessoirement de profiter d’un module GPS.

Google Maps peut être très pratique pour s'orienter sur le terrain et localiser des éléments à cartographier

Dans ce billet, on réalisait l’importation des données à partir d’une extraction de la base téléchargée sur geofabrik mais dans le cas présent cette méthode se révèle lourde car il faudra re-télécharger le fichier à chaque fois qu’on voudra mettre à jour la carte. Ici il est plus intéressant de faire appel à une API pour extraire directement les données qui nous intéressent. J’utilise ici l’Overpass API, j’en ai essayé d’autre mais elles sont soit très peu réactives, soit HS, soit non à jour… Pour ce qui est du code on charge d’abord les données avec RCurl puis on parse le XML. Si les choses étaient simples on pourrait directement interpréter le XML avec la fonction as_osmar mais les API retournent souvent les objets en leur enlevant certains attributs ce qui pose problème à la fonction as_osmar. Une solution simple ici est de créer artificiellement les attributs manquants. Une fois l’objet converti au format sp, on exporte les données au format KML.

library(osmar)
library(sp)
library (XML)
library(rgdal)
osm.xml <- getURL("http://overpass-api.de/api/interpreter?data=node[amenity=bicycle_rental](45.64,4.57,45.86,5.12);out;", .encoding="UTF-8")
osm.xml <- xmlParse(osm.xml)
xmlSApply(xmlRoot(osm.xml), addAttributes,
"version"=1,
"timestamp"="2000-01-01T01:01:01Z",
"uid"=1,
"user"="a",
"changeset"=1)

stations <- as_osmar(osm.xml)
stations <-addtags(stations)
stations <- as_sp(stations, what="points")
stations$capacity <- as.numeric(as.character(stations@data$capacity))
stations.fix <- stations[which(stations$capacity==0 | is.na(stations$capacity)),]
writeOGR(stations.fix[,-5], dsn="stafix.kml", layer= "stations", driver="KML")

Il s’agit maintenant d’ouvrir le fichier KML avec Google Maps. Pour cela, il faut héberger son fichier KML soit sur votre propre serveur, soit à l’aide d’un service comme Google Sites. Ne reste plus qu’à ouvrir l’URL dans Google Maps et récupérer un lien abrégé pour retrouver sa carte sur n’importe quel appareil capable d’afficher Google Maps. Bien sur les données ne sont pas mises à jour de façon dynamique mais cette méthode a l’avantage d’être relativement simple et rapide à mettre en place.

Facebooktwitter