Skip to content

Instantly share code, notes, and snippets.

@YannBouyeron
Last active June 11, 2019 22:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YannBouyeron/9e9611edeb7e0f7e2c357c22fe659c54 to your computer and use it in GitHub Desktop.
Save YannBouyeron/9e9611edeb7e0f7e2c357c22fe659c54 to your computer and use it in GitHub Desktop.
Mise en évidence de la divergence associée aux dorsales en exploitant des données GPS avec Python3 et les modules Pandas et Basemap. Python Géologie GIS

Tectonique des plaques avec Pandas et Basemap

On cherche ici à confirmer le contexte tectonique divergent associé aux dorsales grâce aux données GPS, en exploitant des bases de données de différents types (SQL, CSV, XLSX) avec Python3 et les modules Pandas et Basemap.

Installer les modules nécessaires.

Le module sqlite3 est dans la bibliothèque standard de python, vous n’avez donc pas besoin de l’installer.

Les modules suivants ne font pas partie de la bibliothèque standard de python (cliquez sur les liens pour accéder aux sites officiels de ces modules et aux procédures d’installations):

  • Pandas permet de faire de l’analyse de données
  • Matplotlib et Basemap nous permettront de créer le fond de carte et de le modifier
  • Numpy est nécessaire au fonctionnement de matplotlib
  • Koala permet de tester facilement des régressions linéaire , exponentielle, et puissance.

Des introductions relatives à ces modules sont disponibles: Pandas, Matplotlib, Numpy

Koala doit être téléchargé ici et placé dans le répertoire actif à partir duquel vous travaillez.

Importez les modules nécessaires

Une fois les modules installés, vous pouvez les importer de la manière suivante:

>>> from sqlite3 import *

>>> import pandas as pd

>>> import numpy as np

>>> from mpl_toolkits.basemap import Basemap

>>> import matplotlib.pyplot as plt

>>> from koala import Koala

Si vous n’avez pas d’UI (interface graphique ... c’est à dire un bureau avec des dossiers , des fichiers, voire même un joli chaton dans un panier fleuri en fond d’écran), ajoutez ces deux lignes au tout début de votre code:

>>> import matplotlib
>>> matplotlib.use('Agg') # no UI backend

Récupérez la base de données GPS

Cette base de données au format SQL contient les positions en latitude et longitude des stations EISL, PAMA, et BRAZZ au cours du temps.

Vous pouvez télécharger cette base de données ici.

Connectez vous à la base:

>>> con = connect("gps.db")	

Examinez le contenu de la base:

>>> liste_tables = pd.read_sql_query("select name from sqlite_master where type = 'table'", con)

>>> liste_tables
    name
0  brazz
1   pama
2   eisl

Récupérez chacune des tables:

>>> brazz = pd.read_sql_query("select * from brazz", con)

>>> eisl = pd.read_sql_query("select * from eisl", con)

>>> pama = pd.read_sql_query("select * from pama", con)

Calculez les déplacements en latitude et en longitude des 3 stations gps

Nous allons utiliser le module Koala afin de reéaliser des régressions linéaires et de récupérer les équations de ces droites de régressions.

Convertissons notre objet DataFrame en objet Koala:

>>> kbrazz = Koala(brazz)

Examinons le contenu de la table kbrazz:

>>> kbrazz.head()
   temps                 lat              long
0  1995.1759                   0                 0
1  1995.1786  0.0992637499621001  1.17157402028476
2  1995.1814    -0.7112473790162  2.24455692153047
3  1995.1841  -0.859168912375599  0.17355308905353
4  1995.1869    -0.6836366309012     0.11077272029

Utilisez ensuite la méthode lin afin de tester une régression linéaire. Cette méthode requiert 2 arguments: les deux séries de données (X et Y) pour lesquelles on souhaite tester la régression:

>>> lat_brazz = kbrazz.lin("temps", "lat")

La méthode lin de l’objet Koala retourne un dictionnaire contenant toutes les informations relatives à la régression:

>>> lat_brazz
AttrDict({'equation': 'y = 1.2228585497565216 x + -2440.3739520157933', 'R': 0.995359092755059, 'a': 1.2228585497565216, 'b': -2440.3739520157933, 'f': 'y = 1.22x +-2440.37', 'r': 'R = 1.0', 'graph': <module 'matplotlib.pyplot' from '/usr/local/lib/python3.6/site-packages/matplotlib/pyplot.py'>})

Si vous possédez une UI, la méthode lin affiche automatiquement le graphique (plot + droite de régression). Dans tous les cas, vous pouvez sauvegarder ce graphique grâce à la commande savefig:

>>> plt.savefig("latbrazz.png")

On peut éventuellement annoter le graphique en y ajoutant par exemple l’équation et le coefficient de corrélation:

>>> plt.text(2000, 0, lat_brazz.f)
Text(2000,0,'y = 1.22x +-2440.37')

>>> plt.text(2000, -1, lat_brazz.r)
Text(2000,-1,'R = 1.0')
 
>>> plt.savefig("latbrazz2.png")

Faisons de même pour le déplacement de brazz en longitude

>>> lon_brazz = kbrazz.lin("temps", "long")

>>> plt.savefig("lonbrazz.png")

Puis conservons les coefficients directeurs des droites de régressions en les affectant à des variables. Ces coefficients directeurs correspondent à une variation de latitude (ou de longitude) sur une variation de temps, c’est à dire une vitesse de déplacement (en cm/an).

v_lat_brazz = lat_brazz.a
v_lon_brazz = lon_brazz.a

Le vecteur déplacement global est la somme des vecteurs déplacement latitude et longitude. Sa norme est égale à la racine carrée de la somme des carrés des vecteurs déplacement latitude et longitude:

n_brazz = round((v_lon_brazz**2 + v_lat_brazz**2)**0.5,2)

Faisons de même pour EISL et PAMA:

>>> keisl = Koala(eisl)

>>> lat_eisl = keisl.lin("temps", "lat")
>>> plt.savefig("lateisl.png")

>>> lon_eisl = keisl.lin("temps", "long")
>>> plt.savefig("loneisl.png")

>>> v_lat_eisl = lat_eisl.a
>>> v_lon_eisl = lon_eisl.a
>>> n_eisl = round((v_lon_eisl**2 + v_lat_eisl**2)**0.5,2)

>>> kpama = Koala(pama)

>>> lat_pama = kpama.lin("temps", "lat")
>>> plt.savefig("latpama.png")

>>> lon_pama = kpama.lin("temps", "long")
>>> plt.savefig("lonpama.png")

>>> v_lat_pama = lat_pama.a
>>> v_lon_pama = lon_pama.a
>>> n_pama = round((v_lon_pama**2 + v_lat_pama**2)**0.5,2)

Puis conservons toutes ces données dans un dictionnaire; nous en aurons besoin plus tard pour tracer les vecteurs sur le fond de carte.

vecteur = {"brazz":(v_lon_brazz, v_lat_brazz, n_brazz), "eisl":(v_lon_eisl, v_lat_eisl, n_eisl), "pama":(v_lon_pama, v_lat_pama, n_pama)}

On ferme l’objet plt, pour ne pas surcharger le fond de carte que l’on va créer:

plt.close()

Création du fond de carte

On utilise ici le modèle etopo qui permet d’avoir les reliefs.

>>> map = Basemap(projection='aeqd', lon_0 = -85, lat_0 = 10, width = 18000000, height = 15000000)

>>> map.etopo()

>>> map.drawcoastlines()

>>> plt.show()
>>> plt.savefig("fond.png")

Rajoutons les méridiens et les parallèles:

>>> map.drawmeridians(range(0,360,60), dashes=[3,1], linewidth=0.5, labels=[0,0,0,1], zorder=2)

>>> map.drawparallels(range(-40,50,10), dashes=[4,2], linewidth=0.5, labels=[1,0,0,0], zorder=1)

>>> plt.show()
>>> plt.savefig("fondmp.png")

L’argument dashes pemret de gérer la longueur des tirets et l’espacement.

L’argument labels permet de gérer la position des graduations (latitudes et/ou longitudes)

La dorsale medio-atlantique et les fosses sont bien visibles; en revanche la dorsale pacifique n’est pas très nette. Nous allons ajouter les foyers sismiques et les volcans, de manière à mieux distinguer les frontières de plaques.

Placement des foyers sismiques

Le site https://earthquake.usgs.gov donne accès aux séismes récents (1 heure, 1 semaine, ou 1 mois) répertoriés et localisés dans un fichier csv que l’on peut récuperer avec pandas:

>>> seismes = pd.read_csv("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv")

Cependant , selon les mois, l’activité sismique de la dorsale Pacifique n’est pas toujours suffisante pour bien reperer cette dorsale, donc j'utilise cette base dont je ne connais pas la source, mais qui semble tout a fait cohérente (au moins en ce qui concerne la localisation... et c’est tout ce dont nous avons besoin). Il faut la télécharger depuis Gist et l’importer localement.

>>> seismes = pd.read_csv("earthquakes.csv")

Listons les colonnes de cette base de données:

>>> seismes.columns
Index(['time', 'latitude', 'longitude', 'depth', 'mag', 'magType', 'nst',
       'gap', 'dmin', 'rms', 'net', 'id', 'updated', 'place', 'type'],
      dtype='object')

Et conservons toutes les lignes mais seulement les colonnes latitude et longitude:

>>> df = seismes.loc[:,["latitude", "longitude"]]

Plaçons alors les foyers sismiques sur notre fond de carte:

>>> for i in range(len(df)):
>>> 	x, y = df.longitude[i], df.latitude[i]
>>> 	try:
>>>         	x, y = map(x,y)
>>> 	        map.plot(x, y, marker='*', color='y', markersize=2)
>>> 	except:
>>> 		pass
>>>
>>> plt.show()
>>> plt.savefig("seismes.png")

(On aurait éventuellement pu garder la profondeur depth et adapter la boucle for ci dessus afin d’attribuer des couleurs distinctes aux foyers sismiques en fonction de leurs profondeurs afin de "visualiser" le plan de Benioff)

Placement des volcans

La base de données utilisée ici provient du site data.world. Ce site recense des milliers de bases de données (dans différents formats: sql, csv, xlsx...) qui sont dans l’ensemble très bien documentées. Il est nécessaire de s’inscrire sur le site pour pouvoir y faire des recherches. La base est au format xlsx , et ce lien permet d’y accéder sans être inscrit sur data.world.

>>> volcans = pd.read_excel("https://query.data.world/s/jejujyib5byfslvmbixubz6leb3f4d")

Cette base contient beaucoup de colonnes qui ne nous seront pas utiles, et en plus elle recense les éruptions "significatives" depuis -4360 BC ... donc il va falloir filtrer tout ca afin de ne conserver que les volcans les plus "récents" (actifs depuis 1900) pour ne pas trop surcharger notre carte.

>>> vf = volcans.loc[:,["Year", "Latitude", "Longitude"]]

>>> for v in range(len(vf)):
>>> 	if vf.Year[v] > 1900:
>>> 	    x, y = vf.Longitude[v], vf.Latitude[v]
>>> 	    try:
>>> 	        x, y = map(x,y)
>>> 	        map.plot(x, y, marker='*', color="r", markersize=2)
>>> 	    except:
>>> 	        pass
>>> plt.show()
>>> plt.savefig("vulcan.png")

Placement des stations GPS

>>> stations = [("EISL", -109.57, -27.14), ("PAMA", -149.57, -17.56), ("BRAZZ", -47.80, -15.90)] # liste de tuple (nom, lon, lat)

>>> for s in stations:
>>>     x, y = map(s[1], s[2])
>>>     map.plot(x, y, marker='+', markersize=10, color="k")
>>>     plt.text(x, y, s[0], ha = "left", va = "top", fontsize = 8)

>>> plt.show()
>>> plt.savefig("gpscarte.png")

Il y’a un bug: les arguments ha (horizontal alignement) et va (vertical alignement) sont "inversés", donc pour placer le nom de la station en bas à droite du repère de la station il faut faire comme si on voulait le placer en haut à gauche !!!

Palcement des vecteurs déplacements sur la carte.

On utilise la méthode quiver qui permet de placer des vecteurs. Cette méthode requiert 4 arguments obligatoires:

  • x et y : coordonnées de la base du vecteur

  • u, v : les deux composantes du vecteurs

Les autres arguments sont optionnels, ils permettent notamment de configurer l’échelle et l’apparence du vecteur.

Pour des raisons de place, je n’ai pas utilisé la même échelle pour les différents vecteurs: EISL et BRAZZ sont représentés au 1/8 tandis que PAMA est au 1/15. Attention, l’unité est le pouce (inches) et non pas le centimètre.

>>> x, y = map(stations[0][1], stations[0][2])

>>> map.quiver(x, y, v_lon_eisl, v_lat_eisl, scale_units='inches', scale=8, headwidth=12, headlength=15, units='inches', width=0.01)

>>> x, y = map(stations[1][1], stations[1][2])

>>> map.quiver(x, y, v_lon_pama, v_lat_pama, scale_units='inches', scale=14, headwidth=12, headlength=15, units='inches', width=0.01)

>>> x, y = map(stations[2][1], stations[2][2])

>>> map.quiver(x, y, v_lon_brazz, v_lat_brazz, scale_units='inches', scale=8, headwidth=12, headlength=10, units="inches", width=0.01)

>>> for s in stations:
>>>     x, y = map(s[1], s[2])
>>>     plt.text(x, y," v =  " + str( vecteur[str.lower(s[0])][2]) + " cm/an", ha="left", va="bottom", fontsize=6)

>>> plt.show()
>>> plt.savefig("vecteur.png")

On observe que les stations EISL et PAMA qui sont situées de part et d’autre de la dorsale Pacifique se déplacent dans des directions opposées, ce qui confirme le contexte tectonique divergent associé aux dorsales.

import matplotlib # no UI backend
matplotlib.use('Agg') # no UI backend
import pandas as pd
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from sqlite3 import *
from koala import Koala
# Récuperation de la base de données GPS
con = connect("gps.db")
brazz = pd.read_sql_query("select * from brazz", con)
eisl = pd.read_sql_query("select * from eisl", con)
pama = pd.read_sql_query("select * from pama", con)
# Mesure des déplacements lat et long des 3 stations gps
kbrazz = Koala(brazz)
lat_brazz = kbrazz.lin("temps", "lat")
lon_brazz = kbrazz.lin("temps", "long")
v_lat_brazz = lat_brazz.a
v_lon_brazz = lon_brazz.a
n_brazz = round((v_lon_brazz**2 + v_lat_brazz**2)**0.5,2)
keisl = Koala(eisl)
lat_eisl = keisl.lin("temps", "lat")
lon_eisl = keisl.lin("temps", "long")
v_lat_eisl = lat_eisl.a
v_lon_eisl = lon_eisl.a
n_eisl = round((v_lon_eisl**2 + v_lat_eisl**2)**0.5,2)
kpama = Koala(pama)
lat_pama = kpama.lin("temps", "lat")
lon_pama = kpama.lin("temps", "long")
v_lat_pama = lat_pama.a
v_lon_pama = lon_pama.a
n_pama = round((v_lon_pama**2 + v_lat_pama**2)**0.5,2)
vecteur = {"brazz":(v_lon_brazz, v_lat_brazz, n_brazz), "eisl":(v_lon_eisl, v_lat_eisl, n_eisl), "pama":(v_lon_pama, v_lat_pama, n_pama)}
plt.close()
# Création du fond de carte
map = Basemap(projection='aeqd', lon_0 = -85, lat_0 = 10, width = 18000000, height = 15000000)
map.etopo()
map.drawcoastlines()
map.drawmeridians(range(0,360,60), dashes=[3,1], linewidth=0.5, labels=[0,0,0,1], zorder=2)
map.drawparallels(range(-40,50,10), dashes=[4,2], linewidth=0.5, labels=[1,0,0,0], zorder=1)
plt.savefig("font.png")
# Placement des foyers sismiques
seismes = pd.read_csv("earthquakes.csv") # https://gist.github.com/astrofrog/b29141f2b39bb2dfe7ce
df = seismes.loc[:,["latitude", "longitude"]]
for i in range(len(df)):
x, y = df.longitude[i], df.latitude[i]
try:
x, y = map(x,y)
map.plot(x, y, marker='*', color='y', markersize=2)
except:
pass
plt.savefig("seismes.png")
# Placement des volcans actifs depuis 1900
volcans = pd.read_excel("https://query.data.world/s/jejujyib5byfslvmbixubz6leb3f4d")
vf = volcans.loc[:,["Year", "Latitude", "Longitude"]]
for v in range(len(vf)):
if vf.Year[v] > 1900:
x, y = vf.Longitude[v], vf.Latitude[v]
try:
x, y = map(x,y)
map.plot(x, y, marker='*', color="r", markersize=2)
except:
pass
plt.savefig("vulcan.png")
# Placement des stations GPS
stations = [("EISL", -109.57, -27.14), ("PAMA", -149.57, -17.56), ("BRAZZ", -47.80, -15.90)] # liste de tuple (nom, lon, lat)
for s in stations:
x, y = map(s[1], s[2])
map.plot(x, y, marker='+', markersize=10, color="k")
plt.text(x, y, s[0], ha = "left", va = "top", fontsize =8)
plt.savefig("gpscarte.png")
# Placement des vecteurs déplacements sur la carte
x, y = map(stations[0][1], stations[0][2])
map.quiver(x, y, v_lon_eisl, v_lat_eisl, scale_units='inches', scale=8, headwidth=12, headlength=15, units='inches', width=0.01)
x, y = map(stations[1][1], stations[1][2])
map.quiver(x, y, v_lon_pama, v_lat_pama, scale_units='inches', scale=14, headwidth=12, headlength=15, units='inches', width=0.01)
x, y = map(stations[2][1], stations[2][2])
map.quiver(x, y, v_lon_brazz, v_lat_brazz, scale_units='inches', scale=8, headwidth=12, headlength=10, units="inches", width=0.01)
for s in stations:
x, y = map(s[1], s[2])
plt.text(x, y," v = " + str( vecteur[str.lower(s[0])][2]) + " cm/an", ha="left", va="bottom", fontsize=6)
plt.savefig("vecteur.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment