def getTempData(): history = Temp_MinMax({}, {}) for daysOffset in range(-historyDays, 8 + 1): date = now + datetime.timedelta(daysOffset) history.min[date] = dailyRecords.getInfo(city, date, daily.MIN_TEMP) history.max[date] = dailyRecords.getInfo(city, date, daily.MAX_TEMP) return history
def __call__(self, city): dInfo = dailyRecords.getInfo(city, today(city), self.field) msg = '' datemarker = dateMarkerFromDate(today(city)) alreadyReportedRecord, oldTweet = self.datemarker.get( datemarker, (None, None)) if (dInfo.median != None and alreadyReportedRecord != dInfo.recent and daily.timeByCity[city].hour < 11 and dInfo.recent > dInfo.median): maybePostWarmMorningTweet(daily.timeByCity[city], dInfo.recent, dInfo.median) self.datemarker[datemarker] = dInfo.recent
def call(self, city, sampleDay): allcast = forecast.getForecastDataEnvCan(city) try: cast = allcast[sampleDay] except KeyError: return if len(cast[self.field.index]) == 0: # No forecast is available for this field for this day, skip return nextDay = sampleDay + datetime.timedelta(1) try: cast2 = allcast[sampleDay + datetime.timedelta(1)] except KeyError: return #print(cast.MIN_TEMP, cast2.MIN_TEMP, str(min(int(cast.MIN_TEMP),int(cast2.MIN_TEMP)))) cast = cast._replace( MIN_TEMP=str(min(int(cast.MIN_TEMP), int(cast2.MIN_TEMP)))) try: #print(city, sampleDay, cast) dInfo = dailyRecords.getInfo(city, sampleDay, self.field, recentValOverride=cast) except KeyError: return msg = '' msgPrefix = '' datemarker = dateMarkerFromDate(sampleDay) alreadyReportedRecord = self.datemarker.get(datemarker, None) if alreadyReportedRecord != None: print(repr(alreadyReportedRecord)) updatedAlert = 'This alert corrects the last alert which reported a value of %.1f%s.<br>\n' % ( alreadyReportedRecord.value, self.field.htmlunits) msgPrefix = updatedAlert + '\n' + alreadyReportedRecord.tweet #print('cast={} recent={} max={} day={} since={}'.format(str(cast), float(dInfo.recent), float(dInfo.max.value), sampleDay.year, dInfo.maxSince.year)) if (dInfo.recent != None and (alreadyReportedRecord == None or alreadyReportedRecord.value != dInfo.recent)): if ((dInfo.recent > dInfo.max.value or (sampleDay.year - dInfo.maxSince.year) > 55) and self.skipMaxRecords == False and not (self.skipMaxEstimated and dInfo.recentEstimated)): print(msgPrefix) tweet = maybePostTweet(city, sampleDay, self.field, dInfo.recent, dInfo.maxSince.value, dInfo.maxSince.year, recordIsMax=True) msg += tweet + '<br>' if dInfo.maxSince.value == None: compareDay = datetime.date(dInfo.max.year, sampleDay.month, sampleDay.day) else: compareDay = datetime.date(dInfo.maxSince.year, sampleDay.month, sampleDay.day) self.datemarker[datemarker] = PreviousReport( dInfo.recent, tweet) if len(msg) > 0: return Email(field=self.field, date=sampleDay, message=msgPrefix + msg)
low = None else: search = re.search('<td class="(.*)">([-0-9]*)</td>', strippedLine) if search != None: (label, temperature) = search.groups() if temperature != '-': if label == 'high': high = int(temperature) elif label == 'low lbtext': low = int(temperature) if strippedLine == '</tr>' and low != None and high != None: forecastOffset = (curDay - forecastIssued).days print "%s(%d): Low %d, High %d" % (curDay, forecastOffset, low, high) lowRec = dailyRecords.getInfo('ottawa', curDay, daily.MIN_TEMP) highRec = dailyRecords.getInfo('ottawa', curDay, daily.MAX_TEMP) if lowRec.recent != None and highRec.recent != None: actualLow = lowRec.recent actualHigh = highRec.recent deviation = LowHigh(low - actualLow, high - actualHigh, low - lowRec.avg, high - highRec.avg) deviationsByDay[forecastOffset - 1].forecastLow.append( deviation.forecastLow) deviationsByDay[forecastOffset - 1].forecastHigh.append( deviation.forecastHigh) deviationsByDay[forecastOffset - 1].normalLow.append( deviation.normalLow) deviationsByDay[forecastOffset - 1].normalHigh.append(
def call(self, city, sampleDay): try: dInfo = dailyRecords.getInfo(city, sampleDay, self.field) except KeyError: return msg = '' updatedAlert = '' datemarker = dateMarkerFromDate(sampleDay) alreadyReportedRecord = self.datemarker.get(datemarker,None) alreadyReportedRecordTweet = None if alreadyReportedRecord != None: updatedAlert = 'This alert corrects the last alert which reported a value of %.1f%s.<br>\n' % (alreadyReportedRecord.value, self.field.htmlunits) alreadyReportedRecordTweet = alreadyReportedRecord.tweet if ( dInfo.recent != None and ( alreadyReportedRecord == None or alreadyReportedRecord.value != dInfo.recent ) and not (self.skipIncomplete and dInfo.incomplete) and not (self.skipBelowZero and dInfo.recent < 0) ): tweet = None #if self.field is daily.MIN_TEMP and sampleDay == dt.date(2017,3,5): # import pudb; pu.db closeToMax = calcCloseToRecordMax(self.field, dInfo.max.value, dInfo.recent) closeToMin = calcCloseToRecordMax(self.field, dInfo.min.value, dInfo.recent) recordMax = ( dInfo.recent > dInfo.max.value or ( sampleDay.year - dInfo.maxSince.year) > 55 ) tryMax = ( self.skipMaxRecords == False and not (self.skipMaxEstimated and dInfo.recentEstimated ) and not (self.skipMaxIncomplete and dInfo.incomplete) ) recordMin = ( dInfo.recent < dInfo.min.value or ( sampleDay.year - dInfo.minSince.year) > 55 ) tryMin = ( self.skipMinRecords == False and not (self.skipMinEstimated and dInfo.recentEstimated) and not (self.skipMinIncomplete and dInfo.incomplete) ) if tryMax and recordMax: print(updatedAlert, end=' ') tweet = maybePostTweet(city, sampleDay, self.field, dInfo.recent, dInfo.recentEstimatedHour, dInfo.maxSince.value, dInfo.maxSince.year, oldTweet=alreadyReportedRecordTweet, recordIsMax=True) msg += tweet + '<br>' if dInfo.maxSince.value == None: compareDay = datetime.date(dInfo.max.year, sampleDay.month, sampleDay.day) else: compareDay = datetime.date(dInfo.maxSince.year, sampleDay.month, sampleDay.day) msg += htmlday.htmlTable( daily.load(city), (sampleDay, compareDay) ) elif tryMax and closeToMax: tweet = maybePostCloseTweet( city, sampleDay, self.field, dInfo.recent, dInfo.recentEstimatedHour, dInfo.max.value, oldTweet=alreadyReportedRecordTweet, recordIsMax=True) elif tryMin and recordMin: print(updatedAlert, end=' ') #import pudb; pu.db tweet = maybePostTweet(city, sampleDay, self.field, dInfo.recent, dInfo.recentEstimatedHour, dInfo.minSince.value, dInfo.minSince.year, oldTweet=alreadyReportedRecordTweet, recordIsMax=False) msg += tweet + '<br>' if dInfo.minSince.value == None: compareDay = datetime.date(dInfo.min.year, sampleDay.month, sampleDay.day) else: compareDay = datetime.date(dInfo.minSince.year, sampleDay.month, sampleDay.day) print((dInfo.minSince.value, compareDay, sampleDay)) msg += htmlday.htmlTable( daily.load(city), (sampleDay, compareDay) ) elif tryMin and closeToMin: tweet = maybePostCloseTweet( city, sampleDay, self.field, dInfo.recent, dInfo.recentEstimatedHour, dInfo.min.value, oldTweet=alreadyReportedRecordTweet, recordIsMax=False) if tweet is not None: self.datemarker[datemarker] = (dInfo.recent, tweet) if len(msg) > 0: return Email(field=self.field, date=sampleDay, message=msg)
def main( city, force=False, lastCheckedValue=None, today=None, maxValueToCheck=None, allYear=False, allWinter=False, justTop5=False, dataSinceDay=None, ): #import pdb; pdb.set_trace() data = daily.load(city) if dataSinceDay is not None: for day in tuple(data.keys()): if day < dataSinceDay: del data[day] monthlyAverages.cityData = data if today is None: today = daily.timeByCity[city].date() #if allYear: # today = dt.date(daily.timeByCity[city].date().year, 12, 31) yearToCheck = (today - dt.timedelta(7)).year if yearToCheck != today.year: today = dt.date(yearToCheck, 12, 31) monthlyAverages.now = today tomorrow = today + dt.timedelta(days=1) todayMaxInfo = dailyRecords.getInfo(city, today, daily.MAX_TEMP) todayAverageMax = roundAwayFromZero(todayMaxInfo.normal) todayMax = None if todayMaxInfo.recent is not None: todayMax = int(todayMaxInfo.recent) if lastCheckedValue is None: minValueToCheck = int(todayAverageMax) + 2 else: minValueToCheck = int(lastCheckedValue) + 1 if maxValueToCheck is None: maxValueToCheck = todayMax if todayMax is None: maxValueToCheck = 35 maxValuesToCheck = filter(lambda t: t % 10 == 0, range(minValueToCheck, maxValueToCheck + 1)) fieldList = [ #*[ ( ExprVal('max>={} if max is not None else None'.format(t), # title=str(t) + "℃", # name="max>=" + str(t), # units="days", # unit="day", # precision=0, # field=daily.MAX_TEMP, # description=str(t)+"℃ days"), # True ) for t in maxValuesToCheck ], #[ ( ExprVal('maxHumidex>max and maxHumidex>=' + str(t), # title=str(t) + " humidex", # name="humidex>=" + str(t), # units="days", # unit="day", # precision=0), # True ) for t in range(30, 51) ] #( FractionVal(daily.TOTAL_RAIN_MM, "Rain"), True ), (FractionVal(daily.TOTAL_SNOW_CM, "snow"), True), #( FractionVal(daily.TOTAL_PRECIP_MM, "precipitation"), True ), #( FractionVal(daily.AVG_WIND, "Wind"), False ), #( Avg(daily.MIN_TEMP, daily.MAX_TEMP, "temperature"), False ), #( FractionVal(daily.MEAN_HUMIDITY, "Humidity"), False ), ] monFilter = monthlyAverages.BeforeDateFilter(month=tomorrow.month, day=tomorrow.day) if allYear: monFilter = monthlyAverages.BeforeDateFilter(month=1, day=1) if allWinter: monFilter = WinterFilter() todayFilter = monthlyAverages.OneDayFilter(month=today.month, day=today.day) #import pudb; pu.db for field, cumulative in fieldList: thisyear = today.year if allWinter: thisyear = today.year if today.month >= 7 else today.year - 1 valByYear = monthlyAverages.yearDatas(monFilter, field=field, lastYear=thisyear, cumulative=cumulative) normalVal = monthlyAverages.normalMonthlyDatas(today.year, monFilter, field, cumulative=cumulative) if thisyear not in valByYear: continue ci80 = confidenceInterval80(valByYear, thisyear) ci50 = confidenceInterval50(valByYear, thisyear) thisYearVal = valByYear[thisyear] maxSince = None minSince = None for year in reversed(sorted(valByYear.keys())): if year != thisyear: val = valByYear[year] if maxSince is None and val >= thisYearVal: maxSince = year if minSince is None and val <= thisYearVal: minSince = year del val insideCi80 = (thisYearVal >= ci80.low and thisYearVal <= ci80.high) insideCi50 = (thisYearVal >= ci50.low and thisYearVal <= ci50.high) if field.units == 'days': # and False: todayValByYear = monthlyAverages.yearDatas(todayFilter, field=field, lastYear=today.year, cumulative=cumulative) if todayValByYear[today.year] == 0: #The countable event did not occur today, so skip. continue #import pdb; pdb.set_trace() yearByVal = reverseDict(valByYear) top5 = topNValuesLists(yearByVal, 5) if ((allYear or allWinter) and (inListOfLists(top5.values(), thisyear) or args.force)): tweetTopN(city, top5, field, thisyear) if justTop5: continue amountDescription = '' if thisYearVal < ci50[0] and (field.units != 'days' or thisYearVal != 0): amountDescription = 'just ' amount = formatWithUnits(thisYearVal, field, field.precision) if field.units == 'days': amount = formatWithUnits(thisYearVal, field, 0, skipUnits=True) if thisYearVal == 0: amount = "no" aboveBelow = 'above' if thisYearVal < normalVal.average: aboveBelow = 'below' if cumulative: deviation = deviationDescription(thisYearVal, normalVal.average, field) else: diff = abs(thisYearVal - normalVal.average) deviation = formatWithUnits(diff, field, field.precision) + ' ' + aboveBelow start = 'average' if cumulative: start = 'total' title = field.title.lower() ci80Low = formatWithUnits(ci80[0], field, field.precision, skipUnits=True) ci80High = formatWithUnits(ci80[1], field, field.precision) insideOutside = 'outside' if insideCi80: insideOutside = 'inside' cityName = stations.city[city].name avgWithUnits = formatWithUnits(normalVal.average, field, field.precision) #tweetText = ( # '#{cityName}\'s {start} {title} so far this year was' # ' {amountDescription}{amount},' # ' {deviation} {aboveBelow} average; {insideOutside} the normal range of' # ' {ci80Low} to {ci80High}'.format(**locals())) tweetText = ('#{cityName}\'s {start} {title} so far this year was' ' {amountDescription}{amount},' ' {deviation} the average of' ' {avgWithUnits}'.format(**locals())) if allYear: tweetText = ( '#{cityName}\'s {start} {title} during {today.year} was' ' {amountDescription}{amount},' ' {deviation} the average of' ' {avgWithUnits}'.format(**locals())) if field.units == 'days': units = field.unit if thisYearVal != 1: units = field.units nth = alert.nth(thisYearVal) #import pdb; pdb.set_trace() average = formatWithUnits(normalVal.average, field, precision=1) todayString = 'Today is' if today != daily.timeByCity[city].date(): todayString = 'Yesterday was' tweetText = ( '{todayString} #{cityName}\'s {nth} {title} day so far this year,' ' {deviation} the average of {average}.'.format(**locals())) #alertTweets.maybeTweetWithSuffix(city, tweetText) recordMin = normalVal.minimum recordMax = normalVal.maximum print( 'Record minimum was {recordMin}{field.units} in {normalVal.minYear}' .format(**locals())) print( 'Record maximum was {recordMax}{field.units} in {normalVal.maxYear}' .format(**locals())) plotIt = not insideCi80 or args.force if maxSince is None: print('***Max since records began in {}.'.format( min(valByYear.keys()))) plotIt = True elif today.year - maxSince > 10: maxSinceVal = valByYear[maxSince] print('***Max since {maxSince}:{maxSinceVal}{field.units}'.format( **locals())) plotIt = True if minSince is None: print('***Min since records began in {}.'.format( min(valByYear.keys()))) plotIt = True elif today.year - minSince > 10: minSinceVal = valByYear[minSince] print('***Min since {minSince}:{minSinceVal}{field.units}'.format( **locals())) plotIt = True if plotIt: fname = field.name pngname = "%s/Annual_%s.png" % (city, fname) alertTweets.maybeTweetWithSuffix(city, tweetText, fname=pngname) if todayMax is None: return todayAverageMax + 2 return max(todayMax, todayAverageMax + 2)