forked from opentensor/dashboards
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmeta_plotting.py
148 lines (116 loc) · 6.7 KB
/
meta_plotting.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import numpy as np
import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots
plotly_config = dict(width=800, height=600, template='plotly_white')
def plot_trace(df, col='emission', agg='mean', time_col='timestamp', ntop=10, hotkeys=None, hotkey_regex=None, abbrev=8, type='Miners', smooth=1, smooth_agg='mean', opacity=0.):
if hotkeys is not None:
df = df.loc[df.hotkey.isin(hotkeys)]
if hotkey_regex is not None:
df = df.loc[df.hotkey.str.contains(hotkey_regex)]
# select hotkeys with highest average value of col (e.g. emission) over time
top_miners = df.groupby('hotkey')[col].agg(agg).sort_values(ascending=False)
print(f'Top miners by {col!r}:\n{top_miners}')
stats = df.loc[df.hotkey.isin(top_miners.index[:ntop])].sort_values(by=time_col)
# smooth values of col (e.g. emission) over time
# stats[col] = stats.groupby('hotkey')[col].rolling(smooth).agg(smooth_agg).values
stats['hotkey_abbrev'] = stats.hotkey.str[:abbrev]
stats['coldkey_abbrev'] = stats.coldkey.str[:abbrev]
stats['rank'] = stats.hotkey.map({k:i for i,k in enumerate(top_miners.index, start=1)})
print(stats)
y_label = col.title().replace('_',' ') + f' ({agg})'
return px.line(stats.sort_values(by=[time_col,'rank']),
x=time_col, y=col, color='coldkey_abbrev', line_group='hotkey_abbrev',
hover_data=['hotkey','rank'],
labels={col:y_label,'timestamp':'','coldkey_abbrev':f'Coldkey (first {abbrev} chars)','hotkey_abbrev':f'Hotkey (first {abbrev} chars)'},
title=f'Top {ntop} {type}, by {y_label}',
**plotly_config
).update_traces(opacity=opacity)
def plot_cabals(df, sel_col='coldkey', count_col='hotkey', time_col='timestamp', values=None, ntop=10, abbr=8, smooth=1, smooth_agg='mean', opacity=0.):
if values is None:
values = df[sel_col].value_counts().sort_values(ascending=False).index[:ntop].tolist()
print(f'Automatically selected {sel_col!r} = {values!r}')
df = df.loc[df[sel_col].isin(values)]
rates = df.groupby([time_col,sel_col])[count_col].nunique().reset_index()
# smoothing is hard
# rates = rates.groupby(level=1).rolling(smooth, min_periods=1).agg(smooth_agg)
abbr_col = f'{sel_col} (first {abbr} chars)'
rates[abbr_col] = rates[sel_col].str[:abbr]
return px.line(rates.melt(id_vars=[time_col,sel_col,abbr_col]),
x=time_col, y='value', color=abbr_col,
labels={'value':f'Number of Unique {count_col.title()}s per {sel_col.title()}','timestamp':''},
category_orders={abbr_col:[ v[:abbr] for v in values]},
title=f'Unique {count_col.title()}s Associated with Top {ntop} {sel_col.title()}s',
**plotly_config
).update_traces(opacity=opacity)
def plot_churn(df, time_col='timestamp', type='changed', step=1, smooth=1, smooth_agg='mean', opacity=0.5):
"""
Produces a plotly figure which shows number of changed hotkeys in each step
"""
def churn(s):
results = [{'delta':np.nan}]
for i, idx in enumerate(s.index[1:]):
curr = s.loc[idx]
prev = s.iloc[i]
if type == 'changed':
delta = curr.symmetric_difference(prev)
elif type == 'added':
delta = curr.difference(prev)
elif type == 'removed':
delta = prev.difference(curr)
else:
raise ValueError(f'Unknown type {type!r}')
results.append({'delta': len(delta)})
return pd.DataFrame(results, index=s.index)
churn_frame = churn(df.iloc[::step].groupby(['block','timestamp']).hotkey.unique().apply(set))
return px.line(churn_frame.rolling(smooth, min_periods=1).agg(smooth_agg).reset_index(),
x=time_col, y='delta',
labels={'delta':f'Number of {type.title()} Hotkeys','timestamp':''},
hover_name='block',
**plotly_config
).update_traces(opacity=opacity)
def plot_occupancy(df, time_col='timestamp',step=1, smooth=1, smooth_agg='mean', opacity=0.5):
"""
Produces a plotly figure which shows number of unique hotkeys in each step
"""
occupancy_frame = df.iloc[::step].assign(
Type=df.iloc[::step].validator_trust.apply(lambda x: 'Miner' if x==0 else 'Validator')
).groupby(['Type','timestamp','block']).hotkey.nunique()
# make two plots, with a secondary y axis
fig = make_subplots(specs=[[{"secondary_y": True}]])
trace1 = px.line(occupancy_frame.loc['Miner'].rolling(smooth, min_periods=1).agg(smooth_agg).reset_index(),
x='timestamp',y='hotkey', hover_name='block')
trace2 = px.line(occupancy_frame.loc['Validator'].rolling(smooth, min_periods=1).agg(smooth_agg).reset_index(),
x='timestamp', y='hotkey', hover_name='block')
fig.add_trace(trace1.data[0])
fig.add_trace(trace2.update_traces(line_color='red').data[0], secondary_y=True, row=1,col=1)
fig.update_yaxes(title_text='Miner Hotkeys', secondary_y=False) # Customize primary y-axis title
fig.update_yaxes(title_text='Validator Hotkeys', secondary_y=True, tickfont=dict(color='red'), title=dict(font_color='red')) # Customize secondary y-axis title
return fig.update_layout( **plotly_config).update_traces(opacity=opacity)
def plot_animation(df, x='emission_sum', y='total_stake_sum', color='emission_mean', size='hotkey_nunique', step=10, opacity=0.5):
agg_dict = {}
for column_name in [x, y, color, size]:
column, agg_name = column_name.rsplit('_', 1)
if column not in agg_dict:
agg_dict[column] = [agg_name]
else:
agg_dict[column].append(agg_name)
# select every nth block
if step>1:
blocks_subset = df.block.unique()[::step]
df = df.loc[df.block.isin(blocks_subset)]
df_agg = df.groupby(['block','timestamp','coldkey']).agg({'hotkey':'nunique', 'ip':'nunique', **agg_dict})
df_agg.columns = ['_'.join(col).strip() for col in df_agg.columns]
print(df_agg.columns)
return px.scatter(df_agg.reset_index(),
x=x, range_x=[-df_agg[x].max()*0.1, df_agg[x].max()*1.1],
y=y, range_y=[-df_agg[y].max()*0.1, df_agg[y].max()*1.1],
size=size,
opacity=opacity,
color=color,
color_continuous_scale='BlueRed',
animation_frame='block',
animation_group='coldkey',
hover_name='coldkey',
**plotly_config
)