From c27a5ab960b56a6a4ad06e916350a525f86de82f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Thu, 5 Dec 2019 09:46:16 +0100 Subject: [PATCH] Initial commit --- .gitignore | 5 ++ Makefile | 5 ++ config.example.json | 39 +++++++++++++++ distances.py | 114 ++++++++++++++++++++++++++++++++++++++++++++ shell.nix | 7 +++ 5 files changed, 170 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 config.example.json create mode 100644 distances.py create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f70185 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/config.json +/outputs/ +*.dat +*.gnuplot +*.json diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..fec6b23 --- /dev/null +++ b/config.example.json @@ -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 index 0000000..e28caf7 --- /dev/null +++ b/distances.py @@ -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 index 0000000..cdf128c --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +{ pkgs ? import {} }: +pkgs.mkShell { + buildInputs = [ + pkgs.gnuplot + (pkgs.python3.withPackages (p: [p.requests p.pytz])) + ]; +} -- 2.41.0