mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-07-27 23:47:46 +00:00
add lite curves figure (#1119)
This commit is contained in:
@@ -18,6 +18,7 @@ from rdagent.log.ui.utils import (
|
||||
curve_figure,
|
||||
get_statistics_df,
|
||||
get_summary_df,
|
||||
lite_curve_figure,
|
||||
percent_df,
|
||||
)
|
||||
from rdagent.scenarios.kaggle.kaggle_crawler import get_metric_direction
|
||||
@@ -47,42 +48,47 @@ def days_summarize_win():
|
||||
|
||||
|
||||
def curves_win(summary: dict):
|
||||
for k, v in summary.items():
|
||||
with st.container(border=True):
|
||||
st.markdown(f"**:blue[{k}] - :violet[{v['competition']}]**")
|
||||
try:
|
||||
tscores = {k: v for k, v in v["test_scores"].items()}
|
||||
tscores = pd.Series(tscores)
|
||||
vscores = {}
|
||||
for k, vs in v["valid_scores"].items():
|
||||
if not vs.index.is_unique:
|
||||
st.warning(
|
||||
f"Loop {k}'s valid scores index are not unique, only the last one will be kept to show."
|
||||
)
|
||||
st.write(vs)
|
||||
vscores[k] = vs[~vs.index.duplicated(keep="last")].iloc[:, 0]
|
||||
if len(vscores) > 0:
|
||||
metric_name = list(vscores.values())[0].name
|
||||
else:
|
||||
metric_name = "None"
|
||||
vscores = pd.DataFrame(vscores)
|
||||
if "ensemble" in vscores.index:
|
||||
ensemble_row = vscores.loc[["ensemble"]]
|
||||
vscores = pd.concat([ensemble_row, vscores.drop("ensemble")])
|
||||
vscores = vscores.T
|
||||
vscores["test"] = tscores
|
||||
vscores.index = [f"L{i}" for i in vscores.index]
|
||||
vscores.columns.name = metric_name
|
||||
# draw curves
|
||||
cbwin1, cbwin2 = st.columns(2)
|
||||
if cbwin1.toggle("Show Curves", key="show_curves"):
|
||||
for k, v in summary.items():
|
||||
with st.container(border=True):
|
||||
st.markdown(f"**:blue[{k}] - :violet[{v['competition']}]**")
|
||||
try:
|
||||
tscores = {k: v for k, v in v["test_scores"].items()}
|
||||
tscores = pd.Series(tscores)
|
||||
vscores = {}
|
||||
for k, vs in v["valid_scores"].items():
|
||||
if not vs.index.is_unique:
|
||||
st.warning(
|
||||
f"Loop {k}'s valid scores index are not unique, only the last one will be kept to show."
|
||||
)
|
||||
st.write(vs)
|
||||
vscores[k] = vs[~vs.index.duplicated(keep="last")].iloc[:, 0]
|
||||
if len(vscores) > 0:
|
||||
metric_name = list(vscores.values())[0].name
|
||||
else:
|
||||
metric_name = "None"
|
||||
vscores = pd.DataFrame(vscores)
|
||||
if "ensemble" in vscores.index:
|
||||
ensemble_row = vscores.loc[["ensemble"]]
|
||||
vscores = pd.concat([ensemble_row, vscores.drop("ensemble")])
|
||||
vscores = vscores.T
|
||||
vscores["test"] = tscores
|
||||
vscores.index = [f"L{i}" for i in vscores.index]
|
||||
vscores.columns.name = metric_name
|
||||
|
||||
st.plotly_chart(curve_figure(vscores))
|
||||
except Exception as e:
|
||||
import traceback
|
||||
st.plotly_chart(curve_figure(vscores))
|
||||
except Exception as e:
|
||||
import traceback
|
||||
|
||||
st.markdown("- Error: " + str(e))
|
||||
st.code(traceback.format_exc())
|
||||
st.markdown("- Valid Scores: ")
|
||||
# st.write({k: type(v) for k, v in v["valid_scores"].items()})
|
||||
st.json(v["valid_scores"])
|
||||
st.markdown("- Error: " + str(e))
|
||||
st.code(traceback.format_exc())
|
||||
st.markdown("- Valid Scores: ")
|
||||
# st.write({k: type(v) for k, v in v["valid_scores"].items()})
|
||||
st.json(v["valid_scores"])
|
||||
if cbwin2.toggle("Show Curves (Lite)", key="show_curves_lite"):
|
||||
st.pyplot(lite_curve_figure(summary))
|
||||
|
||||
|
||||
def all_summarize_win():
|
||||
@@ -233,8 +239,7 @@ def all_summarize_win():
|
||||
|
||||
# write curve
|
||||
st.subheader("Curves", divider="rainbow")
|
||||
if st.toggle("Show Curves", key="show_curves"):
|
||||
curves_win(summary)
|
||||
curves_win(summary)
|
||||
|
||||
|
||||
with st.container(border=True):
|
||||
|
||||
@@ -10,6 +10,7 @@ import networkx as nx
|
||||
import pandas as pd
|
||||
import plotly.graph_objects as go
|
||||
import typer
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
from rdagent.app.data_science.loop import DataScienceRDLoop
|
||||
from rdagent.core.proposal import Trace
|
||||
@@ -607,6 +608,72 @@ def curve_figure(scores: pd.DataFrame) -> go.Figure:
|
||||
return fig
|
||||
|
||||
|
||||
def lite_curve_figure(summary):
|
||||
cols = 3 # 每行几个图,可调整
|
||||
rows = math.ceil(len(summary) / cols)
|
||||
|
||||
fig, axes = plt.subplots(rows, cols, figsize=(6 * cols, 4.5 * rows), squeeze=False)
|
||||
axes = axes.flatten() # 💡 扁平化 axes 结构,确保 ax.plot 不报错
|
||||
colors = {"Bronze": "#cd7f32", "Silver": "#c0c0c0", "Gold": "#ffd700", "Median": "gray"}
|
||||
|
||||
for idx, competition in enumerate(summary.keys()):
|
||||
data = summary[competition]
|
||||
test_scores_df = pd.DataFrame.from_dict(data["test_scores"], orient="index", columns=["Test Score"])
|
||||
test_scores_df.index.name = "Loop"
|
||||
valid_scores_dict = data["valid_scores"]
|
||||
|
||||
# 提取 ensemble 验证分数
|
||||
ensemble_scores = {}
|
||||
for loop_id, df in valid_scores_dict.items():
|
||||
if "ensemble" in df.index:
|
||||
ensemble_scores[loop_id] = df.loc["ensemble"].iloc[0]
|
||||
|
||||
ensemble_valid_df = pd.DataFrame.from_dict(ensemble_scores, orient="index", columns=["Ensemble Valid Score"])
|
||||
ensemble_valid_df.index.name = "Loop"
|
||||
|
||||
combined_df = pd.merge(ensemble_valid_df, test_scores_df, left_index=True, right_index=True, how="outer")
|
||||
combined_df.sort_index(inplace=True)
|
||||
|
||||
bronze_threshold = data["bronze_threshold"]
|
||||
silver_threshold = data["silver_threshold"]
|
||||
gold_threshold = data["gold_threshold"]
|
||||
sota_loop_id = data["sota_loop_id_new"]
|
||||
|
||||
# 当前 subplot
|
||||
ax = axes[idx]
|
||||
ax.plot(combined_df.index, combined_df["Ensemble Valid Score"], marker="o", markersize=4, label="Valid Score")
|
||||
ax.plot(combined_df.index, combined_df["Test Score"], marker="s", markersize=4, label="Test Score")
|
||||
ax.axhline(y=bronze_threshold, color=colors["Bronze"], linestyle="--", linewidth=2)
|
||||
ax.axhline(y=silver_threshold, color=colors["Silver"], linestyle="--", linewidth=2)
|
||||
ax.axhline(y=gold_threshold, color=colors["Gold"], linestyle="--", linewidth=2)
|
||||
|
||||
# 标记 SOTA loop
|
||||
if sota_loop_id is not None and sota_loop_id in combined_df.index:
|
||||
ax.axvline(x=sota_loop_id, color="red", linestyle=":", linewidth=2, alpha=0.7)
|
||||
# 添加文本标注
|
||||
ax.text(
|
||||
sota_loop_id,
|
||||
ax.get_ylim()[1] * 0.95,
|
||||
f"L{sota_loop_id}",
|
||||
ha="center",
|
||||
va="top",
|
||||
bbox=dict(boxstyle="round,pad=0.3", facecolor="red", alpha=0.3),
|
||||
)
|
||||
|
||||
ax.set_title(f"{competition}")
|
||||
ax.set_xlabel("Loop")
|
||||
ax.set_ylabel("Score")
|
||||
ax.grid(True)
|
||||
ax.legend()
|
||||
|
||||
# 删除多余 subplot(如果有)
|
||||
for j in range(len(summary), len(axes)):
|
||||
fig.delaxes(axes[j])
|
||||
|
||||
plt.tight_layout()
|
||||
return fig
|
||||
|
||||
|
||||
def trace_figure(trace: Trace, merge_loops: list = []):
|
||||
G = nx.DiGraph()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user