def maybeTweetMaxSince(city, valByYear, field, monthDate, monthStr, maxSince, cumulative): if maxSince is None: return if monthDate.year - maxSince < 8: return if len( tuple( filter(lambda t: t in range(maxSince, monthDate.year), valByYear.keys()))) < 8: return thisYearVal = valByYear[monthDate.year] cityName = stations.city[city].name monthAdjective = fieldAdjective(field)[0] amount = formatWithUnits(thisYearVal, field) aggregate = "Total" if cumulative else "Average" #import pudb; pu.db tweet = ('#{cityName} just had its {monthAdjective} {monthStr}' ' since {maxSince}. {aggregate} {field.englishName} was {amount}.' .format(**locals())) if field.units == 'days': tweet = ('#{cityName} had 7 {monthStr} {field.englishName} days;' ' more than any year since {maxSince}.'.format(**locals())) #pprint.PrettyPrinter().pprint(valByYear) #print(tweet) #input() alertTweets.maybeTweetWithSuffix(city, tweet)
def tweetTopN(city, db, field, thisYear): top10 = { 1: '❶', 2: '❷', 3: '❸', 4: '❹', 5: '❺', 6: '❻', 7: '❼', 8: '❽', 9: '❾', 10: '❿', } top10Double = { 1: '⓵', 2: '⓶', 3: '⓷', 4: '⓸', 5: '⓹', 6: '⓺', 7: '⓻', 8: '⓼', 9: '⓽', 10: '⓾' } place = 1 totalCount = sum(len(a) for a in db.values()) adjective = fieldAdjective(field)[0] description = fieldDescription(field) cityName = stations.city[city].name units = field.units tweetText = ( '#{cityName}\'s 5 {adjective} years (by {description}):'.format( **locals())) for key in reversed(sorted(db.keys())): count = place for year in reversed(sorted(db[key])): nth = top10[place] if year == thisYear: nth = top10Double.get(place, '*') if count > 5: break val = key tweetText += "\n{nth} {year}: {val} {units}".format(**locals()) count += 1 place += len(db[key]) alertTweets.maybeTweetWithSuffix(city, tweetText)
def maybeTweetMinSince(city, valByYear, field, monthDate, monthStr, minSince, cumulative): if minSince is None: return if monthDate.year - minSince < 8: return thisYearVal = valByYear[monthDate.year] cityName = stations.city[city].name monthAdjective = fieldAdjective(field)[1] amount = formatWithUnits(thisYearVal, field) aggregate = "Total" if cumulative else "Average" #import pudb; pu.db tweet = ( '#{cityName} just had its {monthAdjective} {monthStr}' ' since {minSince}. {aggregate} {field.englishName} was just {amount}.' .format(**locals())) alertTweets.maybeTweetWithSuffix(city, tweet)
def main(city, year): data = daily.load(city) cold = ValWithDate(+999, None) heat = ValWithDate(-999, None) snow = ValWithDate(0, None) rain = ValWithDate(0, None) wind = ValWithDate(0, None) for day, weather in data.items(): if day.year != year: continue #import pudb; pu.db if (weather.MAX_TEMP is not None and weather.MAX_TEMP > heat.val): heat = ValWithDate(weather.MAX_TEMP, day) if (weather.MIN_TEMP is not None and weather.MIN_TEMP < cold.val): cold = ValWithDate(weather.MIN_TEMP, day) if (weather.TOTAL_SNOW_CM is not None and weather.TOTAL_SNOW_CM > snow.val): snow = ValWithDate(weather.TOTAL_SNOW_CM, day) if (weather.TOTAL_RAIN_MM is not None and weather.TOTAL_RAIN_MM > rain.val): rain = ValWithDate(weather.TOTAL_RAIN_MM, day) if (weather.SPD_OF_MAX_GUST_KPH is not None and weather.SPD_OF_MAX_GUST_KPH > wind.val): wind = ValWithDate(weather.SPD_OF_MAX_GUST_KPH, day) cityName = stations.city[city].name tweet = '#{cityName} 2016 extremes:'.format(**locals()) for name, u in (('heat', '℃'), ('cold', '℃'), ('snow', 'cm'), ('rain', 'mm'), ('wind', 'km/h')): if locals()[name].date is None: continue tweet += ('\n{}: {}{} ({})'.format( name, locals()[name].val, u, locals()[name].date.strftime('%b %d'))) alertTweets.maybeTweetWithSuffix(city, tweet)
def tweetTopN(city, db, monthStr, field, thisYear, daysLeftThisYear): #import pudb; pu.db top10 = { 1: '❶', 2: '❷', 3: '❸', 4: '❹', 5: '❺', 6: '❻', 7: '❼', 8: '❽', 9: '❾', 10: '❿', } top10Double = { 1: '⓵', 2: '⓶', 3: '⓷', 4: '⓸', 5: '⓹', 6: '⓺', 7: '⓻', 8: '⓼', 9: '⓽', 10: '⓾' } place = 1 totalCount = sum(len(a) for a in db.values()) adjective = fieldAdjective(field)[0] description = fieldDescription(field) cityName = stations.city[city].name units = field.units tweetText = '#{cityName}\'s {totalCount} {adjective} {monthStr}s'.format( **locals()) if description is not None: tweetText += '(by {description})'.format(**locals()) for key in reversed(sorted(db.keys())): for year in reversed(sorted(db[key])): #val = '{:.{}f}'.format(key, field.precision+1) #print(field.precision, D('.'+'0'*(field.precision)+'1')) #val = key.quantize(D('.'+'0'*(field.precision)+'1')) val = key nth = top10.get(place, '*') if year == thisYear: nth = top10Double.get(place, '*') if place == 1 and daysLeftThisYear <= 0: tweetText = f'#{cityName} just had its {adjective} {monthStr} ever' if description is not None: tweetText += f' (by {description})' nextLine = "\n{nth} {year}: {val}{units}".format(**locals()) if year == thisYear and daysLeftThisYear > 0: if daysLeftThisYear > 1: nextLine += ' ({daysLeftThisYear} days left)'.format( **locals()) else: nextLine += ' (1 day left)'.format(**locals()) if len(tweetText) + len(nextLine) > 140: tweetText += '...' break tweetText += nextLine place += len(db[key]) #print(tweetText); input() alertTweets.maybeTweetWithSuffix(city, tweetText)
def main(city, args, lastCheckedValue=None, today=None): #import pdb; pdb.set_trace() monthlyAverages.cityData = daily.load(city) if today is None: today = daily.timeByCity[city].date() monthDate = today - datetime.timedelta(7) nextMonthStart = datetime.date( monthDate.year if monthDate.month < 12 else monthDate.year + 1, monthDate.month + 1 if monthDate.month < 12 else 1, 1) daysLeft = (nextMonthStart - today).days monthlyAverages.now = monthDate tomorrow = today + datetime.timedelta(days=1) fieldList = [] if args.daysAbove: fieldList += [(ExprVal('max>=' + str(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 range(20, 29 + 1)] if args.daysBelow: fieldList += [(ExprVal('min<=' + str(t), title=str(t) + "℃", name="min<=" + str(t), units="days", unit="day", precision=0, field=daily.MIN_TEMP, description=str(t) + "℃ nights"), True) for t in range(-10, 1)] #[ ( 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) ] if args.rain: if 'TOTAL_RAIN_MM' not in stations.city[args.city].skipDailyFields: fieldList += [(FractionVal(daily.TOTAL_RAIN_MM, "Rain"), True)] if args.snow: fieldList += [(FractionVal(daily.TOTAL_SNOW_CM, "snow"), True)] if args.snowDays: fieldList += ([(ExprVal('snow>0', title="snow", name="snow", units="days", unit="day", precision=0, field=daily.TOTAL_SNOW_CM, description="snow days"), True)] + [(ExprVal('snow>=' + str(t), title=str(t) + "cm snow", name="snow>=" + str(t), units="days", unit="day", precision=0, field=daily.TOTAL_SNOW_CM, description=str(t) + "cm snow days"), True) for t in range(5, 41, 5)]) if args.wind: fieldList += [(FractionVal(daily.AVG_WIND, "wind"), False)] if args.meanTemp: fieldList += [(ExprVal( 'meanTemp' ' if ("M" not in meanTempFlag and "I" not in meanTempFlag)' ' else ((max+min)/2' ' if ("M" not in minFlag and "I" not in minFlag' ' and "M" not in maxFlag and "I" not in maxFlag)' ' else None)', name="Mean temperature", title="Mean temperature", units="℃", unit="℃", precision=2, field=daily.MEAN_TEMP, description='avg. hourly temp'), False)] if args.avgTemp: fieldList += [(Avg(daily.MIN_TEMP, daily.MAX_TEMP, "Temperature"), False)] if args.humidity: fieldList += [(FractionVal(daily.MEAN_HUMIDITY, "Humidity"), False)] monthStr = monthName(monthDate.month, long=True) monFilter = monthlyAverages.MonthFilter(month=monthDate.month) nextMonthYear = (monthDate.year * 12 + monthDate.month) // 12 nextMonthMonth = monthDate.month % 12 + 1 #import pudb; pu.db for field, cumulative in fieldList: valByYear = monthlyAverages.yearDatas(monFilter, field=field, lastYear=monthDate.year, cumulative=cumulative) normalVal = monthlyAverages.normalMonthlyDatas(monthDate.year, monFilter, field, cumulative=cumulative) if monthDate.year not in valByYear: continue ci80 = confidenceInterval80(valByYear, monthDate) ci50 = confidenceInterval50(valByYear, monthDate) thisYearVal = valByYear[monthDate.year] maxSince = None minSince = None for year in reversed(sorted(valByYear.keys())): if year != monthDate.year: val = valByYear[year] if maxSince is None and val >= thisYearVal: maxSince = year if minSince is None and val <= thisYearVal: minSince = year del val maybeTweetTop5(city, valByYear, nextMonthYear, nextMonthMonth, monthStr, field, monthDate) maybeTweetMaxSince(city, valByYear, field, monthDate, monthStr, maxSince, cumulative) maybeTweetMinSince(city, valByYear, field, monthDate, monthStr, minSince, cumulative) insideCi80 = (thisYearVal >= ci80[0] and thisYearVal <= ci80[1]) insideCi50 = (thisYearVal >= ci50[0] and thisYearVal <= ci50[1]) amountDescription = '' if thisYearVal < ci50[0] and (field.units != 'days' or thisYearVal != 0): amountDescription = 'just ' if daysLeft > 5 and thisYearVal > ci50[0]: amountDescription = 'already ' amount = formatWithUnits(thisYearVal, field) 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) else: diff = abs(float(thisYearVal - normalVal.average)) deviation = formatWithUnits(diff, field) + ' ' + aboveBelow start = 'average' if cumulative: start = 'total' title = field.title.lower() ci80Low = formatWithUnits(ci80[0], field, skipUnits=True) ci80High = formatWithUnits(ci80[1], field) insideOutside = 'outside' if insideCi80: insideOutside = 'inside' cityName = stations.city[city].name average = formatWithUnits(normalVal.average, field, precision=max(field.precision, 1)) tweetText = ('#{cityName}\'s {start} {title} this {monthStr} was' ' {amountDescription}{amount},' ' {deviation} the average of {average}.'.format( **locals())) if daysLeft > 0: tweetText = ( f'With {daysLeft} days left, #{cityName}\'s {start} {title} this {monthStr} is' f' {amountDescription}{amount},' f' {deviation} the average of {average}.') if field.units == 'days': units = field.unit if thisYearVal != 1: units = field.units tweetText = ( '#{cityName} had' ' {amountDescription}{amount} {title} {units} this {monthStr},' ' {deviation} the average of {average}.'.format(**locals())) print(tweetText) #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 monthDate.year - maxSince > 10: maxSinceVal = float(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 monthDate.year - minSince > 10: minSinceVal = float(valByYear[minSince]) print('***Min since {minSince}:{minSinceVal}{field.units}'.format( **locals())) plotIt = True if plotIt: monthlyAverages.annualOrderedByMonth(city, monFilter, field, cumulative=cumulative) plotFname = snow.createPlot( city, running=cumulative, field=field, otheryears=(), name=monthName(monthDate.month) + title.replace(' ', '_').replace('℃', 'C'), dataStartDay=datetime.date(monthDate.year, monthDate.month, 1), plotStartDay=datetime.date(monthDate.year, monthDate.month, 1), plotEndDay=datetime.date(nextMonthYear, nextMonthMonth, 1), plotYMin=None) pngname = plotFname.replace('/svg/', '/') + '.png' command = 'rsvg-convert -o {pngname} --background-color=white {plotFname}'.format( **locals()) print(command) assert os.system(command) == 0 alertTweets.maybeTweetWithSuffix(city, tweetText, fname=pngname)
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)