Threadbourne commited on
Commit
9e4f414
·
verified ·
1 Parent(s): d454cb7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -172
app.py CHANGED
@@ -1,172 +0,0 @@
1
- import gradio as gr
2
- import numpy as np
3
- import pandas as pd
4
- import matplotlib.pyplot as plt
5
-
6
- # --- QUICK VIEW CALLBACK (new, lightweight) ---
7
- def run_quick_view(file, turn_col, mag_col, rolling_window):
8
- if file is None:
9
- return None, "Upload a CSV first."
10
-
11
- df = pd.read_csv(file.name)
12
- if df.empty:
13
- return None, "CSV is empty."
14
-
15
- # Resolve turn axis
16
- use_turn = (turn_col not in [None, "None"] and turn_col in df.columns and pd.api.types.is_numeric_dtype(df[turn_col]))
17
- if use_turn:
18
- d = df.sort_values(turn_col).reset_index(drop=True)
19
- x = d[turn_col].to_numpy()
20
- else:
21
- d = df.reset_index(drop=True)
22
- x = np.arange(len(d)) + 1 # friendlier 1-based index
23
-
24
- # Validate magnitude
25
- if mag_col not in d.columns or not pd.api.types.is_numeric_dtype(d[mag_col]):
26
- return None, f"'{mag_col}' is not a numeric magnitude column."
27
-
28
- y = d[mag_col].astype(float).to_numpy()
29
-
30
- w = int(rolling_window)
31
- w = max(3, min(w, len(d)))
32
- roll = pd.Series(y).rolling(w, min_periods=max(3, w // 3)).mean().to_numpy()
33
-
34
- fig = plt.figure(figsize=(8, 4.5))
35
- ax = fig.add_subplot(111)
36
- ax.scatter(x, y, s=8, alpha=0.6, label="Turns")
37
- ax.plot(x, roll, label=f"Rolling mean (w={w})")
38
- ax.set_title(f"Quick View — {mag_col}")
39
- ax.set_xlabel(turn_col if use_turn else "Turn (row order)")
40
- ax.set_ylabel("Magnitude")
41
- ax.legend()
42
- fig.tight_layout()
43
-
44
- msg = "Quick View: response magnitude over time. Use Advanced tabs for stability bands + perturbations."
45
- return fig, msg
46
-
47
-
48
- # ----------------------------
49
- # APP UI
50
- # ----------------------------
51
- with gr.Blocks(title="Threadscope: Drift & Hold") as demo:
52
- gr.Markdown(
53
- "## Threadscope: Drift & Hold — Bring Your Own Thread\n"
54
- "Upload a CSV to visualize long-form interaction dynamics. **Processed in-session only (no storage).**\n\n"
55
- "**Quick start:** upload → Quick View → adjust rolling window."
56
- )
57
-
58
- # Upload first
59
- file = gr.File(label="Upload", file_types=[".csv"])
60
-
61
- status = gr.Textbox(label="Status", interactive=False)
62
-
63
- # Keep mapping, but tuck into a collapsible section
64
- with gr.Accordion("Data mapping (expand if needed)", open=False):
65
- with gr.Row():
66
- turn_col = gr.Dropdown(label="Turn column (optional)", choices=[], value=None)
67
- speaker_col = gr.Dropdown(label="Speaker column (optional)", choices=[], value=None)
68
- mag_col = gr.Dropdown(label="Magnitude column (numeric)", choices=[], value=None)
69
-
70
- preview = gr.Dataframe(label="Preview (first 15 rows)", interactive=False, wrap=True)
71
-
72
- # Advanced-only controls that still need file-derived choices
73
- with gr.Accordion("Advanced inputs (perturbations)", open=False):
74
- noise_col = gr.Dropdown(label="Noise column (numeric)", choices=[], value=None)
75
- turn_col_for_scramble = gr.Dropdown(label="Turn column for scramble (optional)", choices=[], value="None")
76
-
77
- # Update all dropdowns + preview on upload
78
- file.change(
79
- fn=on_upload_all,
80
- inputs=[file],
81
- outputs=[turn_col, speaker_col, mag_col, noise_col, turn_col_for_scramble, status, preview],
82
- )
83
-
84
- # Tabs: Quick first, Advanced next
85
- with gr.Tabs():
86
- # ----------------------------
87
- # QUICK VIEW (default)
88
- # ----------------------------
89
- with gr.Tab("Quick View"):
90
- gr.Markdown(
91
- "**What this shows:** response magnitude over time + rolling mean.\n\n"
92
- "If you want stability detection (bands + persistence), open **Drift & Hold (Advanced)**."
93
- )
94
- rolling_window_q = gr.Slider(3, 200, value=25, step=1, label="Rolling window (turns)")
95
- run_quick = gr.Button("Run Quick View")
96
- quick_plot = gr.Plot(label="Quick plot")
97
- quick_msg = gr.Textbox(label="Notes", interactive=False)
98
-
99
- run_quick.click(
100
- fn=run_quick_view,
101
- inputs=[file, turn_col, mag_col, rolling_window_q],
102
- outputs=[quick_plot, quick_msg],
103
- )
104
-
105
- # ----------------------------
106
- # DRIFT & HOLD (ADVANCED)
107
- # ----------------------------
108
- with gr.Tab("Drift & Hold (Advanced)"):
109
- gr.Markdown(
110
- "**Stability settings (start with defaults):**\n"
111
- "- Rolling window = 25\n"
112
- "- How wide is “normal”? = 2.0\n"
113
- "- How strict is “stable”? = 1.0\n"
114
- "- How long must it stay stable? = 10\n\n"
115
- "Adjust one slider at a time."
116
- )
117
-
118
- with gr.Row():
119
- rolling_window = gr.Slider(3, 200, value=25, step=1, label="Rolling window (turns)")
120
- band_width = gr.Slider(0.5, 4.0, value=2.0, step=0.1, label="How wide is “normal”? (band width)")
121
-
122
- with gr.Row():
123
- stability_thresh = gr.Slider(0.5, 4.0, value=1.0, step=0.1, label="How strict is “stable”? (threshold)")
124
- persistence = gr.Slider(1, 100, value=10, step=1, label="How long must it stay stable? (persistence)")
125
-
126
- run_btn = gr.Button("Run Drift & Hold")
127
- out_plot = gr.Plot(label="Drift & Hold plot")
128
- out_msg = gr.Textbox(label="Summary", interactive=False)
129
-
130
- with gr.Accordion("Details (computed preview)", open=False):
131
- out_table = gr.Dataframe(label="Computed preview", interactive=False, wrap=True)
132
-
133
- run_btn.click(
134
- fn=run_drift_hold,
135
- inputs=[file, turn_col, mag_col, rolling_window, band_width, stability_thresh, persistence],
136
- outputs=[out_plot, out_msg, out_table],
137
- )
138
-
139
- # ----------------------------
140
- # PERTURBATIONS (ADVANCED)
141
- # ----------------------------
142
- with gr.Tab("Perturbations (Advanced)"):
143
- gr.Markdown(
144
- "**Use this to test robustness:**\n"
145
- "- **Temporal scramble** breaks order but keeps values.\n"
146
- "- **Metric noise** perturbs values but keeps order."
147
- )
148
-
149
- perturb_type = gr.Dropdown(
150
- label="Perturbation type",
151
- choices=["Temporal scramble", "Metric noise injection"],
152
- value="Temporal scramble",
153
- )
154
-
155
- with gr.Row():
156
- strength = gr.Slider(0, 1, value=0.35, step=0.01, label="Strength")
157
- seed = gr.Number(value=7, precision=0, label="Seed")
158
-
159
- run_perturb_btn = gr.Button("Apply perturbation")
160
- pert_plot = gr.Plot(label="Perturbed plot")
161
- pert_msg = gr.Textbox(label="Notes", interactive=False)
162
-
163
- with gr.Accordion("Perturbed preview (first 15 rows)", open=False):
164
- pert_preview = gr.Dataframe(interactive=False, wrap=True)
165
-
166
- run_perturb_btn.click(
167
- fn=run_perturb,
168
- inputs=[file, perturb_type, strength, seed, turn_col_for_scramble, noise_col],
169
- outputs=[pert_plot, pert_msg, pert_preview],
170
- )
171
-
172
- demo.launch()