175 lines
5.2 KiB
Plaintext
175 lines
5.2 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"import json\n",
|
||
|
"import pandas as pd\n",
|
||
|
"import matplotlib.pyplot as plt\n",
|
||
|
"import hvplot.pandas\n",
|
||
|
"import panel as pn\n",
|
||
|
"\n",
|
||
|
"STATE_FILE = './chain-state.ndjson'\n",
|
||
|
"\n",
|
||
|
"MINER_STATE_COL_RENAMES = {\n",
|
||
|
" 'Info.MinerAddr': 'Miner',\n",
|
||
|
" 'Info.MinerPower.MinerPower.RawBytePower': 'Info.MinerPowerRaw',\n",
|
||
|
" 'Info.MinerPower.MinerPower.QualityAdjPower': 'Info.MinerPowerQualityAdj',\n",
|
||
|
" 'Info.MinerPower.TotalPower.RawBytePower': 'Info.TotalPowerRaw',\n",
|
||
|
" 'Info.MinerPower.TotalPower.QualityAdjPower': 'Info.TotalPowerQualityAdj',\n",
|
||
|
"}\n",
|
||
|
"\n",
|
||
|
"MINER_NUMERIC_COLS = [\n",
|
||
|
" 'Info.MinerPowerRaw',\n",
|
||
|
" 'Info.MinerPowerQualityAdj',\n",
|
||
|
" 'Info.TotalPowerRaw',\n",
|
||
|
" 'Info.TotalPowerQualityAdj',\n",
|
||
|
" 'Info.Balance',\n",
|
||
|
" 'Info.CommittedBytes',\n",
|
||
|
" 'Info.ProvingBytes',\n",
|
||
|
" 'Info.FaultyBytes',\n",
|
||
|
" 'Info.FaultyPercentage',\n",
|
||
|
" 'Info.PreCommitDeposits',\n",
|
||
|
" 'Info.LockedFunds',\n",
|
||
|
" 'Info.AvailableFunds',\n",
|
||
|
" 'Info.WorkerBalance',\n",
|
||
|
" 'Info.MarketEscrow',\n",
|
||
|
" 'Info.MarketLocked',\n",
|
||
|
"]\n",
|
||
|
"\n",
|
||
|
"DERIVED_COLS = [\n",
|
||
|
" 'CommittedSectors',\n",
|
||
|
" 'ProvingSectors',\n",
|
||
|
"]\n",
|
||
|
"\n",
|
||
|
"ATTO_FIL_COLS = [\n",
|
||
|
" 'Info.Balance',\n",
|
||
|
" 'Info.PreCommitDeposits',\n",
|
||
|
" 'Info.LockedFunds',\n",
|
||
|
" 'Info.AvailableFunds',\n",
|
||
|
" 'Info.WorkerBalance',\n",
|
||
|
" 'Info.MarketEscrow',\n",
|
||
|
" 'Info.MarketLocked',\n",
|
||
|
"]\n",
|
||
|
"\n",
|
||
|
"def atto_to_fil(x):\n",
|
||
|
" return float(x) * pow(10, -18)\n",
|
||
|
"\n",
|
||
|
"def chain_state_to_pandas(statefile):\n",
|
||
|
" chain = None\n",
|
||
|
" \n",
|
||
|
" with open(statefile, 'rt') as f:\n",
|
||
|
" for line in f.readlines():\n",
|
||
|
" j = json.loads(line)\n",
|
||
|
" chain_height = j['Height']\n",
|
||
|
" \n",
|
||
|
" miners = j['MinerStates']\n",
|
||
|
" for m in miners.values():\n",
|
||
|
" df = pd.json_normalize(m)\n",
|
||
|
" df['Height'] = chain_height\n",
|
||
|
" df.rename(columns=MINER_STATE_COL_RENAMES, inplace=True)\n",
|
||
|
" if chain is None:\n",
|
||
|
" chain = df\n",
|
||
|
" else:\n",
|
||
|
" chain = chain.append(df, ignore_index=True)\n",
|
||
|
" chain.fillna(0, inplace=True)\n",
|
||
|
" chain.set_index('Height', inplace=True)\n",
|
||
|
" \n",
|
||
|
" for c in ATTO_FIL_COLS:\n",
|
||
|
" chain[c] = chain[c].apply(atto_to_fil)\n",
|
||
|
" \n",
|
||
|
" for c in MINER_NUMERIC_COLS:\n",
|
||
|
" chain[c] = chain[c].apply(pd.to_numeric)\n",
|
||
|
" \n",
|
||
|
" # the Sectors.* fields are lists of sector ids, but we want to plot counts, so\n",
|
||
|
" # we pull the length of each list into a new column\n",
|
||
|
" chain['CommittedSectors'] = chain['Sectors.Committed'].apply(lambda x: len(x))\n",
|
||
|
" chain['ProvingSectors'] = chain['Sectors.Proving'].apply(lambda x: len(x))\n",
|
||
|
" return chain\n",
|
||
|
" \n",
|
||
|
"cs = chain_state_to_pandas(STATE_FILE)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# choose which col to plot using a widget\n",
|
||
|
"\n",
|
||
|
"cols_to_plot = MINER_NUMERIC_COLS + DERIVED_COLS\n",
|
||
|
"\n",
|
||
|
"col_selector = pn.widgets.Select(name='Field', options=cols_to_plot)\n",
|
||
|
"cols = ['Miner'] + cols_to_plot\n",
|
||
|
"plot = cs[cols].hvplot(by='Miner', y=col_selector)\n",
|
||
|
"pn.Column(pn.WidgetBox(col_selector), plot)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"scrolled": true
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# plot all line charts in a vertical stack\n",
|
||
|
"\n",
|
||
|
"plots = []\n",
|
||
|
"for c in cols_to_plot:\n",
|
||
|
" title = c.split('.')[-1]\n",
|
||
|
" p = cs[['Miner', c]].hvplot(by='Miner', y=c, title=title)\n",
|
||
|
" plots.append(p)\n",
|
||
|
"pn.Column(*plots)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# miner power area chart\n",
|
||
|
"\n",
|
||
|
"mp = cs[['Miner', 'Info.MinerPowerRaw']].rename(columns={'Info.MinerPowerRaw': 'Power'})\n",
|
||
|
"mp = mp.pivot_table(values=['Power'], index=cs.index, columns='Miner', aggfunc='sum')\n",
|
||
|
"mp = mp.div(mp.sum(1), axis=0)\n",
|
||
|
"mp.columns = mp.columns.get_level_values(1)\n",
|
||
|
"mp.hvplot.area(title='Miner Power Distribution')"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": []
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": "Python 3",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.8.2"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 4
|
||
|
}
|