add lookback query param; add rangeselector buttons

This commit is contained in:
crflynn
2018-10-14 01:38:45 -04:00
parent 7b1cd8193b
commit 782283258e
5 changed files with 322 additions and 260 deletions

View File

@@ -1,104 +1,72 @@
{ {
"downloads":{ "downloads": {
"data":[ "data": [
{ {
"x":[ "x": [
"2017-05-01", "2017-05-01",
"2017-05-02", "2017-05-02",
"2017-05-03" "2017-05-03"
], ],
"y":[ "y": [
"2", "2",
"5", "5",
"4" "4"
], ],
"name":"Downloads", "name": "Downloads",
"type":"scatter", "type": "scatter",
"mode":"lines+markers", "mode": "lines+markers",
"connectgaps":true, "connectgaps": true,
"marker":{ "marker": {
"symbol":"circle", "symbol": "circle",
"line":{ "line": {
"color":"#444", "color": "#444",
"width":1 "width": 1
} }
}, },
"line":{ "line": {
"shape":"linear", "shape": "linear",
"smoothing":1, "smoothing": 1,
"width":2 "width": 2
} }
} }
] ]
}, },
"percentages":{ "percentages": {
"data":[ "data": [
{ {
"x":[ "x": [
"2017-05-01", "2017-05-01",
"2017-05-02", "2017-05-02",
"2017-05-03" "2017-05-03"
], ],
"y":[ "y": [
"2", "2",
"5", "5",
"4" "4"
], ],
"text":[ "text": [
"2", "2",
"5", "5",
"4" "4"
], ],
"name":"Proportional downloads", "name": "Proportional downloads",
"hoverinfo": "x+text+name", "hoverinfo": "x+text+name",
"type":"scatter", "type": "scatter",
"mode":"lines+markers", "mode": "lines+markers",
"connectgaps":true, "connectgaps": true,
"marker":{ "marker": {
"symbol":"circle", "symbol": "circle",
"line":{ "line": {
"color":"#444", "color": "#444",
"width":1 "width": 1
} }
}, },
"line":{ "line": {
"shape":"linear", "shape": "linear",
"smoothing":1, "smoothing": 1,
"width":2 "width": 2
} }
} }
] ]
}, }
"percentages_fill":{
"data":[
{
"x":[
"2017-05-01",
"2017-05-02",
"2017-05-03"
],
"y":[
"2",
"5",
"4"
],
"text":[
"2",
"5",
"4"
],
"hoverinfo": "x+text+name",
"name":"Downloads",
"type":"scatter",
"mode":"lines",
"connectgaps":false,
"line":{
"shape":"linear",
"smoothing":1,
"width":2
},
"fill":"tonexty"
}
]
}
} }

View File

@@ -1,156 +1,212 @@
{ {
"downloads":{ "downloads": {
"layout":{ "layout": {
"autosize":true, "autosize": true,
"height":400, "height": 400,
"margin":{ "margin": {
"r":100, "r": 100,
"t":40, "t": 80,
"autoexpand":true, "autoexpand": true,
"b":80, "b": 80,
"l":100, "l": 100,
"pad":0 "pad": 0
}, },
"paper_bgcolor":"#fff", "paper_bgcolor": "#fff",
"plot_bgcolor":"rgba(175, 175, 175, 0.2)", "plot_bgcolor": "rgba(175, 175, 175, 0.2)",
"showlegend":true, "showlegend": true,
"legend":{ "legend": {
"orientation":"v", "orientation": "v",
"bgcolor":"#e7e7e7", "bgcolor": "#e7e7e7",
"xanchor":"left", "xanchor": "left",
"yanchor":"middle", "yanchor": "middle",
"x":0, "x": 0,
"y":0.5 "y": 0.5
}, },
"title":"Downloads", "title": "Downloads",
"xaxis":{ "xaxis": {
"tickformat":"%m-%d", "tickformat": "%m-%d",
"dtick":604800000, "dtick": 604800000,
"tick0":"2017-08-07", "tick0": "2017-08-07",
"gridcolor":"#FFF", "gridcolor": "#FFF",
"gridwidth":2, "gridwidth": 2,
"anchor":"y", "anchor": "y",
"domain":[ "domain": [
0, 0,
1 1
], ],
"title":"Date", "title": "Date",
"titlefont":{ "titlefont": {
"family":"'Geneva', Verdana, Geneva, sans-serif", "family": "Geneva, Verdana, Geneva, sans-serif",
"size":16, "size": 16,
"color":"#7f7f7f" "color": "#7f7f7f"
},
"showline":true,
"linecolor":"rgba(148, 148, 148, 1)",
"linewidth":2,
"tickangle":-45
},
"yaxis":{
"hoverformat":",.0",
"tickformat":",.0",
"gridcolor":"#FFF",
"gridwidth":2,
"autotick":true,
"rangemode":"tozero",
"showline":true,
"title":"Downloads",
"ticksuffix":"",
"tickmode":"auto",
"linecolor":"rgba(148, 148, 148, 1)",
"linewidth":2
}
}, },
"config":{ "showline": true,
"displaylogo":false, "linecolor": "rgba(148, 148, 148, 1)",
"modeBarButtonsToRemove":[ "linewidth": 2,
"toImage", "tickangle": -45,
"sendDataToCloud", "rangeselector": {
"zoom2d", "buttons": [
"pan2d", {
"select2d", "step": "day",
"lasso2d", "stepmode": "backward",
"zoomIn2d", "count": 31,
"zoomOut2d", "label": "30d"
"toggleSpikelines" },
] {
"step": "day",
"stepmode": "backward",
"count": 61,
"label": "60d"
},
{
"step": "day",
"stepmode": "backward",
"count": 91,
"label": "90d"
},
{
"step": "day",
"stepmode": "backward",
"count": 181,
"label": "all"
}
]
} }
},
"yaxis": {
"hoverformat": ",.0",
"tickformat": ",.0",
"gridcolor": "#FFF",
"gridwidth": 2,
"autotick": true,
"rangemode": "tozero",
"showline": true,
"title": "Downloads",
"ticksuffix": "",
"tickmode": "auto",
"linecolor": "rgba(148, 148, 148, 1)",
"linewidth": 2,
"rangeselector": {
"buttons": [
{
"step": "day",
"stepmode": "backward",
"count": 31,
"label": "30d"
},
{
"step": "day",
"stepmode": "backward",
"count": 61,
"label": "60d"
},
{
"step": "day",
"stepmode": "backward",
"count": 91,
"label": "90d"
},
{
"step": "day",
"stepmode": "backward",
"count": 181,
"label": "all"
}
]
}
}
}, },
"percentages":{ "config": {
"layout":{ "displaylogo": false,
"autosize":true, "modeBarButtonsToRemove": [
"height":400, "toImage",
"margin":{ "sendDataToCloud",
"r":100, "zoom2d",
"t":40, "pan2d",
"autoexpand":true, "select2d",
"b":80, "lasso2d",
"l":100, "zoomIn2d",
"pad":0 "zoomOut2d",
}, "toggleSpikelines"
"paper_bgcolor":"#fff", ]
"plot_bgcolor":"rgba(175, 175, 175, 0.2)",
"showlegend":true,
"legend":{
"orientation":"v",
"bgcolor":"#e7e7e7",
"xanchor":"left",
"yanchor":"middle",
"x":0,
"y":0.5
},
"title":"Proportional Downloads",
"xaxis":{
"tickformat":"%m-%d",
"dtick":604800000,
"tick0":"2017-08-07",
"gridcolor":"#FFF",
"gridwidth":2,
"anchor":"y",
"domain":[
0,
1
],
"title":"Date",
"titlefont":{
"family":"'Geneva', Verdana, Geneva, sans-serif",
"size":16,
"color":"#7f7f7f"
},
"showline":true,
"linecolor":"rgba(148, 148, 148, 1)",
"linewidth":2,
"tickangle":-45
},
"yaxis":{
"range":[
0,
100
],
"dtick":20,
"gridcolor":"#FFF",
"gridwidth":2,
"autotick":false,
"showline":true,
"title":"Download Proportion",
"ticksuffix":"%",
"tickmode":"auto",
"linecolor":"rgba(148, 148, 148, 1)",
"linewidth":2
}
},
"config":{
"displaylogo":false,
"modeBarButtonsToRemove":[
"toImage",
"sendDataToCloud",
"zoom2d",
"pan2d",
"select2d",
"lasso2d",
"zoomIn2d",
"zoomOut2d",
"toggleSpikelines"
]
}
} }
},
"percentages": {
"layout": {
"autosize": true,
"height": 400,
"margin": {
"r": 100,
"t": 80,
"autoexpand": true,
"b": 80,
"l": 100,
"pad": 0
},
"paper_bgcolor": "#fff",
"plot_bgcolor": "rgba(175, 175, 175, 0.2)",
"showlegend": true,
"legend": {
"orientation": "v",
"bgcolor": "#e7e7e7",
"xanchor": "left",
"yanchor": "middle",
"x": 0,
"y": 0.5
},
"title": "Proportional Downloads",
"xaxis": {
"tickformat": "%m-%d",
"dtick": 604800000,
"tick0": "2017-08-07",
"gridcolor": "#FFF",
"gridwidth": 2,
"anchor": "y",
"domain": [
0,
1
],
"title": "Date",
"titlefont": {
"family": "Geneva, Verdana, Geneva, sans-serif",
"size": 16,
"color": "#7f7f7f"
},
"showline": true,
"linecolor": "rgba(148, 148, 148, 1)",
"linewidth": 2,
"tickangle": -45
},
"yaxis": {
"range": [
0,
100
],
"dtick": 20,
"gridcolor": "#FFF",
"gridwidth": 2,
"autotick": false,
"showline": true,
"title": "Download Proportion",
"ticksuffix": "%",
"tickmode": "auto",
"linecolor": "rgba(148, 148, 148, 1)",
"linewidth": 2
}
},
"config": {
"displaylogo": false,
"modeBarButtonsToRemove": [
"toImage",
"sendDataToCloud",
"zoom2d",
"pan2d",
"select2d",
"lasso2d",
"zoomIn2d",
"zoomOut2d",
"toggleSpikelines"
]
}
}
} }

View File

@@ -415,7 +415,7 @@ def etl():
if __name__ == "__main__": if __name__ == "__main__":
date = "2018-07-28" date = "2018-10-13"
env = "prod" env = "prod"
print(date, env) print(date, env)
print(get_daily_download_stats(env, date)) print(get_daily_download_stats(env, date))

View File

@@ -14,7 +14,7 @@ from pypistats.models.download import RecentDownloadCount
from pypistats.models.download import SystemDownloadCount from pypistats.models.download import SystemDownloadCount
blueprint = Blueprint('api', __name__, url_prefix='/api') blueprint = Blueprint("api", __name__, url_prefix="/api")
@blueprint.route("/") @blueprint.route("/")
@@ -27,7 +27,7 @@ def api():
def api_downloads_recent(package): def api_downloads_recent(package):
"""Get the recent downloads of a package.""" """Get the recent downloads of a package."""
package = package.replace(".", "-") package = package.replace(".", "-")
category = request.args.get('period') category = request.args.get("period")
if category is None: if category is None:
downloads = RecentDownloadCount.query.\ downloads = RecentDownloadCount.query.\
filter_by(package=package).all() filter_by(package=package).all()
@@ -55,12 +55,12 @@ def api_downloads_recent(package):
def api_downloads_overall(package): def api_downloads_overall(package):
"""Get the overall download time series of a package.""" """Get the overall download time series of a package."""
package = package.replace(".", "-") package = package.replace(".", "-")
mirrors = request.args.get('mirrors') mirrors = request.args.get("mirrors")
if mirrors == 'true': if mirrors == "true":
downloads = OverallDownloadCount.query.\ downloads = OverallDownloadCount.query.\
filter_by(package=package, category="with_mirrors").\ filter_by(package=package, category="with_mirrors").\
order_by(OverallDownloadCount.date).all() order_by(OverallDownloadCount.date).all()
elif mirrors == 'false': elif mirrors == "false":
downloads = OverallDownloadCount.query.\ downloads = OverallDownloadCount.query.\
filter_by(package=package, category="without_mirrors").\ filter_by(package=package, category="without_mirrors").\
order_by(OverallDownloadCount.date).all() order_by(OverallDownloadCount.date).all()

View File

@@ -12,6 +12,7 @@ from flask import g
from flask import json from flask import json
from flask import redirect from flask import redirect
from flask import render_template from flask import render_template
from flask import request
from flask_wtf import FlaskForm from flask_wtf import FlaskForm
import requests import requests
from wtforms import StringField from wtforms import StringField
@@ -97,8 +98,17 @@ def package_page(package):
"""Render the package page.""" """Render the package page."""
package = package.replace(".", "-") package = package.replace(".", "-")
# Recent download stats # Recent download stats
try:
# Take the min of the lookback and 180
lookback = min(abs(int(request.args.get("lookback", 180))), 180)
except ValueError:
lookback = 180
start_date = str(datetime.date.today() - datetime.timedelta(lookback))
recent_downloads = RecentDownloadCount.query.\ recent_downloads = RecentDownloadCount.query.\
filter_by(package=package).all() filter_by(package=package).all()
if len(recent_downloads) == 0: if len(recent_downloads) == 0:
return redirect(f"/search/{package}") return redirect(f"/search/{package}")
recent = {r: 0 for r in RECENT_CATEGORIES} recent = {r: 0 for r in RECENT_CATEGORIES}
@@ -125,8 +135,8 @@ def package_page(package):
model_data = [] model_data = []
for model in MODELS: for model in MODELS:
records = model.query.filter_by(package=package).\ records = model.query.filter_by(package=package).\
order_by(model.date, filter(model.date >= start_date).\
model.category).all() order_by(model.date, model.category).all()
if model == OverallDownloadCount: if model == OverallDownloadCount:
metrics = ["downloads"] metrics = ["downloads"]
@@ -144,6 +154,8 @@ def package_page(package):
plots = [] plots = []
for model in model_data: for model in model_data:
plot = deepcopy(current_app.config["PLOT_BASE"])[model["metric"]] plot = deepcopy(current_app.config["PLOT_BASE"])[model["metric"]]
# Set data
data = [] data = []
for category, values in model["data"].items(): for category, values in model["data"].items():
base = deepcopy(current_app.config["DATA_BASE"][model["metric"]]["data"][0]) base = deepcopy(current_app.config["DATA_BASE"][model["metric"]]["data"][0])
@@ -154,12 +166,38 @@ def package_page(package):
base["name"] = category.title() base["name"] = category.title()
data.append(base) data.append(base)
plot["data"] = data plot["data"] = data
# Add titles
if model["metric"] == "percentages": if model["metric"] == "percentages":
plot["layout"]["title"] = \ plot["layout"]["title"] = \
f"Daily Download Proportions of {package} package - {model['name'].title().replace('_', ' ')}" # noqa f"Daily Download Proportions of {package} package - {model['name'].title().replace('_', ' ')}" # noqa
else: else:
plot["layout"]["title"] = \ plot["layout"]["title"] = \
f"Daily Download Quantity of {package} package - {model['name'].title().replace('_', ' ')}" # noqa f"Daily Download Quantity of {package} package - {model['name'].title().replace('_', ' ')}" # noqa
# Explicitly set range
plot["layout"]["xaxis"]["range"] = [str(records[0].date - datetime.timedelta(1)), str(datetime.date.today())]
# Add range buttons
plot["layout"]["xaxis"]["rangeselector"] = {"buttons": []}
drange = (datetime.date.today() - records[0].date).days
for k in [30, 60, 90, 120, 9999]:
if k <= drange:
plot["layout"]["xaxis"]["rangeselector"]["buttons"].append({
"step": "day",
"stepmode": "backward",
"count": k+1,
"label": f"{k}d"
})
else:
plot["layout"]["xaxis"]["rangeselector"]["buttons"].append({
"step": "day",
"stepmode": "backward",
"count": drange + 1,
"label": "all"
})
break
plots.append(plot) plots.append(plot)
return render_template( return render_template(