Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1384: Improve Predictoors Table #1398

Merged
merged 11 commits into from
Jul 17, 2024
19 changes: 18 additions & 1 deletion pdr_backend/analytics/predictoor_dashboard/assets/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ body{
padding: 10px;
}

#predictoors_container .show-hide {
display: none;
}

.form-check-label, .form-switch{
margin: 0;
}
}

.wrap_with_gap {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}

.table_title {
display: flex;
justify-content: space-between;
align-items: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
PREDICTOOR_TABLE_COLUMNS = [
{"name": "User Addr", "id": "user_address"},
{"name": "Profit", "id": "total_profit"},
{"name": "AVG Accuracy", "id": "avg_accuracy"},
{"name": "AVG Stake", "id": "avg_stake"},
{"name": "User", "id": "user"},
]

PREDICTOOR_TABLE_HIDDEN_COLUMNS = ["user"]
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
get_feeds_data_from_db,
get_predictoors_data_from_db,
get_payouts_from_db,
get_user_payouts_stats_from_db,
filter_objects_by_field,
get_feed_ids_based_on_predictoors_from_db,
)
Expand All @@ -16,6 +17,10 @@
from pdr_backend.analytics.predictoor_dashboard.dash_components.util import (
select_or_clear_all_by_table,
)
from pdr_backend.analytics.predictoor_dashboard.dash_components.app_constants import (
PREDICTOOR_TABLE_COLUMNS,
PREDICTOOR_TABLE_HIDDEN_COLUMNS,
)
from pdr_backend.cli.arg_feeds import ArgFeeds


Expand All @@ -24,16 +29,18 @@ def get_callbacks(app):
@app.callback(
Output("feeds-data", "data"),
Output("predictoors-data", "data"),
Output("user-payout-stats", "data"),
Output("error-message", "children"),
Input("data-folder", "data"),
)
def get_input_data_from_db(files_dir):
try:
feeds_data = get_feeds_data_from_db(files_dir)
predictoors_data = get_predictoors_data_from_db(files_dir)
return feeds_data, predictoors_data, None
user_payout_stats = get_user_payouts_stats_from_db(files_dir)
return feeds_data, predictoors_data, user_payout_stats, None
except Exception as e:
return None, None, dash.html.H3(str(e))
return None, None, None, dash.html.H3(str(e))

@app.callback(
Output("accuracy_chart", "children"),
Expand Down Expand Up @@ -109,31 +116,27 @@ def create_feeds_table(feeds_data):
columns = [{"name": col, "id": col} for col in feeds_data[0].keys()]
return columns

@app.callback(
Output("predictoors_table", "columns"),
Input("predictoors-data", "data"),
)
def create_predictoors_table(predictoors_data):
if not predictoors_data:
return dash.no_update
columns = [{"name": col, "id": col} for col in predictoors_data[0].keys()]
return columns

@app.callback(
Output("predictoors_table", "data"),
Output("predictoors_table", "selected_rows"),
Output("predictoors_table", "columns"),
Output("predictoors_table", "hidden_columns"),
[
Input("search-input-Predictoors", "value"),
Input("predictoors_table", "selected_rows"),
Input("predictoors_table", "data"),
Input("predictoors-data", "data"),
Input("user-payout-stats", "data"),
],
)
def update_predictoors_table_on_search(
search_value, selected_rows, predictoors_table, predictoors_data
search_value,
selected_rows,
predictoors_table,
predictoors_data,
user_payout_stats,
):
selected_predictoors = [predictoors_table[i] for i in selected_rows]

if not search_value:
filtered_data = predictoors_data
else:
Expand All @@ -142,13 +145,49 @@ def update_predictoors_table_on_search(
predictoors_data, "user", search_value, selected_predictoors
)

if user_payout_stats:
# Her bir data elemanı için, eşleşen user_payout_stat bulunur ve güncellenir.
# Eşleşme yoksa, orijinal data elemanı korunur.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should translate this to english 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry my fault :D

filtered_data = [
{
**data,
**next(
(
user_payout_stat
for user_payout_stat in user_payout_stats
if user_payout_stat["user"] == data["user"]
),
{},
),
}
for data in filtered_data
]

# shorten the user address
for data in filtered_data:
new_data = {
"user_address": data["user"][:5] + "..." + data["user"][-5:],
"total_profit": round(data["total_profit"], 2),
"avg_accuracy": round(data["avg_accuracy"], 2),
"avg_stake": round(data["avg_stake"], 2),
"user": data["user"],
}
Copy link
Member

@KatunaNorbert KatunaNorbert Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we save this values directly on the predictoor_data state inside get_input_data_from_db so we don't have to filter and select them on each predictoor table action?


data.clear()
data.update(new_data)

selected_predictoor_indices = [
i
for i, predictoor in enumerate(filtered_data)
if predictoor in selected_predictoors
]

return filtered_data, selected_predictoor_indices
return (
filtered_data,
selected_predictoor_indices,
PREDICTOOR_TABLE_COLUMNS,
PREDICTOOR_TABLE_HIDDEN_COLUMNS,
)

@app.callback(
Output("feeds_table", "data"),
Expand Down
17 changes: 17 additions & 0 deletions pdr_backend/analytics/predictoor_dashboard/dash_components/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@ def get_predictoors_data_from_db(lake_dir: str):


@enforce_types
def get_user_payouts_stats_from_db(lake_dir: str):
return _query_db(
lake_dir,
f"""
SELECT
"user",
SUM(payout - stake) AS total_profit,
SUM(CASE WHEN payout > 0 THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS avg_accuracy,
AVG(stake) AS avg_stake
FROM
{Payout.get_lake_table_name()}
GROUP BY
"user"
""",
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good job with the query, the data comes in very fast!
I'm wondering if we can unite this query with the get predictoors one and have a get predictoors data query containing all the data we need, should be straight forward.



def get_feed_ids_based_on_predictoors_from_db(
lake_dir: str, predictoor_addrs: List[str]
):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def get_input_column():
searchable_field="user",
columns=[],
data=None,
default_sorting=[
{"column_id": "total_profit", "direction": "desc"}
],
),
id="predictoors_container",
),
Expand All @@ -22,6 +25,7 @@ def get_input_column():
searchable_field="pair",
columns=[],
data=None,
default_sorting=[],
),
id="feeds_container",
style={
Expand Down Expand Up @@ -108,7 +112,7 @@ def get_layout():
dcc.Store(id="data-folder"),
dcc.Store(id="feeds-data"),
dcc.Store(id="predictoors-data"),
dcc.Store(id="predictoors-stake-data"),
dcc.Store(id="user-payout-stats"),
html.H1(
"Predictoor dashboard",
id="page_title",
Expand Down Expand Up @@ -156,94 +160,83 @@ def get_main_container():
)


def get_table(table_id, table_name, searchable_field, columns, data):
return [
html.Div(
[
html.Span(table_name, style={"fontSize": "20px"}),
(
dbc.Switch(
id="toggle-switch-predictoor-feeds",
label="Predictoor feeds only",
value=True,
)
if table_name == "Feeds"
else None
),
],
style={
"display": "flex",
"justifyContent": "space-between",
"alignItems": "center",
},
),
html.Div(
[
dcc.Input(
id=f"search-input-{table_name}",
type="text",
placeholder=f"Search for {searchable_field}",
debounce=True, # Trigger the input event after user stops typing
style={"fontSize": "15px", "min-width": "100px"},
),
html.Div(
[
html.Button(
"Select All",
id=f"select-all-{table_id}",
n_clicks=0,
style={
"border": "0",
"min-width": "90px",
"fontSize": "15px",
"backgroundColor": "#dedede",
"borderRadius": "3px",
},
),
html.Button(
"Clear",
id=f"clear-all-{table_id}",
n_clicks=0,
style={
"border": "0",
"fontSize": "15px",
"backgroundColor": "#dedede",
"borderRadius": "3px",
},
),
],
style={
"display": "flex",
"justifyContent": "space-between",
"alignItems": "center",
"gap": "10px",
},
),
],
style={
"display": "flex",
"justifyContent": "space-between",
"alignItems": "center",
"gap": "10px",
},
),
dash_table.DataTable(
id=table_id,
columns=[{"name": col, "id": col, "sortable": True} for col in columns],
data=data,
row_selectable="multi", # Can be 'multi' for multiple rows
selected_rows=[],
sort_action="native", # Enables data to be sorted
style_cell={"textAlign": "left"},
style_table={
"height": "34vh",
"width": "100%",
"overflow": "auto",
"paddingTop": "5px",
},
fill_width=True,
),
]
def get_table(table_id, table_name, searchable_field, columns, data, default_sorting):
return html.Div(
[
html.Div(
[
html.Span(table_name, style={"fontSize": "20px"}),
(
dbc.Switch(
id="toggle-switch-predictoor-feeds",
label="Predictoor feeds only",
value=True,
)
if table_name == "Feeds"
else None
),
],
className="table_title",
),
html.Div(
[
dcc.Input(
id=f"search-input-{table_name}",
type="text",
placeholder=f"Search for {searchable_field}",
debounce=True, # Trigger the input event after user stops typing
style={"fontSize": "15px", "min-width": "100px"},
),
html.Div(
[
html.Button(
"Select All",
id=f"select-all-{table_id}",
n_clicks=0,
style={
"border": "0",
"min-width": "90px",
"fontSize": "15px",
"backgroundColor": "#dedede",
"borderRadius": "3px",
},
),
html.Button(
"Clear",
id=f"clear-all-{table_id}",
n_clicks=0,
style={
"border": "0",
"fontSize": "15px",
"backgroundColor": "#dedede",
"borderRadius": "3px",
},
),
],
className="wrap_with_gap",
),
],
className="wrap_with_gap",
),
dash_table.DataTable(
id=table_id,
columns=[{"name": col, "id": col, "sortable": True} for col in columns],
sort_by=default_sorting,
data=data,
row_selectable="multi", # Can be 'multi' for multiple rows
selected_rows=[],
sort_action="native", # Enables data to be sorted
style_cell={"textAlign": "left"},
style_table={
"height": "34vh",
"width": "100%",
"overflow": "auto",
"paddingTop": "5px",
},
fill_width=True,
),
],
)


def get_graph(figure):
Expand Down
Loading
Loading