Permalink
Browse files

Merge remote-tracking branch 'david/master' into taurus-mobile-ios

  • Loading branch information...
2 parents e172a66 + 2fa4b08 commit 2a3bbcb7af3e4353c53a5a4a85f9203bbae714ee @lscheinkman lscheinkman committed Dec 15, 2015
@@ -25,7 +25,8 @@ class LineChartView: UIView {
var emptyTextString : String?
var isEmpty : Bool = false
-
+ var selection = -1
+ var selectOnDraw : Int64 = -1
// Callback for when the chart is touched. The int is the index to the closest data element
var selectionCallback :( (Int)->Void)?
@@ -53,6 +54,11 @@ class LineChartView: UIView {
barWidth = Double (contentWidth) / Double(TaurusApplication.getTotalBarsOnChart())
}
+
+ if (selectOnDraw > 0){
+ markerX = Double(selectOnDraw) * self.pointWidth + Double(barMarginLeft)
+ selectOnDraw = -1
+ }
drawAnomalies(rect)
drawMarker(rect)
drawValues( rect)
@@ -71,6 +77,10 @@ class LineChartView: UIView {
if (markerX<0){
return
}
+
+ if (self.selectionCallback == nil){
+ return
+ }
let context = UIGraphicsGetCurrentContext()!
var bar : CGRect = CGRect()
bar.origin.y = 0
@@ -358,19 +368,20 @@ class LineChartView: UIView {
*/
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
- if ( self.selectionCallback != nil){
- if let touch = touches.first {
- let x = Double(touch.locationInView(self).x)
- if (x != markerX){
- markerX = Double(x)
-
- let selection = Int ( (markerX) / self.pointWidth)
-
+
+ if let touch = touches.first {
+ let x = Double(touch.locationInView(self).x)
+ if (x != markerX){
+ markerX = Double(x)
+
+ selection = Int ( (markerX) / self.pointWidth)
+ if ( self.selectionCallback != nil){
selectionCallback! (selection)
- self.setNeedsDisplay()
}
+ self.setNeedsDisplay()
}
}
+
super.touchesBegan(touches, withEvent:event)
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -34,7 +34,7 @@ class InstanceDetailsViewController: UIViewController, UITableViewDataSource, UI
// Serial queue for loading chart data
let loadQueue = dispatch_queue_create("com.numenta.InstanceDetailsController", nil)
- var metricChartData = [MetricAnomalyChartData]()
+ var metricChartData = [MetricAnomalyChartData]()
//
var _aggregation: AggregationType = TaurusApplication.getAggregation()
@@ -366,6 +366,7 @@ class InstanceDetailsViewController: UIViewController, UITableViewDataSource, UI
let cellData = metricChartData[ indexPath.item]
if (MetricType.enumForKey(cellData.metric.getUserInfo("metricType")) == MetricType.TwitterVolume){
+
performSegueWithIdentifier("twitterSegue", sender: nil)
}
@@ -413,6 +414,54 @@ class InstanceDetailsViewController: UIViewController, UITableViewDataSource, UI
controller.metricChartData = self.metricChartData[indexPath.row].shallowCopy()
controller.chartData = self.chartData
+
+ let cell = self.instanceTable.cellForRowAtIndexPath(indexPath) as! MetricCell
+ if (cell.chart.selection != -1){
+ let selection = cell.chart.selection
+ let data = controller.metricChartData?.anomalies
+ var timestamp = controller.chartData?.endDate
+ if (data != nil){
+ let firstBucket = data!.count - TaurusApplication.getTotalBarsOnChart()
+ var selectedBucket = firstBucket + selection/12
+
+ var value = data![selectedBucket]
+
+ let selectedTime = value.0 + Int64(selection % 12) * DataUtils.METRIC_DATA_INTERVAL
+
+ controller.timeToSelect = selectedTime
+
+ if (self.marketHoursOnly){
+ // Find end of collapsed period to be expanded
+ while (selectedBucket < data!.count - 1) {
+ if (value.0 == 0) {
+ selectedBucket--
+ value = data![selectedBucket]
+ break
+ }
+ selectedBucket++;
+ value = data![selectedBucket]
+ }
+
+ // Check if selected collapsed bar
+ if (value.0 == 0) {
+ if (selectedBucket > 0) {
+ // Get previous bar instead
+ selectedBucket--;
+ value = data![selectedBucket]
+ }
+ }
+
+ // Use end of period as end date (right most bar)
+ if (value.0 != 0) {
+ timestamp = value.0
+ }
+
+ controller.chartData?.setEndDate(DataUtils.dateFromTimestamp(timestamp!))
+
+ }
+ }
+
+ }
}
}
}
@@ -42,6 +42,7 @@ class TwitterViewController: UIViewController, UITableViewDataSource, UITableVie
@IBOutlet weak var condensedToggle: UISwitch?
+ var timeToSelect :Int64 = 0
var twittermap = [ Int64 : TwitterEntry]()
var twitterIndex = [Int64]()
@@ -133,6 +134,14 @@ class TwitterViewController: UIViewController, UITableViewDataSource, UITableVie
metricChartView?.updateData()
}
}
+
+
+ if ( self.timeToSelect > 0){
+ let index = Int64(metricChartView!.data.count) - ((metricChartData?.endDate)!+DataUtils.MILLIS_PER_HOUR - timeToSelect)/DataUtils.METRIC_DATA_INTERVAL
+
+ self.metricChartView.selectOnDraw = index
+
+ }
}
@@ -0,0 +1,139 @@
+/*
+* Numenta Platform for Intelligent Computing (NuPIC)
+* Copyright (C) 2015, Numenta, Inc. Unless you have purchased from
+* Numenta, Inc. a separate commercial license for this software code, the
+* following terms and conditions apply:
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero Public License version 3 as
+* published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU Affero Public License for more details.
+*
+* You should have received a copy of the GNU Affero Public License
+* along with this program. If not, see http://www.gnu.org/licenses.
+*
+* http://numenta.org/licenses/
+*
+*/
+
+import Foundation
+import UIKit
+
+class TaurusNotificationService{
+
+ func syncNotifications(){
+
+ // check if notifications are enabled let defaults = NSUserDefaults.standardUserDefaults()
+ let frequency : Int64 = Int64 (NSUserDefaults.standardUserDefaults().integerForKey("maxNotificationsPerCompany")) * 1000
+ let enabled = NSUserDefaults.standardUserDefaults().boolForKey("notificationsEnabled")
+
+ if (enabled == false){
+ return
+ }
+
+ let now = NSDate()
+ let lastRunTime = NSUserDefaults.standardUserDefaults().objectForKey("LastNotification")
+ let flooredDate = DataUtils.dateFromTimestamp(DataUtils.floorTo60Minutes( DataUtils.timestampFromDate(now)))
+ NSUserDefaults.standardUserDefaults().setObject(flooredDate, forKey: "LastNotification")
+
+ let lastTimestamp = lastRunTime == nil ? 0 : DataUtils.timestampFromDate(lastRunTime as! NSDate)
+ let notifications = getNotifications(lastTimestamp, end: DataUtils.timestampFromDate(now), frequency: frequency)
+
+ if ( notifications.count == 0){
+ return
+ }
+ // Build OS notifications
+
+ var alertBody = ""
+ for notification in notifications {
+ TaurusApplication.setLastNotificationTime(notification.getInstanceId(), time: notification.timestamp)
+ if (alertBody.isEmpty == false){
+ alertBody += "\n"
+
+ }
+ alertBody += notification.description
+ }
+
+ let notification = UILocalNotification()
+ notification.fireDate = NSDate(timeIntervalSinceNow: 5)
+ notification.alertBody = alertBody
+ // notification.alertAction = "be awesome!"
+ notification.soundName = UILocalNotificationDefaultSoundName
+ UIApplication.sharedApplication().scheduleLocalNotification(notification)
+
+
+
+
+ }
+
+
+ func getNotifications( start : Int64, end :Int64, frequency : Int64)->[TaurusNotification]{
+ let favorites = TaurusApplication.getFavoriteInstances()
+ var results = [TaurusNotification]()
+ var anomalies = [String: (Int64, AnomalyValue)]()
+
+ for instance in favorites {
+ let lastFired = TaurusApplication.getLastNotificationTime(instance)
+ if (lastFired > end - frequency){
+ // Already showed a notification
+ continue
+ }
+
+ let instanceData = TaurusApplication.getTaurusDatabase().getInstanceData (instance, from: start, to: end)
+
+ for value in instanceData! {
+
+ let logScale = DataUtils.logScale(Double(abs(value.1.anomaly)))
+
+ if (Float(logScale) > 0 /* TaurusApplication.redBarFloor*/){
+
+ if (value.1.metricMask.contains( MetricType.StockVolume) ||
+ value.1.metricMask.contains( MetricType.StockPrice)
+ ){
+ anomalies[instance] = value
+ }
+ }
+ }
+ }
+
+ // Create notifications
+ for (instance, value) in anomalies {
+ let timestamp = value.0
+ let mask = value.1.metricMask
+ let text = formatAnomalyTitle (instance, mask: mask, timestamp: timestamp)
+ let notification = TaurusApplication.dataFactory.createNotification(instance, timestamp: timestamp, description: text)
+ results.append(notification as! TaurusNotification)
+ }
+
+ return results
+ }
+
+ func formatAnomalyTitle (instance: String, mask: MetricType, timestamp : Int64)->String{
+ var anomalyTypes = ""
+ if ( mask.contains(MetricType.StockPrice) || mask.contains(MetricType.StockVolume) ){
+
+ if ( mask.contains(MetricType.TwitterVolume)){
+ anomalyTypes = "Stock & Twitter"
+ }else{
+ anomalyTypes = "Stock"
+ }
+ } else
+ if ( mask.contains(MetricType.TwitterVolume)){
+ anomalyTypes = "Twitter"
+ }
+ let formatter = NSDateFormatter()
+ formatter.dateStyle = NSDateFormatterStyle.ShortStyle
+ formatter.timeStyle = .ShortStyle
+
+ let dateString = formatter.stringFromDate(DataUtils.dateFromTimestamp(timestamp))
+
+
+ let resultStr = instance + "(" + anomalyTypes + "):" + dateString
+
+ return resultStr
+ }
+}
@@ -48,7 +48,7 @@ public class TaurusDataSyncService: DataSyncService{
if (now >= DataUtils.timestampFromDate(date!)) {
// Download the previous hour
from -= DataUtils.MILLIS_PER_HOUR;
- var units : NSCalendarUnit = [NSCalendarUnit.NSYearCalendarUnit,
+ let units : NSCalendarUnit = [NSCalendarUnit.NSYearCalendarUnit,
NSCalendarUnit.NSMonthCalendarUnit ,
NSCalendarUnit.NSDayCalendarUnit ,
NSCalendarUnit.NSHourCalendarUnit ,
@@ -112,6 +112,10 @@ public class TaurusDataSyncService: DataSyncService{
)
}
+ override func synchronizeNotification (){
+ TaurusNotificationService().syncNotifications()
+ }
+
override func loadAllMetrics() -> Int32 {
return super.loadAllMetrics()
@@ -97,9 +97,9 @@
// collaspedAnomalies = nil
}
- func setCollapsed (collapsed: Bool){
+ /* func setCollapsed (collapsed: Bool){
- }
+ }*/
func getEndDate()->NSDate?{
return DataUtils.dateFromTimestamp(endDate)
@@ -133,7 +133,7 @@
let fromTime = lastTimestamp + DataUtils.MILLIS_PER_HOUR - numOfDays * DataUtils.MILLIS_PER_DAY
let from = DataUtils.dateFromTimestamp(fromTime)
- let startProfile = DataUtils.timestampFromDate( NSDate())
+ // let startProfile = DataUtils.timestampFromDate( NSDate())
client.getMetricsValues (getId(), from: from, to: to,ascending: true ){( metricId: String, timestamp: Int64, value: Float, anomaly: Float) in
@@ -145,7 +145,7 @@
newRawData[idx] = Double(value)
-
+
let hour = DataUtils.floorTo60Minutes(timestamp)
let score = aggregated[hour]
if (score == nil || score < anomaly) {
@@ -161,7 +161,7 @@
var newAnomalies = [(Int64, Double)]()
// Populate anomaly array for all scrollable period
- for var time = fromTime; time < lastTimestamp; time += DataUtils.MILLIS_PER_HOUR {
+ for var time = fromTime; time < lastTimestamp + DataUtils.MILLIS_PER_HOUR; time += DataUtils.MILLIS_PER_HOUR {
var value = 0.0
let anomalyValue : Float? = aggregated[time]
if (anomalyValue != nil){
@@ -176,7 +176,7 @@
self.allAnomalies = newAnomalies
- let endProfile = DataUtils.timestampFromDate( NSDate())
+ // let endProfile = DataUtils.timestampFromDate( NSDate())
// Log.line ("time: " + String(endProfile-startProfile))
refreshData()
@@ -215,10 +215,10 @@
// Anomalies
size = Int64( allAnomalies.count)
- start = max(size - (lastTimestamp - endDate) / BAR_INTERVAL - bars+1, 0)
- end = Int ( min ( start+bars, size))
+ start = max(size - (lastTimestamp - endDate) / BAR_INTERVAL - bars, 0)
+ end = Int ( min ( start+bars+1, size))
- let anomalySlice = self.allAnomalies[Range<Int>(start: Int( start), end: end)]
+ let anomalySlice = self.allAnomalies[Range<Int>(start: Int(start), end: end)]
self.anomalies = Array(anomalySlice)
}
@@ -305,7 +305,9 @@
for (var i : Int64 = 0; i < intervalsPerBar; i++){
let index = Int((bars-1) * intervalsPerBar + i )
let srcIndex = endIndex - (intervalsPerBar - i )
- results[ index ] = allRawData![ Int(srcIndex) ]
+
+
+ results[ index] = allRawData![ Int(srcIndex) ]
}

0 comments on commit 2a3bbcb

Please sign in to comment.