Update app.py
Browse files
app.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
# app.py
|
2 |
import pandas as pd
|
3 |
import numpy as np
|
4 |
import matplotlib.pyplot as plt
|
@@ -84,7 +84,7 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
84 |
self.combined_data['Answer_Correctness'] = self.combined_data['Correct'].map({True: 'Correct', False: 'Incorrect'})
|
85 |
|
86 |
self.numeric_cols = self.combined_data.select_dtypes(include=np.number).columns.tolist()
|
87 |
-
self.
|
88 |
self.valid_playback_participants = sorted(list(self.valid_playback_trials.keys()))
|
89 |
print(f"--- Data Loading Successful. Found {len(self.valid_playback_participants)} participants with fixation data. ---")
|
90 |
return self
|
@@ -161,7 +161,7 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
161 |
trial_info = self.combined_data[(self.combined_data['participant_id'] == str(participant)) & (self.combined_data['Question'] == question)].iloc[0]
|
162 |
summary_text = f"**Actual Answer:** `{trial_info['Answer_Correctness']}`"
|
163 |
|
164 |
-
return summary_text, fig, gr.Slider(maximum=slider_max, value=fixation_num, interactive=True)
|
165 |
|
166 |
def analyze_rq1_metric(self, metric):
|
167 |
if not metric or metric not in self.combined_data.columns: return None, "Metric not found."
|
@@ -176,7 +176,23 @@ class EnhancedAIvsRealGazeAnalyzer:
|
|
176 |
def update_question_dropdown(self, participant):
|
177 |
"""Dynamically updates the question dropdown based on the selected participant."""
|
178 |
valid_questions = self.valid_playback_trials.get(participant, [])
|
179 |
-
return gr.Dropdown(choices=sorted(valid_questions), interactive=True, value=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
|
181 |
# --- DATA SETUP & GRADIO APP ---
|
182 |
def setup_and_load_data():
|
@@ -235,10 +251,29 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
235 |
rq2_test_size_slider.release(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|
236 |
rq2_estimators_slider.release(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|
237 |
|
|
|
238 |
# Chained dropdown logic for Tab 3
|
239 |
-
playback_participant.change(
|
240 |
-
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
|
243 |
demo.load(fn=analyzer.analyze_rq1_metric, inputs=rq1_metric_dropdown, outputs=[rq1_plot_output, rq1_summary_output])
|
244 |
demo.load(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|
|
|
1 |
+
# app.py
|
2 |
import pandas as pd
|
3 |
import numpy as np
|
4 |
import matplotlib.pyplot as plt
|
|
|
84 |
self.combined_data['Answer_Correctness'] = self.combined_data['Correct'].map({True: 'Correct', False: 'Incorrect'})
|
85 |
|
86 |
self.numeric_cols = self.combined_data.select_dtypes(include=np.number).columns.tolist()
|
87 |
+
self.time_ metrics = [c for c in self.numeric_cols if any(k in c.lower() for k in ['time', 'duration', 'fixation'])]
|
88 |
self.valid_playback_participants = sorted(list(self.valid_playback_trials.keys()))
|
89 |
print(f"--- Data Loading Successful. Found {len(self.valid_playback_participants)} participants with fixation data. ---")
|
90 |
return self
|
|
|
161 |
trial_info = self.combined_data[(self.combined_data['participant_id'] == str(participant)) & (self.combined_data['Question'] == question)].iloc[0]
|
162 |
summary_text = f"**Actual Answer:** `{trial_info['Answer_Correctness']}`"
|
163 |
|
164 |
+
return summary_text, fig, gr.Slider(maximum=slider_max, value=fixation_num, interactive=True, step=1, minimum=0)
|
165 |
|
166 |
def analyze_rq1_metric(self, metric):
|
167 |
if not metric or metric not in self.combined_data.columns: return None, "Metric not found."
|
|
|
176 |
def update_question_dropdown(self, participant):
|
177 |
"""Dynamically updates the question dropdown based on the selected participant."""
|
178 |
valid_questions = self.valid_playback_trials.get(participant, [])
|
179 |
+
return gr.Dropdown(choices=sorted(valid_questions), interactive=True, value=None, label="2. Select a Question")
|
180 |
+
|
181 |
+
# <<< FIX START: Step 1 -> Add a new handler method for when a question is selected. >>>
|
182 |
+
# This function provides a clean, single entry point to reset the visualization.
|
183 |
+
def handle_new_trial_selection(self, participant, question):
|
184 |
+
"""Called when a new trial is selected. Resets the view to the first fixation."""
|
185 |
+
if not participant or not question:
|
186 |
+
# Return a default/empty state for all outputs if nothing is selected
|
187 |
+
return "Select a trial to begin.", None, gr.Slider(value=0, interactive=False)
|
188 |
+
|
189 |
+
# Start the playback at the very first fixation for a better user experience.
|
190 |
+
# You can change '1' to '0' if you prefer it to start completely empty.
|
191 |
+
initial_fixation_num = 1
|
192 |
+
|
193 |
+
# Call the main generation function with this fixed initial value
|
194 |
+
return self.generate_gaze_playback(participant, question, initial_fixation_num)
|
195 |
+
# <<< FIX END >>>
|
196 |
|
197 |
# --- DATA SETUP & GRADIO APP ---
|
198 |
def setup_and_load_data():
|
|
|
251 |
rq2_test_size_slider.release(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|
252 |
rq2_estimators_slider.release(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|
253 |
|
254 |
+
# <<< FIX START: Step 2 -> Update the event wiring for Tab 3. >>>
|
255 |
# Chained dropdown logic for Tab 3
|
256 |
+
playback_participant.change(
|
257 |
+
fn=analyzer.update_question_dropdown,
|
258 |
+
inputs=playback_participant,
|
259 |
+
outputs=playback_question
|
260 |
+
)
|
261 |
+
|
262 |
+
# When a question is selected, call the new handler to reset the entire playback view.
|
263 |
+
# This is much cleaner and more reliable than the previous .then() chain.
|
264 |
+
playback_question.change(
|
265 |
+
fn=analyzer.handle_new_trial_selection,
|
266 |
+
inputs=[playback_participant, playback_question],
|
267 |
+
outputs=outputs_playback
|
268 |
+
)
|
269 |
+
|
270 |
+
# The slider event handler remains the same and works correctly for scrubbing through fixations.
|
271 |
+
playback_slider.release(
|
272 |
+
fn=analyzer.generate_gaze_playback,
|
273 |
+
inputs=[playback_participant, playback_question, playback_slider],
|
274 |
+
outputs=outputs_playback
|
275 |
+
)
|
276 |
+
# <<< FIX END >>>
|
277 |
|
278 |
demo.load(fn=analyzer.analyze_rq1_metric, inputs=rq1_metric_dropdown, outputs=[rq1_plot_output, rq1_summary_output])
|
279 |
demo.load(fn=analyzer.run_prediction_model, inputs=[rq2_test_size_slider, rq2_estimators_slider], outputs=outputs_rq2)
|