YeCanming commited on
Commit
a90b71f
·
1 Parent(s): 8b7cc68

feat: data

Browse files
Files changed (3) hide show
  1. .gitignore +0 -0
  2. data/.gitkeep +0 -0
  3. 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
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
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.*")