mirror of
https://github.com/LukeHagar/pypistats.dev.git
synced 2025-12-09 20:57:43 +00:00
add lookback query param; add rangeselector buttons
This commit is contained in:
@@ -1,104 +1,72 @@
|
||||
{
|
||||
"downloads":{
|
||||
"data":[
|
||||
"downloads": {
|
||||
"data": [
|
||||
{
|
||||
"x":[
|
||||
"x": [
|
||||
"2017-05-01",
|
||||
"2017-05-02",
|
||||
"2017-05-03"
|
||||
],
|
||||
"y":[
|
||||
"y": [
|
||||
"2",
|
||||
"5",
|
||||
"4"
|
||||
],
|
||||
"name":"Downloads",
|
||||
"type":"scatter",
|
||||
"mode":"lines+markers",
|
||||
"connectgaps":true,
|
||||
"marker":{
|
||||
"symbol":"circle",
|
||||
"line":{
|
||||
"color":"#444",
|
||||
"width":1
|
||||
"name": "Downloads",
|
||||
"type": "scatter",
|
||||
"mode": "lines+markers",
|
||||
"connectgaps": true,
|
||||
"marker": {
|
||||
"symbol": "circle",
|
||||
"line": {
|
||||
"color": "#444",
|
||||
"width": 1
|
||||
}
|
||||
},
|
||||
"line":{
|
||||
"shape":"linear",
|
||||
"smoothing":1,
|
||||
"width":2
|
||||
"line": {
|
||||
"shape": "linear",
|
||||
"smoothing": 1,
|
||||
"width": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"percentages":{
|
||||
"data":[
|
||||
"percentages": {
|
||||
"data": [
|
||||
{
|
||||
"x":[
|
||||
"x": [
|
||||
"2017-05-01",
|
||||
"2017-05-02",
|
||||
"2017-05-03"
|
||||
],
|
||||
"y":[
|
||||
"y": [
|
||||
"2",
|
||||
"5",
|
||||
"4"
|
||||
],
|
||||
"text":[
|
||||
"text": [
|
||||
"2",
|
||||
"5",
|
||||
"4"
|
||||
],
|
||||
"name":"Proportional downloads",
|
||||
"name": "Proportional downloads",
|
||||
"hoverinfo": "x+text+name",
|
||||
"type":"scatter",
|
||||
"mode":"lines+markers",
|
||||
"connectgaps":true,
|
||||
"marker":{
|
||||
"symbol":"circle",
|
||||
"line":{
|
||||
"color":"#444",
|
||||
"width":1
|
||||
"type": "scatter",
|
||||
"mode": "lines+markers",
|
||||
"connectgaps": true,
|
||||
"marker": {
|
||||
"symbol": "circle",
|
||||
"line": {
|
||||
"color": "#444",
|
||||
"width": 1
|
||||
}
|
||||
},
|
||||
"line":{
|
||||
"shape":"linear",
|
||||
"smoothing":1,
|
||||
"width":2
|
||||
"line": {
|
||||
"shape": "linear",
|
||||
"smoothing": 1,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,124 @@
|
||||
{
|
||||
"downloads":{
|
||||
"layout":{
|
||||
"autosize":true,
|
||||
"height":400,
|
||||
"margin":{
|
||||
"r":100,
|
||||
"t":40,
|
||||
"autoexpand":true,
|
||||
"b":80,
|
||||
"l":100,
|
||||
"pad":0
|
||||
"downloads": {
|
||||
"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
|
||||
"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":"Downloads",
|
||||
"xaxis":{
|
||||
"tickformat":"%m-%d",
|
||||
"dtick":604800000,
|
||||
"tick0":"2017-08-07",
|
||||
"gridcolor":"#FFF",
|
||||
"gridwidth":2,
|
||||
"anchor":"y",
|
||||
"domain":[
|
||||
"title": "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"
|
||||
"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
|
||||
"showline": true,
|
||||
"linecolor": "rgba(148, 148, 148, 1)",
|
||||
"linewidth": 2,
|
||||
"tickangle": -45,
|
||||
"rangeselector": {
|
||||
"buttons": [
|
||||
{
|
||||
"step": "day",
|
||||
"stepmode": "backward",
|
||||
"count": 31,
|
||||
"label": "30d"
|
||||
},
|
||||
"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
|
||||
{
|
||||
"step": "day",
|
||||
"stepmode": "backward",
|
||||
"count": 61,
|
||||
"label": "60d"
|
||||
},
|
||||
{
|
||||
"step": "day",
|
||||
"stepmode": "backward",
|
||||
"count": 91,
|
||||
"label": "90d"
|
||||
},
|
||||
{
|
||||
"step": "day",
|
||||
"stepmode": "backward",
|
||||
"count": 181,
|
||||
"label": "all"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"config":{
|
||||
"displaylogo":false,
|
||||
"modeBarButtonsToRemove":[
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"displaylogo": false,
|
||||
"modeBarButtonsToRemove": [
|
||||
"toImage",
|
||||
"sendDataToCloud",
|
||||
"zoom2d",
|
||||
@@ -75,72 +131,72 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"percentages":{
|
||||
"layout":{
|
||||
"autosize":true,
|
||||
"height":400,
|
||||
"margin":{
|
||||
"r":100,
|
||||
"t":40,
|
||||
"autoexpand":true,
|
||||
"b":80,
|
||||
"l":100,
|
||||
"pad":0
|
||||
"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
|
||||
"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":[
|
||||
"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"
|
||||
"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
|
||||
"showline": true,
|
||||
"linecolor": "rgba(148, 148, 148, 1)",
|
||||
"linewidth": 2,
|
||||
"tickangle": -45
|
||||
},
|
||||
"yaxis":{
|
||||
"range":[
|
||||
"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
|
||||
"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":[
|
||||
"config": {
|
||||
"displaylogo": false,
|
||||
"modeBarButtonsToRemove": [
|
||||
"toImage",
|
||||
"sendDataToCloud",
|
||||
"zoom2d",
|
||||
|
||||
@@ -415,7 +415,7 @@ def etl():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
date = "2018-07-28"
|
||||
date = "2018-10-13"
|
||||
env = "prod"
|
||||
print(date, env)
|
||||
print(get_daily_download_stats(env, date))
|
||||
|
||||
@@ -14,7 +14,7 @@ from pypistats.models.download import RecentDownloadCount
|
||||
from pypistats.models.download import SystemDownloadCount
|
||||
|
||||
|
||||
blueprint = Blueprint('api', __name__, url_prefix='/api')
|
||||
blueprint = Blueprint("api", __name__, url_prefix="/api")
|
||||
|
||||
|
||||
@blueprint.route("/")
|
||||
@@ -27,7 +27,7 @@ def api():
|
||||
def api_downloads_recent(package):
|
||||
"""Get the recent downloads of a package."""
|
||||
package = package.replace(".", "-")
|
||||
category = request.args.get('period')
|
||||
category = request.args.get("period")
|
||||
if category is None:
|
||||
downloads = RecentDownloadCount.query.\
|
||||
filter_by(package=package).all()
|
||||
@@ -55,12 +55,12 @@ def api_downloads_recent(package):
|
||||
def api_downloads_overall(package):
|
||||
"""Get the overall download time series of a package."""
|
||||
package = package.replace(".", "-")
|
||||
mirrors = request.args.get('mirrors')
|
||||
if mirrors == 'true':
|
||||
mirrors = request.args.get("mirrors")
|
||||
if mirrors == "true":
|
||||
downloads = OverallDownloadCount.query.\
|
||||
filter_by(package=package, category="with_mirrors").\
|
||||
order_by(OverallDownloadCount.date).all()
|
||||
elif mirrors == 'false':
|
||||
elif mirrors == "false":
|
||||
downloads = OverallDownloadCount.query.\
|
||||
filter_by(package=package, category="without_mirrors").\
|
||||
order_by(OverallDownloadCount.date).all()
|
||||
|
||||
@@ -12,6 +12,7 @@ from flask import g
|
||||
from flask import json
|
||||
from flask import redirect
|
||||
from flask import render_template
|
||||
from flask import request
|
||||
from flask_wtf import FlaskForm
|
||||
import requests
|
||||
from wtforms import StringField
|
||||
@@ -97,8 +98,17 @@ def package_page(package):
|
||||
"""Render the package page."""
|
||||
package = package.replace(".", "-")
|
||||
# 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.\
|
||||
filter_by(package=package).all()
|
||||
|
||||
if len(recent_downloads) == 0:
|
||||
return redirect(f"/search/{package}")
|
||||
recent = {r: 0 for r in RECENT_CATEGORIES}
|
||||
@@ -125,8 +135,8 @@ def package_page(package):
|
||||
model_data = []
|
||||
for model in MODELS:
|
||||
records = model.query.filter_by(package=package).\
|
||||
order_by(model.date,
|
||||
model.category).all()
|
||||
filter(model.date >= start_date).\
|
||||
order_by(model.date, model.category).all()
|
||||
|
||||
if model == OverallDownloadCount:
|
||||
metrics = ["downloads"]
|
||||
@@ -144,6 +154,8 @@ def package_page(package):
|
||||
plots = []
|
||||
for model in model_data:
|
||||
plot = deepcopy(current_app.config["PLOT_BASE"])[model["metric"]]
|
||||
|
||||
# Set data
|
||||
data = []
|
||||
for category, values in model["data"].items():
|
||||
base = deepcopy(current_app.config["DATA_BASE"][model["metric"]]["data"][0])
|
||||
@@ -154,12 +166,38 @@ def package_page(package):
|
||||
base["name"] = category.title()
|
||||
data.append(base)
|
||||
plot["data"] = data
|
||||
|
||||
# Add titles
|
||||
if model["metric"] == "percentages":
|
||||
plot["layout"]["title"] = \
|
||||
f"Daily Download Proportions of {package} package - {model['name'].title().replace('_', ' ')}" # noqa
|
||||
else:
|
||||
plot["layout"]["title"] = \
|
||||
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)
|
||||
|
||||
return render_template(
|
||||
|
||||
Reference in New Issue
Block a user