Add miner rewards functionality and update chart methods

- Add `miner_rewards` function in `pipelines.py` to fetch data based on `days_ago`
- Update `route.py` to include `/miner_rewards` endpoint and handle data serialization
- Add `miner_rewards_schema` in `schemas.py` for serializing miner rewards data
- Modify charts shortcode to include method for multiple chart methods
This commit is contained in:
Sam 2024-12-27 19:22:42 +00:00
parent 84bc4fe599
commit eb6f97f54a
7 changed files with 131 additions and 190 deletions

View File

@ -80,144 +80,16 @@ def bitcoin_business_growth_percent_diff_days_ago(args):
where days_ago = 1
order by difference desc
"""
# def bitcoin_business_growth_timeseries(query):
# pipeline = [
# {
# "$match": {
# "days_ago": {"$lte": int(query["days_ago"])},
# "country_name": query["country_name"],
# }
# },
# {
# "$project": {
# "country_name": "$country_name",
# "date": "$date",
# "cumulative_value": "$cumulative_value",
# }
# },
# {"$sort": {"country_name": 1, "days_ago": 1}},
# ]
# return pipeline
# def mangrove_by_country_latest():
# pipeline = [
# {
# "$match": {"year": "2020"},
# },
# ]
# return pipeline
#
#
# def mangrove_by_country_agg(query):
# pipeline = [
# {"$match": {"country_with_parent": query["country_with_parent"]}},
# {
# "$group": {
# "_id": {"country_with_parent": "$country_with_parent", "year": "$year"},
# "total_pixels": {"$sum": "$total_n_pixels"},
# }
# },
# {
# "$project": {
# "_id": 0,
# "country_with_parent": "$_id.country_with_parent",
# "year": "$_id.year",
# "total_pixels": 1,
# }
# },
# {"$sort": {"year": 1}},
# ]
# return pipeline
#
#
# def bitcoin_business_growth_timeseries(query):
# pipeline = [
# {
# "$match": {
# "days_ago": {"$lte": int(query["days_ago"])},
# "country_name": query["country_name"],
# }
# },
# {
# "$project": {
# "country_name": "$country_name",
# "date": "$date",
# "cumulative_value": "$cumulative_value",
# }
# },
# {"$sort": {"country_name": 1, "days_ago": 1}},
# ]
# return pipeline
#
#
# def bitcoin_business_growth_percent_diff_days_ago(query):
pipeline = [
{"$match": {"days_ago": {"$lte": int(query["days_ago"])}}},
{"$sort": {"country_name": 1, "days_ago": 1}},
{
"$group": {
"_id": "$country_name",
"firstvalue": {"$first": "$cumulative_value"},
"lastvalue": {"$last": "$cumulative_value"},
"firstdate": {"$min": "$date"},
"lastdate": {"$max": "$date"},
}
},
{
"$project": {
"country_name": "$_id",
"first_value": "$firstvalue",
"last_value": "$lastvalue",
"difference": {
"$subtract": [
{"$todouble": "$firstvalue"},
{"$todouble": "$lastvalue"},
]
},
"first_date": "$firstdate",
"last_date": "$lastdate",
"percent_difference": {
"$cond": {
"if": {"$eq": [{"$todouble": "$lastvalue"}, 0]},
"then": {
"$cond": {
"if": {"$gt": [{"$todouble": "$firstvalue"}, 0]},
"then": "new",
"else": "none",
}
},
"else": {
"$round": [
{
"$multiply": [
{
"$divide": [
{
"$subtract": [
{"$todouble": "$firstvalue"},
{"$todouble": "$lastvalue"},
]
},
{"$todouble": "$lastvalue"},
]
},
100,
]
}
]
},
}
},
}
},
]
return pipeline
#
#
# def bitcoin_business_growth_latest(query):
# pipeline = [
# {
# "$match": query["filter"],
# },
# {"$sort": {"date": 1}},
# ]
# return pipeline
def miner_rewards(args):
days_ago = parse_int(args["days_ago"])
return f"""
with
filtered_data as (
select * from models_final.final__miner_rewards order by date desc limit {days_ago}
)
select *
from filtered_data
order by date asc
"""

View File

@ -66,44 +66,16 @@ async def bitcoin_business_growth_percent_diff(query: str):
serializedData = serializer.serialize_many(rawData)
return serializedData
# @router.get("/bitcoin_business_growth_percent_diff")
# async def bitcoin_business_growth_percent_diff(query: str):
# query = ast.literal_eval(query)
#
# query = queries.bitcoin_business_growth_percent_diff_days_ago(query)
# handler = PostgresHandler(connection)
#
# schema = schemas.bitcoin_business_growth_percent_diff_schema
# pipeline = pipelines.bitcoin_business_growth_percent_diff_days_ago(query)
# serializer = DataSerializer(schema)
# handler = MongoDBHandler(collection_name)
# rawData = handler.aggregate(pipeline)
# serializedData = serializer.serialize_many(rawData)
# return serializedData
# @router.get("/mangrove_by_country_agg")
# async def mangrove_by_country_agg(query: str):
# query = ast.literal_eval(query)
# db = client.baseddata
# collection_name = db["final__protected_mangroves_summary_stats_by_country_agg"]
# schema = schemas.mangrove_by_country_agg_schema
# pipeline = pipelines.mangrove_by_country_agg(query)
# serializer = DataSerializer(schema)
# handler = MongoDBHandler(collection_name)
# rawData = handler.aggregate(pipeline)
# serializedData = serializer.serialize_many(rawData)
# return serializedData
#
@router.get("/miner_rewards")
async def miner_rewards(query: str):
args = parse_args_to_dict(query)
# @router.get("/bitcoin_business_growth_timeseries")
# async def bitcoin_business_growth_timeseries(query: str):
# query = ast.literal_eval(query)
# db = client.baseddata
# collection_name = db["final__bitcoin_business_growth_by_country"]
# schema = schemas.bitcoin_business_growth_timeseries_schema
# pipeline = pipelines.bitcoin_business_growth_timeseries(query)
# serializer = DataSerializer(schema)
# handler = MongoDBHandler(collection_name)
# rawData = handler.aggregate(pipeline)
# serializedData = serializer.serialize_many(rawData)
# return serializedData
pipeline = pipelines.miner_rewards(args)
handler = PostgresHandler()
schema = schemas.miner_rewards_schema
serializer = DataSerializer(schema)
rawData = handler.execute_query(pipeline)
serializedData = serializer.serialize_many(rawData)
return serializedData

View File

@ -7,19 +7,22 @@ def mangrove_by_country_latest_schema(data):
"cumulative_pct_diff": float(data["cumulative_pct_diff"]),
}
def mangrove_country_timeseries_schema(data):
return {
"year": str(data["year"]),
"total_n_pixels": int(data["total_n_pixels"]),
}
def mangrove_by_country_agg_schema(data):
return {
"country_with_parent": str(data["country_with_parent"]),
"year": int(data["year"]),
"total_pixels": int(data["total_pixels"])
"total_pixels": int(data["total_pixels"]),
}
def bitcoin_business_growth_percent_diff_schema(data):
return {
"country_name": str(data["country_name"]),
@ -27,22 +30,34 @@ def bitcoin_business_growth_percent_diff_schema(data):
"first_value": int(data["first_value"]),
"last_value": int(data["last_value"]),
"difference": int(data["difference"]),
"percent_difference": str(data["percent_difference"])
"percent_difference": str(data["percent_difference"]),
}
def bitcoin_business_growth_timeseries_schema(data):
return {
"country_name": str(data["country_name"]),
"date": data["date"],
"cumulative_value": int(data["cumulative_value"])
"cumulative_value": int(data["cumulative_value"]),
}
def miner_rewards_schema(data):
return {
"date": data["date"],
"block_subsidy": data["block_subsidy"],
"total_reward_usd": data["total_reward_usd"],
"totalfee_usd": data["totalfee_usd"],
"subsidy_usd": data["subsidy_usd"],
}
class DataSerializer:
def __init__(self, schema_func):
self.schema_func = schema_func
def serialize_one(self, data) -> dict:
return self.schema_func(dict( data ))
return self.schema_func(dict(data))
def serialize_many(self, data_list) -> list:
return [self.serialize_one(data) for data in data_list]

View File

@ -18,7 +18,7 @@ The chart always reflects the countries selected in the table.
{{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="bitcoin-business-growth-chart bitcoin-business-growth-table" >}}
{{< table id="bitcoin-business-growth-table" endpoint="bitcoin_business_growth_percent_diff" headers="{'country_name': 'Country', 'date_range': 'Date Range', 'first_value': 'Previous #', 'last_value': 'Current #', 'difference': 'Diff', 'percent_difference': '% Diff'}" maxHeight="400px" sortable="true" valueId="country_name" selectableRows="multi" targets="bitcoin-business-growth-chart" defaultFirstSelected="true" >}}
{{< chart id="bitcoin-business-growth-chart" endpoint="bitcoin_business_growth_timeseries" chartType="line" xAxisField="date" yAxisField="cumulative_value" scaleChart=true xAxisType="category" >}}
{{< chart chartMethod="tableRowSelectChart" id="bitcoin-business-growth-chart" endpoint="bitcoin_business_growth_timeseries" chartType="line" xAxisField="date" yAxisField="cumulative_value" scaleChart=true xAxisType="category" >}}
#### Attribution and License
Data obtained from © [OpenStreetMap](https://www.openstreetmap.org/copyright)

View File

@ -11,4 +11,6 @@ tags: ["Bitcoin", "Stats"]
The following chart shows daily miner revenue in USD for the period selected in the dropdown. This information is based on the sum of bitcoin mined each day (i.e. the block-subsidy) plus the transaction fees. Price data is obtained from [CoinGecko](https://www.coingecko.com/).
{{< chart src="/js/miner-rewards.js" >}}
{{< dropdown_filter id="days_ago_dropdown_filter" id_filter="days_ago" options="1 day:1,7 day:7,28 day:28,1 year:365,5 year:1826,10 year:3652,all time:10000" default_selection="7 day" targets="miner-rewards-chart" >}}
{{< chart chartMethod="simpleChart" id="miner-rewards-chart" endpoint="miner_rewards" chartType="line" xAxisField="date" yAxisField="total_reward_usd" scaleChart=true xAxisType="category" >}}

View File

@ -1,7 +1,7 @@
<script src="https://cdn.jsdelivr.net/npm/echarts@5.5.1/dist/echarts.min.js"></script>
<script>
chartData = [];
function createChart(
function tableRowSelectChart(
id,
endpoint,
chartType,
@ -10,7 +10,7 @@
sortField = null,
scaleChart = false,
xAxisType = "time",
formatValueDecimalPlaces = null
formatValueDecimalPlaces = null,
) {
async function fetchDataForChart(query, valueId) {
try {
@ -47,7 +47,9 @@
tooltip: {
...tooltip,
valueFormatter(value, index) {
return formatValueDecimalPlaces == null ? value : nFormatter(value, formatValueDecimalPlaces);
return formatValueDecimalPlaces == null
? value
: nFormatter(value, formatValueDecimalPlaces);
},
},
xAxis: {
@ -84,6 +86,7 @@
[valueId]: eventDetail.filterValue,
};
query = queryConstructor(selectedRow);
fetchDataForChart(query, valueId);
} else {
delete chartData[eventDetail.filterValue];
@ -93,4 +96,71 @@
}
});
}
chartData = [];
function simpleChart(
id,
endpoint,
chartType,
xAxisField,
yAxisField,
sortField = null,
scaleChart = false,
xAxisType = "time",
formatValueDecimalPlaces = null,
) {
async function fetchDataForChart(query) {
try {
const apiEndpoint = `${apiURL}/${endpoint}?${query}`;
const response = await fetch(apiEndpoint);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
chartData = await response.json();
updateChart();
console.log(chartData);
} catch (error) {
console.error("Fetching data failed:", error);
}
}
function updateChart() {
var chartDom = document.getElementById(`${id}`);
var myChart = echarts.init(chartDom);
var option = {
tooltip: {
...tooltip,
valueFormatter(value, index) {
return formatValueDecimalPlaces == null
? value
: nFormatter(value, formatValueDecimalPlaces);
},
},
xAxis: {
type: "category",
data: chartData.map((item) => item.date),
},
yAxis: {
scale: scaleChart,
type: "value",
},
series: [
{
data: chartData.map((item) => item.total_reward_usd),
type: "line",
},
],
};
myChart.setOption(option, true);
}
query = queryConstructor();
fetchDataForChart(query);
document.addEventListener("filterChange", function (event) {
query = queryConstructor();
fetchDataForChart(query);
});
}
</script>

View File

@ -2,9 +2,19 @@
<section class = 'chart-container'>
<div class = "chart" id='{{ .Get "id" }}'>
<script>
document.addEventListener("DOMContentLoaded", function () {
createChart(id={{ .Get "id" }}, endpoint={{ .Get "endpoint" }}, chartType={{ .Get "chartType" }}, xAxisField={{ .Get "xAxisField" }}, yAxisField={{ .Get "yAxisField" }}, sortField={{ .Get "sortField" }}, scaleChart={{ .Get "scaleChart" }}, xAxisType={{ .Get "xAxisType" }})
{{ .Get "chartMethod" | safeJS }}(
id={{ .Get "id" }},
endpoint={{ .Get "endpoint" }},
chartType={{ .Get "chartType" }},
xAxisField={{ .Get "xAxisField" }},
yAxisField={{ .Get "yAxisField" }},
sortField={{ .Get "sortField" }},
scaleChart={{ .Get "scaleChart" }},
xAxisType={{ .Get "xAxisType" }})
});
</script>
</div>
</section>