Spaces:
Sleeping
Sleeping
YeCanming commited on
Commit ·
a90b71f
1
Parent(s): 8b7cc68
feat: data
Browse files- .gitignore +0 -0
- data/.gitkeep +0 -0
- src/streamlit_app.py +95 -38
.gitignore
ADDED
|
File without changes
|
data/.gitkeep
ADDED
|
File without changes
|
src/streamlit_app.py
CHANGED
|
@@ -1,40 +1,97 @@
|
|
| 1 |
-
import altair as alt
|
| 2 |
-
import numpy as np
|
| 3 |
-
import pandas as pd
|
| 4 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import tomli
|
| 4 |
+
import plotly.graph_objects as go
|
| 5 |
+
from typing import List, Dict
|
| 6 |
|
| 7 |
+
# === 配置路径 ===
|
| 8 |
+
DATA_ROOT = Path(__file__).parent.parent / "data"
|
| 9 |
+
|
| 10 |
+
# === 页面设置 ===
|
| 11 |
+
st.set_page_config(page_title="Flowillower 🌸", layout="wide")
|
| 12 |
+
st.markdown("<h1 style='text-align: center; color: #7b68ee;'>Flowillower 🌸</h1>", unsafe_allow_html=True)
|
| 13 |
+
st.markdown("<p style='text-align: center;'>Elegant and Transparent Experiment Tracking</p>", unsafe_allow_html=True)
|
| 14 |
+
st.divider()
|
| 15 |
+
|
| 16 |
+
# === 加载所有 Study ===
|
| 17 |
+
def get_all_studies(data_root: Path) -> List[Path]:
|
| 18 |
+
return [p for p in data_root.iterdir() if p.is_dir()]
|
| 19 |
+
|
| 20 |
+
studies = get_all_studies(DATA_ROOT)
|
| 21 |
+
study_names = []
|
| 22 |
+
|
| 23 |
+
for s in studies:
|
| 24 |
+
meta_file = s / ".study_meta.toml"
|
| 25 |
+
if meta_file.exists():
|
| 26 |
+
try:
|
| 27 |
+
meta = tomli.loads(meta_file.read_text())
|
| 28 |
+
name = meta.get("display_name", s.name)
|
| 29 |
+
except:
|
| 30 |
+
name = s.name
|
| 31 |
+
else:
|
| 32 |
+
name = s.name
|
| 33 |
+
study_names.append((name, s))
|
| 34 |
+
|
| 35 |
+
# === Study 选择器 ===
|
| 36 |
+
study_name_list = [name for name, _ in study_names]
|
| 37 |
+
selected_study_name = st.sidebar.selectbox("Select a Study", study_name_list)
|
| 38 |
+
selected_study_path = dict(study_names)[selected_study_name]
|
| 39 |
+
|
| 40 |
+
# === Study 概览区 ===
|
| 41 |
+
st.subheader(f"📁 Study Overview: {selected_study_name}")
|
| 42 |
+
st.markdown("Metadata, description, config summary can be shown here (to be implemented).")
|
| 43 |
+
st.divider()
|
| 44 |
+
|
| 45 |
+
# === 加载所有 Trial ===
|
| 46 |
+
def get_all_trials(study_path: Path) -> List[Path]:
|
| 47 |
+
return [p for p in study_path.iterdir() if p.is_dir()]
|
| 48 |
+
|
| 49 |
+
trials = get_all_trials(selected_study_path)
|
| 50 |
+
trial_names = [t.name for t in trials]
|
| 51 |
+
selected_trial_name = st.sidebar.selectbox("🧪 Select Trial", trial_names)
|
| 52 |
+
selected_trial_path = selected_study_path / selected_trial_name
|
| 53 |
+
|
| 54 |
+
# === 加载 track 的 metric 数据 ===
|
| 55 |
+
def load_track_data(trial_path: Path) -> Dict[str, List[Dict]]:
|
| 56 |
+
track_dir = trial_path / "logs/scalar"
|
| 57 |
+
result = {}
|
| 58 |
+
if not track_dir.exists(): return result
|
| 59 |
+
|
| 60 |
+
for f in track_dir.glob("metrics_*.toml"):
|
| 61 |
+
track_name = f.stem.replace("metrics_", "")
|
| 62 |
+
with open(f, "rb") as fp:
|
| 63 |
+
try:
|
| 64 |
+
data = tomli.load(fp).get("metrics", [])
|
| 65 |
+
result[track_name] = data
|
| 66 |
+
except:
|
| 67 |
+
continue
|
| 68 |
+
return result
|
| 69 |
+
|
| 70 |
+
# === 展示 Trial 详细信息 ===
|
| 71 |
+
st.subheader(f"📊 Trial: {selected_trial_name}")
|
| 72 |
+
track_data = load_track_data(selected_trial_path)
|
| 73 |
+
|
| 74 |
+
if not track_data:
|
| 75 |
+
st.warning("No metrics data found for this trial.")
|
| 76 |
+
else:
|
| 77 |
+
for track_name, records in track_data.items():
|
| 78 |
+
st.markdown(f"### Track: {track_name}")
|
| 79 |
+
if not records:
|
| 80 |
+
st.info("No data in this track.")
|
| 81 |
+
continue
|
| 82 |
+
|
| 83 |
+
# 自动获取所有标量键(除 global_step)
|
| 84 |
+
keys = [k for k in records[0].keys() if k != "global_step"]
|
| 85 |
+
for key in keys:
|
| 86 |
+
fig = go.Figure()
|
| 87 |
+
fig.add_trace(go.Scatter(
|
| 88 |
+
x=[r["global_step"] for r in records],
|
| 89 |
+
y=[r.get(key, None) for r in records],
|
| 90 |
+
mode='lines+markers',
|
| 91 |
+
name=key
|
| 92 |
+
))
|
| 93 |
+
fig.update_layout(title=f"{track_name.upper()} - {key}", template="plotly_dark", height=350)
|
| 94 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 95 |
+
|
| 96 |
+
st.divider()
|
| 97 |
+
st.markdown("*Flowillower 🌸 — Minimalist, Poetic and Open Source.*")
|