Skip to content

Commit c8afe93

Browse files
author
Gordon Shotwell
authored
Target app refactor (posit-dev#52)
* Remove conditional panel * Add data tab with value boxes
1 parent cbbaf79 commit c8afe93

File tree

2 files changed

+65
-79
lines changed

2 files changed

+65
-79
lines changed

apps/target-app/app.py

Lines changed: 64 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
from numpy import char, place
12
from shiny.express import ui, input, render
2-
from shiny import render_plot, req, reactive
3+
from shiny import reactive
34
import pandas as pd
45
from pathlib import Path
56
from plots import (
@@ -11,45 +12,33 @@
1112
import faicons as fa
1213
import io
1314
from shinywidgets import render_plotly
15+
import time
1416

1517
file_path = Path(__file__).parent / "simulated-data.csv"
1618

17-
ui.page_opts(title="Monitoring")
1819
df = pd.read_csv(file_path, dtype={"sub_account": str})
1920
df["date"] = pd.to_datetime(df["date"], errors="coerce")
2021

2122

22-
@reactive.calc
23-
def monitor_sampled_data() -> pd.DataFrame:
24-
start_date, end_date = input.dates()
25-
start_date = pd.to_datetime(start_date)
26-
end_date = pd.to_datetime(end_date)
27-
df_value = df
28-
out = df_value[
29-
(df_value["date"] > start_date) & (df_value["date"] <= end_date)
30-
].sample(n=input.sample(), replace=True)
31-
return out
32-
33-
3423
@reactive.calc()
35-
def monitor_filtered_data() -> pd.DataFrame:
36-
sample_df = monitor_sampled_data()
37-
sample_df = sample_df.loc[sample_df["account"] == input.account()]
38-
return sample_df.reset_index(drop=True)
24+
def account_data():
25+
return df[
26+
(df["account"] == input.account()) & (df["sub_account"] == input.sub_account())
27+
]
3928

4029

4130
@reactive.calc()
42-
def training_data():
43-
return df[
44-
(df["account"] == input.account()) & (df["sub_account"] == input.sub_account())
31+
def character_filter():
32+
return account_data()[
33+
(account_data()["text"].str.len() >= input.chars()[0])
34+
& (account_data()["text"].str.len() <= input.chars()[1])
4535
]
4636

4737

4838
@reactive.effect
4939
@reactive.event(input.reset)
5040
def reset_vals():
51-
ui.update_date_range("dates", start="2023-01-01", end="2023-04-01")
52-
ui.update_numeric("sample", value=10000)
41+
ui.update_slider("chars", value=[500, 6000])
5342

5443

5544
with ui.sidebar():
@@ -71,56 +60,70 @@ def sub_selector():
7160
choices = choice_data["sub_account"].unique().tolist()
7261
ui.input_select("sub_account", "Sub Account", choices=choices)
7362

74-
with ui.panel_conditional("input.tabs !== 'Training Dashboard'"):
75-
ui.input_date_range(
76-
"dates",
77-
"Dates",
78-
start="2023-01-01",
79-
end="2023-04-01",
63+
with ui.tooltip(id="btn_tooltip", placement="right"):
64+
ui.input_slider(
65+
"chars",
66+
"Text length",
67+
min=0,
68+
max=df["text"].str.len().max(),
69+
value=[500, 6000],
8070
)
81-
ui.input_numeric("sample", "Sample Size", value=10000, step=5000)
82-
ui.input_action_button("reset", "Reset Values", class_="btn-primary")
83-
84-
85-
with ui.navset_bar(id="tabs", title="Monitoring"):
86-
with ui.nav_panel("Training Dashboard"):
87-
with ui.layout_columns():
88-
with ui.card():
89-
ui.card_header("Model Metrics")
90-
91-
@render_plotly
92-
def metric():
93-
if input.metric() == "ROC Curve":
94-
return plot_auc_curve(
95-
training_data(), "is_electronics", "training_score"
96-
)
97-
else:
98-
return plot_precision_recall_curve(
99-
training_data(), "is_electronics", "training_score"
100-
)
71+
"The number of characters in the text"
72+
73+
ui.input_action_button("reset", "Reset Values", class_="btn-primary")
74+
75+
with ui.nav_panel("Training Dashboard"):
76+
with ui.layout_columns():
77+
with ui.card():
78+
ui.card_header("Model Metrics")
10179

10280
@render_plotly
10381
def metric():
104-
df_value = df()
105-
df_filtered = df_value[df_value["account"] == input.account()]
10682
if input.metric() == "ROC Curve":
10783
return plot_auc_curve(
108-
df_filtered, "is_electronics", "training_score"
84+
character_filter(), "is_electronics", "training_score"
10985
)
11086
else:
11187
return plot_precision_recall_curve(
112-
df_filtered, "is_electronics", "training_score"
88+
character_filter(), "is_electronics", "training_score"
11389
)
11490

115-
@render_plotly
116-
def score_dist():
117-
return plot_score_distribution(training_data())
91+
ui.input_select(
92+
"metric", "Metric", choices=["ROC Curve", "Precision Recall"]
93+
)
94+
95+
with ui.card():
96+
ui.card_header("Model Scores")
11897

11998
@render_plotly
12099
def score_dist():
121-
df_value = df()
122-
df_filtered = df_value[df_value["account"] == input.account()]
123-
return plot_score_distribution(df_filtered)
100+
return plot_score_distribution(character_filter())
101+
102+
103+
vb_theme = "bg-blue"
104+
105+
with ui.nav_panel("Data"):
106+
with ui.layout_columns():
107+
with ui.value_box(theme=vb_theme):
108+
"Number of records"
109+
110+
@render.text
111+
def data_count():
112+
return str(character_filter().shape[0])
113+
114+
with ui.value_box(theme=vb_theme):
115+
"Mean Score"
116+
117+
@render.text
118+
def mean_score(theme=vb_theme):
119+
return f"{character_filter()['training_score'].mean() * 100:.2f}%"
120+
121+
with ui.value_box(theme=vb_theme):
122+
"Mean Text Length"
123+
124+
@render.text
125+
def mean_text_length():
126+
return f"{character_filter()['text'].str.len().mean():.2f} characters"
124127

125128
with ui.card(full_screen=True):
126129
with ui.card_header():
@@ -134,27 +137,10 @@ def score_dist():
134137
@render.download(filename=lambda: f"{input.account()}_scores.csv")
135138
def download_data():
136139
with io.BytesIO() as buf:
137-
filtered_data().to_csv(buf, index=False)
140+
account_data().to_csv(buf, index=False)
138141
buf.seek(0)
139142
yield buf.getvalue()
140143

141144
@render.data_frame
142145
def data_output():
143-
return filtered_data().drop(columns=["text"])
144-
145-
146-
with ui.nav_panel("Model Monitoring"):
147-
with ui.layout_columns():
148-
with ui.card():
149-
ui.card_header("API Response Time")
150-
151-
@render_plotly
152-
def api_response():
153-
return plot_api_response(filtered_data())
154-
155-
with ui.card():
156-
ui.card_header("Production Scores")
157-
158-
@render_plotly
159-
def prod_score_dist():
160-
return plot_score_distribution(filtered_data())
146+
return account_data().drop(columns=["text"])

0 commit comments

Comments
 (0)