/* adjacentStops : map(fromId => toId) contains all links which we wish to plot autocorrelation graph startTime : beginning time of plot endTime : end time of plot interval : each interval in plot */ func AutoCorrelationPlot(adjacentStops map[string]string, startTime, endTime time.Time, interval time.Duration, wr io.Writer, templatePath string) { // Partition between startTime and endTime partitionedTimes := getPartitionedTimes(startTime, endTime, interval) series := make([]Acs, 0) for fromId, toId := range adjacentStops { logger.GetLogger().Info("Handling journey: %v -> %v", fromId, toId) fromStop := selectdb.SelectStop(fromId) toStop := selectdb.SelectStop(toId) // Get average journey times corresponding to partitions partitionedAvgJourneyTimes, _, invalidIndices := getAverageJourneyTimes(fromId, toId, partitionedTimes) // Calculate autocorrelation sequence acs, invalidResultIndices := statistics.AutoCorrelationSequence(partitionedAvgJourneyTimes, invalidIndices) // Insert into series of acs to plot chart series = append(series, Acs{fromStop, toStop, acs, invalidResultIndices}) } // Generate chart - Write to *.html xlabs := make([]int, len(partitionedTimes)) for i := 0; i < len(partitionedTimes); i++ { xlabs[i] = i } chart := AutoCorrelationChart{ xlabs, series, } writeAutoCorrelationChart(wr, chart, templatePath) }
func performancePlotHandler(w http.ResponseWriter, r *http.Request) { /* Extract fields in GET request */ line := r.URL.Query().Get("line") bound := r.URL.Query().Get("bound") origin := r.URL.Query().Get("origin") departureTime := parseISOTime(r.URL.Query().Get("departureTime")) /* Find out which vehicle produced the data and list its journey history */ vehicleId, vehicleHistory := lookupVehicleHistory(line, bound, origin, departureTime) /* Some additional info for nice display*/ originName := selectdb.SelectStop(origin) destinationName := selectdb.SelectStop(selectdb.SelectTerminus(line, bound)) /* Write HTML output */ writePerformancePlotDetails(w, PerformancePlotDetails{ Line: line, Bound: bound, Origin: origin, DepartureTime: formatTime(departureTime), OriginName: originName, DestinationName: destinationName, VehicleId: vehicleId, VehicleHistory: vehicleHistory, }) }
/* Grabs all data stored in "performance_measure" to produce time plots */ func PerformancePlot(startTime time.Time, wr io.Writer, templatePath string) { performanceMeasures, err := selectdb.SelectPerformanceMeasure(startTime) if err != nil { logger.GetLogger().Panic(err) } charts := make([]PerformanceChart, 0) for line, boundDetails := range performanceMeasures { for bound, innerSlice := range boundDetails { departureTimes := make([]time.Time, len(innerSlice)) tflExpectedTimes := make([]time.Duration, len(innerSlice)) predictedTimes := make([]time.Duration, len(innerSlice)) actualTimes := make([]time.Duration, len(innerSlice)) var origin, destination string for i, details := range innerSlice { departureTimes[i] = toTime(details["departureTime"]) tflExpectedTimes[i] = toDuration(details["tflExpectedTime"]) predictedTimes[i] = toDuration(details["predictedTime"]) actualTimes[i] = toDuration(details["actualTime"]) origin = details["fromStop"] destination = details["toStop"] } performanceTestSeries := PerformanceTestSeries{ X: departureTimes, Y1: tflExpectedTimes, Y2: predictedTimes, Y3: actualTimes, } sort.Sort(performanceTestSeries) originName := selectdb.SelectStop(origin) destinationName := selectdb.SelectStop(destination) charts = append(charts, PerformanceChart{ Line: line, Bound: bound, Origin: origin, Destination: destination, OriginName: originName, DestinationName: destinationName, XValues: performanceTestSeries.X, TflExpectedTimes: performanceTestSeries.Y1, PredictedTimes: performanceTestSeries.Y2, ActualTimes: performanceTestSeries.Y3, ServerDomain: credentials.GetGoServerDomain(), }) } } writePerformanceChart(wr, charts, templatePath) }
/* Plots the journey times throughout a day between a pair of stops */ func JourneyTimePlot(adjacentStops map[string]string, dates []time.Time, interval time.Duration, wr io.Writer, templatePath string) { var charts []JourneyTimeChart for fromStop, toStop := range adjacentStops { logger.GetLogger().Info("Handling journey: %v -> %v", fromStop, toStop) series := make([]JourneyTimeSeries, 0) var partitionedTimes []Partition for _, date := range dates { // Partition between startTime (start of day) and endTime (end of day) startTime := date.Truncate(24 * time.Hour) endTime := date.Truncate(24 * time.Hour).Add(24 * time.Hour) partitionedTimes = getPartitionedTimes(startTime, endTime, interval) // Get average journey times corresponding to partitions, and their 95% confidence intervals partitionedAvgJourneyTimes, stdDevJourneyTimes, invalidIndices := getAverageJourneyTimes(fromStop, toStop, partitionedTimes) lowerCI, upperCI, err := statistics.ConfidenceInterval(partitionedAvgJourneyTimes, stdDevJourneyTimes) if err != nil { logger.GetLogger().Panic(err) } // Insert into series the journey time of each partition to plot chart series = append(series, JourneyTimeSeries{date, partitionedAvgJourneyTimes, lowerCI, upperCI, invalidIndices, randomColour()}) } // Generate chart - Write to *.html xlabs := make([]string, len(partitionedTimes)) for i := 0; i < len(partitionedTimes); i++ { start := partitionedTimes[i].start // e.g. label x axis with time - e.g. 3:00 PM xlabs[i] = start.Format(time.Kitchen) } // Title of chart fromStopName := selectdb.SelectStop(fromStop) toStopName := selectdb.SelectStop(toStop) title := fmt.Sprintf("Journey times between %v and %v", fromStopName, toStopName) chart := JourneyTimeChart{ title, fromStop, toStop, xlabs, series, } charts = append(charts, chart) } writeJourneyTimeCharts(wr, charts, templatePath) }
func performancePlotHandlerV2(w http.ResponseWriter, r *http.Request) { /* Extract fields in GET request */ line := r.URL.Query().Get("line") bound := r.URL.Query().Get("bound") origin := r.URL.Query().Get("origin") destination := r.URL.Query().Get("destination") departureTime := parseISOTime(r.URL.Query().Get("departureTime")) /* Error message string that functions should append to */ errorMessage := "" /* Some additional info for nice display*/ originName := selectdb.SelectStop(origin) destinationName := selectdb.SelectStop(destination) /* Find out which vehicle produced the data and list its journey history */ vehicleId, vehicleHistory, actualJourneyTime, totalPredictions, totalStddevs := lookupVehicleHistory2(line, bound, origin, destination, departureTime, &errorMessage) /* Write HTML output */ writePerformancePlotDetails2(w, PerformancePlotDetails2{ ErrorMessage: errorMessage, Line: line, Bound: bound, Origin: origin, DepartureTime: departureTime.Format(timeFormatString), OriginName: originName, DestinationName: destinationName, VehicleId: vehicleId, VehicleHistory: vehicleHistory, PredictionMethods: performanceeval.Methods(), ActualTime: actualJourneyTime, Predictions: totalPredictions, Stddevs: totalStddevs, }) }
/* Grabs all stored historic and real time data, produce time plots and also percentages of consistently delayed or early */ func DelayConsistencyPlot(startTime, endTime time.Time, wr io.Writer, templatePath string) { charts := make([]DelayConsistencyChart, 0) availableRoutes := selectdb.SelectAvailableRoutesTflPredictions() for _, route := range availableRoutes { // Extract fields from routes line := route["line"] bound := route["bound"] fromStop := route["fromStop"] toStop := route["toStop"] fromStopName := selectdb.SelectStop(fromStop) toStopName := selectdb.SelectStop(toStop) actualJourneyTimes := performanceeval.FetchActualJourneyTimes(line, bound, fromStop, toStop, startTime, endTime) // Extract the actual departure times for generating predictions later on (discarding those that are) actualDepartureTimes := make([]time.Time, len(actualJourneyTimes)) actualJourneyTimeDurations := make([]time.Duration, len(actualJourneyTimes)) i := 0 for departureTime, duration := range actualJourneyTimes { actualDepartureTimes[i] = departureTime actualJourneyTimeDurations[i] = duration i++ } // Fetch Tfl predictions // tflPredictions := performanceeval.FetchTflJourneyTimes(line, bound, fromStop, toStop, actualDepartureTimes) /* Cache for real time estimates which can be reused for different prediction methods map (fromStop => (toStop => (departureTime => "estimate"/"stddev" => int in seconds)))) */ realTimeEstimatesCache := make(map[string]map[string]map[time.Time]map[string]int64) // Generate predictions using our methods (best historic and real time only) predictions := make(map[performanceeval.Method]map[time.Time]time.Duration) predictionsAdjacentStops := make(map[performanceeval.Method]map[time.Time]map[string]map[string]time.Duration) methods := []performanceeval.Method{ performanceeval.DefaultHistoric(), performanceeval.DefaultRealTime(), } // Highest # consistency possible - number of pairs of adjacent stops in route maxScore := 0 for _, method := range methods { predictions[method], predictionsAdjacentStops[method], maxScore = predictJourneyTimesWithDetails(line, bound, fromStop, toStop, actualDepartureTimes, method, realTimeEstimatesCache) } // Convert the above into PerformanceTestSeries2 actualJourneyTimesSeries := PerformanceTestSeries2{ SeriesName: "Actual Time", X: actualDepartureTimes, Y: actualJourneyTimeDurations, Count: len(actualJourneyTimeDurations), } sort.Sort(actualJourneyTimesSeries) /*tflPredictionsSeries := mapToPerformanceTestSeries2("Tfl Expected Time", tflPredictions, actualJourneyTimes) sort.Sort(tflPredictionsSeries)*/ performanceTestSeries2 := []PerformanceTestSeries2{ actualJourneyTimesSeries, // tflPredictionsSeries, } // Add all prediction series into performance test series 2 for method, predictedJouneyTimes := range predictions { predictionSeries := mapToPerformanceTestSeries2(method.String(), predictedJouneyTimes, actualJourneyTimes) sort.Sort(predictionSeries) performanceTestSeries2 = append(performanceTestSeries2, predictionSeries) } // Form delay consistency (percentages) series delayConsistencySeries := getDelayConsistencySeries(predictionsAdjacentStops[performanceeval.DefaultHistoric()], predictionsAdjacentStops[performanceeval.DefaultRealTime()], maxScore) charts = append(charts, DelayConsistencyChart{ Line: line, Bound: bound, Origin: fromStop, Destination: toStop, OriginName: fromStopName, DestinationName: toStopName, MultipleSeries: performanceTestSeries2, MultiplePercentageSeries: []DelayConsistencySeries{delayConsistencySeries}, ServerDomain: credentials.GetGoServerDomain(), }) logger.GetLogger().Info("Done for line: %v, bound: %v, fromStop: %v, toStop: %v", line, bound, fromStop, toStop) } summary := DelayConsistencyPlotSummary{ Methods: performanceeval.Methods(), Charts: charts, } writeDelayConsistencyChart(wr, summary, templatePath) }
/* Grabs all stored data to produce time plots */ func PerformancePlot2(startTime, endTime time.Time, wr io.Writer, templatePath string) { charts := make([]PerformanceChart2, 0) availableRoutes := selectdb.SelectAvailableRoutesTflPredictions() for _, route := range availableRoutes { // Extract fields from routes line := route["line"] bound := route["bound"] fromStop := route["fromStop"] toStop := route["toStop"] fromStopName := selectdb.SelectStop(fromStop) toStopName := selectdb.SelectStop(toStop) actualJourneyTimes := performanceeval.FetchActualJourneyTimes(line, bound, fromStop, toStop, startTime, endTime) // Extract the actual departure times for generating predictions later on (discarding those that are) actualDepartureTimes := make([]time.Time, len(actualJourneyTimes)) actualJourneyTimeDurations := make([]time.Duration, len(actualJourneyTimes)) i := 0 for departureTime, duration := range actualJourneyTimes { actualDepartureTimes[i] = departureTime actualJourneyTimeDurations[i] = duration i++ } // Fetch Tfl predictions tflPredictions := performanceeval.FetchTflJourneyTimes(line, bound, fromStop, toStop, actualDepartureTimes) /* Cache for real time estimates which can be reused for different prediction methods map (fromStop => (toStop => (departureTime => "estimate"/"stddev" => int in seconds)))) */ realTimeEstimatesCache := make(map[string]map[string]map[time.Time]map[string]int64) // Generate predictions using our methods predictions := make(map[performanceeval.Method]map[time.Time]time.Duration) for _, method := range performanceeval.Methods() { predictions[method] = performanceeval.PredictJourneyTimes(line, bound, fromStop, toStop, actualDepartureTimes, method, realTimeEstimatesCache) } // Convert the above into PerformanceTestSeries2 actualJourneyTimesSeries := PerformanceTestSeries2{ SeriesName: "Actual Time", X: actualDepartureTimes, Y: actualJourneyTimeDurations, Count: len(actualJourneyTimeDurations), } sort.Sort(actualJourneyTimesSeries) tflPredictionsSeries := mapToPerformanceTestSeries2("Tfl Expected Time", tflPredictions, actualJourneyTimes) sort.Sort(tflPredictionsSeries) performanceTestSeries2 := []PerformanceTestSeries2{ actualJourneyTimesSeries, tflPredictionsSeries, } // Add all prediction series into performance test series 2 for method, predictedJouneyTimes := range predictions { predictionSeries := mapToPerformanceTestSeries2(method.String(), predictedJouneyTimes, actualJourneyTimes) sort.Sort(predictionSeries) performanceTestSeries2 = append(performanceTestSeries2, predictionSeries) } charts = append(charts, PerformanceChart2{ Line: line, Bound: bound, Origin: fromStop, Destination: toStop, OriginName: fromStopName, DestinationName: toStopName, MultipleSeries: performanceTestSeries2, ServerDomain: credentials.GetGoServerDomain(), }) logger.GetLogger().Info("Done for line: %v, bound: %v, fromStop: %v, toStop: %v", line, bound, fromStop, toStop) } summary := PerformancePlotSummary2{ Methods: performanceeval.Methods(), Charts: charts, } writePerformanceChart2(wr, summary, templatePath) }