/ appfigures.py
appfigures.py
1 #!/usr/bin/env python3 2 3 4 def openURL(urlFragment): 5 from os import environ 6 from urllib.request import Request, urlopen 7 8 CLIENT_KEY = environ["CLIENT_KEY"] 9 BASE = "https://api.appfigures.com/v2/" 10 AUTH_HEADER = environ["AUTH_HEADER"] 11 12 return urlopen( 13 Request( 14 BASE + urlFragment, 15 headers={"X-Client-Key": CLIENT_KEY, "Authorization": AUTH_HEADER}, 16 ) 17 ) 18 19 20 def getData(pj): 21 from datetime import datetime 22 23 # Remove last couple days, since they're 0 24 return list( 25 zip( 26 *[ 27 ( 28 datetime.strptime(z["date"], "%Y-%m-%d"), 29 z["downloads"], 30 z["updates"], 31 z["downloads"] - z["uninstalls"], 32 ) 33 for z in sorted(pj.values(), key=lambda _: _["date"]) 34 ][:-4] 35 ) 36 ) 37 38 39 def combineDaily(pj, func, numDays): 40 assert numDays in (1, 7) 41 return tuple([func(pj[i : i + numDays]) for i in range(0, len(pj), numDays)]) 42 43 44 def getLastElem(arr): 45 return arr[-1] 46 47 48 def getAxes(t, y_axis_choice, numDays): 49 assert len(t[0]) == len(t[y_axis_choice]) 50 assert y_axis_choice in (1, 2, 3) 51 assert numDays in (1, 7) 52 assert t[0] == combineDaily(t[0], getLastElem, 1) 53 assert t[y_axis_choice] == combineDaily(t[y_axis_choice], sum, 1) 54 55 return ( 56 combineDaily(t[0], getLastElem, numDays), 57 combineDaily(t[y_axis_choice], sum, numDays), 58 ) 59 60 61 def plotData(filename, ylabel, timespan, x, y): 62 # allow this to run on a headless server 63 import matplotlib 64 65 matplotlib.use("Agg") 66 67 import matplotlib.pyplot as plt 68 import matplotlib.dates as mdates 69 70 assert len(x) == len(y) 71 72 # https://stackoverflow.com/questions/9627686/plotting-dates-on-the-x-axis-with-pythons-matplotlib#9627970 73 plt.clf() 74 plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d")) 75 plt.gca().xaxis.set_major_locator(mdates.AutoDateLocator()) 76 plt.xlabel("Date") 77 78 assert ylabel in ("Downloads", "Updates", "Net New Installs") 79 plt.ylabel(ylabel) 80 81 assert timespan in ("Daily", "Weekly") 82 plt.title("Status.im %s %s (Appfigures)" % (timespan, ylabel)) 83 84 plt.plot(x, y) 85 plt.gcf().autofmt_xdate() 86 plt.savefig(filename, dpi=150) 87 88 89 def checkOutputPath(path): 90 from os import access, F_OK 91 92 return access(path, F_OK) 93 94 95 def main(): 96 from json import loads 97 from os.path import join 98 from sys import argv 99 100 outputPath = argv[1] 101 102 # TOCTOU, but doesn't much matter. Just helpful to detect 103 # failures early if possible. 104 assert checkOutputPath(outputPath) 105 106 getPath = lambda n: join(outputPath, n) 107 108 data = getData(loads(openURL("sales/dates/-120/0").read())) 109 110 # data has, in order: date, downloads, updates, and net new installs 111 for interval, numDays in (("Daily", 1), ("Weekly", 7)): 112 fi = interval.lower() 113 plotData( 114 getPath("downloads_%s.png" % fi), 115 "Downloads", 116 interval, 117 *getAxes(data, 1, numDays) 118 ) 119 plotData( 120 getPath("updates_%s.png" % fi), 121 "Updates", 122 interval, 123 *getAxes(data, 2, numDays) 124 ) 125 plotData( 126 getPath("netnewinstalls_%s.png" % fi), 127 "Net New Installs", 128 interval, 129 *getAxes(data, 3, numDays) 130 ) 131 132 133 main()