MyWay timeliness by stop/route
MyWay timeliness by stop/route

--- a/labs/index.php
+++ b/labs/index.php
@@ -18,11 +18,11 @@
 		<p>Displays the deviation from the timetable over the day</p></a></li>
 		<li><a href="myway_timeliness_freqdist.php"><h3>Frequency Distribution of Time Deviation</h3>
 		<p>Displays spread of time deviations</p></a></li>
-		<!--<li><a href="myway_timeliness_route.php"><h3>Timeliness over Route</h3>
+		<li><a href="myway_timeliness_route.php"><h3>Timeliness over Route</h3>
 		<p>Displays the deviation from timetable as a specific route progresses</p></a></li>
 		<li><a href="myway_timeliness_stop.php"><h3>Timeliness at Stop</h3>
 		<p>Displays the deviation from the timetable at a specific stop</p></a></li>
-            --></ul>
+            </ul>
 	    </div>
 <?php
 include_footer()

--- a/labs/myway_timeliness_calculate.php
+++ b/labs/myway_timeliness_calculate.php
@@ -87,7 +87,8 @@
 						//work out time delta, put into array with index of delta
 						$timeDeltas[] = Array(
 							"timeDiff" => $timeDiff,
-							"stop_code" => $potentialStop['stop_code']
+							"stop_code" => $potentialStop['stop_code'],
+                                                        "stop_sequence" => $timedTrip['stop_sequence']
 						);
 						echo "Found trip {$trip['trip_id']} at stop {$potentialStop['stop_code']} (#{$potentialStop['stop_id']}, sequence #{$trip['stop_sequence']})<br>";
                                                 echo "Arriving at {$timedTrip['arrival_time']}, difference of " . round($timeDiff / 60, 2) . " minutes<br>";
@@ -110,18 +111,18 @@
 		echo "Lowest difference of " . round($lowestDelta / 60, 2) . " minutes will be recorded for this observation<br>";
 		$observation_id = $obsv['observation_id'];
 		$route_full_name = $obsv['route_full_name'];
-		$myway_route = $obsv['myway_stop'];
 		$stop_code = $timeDeltas[0]["stop_code"];
-		$stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, myway_route, stop_code, timing_delta, time, date, timing_period)
-				      values (:observation_id, :route_full_name, :myway_route, :stop_code, :timing_delta, :time, :date, :timing_period)");
+		$stop_sequence = $timeDeltas[0]["stop_sequence"];
+		$stmt = $conn->prepare("insert into myway_timingdeltas (observation_id, route_full_name, stop_code, timing_delta, time, date, timing_period, stop_sequence)
+				      values (:observation_id, :route_full_name, :stop_code, :timing_delta, :time, :date, :timing_period, :stop_sequence)");
 		$stmt->bindParam(':observation_id', $observation_id);
 		$stmt->bindParam(':route_full_name', $route_full_name);
-		$stmt->bindParam(':myway_route', $myway_route);
 		$stmt->bindParam(':stop_code', $stop_code);
 		$stmt->bindParam(':timing_delta', $lowestDelta);
 		$stmt->bindParam(':time', $time);
 		$stmt->bindParam(':date', $date);
 		$stmt->bindParam(':timing_period', $timing_period);
+                $stmt->bindParam(':stop_sequence', $stop_sequence);
 		// insert a record
 		$stmt->execute();
 		if ($stmt->rowCount() > 0) {

--- /dev/null
+++ b/labs/myway_timeliness_route.json.php
@@ -1,1 +1,25 @@
-
+<?php
+include ('../include/common.inc.php');
+header('Content-Type: text/javascript; charset=utf8');
+// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
+header('Access-Control-Max-Age: 3628800');
+header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
+?>
+{
+    "label": "<?php echo $_REQUEST['routeid']; ?>",
+    "data": <?php
+   $query = "select * from myway_timingdeltas where route_full_name = :route_full_name AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)  order by stop_sequence;";
+$query = $conn->prepare($query);
+$query->bindParam(':route_full_name', $_REQUEST['routeid'],PDO::PARAM_STR, 42);
+		
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $delta) {
+	$points[] = "[{$delta['stop_sequence']}, {$delta['timing_delta']}]";
+};
+echo "[".implode(",",$points)."]";
+?>
+}

--- /dev/null
+++ b/labs/myway_timeliness_route.php
@@ -1,1 +1,120 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
 
+    <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]--> 
+ 
+    <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script> 
+  <form method="get" action="">
+    <select id="routeid" name="routeid">
+<?php
+$query = "select distinct route_full_name from myway_routes where myway_route != '' order by route_full_name";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $route) {
+           echo "<option value=\"{$route['route_full_name']}\">{$route['route_full_name']}</option>";
+  
+};
+?>    </select>
+  <center><div id="placeholder" style="width:900px;height:550px"></div></center>
+<script type="text/javascript"> 
+$(function () {
+
+       var placeholder = $("#placeholder");
+ var data = [];
+    var options = {
+            xaxis: {
+            },
+            yaxis: {
+                tickFormatter: yformatter
+            },
+            grid: { hoverable: true, clickable: true, labelMargin: 32   },
+    };
+    
+    var plot = $.plot(placeholder, data, options);
+ 
+// fetch one series, adding to what we got
+    var alreadyFetched = {};
+    
+   $("#routeid").change(function () {
+   var select = $(this);
+        
+        // find the URL in the link right next to us 
+    //    var dataurl = button.siblings('a').attr('href');
+ var dataurl = "myway_timeliness_route.json.php?routeid=" + select.val();
+        // then fetch the data with jQuery
+        function onDataReceived(series) {
+            // extract the first coordinate pair so you can see that
+            // data is now an ordinary Javascript object
+            var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
+ 
+      
+            // let's add it to our current data
+            if (!alreadyFetched[series.label]) {
+                alreadyFetched[series.label] = true;
+                data.push(series);
+            }
+            
+            // and plot all we got
+            $.plot(placeholder, data, options);
+         }
+        
+        $.ajax({
+            url: dataurl,
+            method: 'GET',
+            dataType: 'json',
+            success: onDataReceived
+        });
+    });
+ 
+
+ });
+
+
+
+function yformatter(v) {
+    if (Math.floor(v/60) < -9) return "";
+    return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
+}
+  function showTooltip(x, y, contents) {
+        $('<div id="tooltip">' + contents + '</div>').css( {
+            position: 'absolute',
+            display: 'none',
+            top: y + 5,
+            left: x + 5,
+            border: '1px solid #fdd',
+            padding: '2px',
+            'background-color': '#fee',
+            opacity: 0.80
+        }).appendTo("body").fadeIn(200);
+    }
+ 
+    var previousPoint = null;
+    $("#placeholder").bind("plothover", function (event, pos, item) {
+        $("#x").text(pos.x.toFixed(2));
+        $("#y").text(pos.y.toFixed(2));
+ 
+            if (item) {
+                if (previousPoint != item.dataIndex) {
+                    previousPoint = item.dataIndex;
+                    
+                    $("#tooltip").remove();
+                    var x = item.datapoint[0],
+                        y = item.datapoint[1].toFixed(2);
+                    
+                    showTooltip(item.pageX, item.pageY,
+                                item.series.label + " at stop_sequence "+ x +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
+                }
+            }
+            else {
+                $("#tooltip").remove();
+                previousPoint = null;            
+            }
+    });
+
+</script> 

--- /dev/null
+++ b/labs/myway_timeliness_stop.json.php
@@ -1,1 +1,31 @@
-
+<?php
+include ('../include/common.inc.php');
+header('Content-Type: text/javascript; charset=utf8');
+// header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
+header('Access-Control-Max-Age: 3628800');
+header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
+?>
+{
+    "label": "<?php echo $_REQUEST['stopid']; ?>",
+    "data": <?php
+   $query = "select * from myway_timingdeltas INNER JOIN myway_observations
+ON myway_observations.observation_id=myway_timingdeltas.observation_id
+   where myway_stop = :myway_stop
+   AND abs(timing_delta) < 2*(select stddev(timing_delta) from myway_timingdeltas)
+   order by myway_timingdeltas.time;";
+$query = $conn->prepare($query);
+$query->bindParam(':myway_stop', $_REQUEST['stopid'],PDO::PARAM_STR, 42);
+		
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $delta) {
+	$points[] = "[".((strtotime("00:00Z") + midnight_seconds(strtotime($delta['time'])))*1000).", {$delta['timing_delta']}]";
+};
+if (count($points) == 0) {
+    echo "[]"; }
+    else echo "[".implode(",",$points)."]";
+?>
+}

--- /dev/null
+++ b/labs/myway_timeliness_stop.php
@@ -1,1 +1,131 @@
+<?php
+include ('../include/common.inc.php');
+include_header("MyWay Deltas", "mywayDelta");
+?>
 
+    <!--[if lte IE 8]><script language="javascript" type="text/javascript" src="../js/flot/excanvas.min.js"></script><![endif]--> 
+ 
+    <script language="javascript" type="text/javascript" src="../js/flot/jquery.flot.js"></script> 
+   <form method="get" action="">
+    <select id="stopid" name="stopid">
+<?php
+$query = "select distinct myway_stop from myway_stops where myway_stop != '' order by myway_stop";
+$query = $conn->prepare($query);
+$query->execute();
+if (!$query) {
+	databaseError($conn->errorInfo());
+	return Array();
+}
+foreach ($query->fetchAll() as $stop) {
+           echo "<option value=\"{$stop['myway_stop']}\">{$stop['myway_stop']}</option>";
+  
+};
+?>    </select> <center><div id="placeholder" style="width:900px;height:550px"></div></center>
+<script type="text/javascript"> 
+$(function () {
+    var d = new Date();
+						d.setUTCMinutes(0);
+						d.setUTCHours(0);
+    var midnight = d.getTime();
+
+       var placeholder = $("#placeholder");
+ var data = [];
+    var options = {
+            xaxis: {
+                mode: "time",
+                min: midnight + (1000*60*60*8),
+                max: midnight + (1000*60*60*23.5)
+            },
+            yaxis: {
+                tickFormatter: yformatter
+            },
+            grid: { hoverable: true, clickable: true, labelMargin: 32   },
+    };
+
+    var plot = $.plot(placeholder, data, options);
+        var o;
+    o = plot.pointOffset({ x: midnight+ (9*60*60*1000), y: -1.2});
+    placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">9am</div>');
+    o = plot.pointOffset({ x: midnight+ (16*60*60*1000), y: -1.2});
+    placeholder.append('<div style="position:absolute;left:' + (o.left + 4) + 'px;top:' + o.top + 'px;color:#666;font-size:smaller">4pm</div>');
+// fetch one series, adding to what we got
+    var alreadyFetched = {};
+    
+   $("#stopid").change(function () {
+   var select = $(this);
+        
+        // find the URL in the link right next to us 
+    //    var dataurl = button.siblings('a').attr('href');
+ var dataurl = "myway_timeliness_stop.json.php?stopid=" + select.val();
+        // then fetch the data with jQuery
+        function onDataReceived(series) {
+            // extract the first coordinate pair so you can see that
+            // data is now an ordinary Javascript object
+            var firstcoordinate = '(' + series.data[0][0] + ', ' + series.data[0][1] + ')';
+ 
+      
+            // let's add it to our current data
+            if (!alreadyFetched[series.label]) {
+                alreadyFetched[series.label] = true;
+                data.push(series);
+            }
+            
+            // and plot all we got
+            $.plot(placeholder, data, options);
+         }
+        
+        $.ajax({
+            url: dataurl,
+            method: 'GET',
+            dataType: 'json',
+            success: onDataReceived
+        });
+    });
+
+ });
+function yformatter(v) {
+    if (Math.floor(v/60) < -9) return "";
+    return Math.abs(Math.floor(v/60)) + " min " + (v == 0 ? "" : (v >0 ? "early":"late"))
+}
+  function showTooltip(x, y, contents) {
+        $('<div id="tooltip">' + contents + '</div>').css( {
+            position: 'absolute',
+            display: 'none',
+            top: y + 5,
+            left: x + 5,
+            border: '1px solid #fdd',
+            padding: '2px',
+            'background-color': '#fee',
+            opacity: 0.80
+        }).appendTo("body").fadeIn(200);
+    }
+ 
+    var previousPoint = null;
+    $("#placeholder").bind("plothover", function (event, pos, item) {
+        $("#x").text(pos.x.toFixed(2));
+        $("#y").text(pos.y.toFixed(2));
+ 
+            if (item) {
+                if (previousPoint != item.dataIndex) {
+                    previousPoint = item.dataIndex;
+                    
+                    $("#tooltip").remove();
+                    var x = item.datapoint[0].toFixed(2),
+                        y = item.datapoint[1].toFixed(2);
+                    
+                    var d = new Date();
+d.setTime(x);
+var time = d.getUTCHours() +':'+ (d.getUTCMinutes().toString().length == 1 ? '0'+ d.getMinutes():  d.getUTCMinutes())
+
+                    
+                    showTooltip(item.pageX, item.pageY,
+                                item.series.label + " at "+ time +" = " + Math.abs(new Number(y/60).toFixed(2))+" minutes "+(y >0 ? "early":"late"));
+                }
+            }
+            else {
+                $("#tooltip").remove();
+                previousPoint = null;            
+            }
+    });
+
+</script> 

--- a/servicealerts_api.php
+++ b/servicealerts_api.php
@@ -36,7 +36,7 @@
 		$return['entities'][] = $entity;
 	}
 }
-//header('Content-Type: text/javascript; charset=utf8');
+header('Content-Type: text/javascript; charset=utf8');
 // header('Access-Control-Allow-Origin: http://bus.lambdacomplex.org/');
 header('Access-Control-Max-Age: 3628800');
 header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');