]> git.immae.eu Git - perso/Immae/Projets/Scripts/GoogleMapsTrafficPlots.git/commitdiff
Initial commit master
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 5 Dec 2019 08:46:16 +0000 (09:46 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 5 Dec 2019 08:51:27 +0000 (09:51 +0100)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
config.example.json [new file with mode: 0644]
distances.py [new file with mode: 0644]
shell.nix [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3f70185
--- /dev/null
@@ -0,0 +1,5 @@
+/config.json
+/outputs/
+*.dat
+*.gnuplot
+*.json
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..71ec2f9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+NIX_PATH=nixpkgs=https://releases.nixos.org/nixos/19.09/nixos-19.09.840.8bf142e001b/nixexprs.tar.xz
+.PHONY: build
+
+build:
+       NIX_PATH=$(NIX_PATH) nix-shell --pure --run "python distances.py"
diff --git a/config.example.json b/config.example.json
new file mode 100644 (file)
index 0000000..fec6b23
--- /dev/null
@@ -0,0 +1,39 @@
+{
+  "api_key": "your-api-key see https://developers.google.com/maps/documentation/distance-matrix/start",
+  "locations": {
+    "home": "6 Rue Ribotti, 06300 Nice, France",
+    "work": "43.586337,6.939781"
+  },
+  "plots": {
+    "home-work": {
+      "days": ["monday","tuesday","wednesday","thursday","friday"],
+      "name": "Home -> Work",
+      "times": [
+        "6:30", "7:00", "7:30", "8:00", "8:30",
+        "9:00", "9:30", "10:00"
+      ],
+      "origin": "home",
+      "destination": "work"
+    },
+    "work-home": {
+      "days": ["monday","tuesday","wednesday","thursday","friday"],
+      "name": "Work -> Home",
+      "times": [
+        "16:00", "16:30", "17:00", "17:30", "18:00",
+        "18:30", "19:00", "19:30", "20:00"
+      ],
+      "origin": "work",
+      "destination": "home"
+    },
+    "work-gym": {
+      "days": ["monday"],
+      "name": "Work -> Monday’s gym",
+      "times": [
+        "11:00", "11:15", "11:30", "11:45",
+        "12:00", "12:15"
+      ],
+      "origin": "work",
+      "destination": "330 Rue Henri Laugier, 06600 Antibes, France"
+    }
+  }
+}
diff --git a/distances.py b/distances.py
new file mode 100644 (file)
index 0000000..e28caf7
--- /dev/null
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+import requests
+from datetime import datetime, timedelta
+from collections import defaultdict
+import json
+import os, sys
+import pytz
+import argparse
+
+URL= "https://maps.googleapis.com/maps/api/distancematrix/json"
+
+parser = argparse.ArgumentParser(description='Plot traffic information for various origin-destinations')
+parser.add_argument('-c', '--config', type=str, default='config.json', help='Config file to load (default config.jsonà')
+parser.add_argument('-n', '--dry-run', action='store_true', help='Run in dry-run mode (don’t make any api call)')
+parser.add_argument('-d', '--date', type=str, default='now', help='date (%%Y-%%m-%%d) for which to generate the plots')
+parser.add_argument('-s', '--stats', action='store_true', help='only print number of weekly calls for the config')
+args = parser.parse_args()
+
+WEEKDAYS = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
+SETTINGS = json.load(open(args.config, "r"))
+
+if args.date == "now":
+    date = datetime.now(tz=pytz.timezone("Europe/Paris"))
+else:
+    date = datetime.strptime(args.date, "%Y-%m-%d").replace(tzinfo=pytz.timezone("Europe/Paris"))
+
+def parse_plot(info):
+    def condition(d):
+        return "days" not in info or WEEKDAYS[d.weekday()] in info["days"]
+    return {
+            "name": info["name"],
+            "origin": SETTINGS.get("locations", {}).get(info["origin"], info["origin"]),
+            "destination": SETTINGS.get("locations", {}).get(info["destination"], info["destination"]),
+            "condition": condition,
+            "times": [t.split(":") for t in info["times"]],
+            }
+
+plots = {}
+for name,info in SETTINGS["plots"].items():
+    plots[name] = parse_plot(info)
+
+def to_time(date, hour, minute):
+    return date.replace(date.year, date.month, date.day, int(hour), int(minute), 0, 0)
+
+def get(time, origin, destination):
+    keys = {
+            "origins": origin,
+            "destinations": destination,
+            "departure_time": int(time.timestamp()),
+            "key": SETTINGS["api_key"],
+            }
+    return requests.get(URL, params=keys)
+
+def stats():
+    total_calls_per_week = 0
+    for k, infos in plots.items():
+        calls_per_week = 0
+        for i in range(0, 7):
+            if infos["condition"](date + timedelta(i)):
+                calls_per_week += 1
+        total_calls_per_week += calls_per_week * len(infos["times"])
+    print("{} calls per week to api".format(total_calls_per_week))
+if args.stats:
+    stats()
+    sys.exit(0)
+
+gnuplot = """
+reset
+set terminal png size 1024,768 enhanced font "Helvetica"
+set output 'outputs/{fname}.png'
+set datafile separator "\\t"
+set xlabel "Time"
+set ylabel "Duration"
+
+set xdata time
+set timefmt "%H:%M"
+set format x "%H:%M"
+set title "{date} {name}"
+plot '{fname}.dat' using 1:2 with linespoints pointtype 5 title ""
+"""
+
+def get_times(name, infos, date, dry_run=False):
+    result = {}
+    if "condition" in infos and not infos["condition"](date):
+        return result
+    for time in infos["times"]:
+        t = to_time(date, time[0], time[1])
+        try:
+            if dry_run:
+                v = 42
+            else:
+                v = get(t, infos["origin"], infos["destination"]).json()
+                v = int(v["rows"][0]["elements"][0]["duration_in_traffic"]["value"] / 60)
+        except:
+            continue
+        result[t.strftime("%H:%M")] = v
+    with open(date.strftime("%Y-%m-%d_{}.json".format(name)), "w") as f:
+        f.write(json.dumps(result, indent=True))
+
+    fname = date.strftime("%Y-%m-%d_{}".format(name))
+    with open("{}.dat".format(fname), "w") as f:
+        for time, duration in result.items():
+            f.write('{}\t{}\n'.format(time, duration))
+    with open("{}.gnuplot".format(fname), "w") as f:
+        f.write(gnuplot.format(**{
+            "fname": fname,
+            "name": infos["name"],
+            "date": date.strftime("%Y-%m-%d")
+            }))
+    os.system("gnuplot -c {}.gnuplot".format(fname))
+    return result
+
+for name, infos in plots.items():
+    get_times(name, infos, date, dry_run=args.dry_run)
diff --git a/shell.nix b/shell.nix
new file mode 100644 (file)
index 0000000..cdf128c
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,7 @@
+{ pkgs ? import <nixpkgs> {} }:
+pkgs.mkShell {
+  buildInputs = [
+    pkgs.gnuplot
+    (pkgs.python3.withPackages (p: [p.requests p.pytz]))
+  ];
+}