| import os |
| import json |
| import threading |
| import gradio as gr |
| import statistics |
| from scipy import stats |
| import numpy as np |
| import altair as alt |
| import pandas as pd |
|
|
| DATA_DIR = './storage' |
| DATA_FILE = os.path.join(DATA_DIR, 'guesses.json') |
| lock = threading.Lock() |
|
|
| def ensure_data_directory(): |
| os.makedirs(DATA_DIR, exist_ok=True) |
|
|
| def load_guesses(): |
| ensure_data_directory() |
| if not os.path.exists(DATA_FILE): |
| with open(DATA_FILE, 'w') as f: |
| json.dump([], f) |
| with open(DATA_FILE, 'r') as f: |
| return json.load(f) |
|
|
| def save_guesses(guesses): |
| with open(DATA_FILE, 'w') as f: |
| json.dump(guesses, f) |
|
|
| def add_guess(guess): |
| with lock: |
| guesses = load_guesses() |
| guesses.append(guess) |
| save_guesses(guesses) |
| message = compute_statistics(guesses, include_message=True) |
| chart = generate_plot(guesses) |
| return message, None, chart |
|
|
| def get_current_results(): |
| with lock: |
| guesses = load_guesses() |
| message = compute_statistics(guesses, include_message=False) |
| chart = generate_plot(guesses) |
| return message, chart |
|
|
| def compute_statistics(guesses, include_message): |
| n = len(guesses) |
| if n == 0: |
| return "No guesses have been made yet." |
| |
| average = sum(guesses) / n |
| median = statistics.median(guesses) |
| |
| Q1 = np.percentile(guesses, 25) |
| Q3 = np.percentile(guesses, 75) |
| IQR = Q3 - Q1 |
|
|
| |
| message = ( |
| (f"Your guess has been recorded.\n" if include_message else "") + |
| f"Current average of all {n} guesses: {average:.2f}\n" + |
| f"Median of all guesses: {median:.2f}\n" + |
| f"Interquartile Range (IQR): {IQR:.2f}\n" + |
| "(The IQR is the range between the 25th percentile and 75th percentile of the data.)\n" |
| ) |
|
|
| if n >= 2: |
| |
| s = statistics.stdev(guesses) |
| |
| SE = s / (n ** 0.5) |
| |
| df = n - 1 |
| |
| confidence_level = 0.95 |
| alpha = 1 - confidence_level |
| |
| t_value = stats.t.ppf(1 - alpha/2, df) |
| |
| ME = t_value * SE |
| |
| ci_lower = average - ME |
| ci_upper = average + ME |
| |
| message += f"95% confidence interval for the average: ({ci_lower:.2f}, {ci_upper:.2f})" |
| else: |
| |
| message += "Not enough data to compute confidence interval for the average." |
| |
| return message |
|
|
| def generate_plot(guesses): |
| if len(guesses) < 2: |
| return None |
|
|
| |
| df = pd.DataFrame({'Guess': guesses}) |
|
|
| |
| histogram = alt.Chart(df).mark_bar().encode( |
| alt.X('Guess', bin=alt.Bin(maxbins=20), title='Guess Value'), |
| alt.Y('count()', title='Frequency'), |
| tooltip=[alt.Tooltip('count()', title='Frequency')] |
| ).properties( |
| title='Histogram of Guesses', |
| width=500, |
| height=300 |
| ) |
|
|
| |
| df_sorted = df.sort_values('Guess').reset_index(drop=True) |
| df_sorted['ECDF'] = (df_sorted.index + 1) / len(df_sorted) |
|
|
| cdf = alt.Chart(df_sorted).mark_line(interpolate='step-after').encode( |
| x=alt.X('Guess', title='Guess Value'), |
| y=alt.Y('ECDF', title='Cumulative Probability'), |
| tooltip=[ |
| alt.Tooltip('Guess', title='Guess Value'), |
| alt.Tooltip('ECDF', title='Cumulative Probability', format='.2f') |
| ] |
| ).properties( |
| title='Cumulative Distribution Function (CDF)', |
| width=500, |
| height=300 |
| ) |
|
|
| |
| combined_chart = alt.vconcat(histogram, cdf).configure_title( |
| fontSize=16, |
| anchor='middle' |
| ).interactive() |
|
|
| return combined_chart |
|
|
| with gr.Blocks() as demo: |
| gr.Markdown("# Collective Guessing Game") |
| gr.Markdown("Submit your guess and contribute to the global statistics!") |
| guess_input = gr.Number(label="Enter your guess") |
| submit_button = gr.Button("Submit Guess") |
| with gr.Accordion("View Current Results!", open=False): |
| output_text = gr.Textbox(label="Results", lines=10) |
| output_plot = gr.Plot(label="Data Visualization") |
| refresh_button = gr.Button("Refresh Results") |
| submit_button.click( |
| fn=add_guess, |
| inputs=guess_input, |
| outputs=[output_text, guess_input, output_plot] |
| ) |
| refresh_button.click( |
| fn=get_current_results, |
| outputs=[output_text, output_plot] |
| ) |
| demo.load(fn=get_current_results, outputs=[output_text, output_plot]) |
| |
| demo.launch() |