Skip to Content

Nous adressons toutes nos pensées à la famille de notre ami Jérôme !

http://www.forumsig.org/showthread.php/43488-Disparition-de-Phoenix

Python: création de cartes dynamiques Google Maps avec Google Charts (kml)


python

Pour créer les graphiques avec Python, nous avons utilisé jusqu'à présent matplotlib mais il y a énormément d'autres possibilités (pypi.python.org/pypi).

Parmi celles-ci, il y en a qui utilisent des services web dynamiques comme Google Chart.

Le blog.thematicmapping.org/2008/04/using-google-charts-with-kml.html montre comment utiliser Google Chart dans un fichier kml pour fournir des cartes dynamiques. Cette particularité est exploitée par Luis Apiolaza qui illustre sur son site comment le faire avec Python. C'est cette démarche que nous allons analyser (apiolaza.net/code/dynamic-maps-python.html).

Google Charts

Créé en 2007, Google Charts est une API qui renvoie une image au format PNG à partir d'une URL simple avec une série de paramètres. Plusieurs types de graphiques sont possibles en fonction des paramètres choisis (code.google.com/intl/fr/apis/chart/).

exemple:

http://chart.apis.google.com/chart?cht=p3&chd=t:10.0,10.0,10.0&chs=450x200&chl=Premier|Deuxième|Troisième&chco=ff0000,00ff00,0000ff

chart.apis.google.com/chart

  • http://chart.apis.google.com/chart? sert à appeler l'API;
  • Le paramètre cht spécifie le type de graphique. Dans ce cas-ci, un digramme circulaire en 3D ("p3") ;
  • chd sert à transférer les données, ici au format texte;
  • chs est la taille du graphique ( en pixels);
  • chl sert à spécifier les étiquettes par rapport à l'ordre des données fournies avec chd;
  • chco sert à indiquer les couleurs à afficher;
  • d'autres éléments peuvent être spécifiés comme les axes etc.

En tant qu'API REST, les données sont envoyées directement dans l'URL dont la longueur est limitée par le GET (2k). C'est pourquoi Google a créé des formats « condensés » pour les données (Simple Encoding Format, s, et Extended Encoding Format, e, voir code.google.com/intl/fr/apis/chart/docs/data_formats.html). Une autre solution proposée est d'utiliser POST à partir de langages comme PHP ou Python, voir code.google.com/intl/fr/apis/chart/docs/post_requests.html).

http://chart.apis.google.com/chart?cht=p3&chd=s:UUU&chs=450x200&chl=Premier|Deuxième|Troisième&chco=ff0000,00ff00,0000ff

 chart.apis.google.com/chart

Le gros avantage de cette solution est qu'il est donc possible de créer un graphique et de l'utiliser dans n'importe quelle page HTML sans nécessiter de fichier « physique » puisque ce n'est qu'un lien. Tous les exemples de graphiques figurent dans code.google.com/intl/fr/apis/chart/docs/gallery/chart_gall.html

Python et Google Charts

Sachant comment est construite une URL, il est alors très facile d'automatiser le processus en Python et même, de télécharger le fichier résultant:

linechart

  1. >>> import urllib2
  2.  
  3.  
  4. >>> #fonction pour créer des lineCharts simples (de http://apiolaza.net/code/dynamic-maps-python.html, légèrement modifiée)
  5. >>> def lineChart(data, size):
  6. ... baseURL = 'http://chart.apis.google.com/chart?cht=lc&chs='
  7. ... baseData = '&chd=t:' #lineChart
  8. ... newData = ','.join(data)
  9. ... baseData = baseData + newData
  10. ... URL = baseURL + size + baseData
  11. ... return URL
  12.  
  13. >>> #entrée des éléments
  14. >>> data = ['27','76.5','92','34','65','81','82','80','63','24','70.54','45.89','29.75','27']
  15. >>> size = '250x100'
  16.  
  17. >>> #création de l'URL Google Chart
  18. >>> chart = lineChart(data,size)
  19. >>> chart
  20. 'http://chart.apis.google.com/chart?cht=lc&chs=250x100&chd=t:27,76.5,92,34,65,81,82,80,63,24,70.54,45.89,29.75,27'
  21.  
  22. >>> #écriture du fichier png résultant
  23. >>> res = urllib2.urlopen(chart)
  24. >>> open('chartpy.png','wb').write(res.read())

et le résultat est :

Comme toujours avec Python, des modules ont été créés pour automatiser le processus comme « Python Google Chart » (pygooglechart),  « Python Google Chart Wrapper » (GChartWrapper) ou Graphy.

L'exemple précédent traité avec GChartWrapper:

avec GchartWrapper

  1. >>> from GChartWrapper import *
  2. >>> G = Line('27,76.5,92,34,65,81,82,80,63,24,70.54,45.89,29.75,27',encoding='text')
  3. >>> G.size(250,100)
  4. >>> G.axes.type('xy')
  5. >>> G.url
  6. 'http://chart.apis.google.com/chart?chxt=x,y&chd=t:27,76.5,92,34,65,81,82,80,63,24,70.54,45.89,29.75,27&chma=0,0,30,0&chs=250x100&cht=lc'
  7. >>> G.show() #montre le graphique dans le butineur par défaut
  8. >>> import urllib2
  9. >>> fichier = urllib2.urlopen(G.url)
  10. >>> open('chartGchart.png','wb').write(fichier.read())

Quelques exemples de graphiques crées avec GChartWrapper ou pygooglechart:

 

De nombreux autres exemples sont fournis à:

D'autres possibilités d'utilisation sont données dans :

                                             avec matplotlib                   chart.apis.google.com/chart

 

Création de cartes Google Maps dynamiques

Google Charts permet donc de créer une multitude de graphiques sous forme d'une URL relativement simple qui peut être utilisée dans un fichier kml pour créer des cartes dynamiques. Examinons la démarche de Luis Apiolaza, précédemment cité.

La première démarche est l'obtention de l'URL du ou des graphiques que l'on veut utiliser:

graphique

  1. from GChartWrapper import *
  2.  
  3. # création d'un graphique Google Chart et renvoi de l'URL
  4. def macharte(data):
  5. G = Line(data)
  6. G.size(250,100)
  7. G.color('76A4FB')
  8. G.axes.type('xy')
  9. G.grid(20.0,25.0,1,0)
  10. return G.url

Ensuite, pour la démonstration, j'utilise mon serveur Dropbox (www.dropbox.com/)

lecture

  1. import urllib
  2. # Lecture des données: connection à mon serveur Dropbox et extraction des lignes.
  3. f = urllib.urlopen('http://dl.dropbox.com/u/678636/test3.csv')
  4. stations = f.readlines()

Les données dans le fichier csv sont sous la forme nom (0), long (1), lat (2) et propriété (3). Pour la démonstration, l'auteur génère des données aléatoires.

création du fichier kml

  1. '''script de http://apiolaza.net/code/dynamic-maps-python.html,légèrement modifié'''
  2.  
  3. import random:
  4.  
  5. #création du fichier kml
  6. kmlBody = ('')
  7. for s in stations:
  8. data = s.split(',')
  9. # Géneration de données aléatoires
  10. a = []
  11. for r in range(60):
  12. a.append(round(random.gauss(50,10), 1))
  13. chart = macharte(a)
  14. kml = (
  15. '<Placemark>\n'
  16. '<name>%s</name>\n'
  17. '<description>\n'
  18. '<![CDATA[\n'
  19. '<p>Valeur: %s</p>\n'
  20. '<p><img src="%s" width="250" height="100" /></p>\n'
  21. ']]>\n'
  22. '</description>\n'
  23. '<Point>\n'
  24. '<coordinates>%f,%f</coordinates>\n'
  25. '</Point>\n'
  26. '</Placemark>\n'
  27. ) %(data[0], data[3], chart, float(data[1]), float(data[2]))
  28.  
  29. kmlBody = kmlBody + kml
  30.  
  31.  
  32. #"morceaux" du fichier KML
  33. kmlHeader = ('<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n'
  34. '<kml xmlns=\"http://earth.google.com/kml/2.2\">\n'
  35. '<Document>\n')
  36.  
  37. kmlFooter = ('</Document>\n'
  38. '</kml>\n')
  39.  
  40. kmlfinal = kmlHeader + kmlBody + kmlFooter
  41. print kmlfinal
  42. open('mon.kml','wb').write(kmlfinal)

Le résultat est:

fichier kml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <kml xmlns="http://earth.google.com/kml/2.2">
  3. <Document>
  4. <Placemark>
  5. <name>Arnao</name>
  6. <description>
  7. <![CDATA[
  8. <p>Valeur: marea
  9. </p>
  10. <p><img src="http://chart.apis.google.com/chart?chxt=x,y&chd=t:46.6,34.3,54.6,41.7,35.6,47.6,64.9,47.1,29.6,57.1,63.7,63.5,44.1,54.5,61.8,43.4,55.6,43.7,61.5,52.0,60.7,57.7,73.9,53.1,42.0,49.1,41.5,47.3,58.7,41.8,50.8,67.0,47.6,51.8,53.0,61.7,48.3,51.6,45.0,47.3,71.2,60.0,48.3,68.5,56.6,42.9,54.7,47.5,44.6,63.7,41.2,52.4,40.6,57.7,41.2,60.8,37.5,32.9,59.6,33.8&chg=20.0,25.0,1.0,0.0&chco=76a4fb&chs=250x100&cht=lc" width="250" height="100" /></p>
  11. ]]>
  12. </description>
  13. <Point>
  14. <coordinates>-5.981755,43.576785</coordinates>
  15. </Point>
  16. </Placemark>
  17. <Placemark>
  18. <name>Salinas</name>
  19. <description>
  20. <![CDATA[
  21. <p>Valeur: marea
  22. </p>
  23. <p><img src="http://chart.apis.google.com/chart?chxt=x,y&chd=t:47.2,49.8,66.1,37.1,41.6,53.9,54.2,56.9,42.6,50.2,45.7,62.5,53.3,45.8,64.7,44.0,50.5,47.5,43.4,59.1,36.9,44.4,51.6,64.8,47.2,60.9,44.2,32.1,49.6,46.1,48.0,60.4,43.7,42.6,49.6,39.0,45.3,66.4,60.3,72.5,52.2,48.6,68.8,36.9,53.4,52.3,66.1,47.9,48.3,44.9,74.1,35.6,28.2,61.3,46.6,54.1,43.0,50.3,40.8,63.2&chg=20.0,25.0,1.0,0.0&chco=76a4fb&chs=250x100&cht=lc" width="250" height="100" /></p>
  24. ]]>
  25. </description>
  26. <Point>
  27. <coordinates>-5.959396,43.578401</coordinates>
  28. </Point>
  29. </Placemark>
  30. <Placemark>
  31. <name>Bayas</name>
  32. <description>
  33. <![CDATA[
  34. <p>Valeur: marea</p>
  35. <p><img src="http://chart.apis.google.com/chart?chxt=x,y&chd=t:53.3,49.6,59.7,31.9,44.5,43.7,62.7,65.6,53.7,37.5,70.6,65.0,43.4,46.3,49.8,61.3,52.8,54.1,51.8,61.1,61.1,50.8,50.8,63.2,47.2,56.3,53.1,60.3,36.0,46.1,73.4,35.8,43.6,52.7,53.4,61.2,39.4,56.2,66.0,32.1,51.7,55.1,58.9,50.2,29.2,51.8,49.4,53.5,63.7,66.5,45.5,40.3,45.6,38.5,46.4,49.2,29.5,58.4,56.6,58.8&chg=20.0,25.0,1.0,0.0&chco=76a4fb&chs=250x100&cht=lc" width="250" height="100" /></p>
  36. ]]>
  37. </description>
  38. <Point>
  39. <coordinates>-6.046944,43.573365</coordinates>
  40. </Point>
  41. </Placemark>
  42. </Document>
  43. </kml>

Ce fichier kml pourrait aussi être créé avec les modules permettant de traiter les fichiers XML (Elementtree etc.). Le résultat peut être vu (toujours en utilisant mon serveur Dropbox)

- sur Google Maps.

ouverture avec le butineur par défaut

  1. import webbrowser
  2. url="http://maps.google.com/maps?q=http://dl.dropbox.com/u/678636/"+"mon.kml"
  3. import webbrowser
  4. webbrowser.open_new(url)

- ou directement:

maps.google.com/maps

 

- ou avec Google Earth:

 

En pratique, il suffit donc de mettre à jour le fichier kml avec le script Python. L'application résultante de Luis Apiolaza, maps.google.com/maps, est là pour le montrer.

Conclusions

Comme nous venons de le voir, les possibilités de Google Chart sont très intéressantes.

Cependant, l'API a aussi des contraintes:

  • les données sont envoyées directement dans l'URL (taille !), mais les modules Python permettent de les « compresser » suivant les algorithmes de Google;
  • exemple: Extended Encoding Format (chd=e)

    1. >>> from pygooglechart import SimpleLineChart
    2. >>> chart = SimpleLineChart(200,200, y_range=(0, 10))
    3. >>> chart.add_data([1.0, 2.0, 6.0, 7.0, 5.0, 1.0])
    4. >>> chart.add_data([2.0, 5.0, 5.0, 2.0, 1.0, 2.0])
    5. >>> chart.get_url()
    6. 'http://chart.apis.google.com/chart?cht=lc&chs=200x200&chd=e:GaMzmZszgAGa,MzgAgAMzGaMz'
  • la taille des images résultantes est limitée à un maximum de 300000 pixels;
  • la résolution des images PNG résultantes est bonne pour être visualisées (72 x 72 ppi) mais faible pour autre chose.

Nonobstant ces quelques désagréments, c'est toujours un plaisir de travailler en Python, sans logiciel payant ou non, sans serveur cartographique et ce, quelques soient les réserves exprimées sur Google.

 

Tous les traitements ont été effectués sur Mac OS X avec Python 2.5.4. Hormis les captures d'écran (Google Maps, Google Earth) et l'image matplotlib, toutes les images ont été créées avec Python et Google Chart.


Site officiel : pygooglechart (PyPI)
Site officiel : pygooglechart (Python Google Chart)
Site officiel : GChartWrapper (PyPI)
Site officiel : GChartWrapper (Python Google Chart Wrapper)
Site officiel : Graphy (PyPI)
Site officiel : Graphy


GNU FDL Copyright (C) Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

Commentaires

open() pour kml

bjr,

je souhaite utiliser votre code pour générer un kml à partir de mon site, mais cela ne fonctionne pas.
il n'y a pas d'erreur mais aucun fichier ne se lance.

voila mon code :

kmlBody = ('test')

kmlHeader = ('\n'
'\n'
'\n')

kmlFooter = ('\n'
'\n')

kmlfinal = kmlHeader + kmlBody + kmlFooter
print kmlfinal
open('mon.kml','wb').write(kmlfinal)

je souhaite que quand ce code est sollicité, le fichier kml se télécharge.

en changeant les attributs de la fonction open (wb) cela met une erreur I/O seul 'wb' ne me donne pas d'erreur mais ne me génère pas non plus de fichier.

merci de votre aide.

www.forumsig.org

Bonjour

Pour toutes questions techniques, préférez le forumsig pour les poser.

Poster un nouveau commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.