Skip to content

Commit c021583

Browse files
a-koreamrit110
andauthored
Add ability to truncate report and centralise report generation. (#579)
* add last_n_evals arg to backend export * finish slider w/ text * merge main * change to update one json+html * fix notebook path typo * fix notebook path typo for los --------- Co-authored-by: Amrit Krishnan <amrit110@gmail.com>
1 parent 1ea282e commit c021583

File tree

11 files changed

+501
-455
lines changed

11 files changed

+501
-455
lines changed

cyclops/report/model_card/fields.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,6 @@ class MetricCard(
594594
description="History of the metric over time.",
595595
)
596596

597-
trend: Optional[StrictStr] = Field(
598-
None,
599-
description="The trend of the metric over time.",
600-
)
601-
602597
timestamps: Optional[List[StrictStr]] = Field(
603598
None,
604599
description="Timestamps for each point in the history.",

cyclops/report/model_card/sections.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
3030
class Overview(BaseModelCardSection):
3131
"""Overview section with aggregate metrics."""
3232

33+
last_n_evals: Optional[int] = Field(
34+
None,
35+
description="The number of evaluations to display in the model card.",
36+
)
37+
3338
metric_cards: Optional[MetricCardCollection] = Field(
3439
None,
3540
description="Comparative metrics between baseline and periodic report.",

cyclops/report/report.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
get_slices,
5252
get_thresholds,
5353
get_timestamps,
54-
get_trends,
5554
regex_replace,
5655
regex_search,
5756
str_to_snake_case,
@@ -98,7 +97,7 @@ def from_json_file(
9897
The path to a JSON file containing model card data.
9998
output_dir : str, optional
10099
The directory to save the report to. If not provided, the report will
101-
be saved in a directory called `cyclops_reports` in the current working
100+
be saved in a directory called `cyclops_report` in the current working
102101
directory.
103102
104103
Returns
@@ -1054,6 +1053,7 @@ def export(
10541053
template_path: Optional[str] = None,
10551054
interactive: bool = True,
10561055
save_json: bool = True,
1056+
last_n_evals: Optional[int] = None,
10571057
synthetic_timestamp: Optional[str] = None,
10581058
) -> str:
10591059
"""Export the model card report to an HTML file.
@@ -1070,6 +1070,9 @@ def export(
10701070
Whether to create an interactive HTML report. The default is True.
10711071
save_json : bool, optional
10721072
Whether to save the model card as a JSON file. The default is True.
1073+
last_n_evals : int, optional
1074+
The number of most recent evaluations to include in the report and
1075+
calculate trends for. If not provided, all evaluations will be included.
10731076
synthetic_timestamp : str, optional
10741077
A synthetic timestamp to use for the report. This is useful for
10751078
generating back-dated reports. The default is None, which uses the
@@ -1089,10 +1092,8 @@ def export(
10891092

10901093
# write to file
10911094
if synthetic_timestamp is not None:
1092-
today = synthetic_timestamp
10931095
today_now = synthetic_timestamp
10941096
else:
1095-
today = dt_date.today().strftime("%Y-%m-%d")
10961097
today_now = dt_datetime.now().strftime("%Y-%m-%d %H:%M:%S")
10971098

10981099
current_report_metrics: List[List[PerformanceMetric]] = []
@@ -1102,9 +1103,7 @@ def export(
11021103
report_paths = glob.glob(
11031104
os.path.join(
11041105
self.output_dir,
1105-
"cyclops_reports",
1106-
"*",
1107-
"*",
1106+
"cyclops_report",
11081107
"*.json",
11091108
),
11101109
)
@@ -1135,6 +1134,10 @@ def export(
11351134
metric_cards,
11361135
)
11371136

1137+
if self._model_card.overview is not None:
1138+
last_n_evals = 0 if last_n_evals is None else last_n_evals
1139+
self._model_card.overview.last_n_evals = last_n_evals
1140+
11381141
self._validate()
11391142
template = self._get_jinja_template(template_path=template_path)
11401143

@@ -1143,7 +1146,6 @@ def export(
11431146
"sweep_graphics": sweep_graphics,
11441147
"get_slices": get_slices,
11451148
"get_thresholds": get_thresholds,
1146-
"get_trends": get_trends,
11471149
"get_passed": get_passed,
11481150
"get_names": get_names,
11491151
"get_histories": get_histories,
@@ -1154,12 +1156,9 @@ def export(
11541156
plotlyjs = get_plotlyjs() if interactive else None
11551157
content = template.render(model_card=self._model_card, plotlyjs=plotlyjs)
11561158

1157-
now = dt_datetime.now().strftime("%H-%M-%S")
11581159
report_path = os.path.join(
11591160
self.output_dir,
1160-
"cyclops_reports",
1161-
today,
1162-
now,
1161+
"cyclops_report",
11631162
output_filename or "model_card.html",
11641163
)
11651164
self._write_file(report_path, content)

cyclops/report/templates/model_report/macros.jinja

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,14 @@
172172

173173
{% macro render_perf(name, comp)%}
174174
<div class="card" id={{name}}>
175-
<h3 style="color: black; font-weight:normal;">How is your model doing?</h3><br>
176-
<h3 style="color: gray; font-weight:normal;">A quick glance of your most important metrics.</h3>
175+
<div class="column" style="float: left; width: 80%;">
176+
<h3 style="color: black; font-weight:normal;">How is your model doing?</h3><br>
177+
<h3 style="color: gray; font-weight:normal;">A quick glance of your most important metrics.</h3>
178+
</div>
179+
<span>
180+
<h3 id="slider_p_title"><span style="color: black; font-weight:normal;">Last</span> <span id="slider_p_num">{{ comp.last_n_evals }}</span> <span style="color: black; font-weight:normal;">Evaluations</span></h3>
181+
<input type="range" min="1" max="{{ comp.last_n_evals+10 }}" value="{{ comp.last_n_evals }}" id="n_evals_slider_p" style="width: 100%;">
182+
</span>
177183
{% for metric_card in comp.metric_cards.collection%}
178184
{% if metric_card.slice == 'overall' %}
179185
{{ render_metric_card(metric_card, loop.index-1, "subcard_overview") }}
@@ -185,15 +191,23 @@
185191

186192
{% macro render_perf_over_time(name, comp)%}
187193
<div class="card" id={{name}} style="display: block;">
188-
<h3 style="color: black; font-weight:normal;">How is your model doing over time?</h3><br>
189-
<h3 style="color: gray; font-weight:normal;">See how your model is performing over several metrics and subgroups over time.</h3>
190-
<div style="display: flex; align-items: center; justify-content: center; padding: 10px; margin-bottom: 20px;">
191-
<h4 style="padding-right: 10px;">Multi-plot Selection:</h4>
192-
<div class="radio-buttons" id="plot-selection">
193-
<input type="radio" id="Plot 1" name="plot" value="Plot 1" checked>
194-
<label for="Plot 1">Plot 1</label>
195-
<input type="radio" id="+" name="plot" value="+">
196-
<label for="+" style="padding: 2.5px; font-weight:bold; font-size: 18px;">+</label>
194+
<span style="float: right; width: 10%; margin-right: 10%;">
195+
<h3 id="slider_pot_title"><span style="color: black; font-weight:normal;">Last</span> <span id="slider_pot_num">{{ comp.last_n_evals }}</span> <span style="color: black; font-weight:normal;">Evaluations</span></h3>
196+
<input type="range" min="1" max="{{ comp.last_n_evals+10 }}" value="{{ comp.last_n_evals }}" id="n_evals_slider_pot" style="width: 100%;">
197+
</span>
198+
<div style="display: flex; flex-direction: column;">
199+
<div class="column" style="float: left; width: 90%;">
200+
<h3 style="color: black; font-weight:normal;">How is your model doing over time?</h3><br>
201+
<h3 style="color: gray; font-weight:normal;">See how your model is performing over several metrics and subgroups over time.</h3>
202+
</div>
203+
<div style="display: flex; align-items: center; justify-content: center; padding: 10px; margin-bottom: 20px;">
204+
<h4 style="padding-right: 10px;">Multi-plot Selection:</h4>
205+
<div class="radio-buttons" id="plot-selection">
206+
<input type="radio" id="Plot 1" name="plot" value="Plot 1" checked>
207+
<label for="Plot 1">Plot 1</label>
208+
<input type="radio" id="+" name="plot" value="+">
209+
<label for="+" style="padding: 2.5px; font-weight:bold; font-size: 18px;">+</label>
210+
</div>
197211
</div>
198212
</div>
199213
<div class="column" style="float: left;">

cyclops/report/templates/model_report/model_report.jinja

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,8 +531,53 @@
531531
"rgb(23, 190, 207)"
532532
];
533533
534+
// create global variable for max_n_evals
535+
var histories = JSON.parse({{ get_histories(model_card)|safe|tojson }});
536+
// get max_n_evals from histories
537+
var history_data = [];
538+
for (let i = 0; i < histories[0].length; i++) {
539+
history_data.push(parseFloat(histories[0][i]));
540+
}
541+
var max_n_evals = history_data.length;
542+
543+
// Add event listeners to radio buttons
544+
for (let input of inputs_all) {
545+
input.addEventListener('change', updatePlot);
546+
}
547+
// Add event listener to update plot when window is resized
548+
window.addEventListener('resize', updatePlot);
549+
for (let selection of plot_selection) {
550+
selection.addEventListener('change', updatePlotSelection);
551+
}
552+
534553
535554
// Initial update when the page loads
536555
updatePlot();
537556
document.addEventListener('DOMContentLoaded', setCollapseButton);
557+
558+
function updateLastNEvals() {
559+
var n_evals_slider_p = document.getElementById("n_evals_slider_p");
560+
var slider_p_num = document.getElementById("slider_p_num");
561+
var n_evals_slider_pot = document.getElementById("n_evals_slider_pot");
562+
var slider_pot_num = document.getElementById("slider_pot_num");
563+
564+
n_evals_slider_p.max = max_n_evals;
565+
n_evals_slider_pot.max = max_n_evals;
566+
567+
if (n_evals_slider_p !== null) {
568+
n_evals_slider_p.oninput = function() {
569+
last_n_evals = this.value;
570+
slider_p_num.innerHTML = last_n_evals;
571+
generate_model_card_plot();
572+
}
573+
}
574+
if (n_evals_slider_pot !== null) {
575+
n_evals_slider_pot.oninput = function() {
576+
last_n_evals = this.value;
577+
slider_pot_num.innerHTML = last_n_evals;
578+
updatePlot();
579+
}
580+
}
581+
}
582+
document.addEventListener('DOMContentLoaded', updateLastNEvals);
538583
</script>

0 commit comments

Comments
 (0)