Skip to content

Commit

Permalink
Change sim plots entrypoint, add tests (#979)
Browse files Browse the repository at this point in the history
* Adds new entrypoint for dash.
* Add tests for dashboard.
* Update md files.
* fix multiple plots on the same row are not shrinking
---------

Co-authored-by: Norbert <katunanorbert@gmail.com>
  • Loading branch information
calina-c and KatunaNorbert authored May 1, 2024
1 parent 476272b commit 5a20bc8
Show file tree
Hide file tree
Showing 12 changed files with 212 additions and 96 deletions.
4 changes: 2 additions & 2 deletions READMEs/predictoor.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ cd ~/code/pdr-backend # or wherever your pdr-backend dir is
source venv/bin/activate

# start the plots server
sim_plots
pdr sim_plots
```

The plots server will give a url, such as [http://127.0.0.1:8050](http://127.0.0.1:8050). Open that url in your browser to see plots update in real time.
Expand All @@ -104,7 +104,7 @@ To see simulation CLI options: `pdr sim -h`.
Simulation uses Python [logging](https://docs.python.org/3/howto/logging.html) framework. Configure it via [`logging.yaml`](../logging.yaml). [Here's](https://medium.com/@cyberdud3/a-step-by-step-guide-to-configuring-python-logging-with-yaml-files-914baea5a0e5) a tutorial on yaml settings.

By default, Dash plots the latest sim (even if it is still running). To enable plotting for a specific run, e.g. if you used multisim or manually triggered different simulations, the sim engine assigns unique ids to each run.
Select that unique id from the `sim_state` folder, and run `sim_plots --run_id <unique_id>` e.g. `sim_plots --run-id 97f9633c-a78c-4865-9cc6-b5152c9500a3`
Select that unique id from the `sim_state` folder, and run `pdr sim_plots --run_id <unique_id>` e.g. `pdr sim_plots --run-id 97f9633c-a78c-4865-9cc6-b5152c9500a3`

You can run many instances of Dash at once, with different URLs. To run on different ports, use the `--port` argument.

Expand Down
4 changes: 2 additions & 2 deletions READMEs/trader.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ cd ~/code/pdr-backend # or wherever your pdr-backend dir is
source venv/bin/activate

#start the plots server
sim_plots
pdr sim_plots
```

The plots server will give a url, such as [http://127.0.0.1:8050](http://127.0.0.1:8050). Open that url in your browser to see plots update in real time.
Expand All @@ -96,7 +96,7 @@ To see simulation CLI options: `pdr sim -h`.
Simulation uses Python [logging](https://docs.python.org/3/howto/logging.html) framework. Configure it via [`logging.yaml`](../logging.yaml). [Here's](https://medium.com/@cyberdud3/a-step-by-step-guide-to-configuring-python-logging-with-yaml-files-914baea5a0e5) a tutorial on yaml settings.

By default, Dash plots the latest sim (even if it is still running). To enable plotting for a specific run, e.g. if you used multisim or manually triggered different simulations, the sim engine assigns unique ids to each run.
Select that unique id from the `sim_state` folder, and run `sim_plots --run_id <unique_id>` e.g. `sim_plots --run_id 97f9633c-a78c-4865-9cc6-b5152c9500a3`
Select that unique id from the `sim_state` folder, and run `pdr sim_plots --run_id <unique_id>` e.g. `pdr sim_plots --run_id 97f9633c-a78c-4865-9cc6-b5152c9500a3`

You can run many instances of Dash at once, with different URLs. To run on different ports, use the `--port` argument.

Expand Down
35 changes: 34 additions & 1 deletion pdr_backend/cli/cli_arguments.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import argparse
from argparse import Namespace
import logging
import sys
from argparse import Namespace
from typing import List

from enforce_typing import enforce_types
from eth_utils import to_checksum_address

from pdr_backend.cli.nested_arg_parser import NestedArgParser
from pdr_backend.sim.sim_plotter import SimPlotter

logger = logging.getLogger("cli")

Expand Down Expand Up @@ -46,6 +47,7 @@
pdr deployer (for >1 predictoor bots)
pdr lake PPSS_FILE NETWORK
pdr analytics PPSS_FILE NETWORK
pdr sim_plots [--run_id RUN_ID] [--port PORT]
Utilities:
pdr get_predictoors_info ST END PQDIR PPSS_FILE NETWORK --PDRS
Expand Down Expand Up @@ -153,6 +155,13 @@ def check_address(addr) -> str:
return addr2


def validate_run_id(run_id):
if run_id not in SimPlotter.get_all_run_names():
raise ValueError(f"Invalid run_id: {run_id}")

return run_id


@enforce_types
class PDRS_Mixin:
def add_argument_PDRS(self):
Expand Down Expand Up @@ -560,6 +569,29 @@ def network_choices(self):
return ["sapphire-testnet", "sapphire-mainnet"]


class SimPlotsArgParser(CustomArgParser):
# pylint: disable=unused-argument
def __init__(self, description: str, command_name: str):
super().__init__(description=description)

self.add_argument(
"--run_id",
help=(
"The run_id of the simulation to visualize. "
"If not provided, the latest run_id will be used."
),
type=validate_run_id,
)

self.add_argument(
"--port",
nargs="?",
help="The port to run the server on. Default is 8050.",
type=int,
default=8050,
)


# below, list each entry in defined_parsers in same order as HELP_LONG
defined_parsers = {
# main tools
Expand Down Expand Up @@ -604,6 +636,7 @@ def network_choices(self):
"do_dfbuyer": DfbuyerArgParser("Run dfbuyer bot", "dfbuyer"),
"do_publisher": PublisherArgParser("Publish feeds", "publisher"),
"do_topup": TopupArgParser("Topup OCEAN and ROSE in dfbuyer, trueval, ..", "topup"),
"do_sim_plots": SimPlotsArgParser("Visualize simulation data", "sim_plots"),
}


Expand Down
7 changes: 7 additions & 0 deletions pdr_backend/cli/cli_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from pdr_backend.predictoor.predictoor_agent import PredictoorAgent
from pdr_backend.publisher.publish_assets import publish_assets
from pdr_backend.sim.multisim_engine import MultisimEngine
from pdr_backend.sim.sim_dash import sim_dash
from pdr_backend.sim.sim_engine import SimEngine
from pdr_backend.trader.approach1.trader_agent1 import TraderAgent1
from pdr_backend.trader.approach2.trader_agent2 import TraderAgent2
Expand Down Expand Up @@ -356,3 +357,9 @@ def do_deploy_pred_submitter_mgr(args, nested_args=None):
logger.info(
"Prediction Submitter Manager Contract deployed at %s", contract_address
)


@enforce_types
# pylint: disable=unused-argument
def do_sim_plots(args, nested_args=None):
sim_dash(args)
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

from dash import Input, Output, State

from pdr_backend.sim.sim_plotter import SimPlotter
from pdr_dash_plots.util import get_figures_by_state, get_latest_run_id
from pdr_dash_plots.view_elements import (
from pdr_backend.sim.dash_plots.util import get_figures_by_state
from pdr_backend.sim.dash_plots.view_elements import (
arrange_figures,
get_header_elements,
get_waiting_template,
non_final_state_div,
selected_var_checklist,
snapshot_slider,
)
from pdr_backend.sim.sim_plotter import SimPlotter


def wait_for_state(sim_plotter, run_id, set_ts):
Expand Down Expand Up @@ -64,7 +64,7 @@ def update_selected_vars(clickData, selected_vars):
)
# pylint: disable=unused-argument
def update_graph_live(n, selected_vars, slider_value, selected_vars_old):
run_id = app.run_id if app.run_id else get_latest_run_id()
run_id = app.run_id if app.run_id else SimPlotter.get_latest_run_id()
set_ts = None

if slider_value is not None:
Expand Down
15 changes: 1 addition & 14 deletions pdr_dash_plots/util.py → pdr_backend/sim/dash_plots/util.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,6 @@
import os
from pathlib import Path

from pdr_backend.aimodel import aimodel_plotter
from pdr_backend.sim.dash_plots.view_elements import figure_names
from pdr_backend.sim.sim_plotter import SimPlotter
from pdr_dash_plots.view_elements import figure_names


def get_latest_run_id():
path = sorted(Path("sim_state").iterdir(), key=os.path.getmtime)[-1]
return str(path).replace("sim_state/", "")


def get_all_run_names():
path = Path("sim_state").iterdir()
return [str(p).replace("sim_state/", "") for p in path]


def get_figures_by_state(sim_plotter: SimPlotter, selected_vars):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime

from dash import dcc, html
from plotly.graph_objs import Figure

Expand Down Expand Up @@ -62,11 +63,9 @@ def arrange_figures(figures):
return [
html.Div(
[
dcc.Graph(figure=figures["pdr_profit_vs_time"], style={"width": "50%"}),
dcc.Graph(
figure=figures["pdr_profit_vs_time"], style={"width": "100%"}
),
dcc.Graph(
figure=figures["trader_profit_vs_time"], style={"width": "100%"}
figure=figures["trader_profit_vs_time"], style={"width": "50%"}
),
],
style={"display": "flex", "justifyContent": "space-between"},
Expand All @@ -79,10 +78,10 @@ def arrange_figures(figures):
html.Div(
[
dcc.Graph(
figure=figures["pdr_profit_vs_ptrue"], style={"width": "100%"}
figure=figures["pdr_profit_vs_ptrue"], style={"width": "50%"}
),
dcc.Graph(
figure=figures["trader_profit_vs_ptrue"], style={"width": "100%"}
figure=figures["trader_profit_vs_ptrue"], style={"width": "50%"}
),
],
style={"display": "flex", "justifyContent": "space-between"},
Expand All @@ -92,9 +91,9 @@ def arrange_figures(figures):
dcc.Graph(
figure=figures["aimodel_varimps"],
id="aimodel_varimps",
style={"width": "100%"},
style={"width": "50%"},
),
dcc.Graph(figure=figures["aimodel_response"], style={"width": "100%"}),
dcc.Graph(figure=figures["aimodel_response"], style={"width": "50%"}),
],
style={"display": "flex", "justifyContent": "space-between"},
),
Expand All @@ -111,11 +110,17 @@ def format_ts(s):
return datetime.strptime(base, "%Y%m%d%H%M%S").strftime("%H:%M:%S")


def snapshot_slider(run_id, set_ts, slider_value):
def prune_snapshots(run_id):
snapshots = SimPlotter.available_snapshots(run_id)[:-1]
max_states_ux = 50
if len(snapshots) > max_states_ux:
snapshots = snapshots[:: len(snapshots) // max_states_ux]
return snapshots[:: len(snapshots) // max_states_ux]

return snapshots


def snapshot_slider(run_id, set_ts, slider_value):
snapshots = prune_snapshots(run_id)

marks = {
i: {"label": format_ts(s), "style": {"transform": "rotate(45deg)"}}
Expand Down
28 changes: 28 additions & 0 deletions pdr_backend/sim/sim_dash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python
from dash import Dash, dcc, html

from pdr_backend.sim.dash_plots.callbacks import get_callbacks
from pdr_backend.sim.dash_plots.view_elements import empty_graphs_template

app = Dash(__name__)
app.config["suppress_callback_exceptions"] = True
app.layout = html.Div(
html.Div(
[
html.Div(empty_graphs_template, id="live-graphs"),
dcc.Interval(
id="interval-component",
interval=3 * 1000, # in milliseconds
n_intervals=0,
disabled=False,
),
]
)
)

get_callbacks(app)


def sim_dash(args):
app.run_id = args.run_id
app.run(debug=True, port=args.port)
11 changes: 11 additions & 0 deletions pdr_backend/sim/sim_plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pickle
import time
from datetime import datetime
from pathlib import Path
from typing import Optional

import numpy as np
Expand Down Expand Up @@ -39,6 +40,16 @@ def available_snapshots(multi_id):

return all_timestamps + ["final"]

@staticmethod
def get_latest_run_id():
path = sorted(Path("sim_state").iterdir(), key=os.path.getmtime)[-1]
return str(path).replace("sim_state/", "")

@staticmethod
def get_all_run_names():
path = Path("sim_state").iterdir()
return [str(p).replace("sim_state/", "") for p in path]

def load_state(self, multi_id, timestamp: Optional[str] = None):
root_path = f"sim_state/{multi_id}"

Expand Down
Loading

0 comments on commit 5a20bc8

Please sign in to comment.