File size: 5,032 Bytes
0ef03ea
 
 
 
 
 
41afdc7
dee01c8
 
0ef03ea
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9b59fc5
dee01c8
 
0ef03ea
3831198
 
 
dee01c8
 
 
3831198
 
 
 
 
41afdc7
3831198
41afdc7
 
 
 
 
 
 
 
 
 
 
 
 
 
0ef03ea
3831198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41afdc7
 
3831198
 
41afdc7
 
 
0ef03ea
dee01c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd0fa88
 
41afdc7
fd0fa88
 
 
 
dee01c8
3831198
dee01c8
 
 
 
 
 
 
 
 
 
 
41afdc7
1
2
3
4
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import os
import json
import threading
import gradio as gr
import statistics
from scipy import stats
import numpy as np  # Added import for numpy to compute percentiles
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)  # Generate the Altair chart
    return message, None, chart  # Return message, cleared input, and 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)
    # Calculate IQR
    Q1 = np.percentile(guesses, 25)
    Q3 = np.percentile(guesses, 75)
    IQR = Q3 - Q1

    # Initialize the message
    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:
        # Calculate sample standard deviation
        s = statistics.stdev(guesses)
        # Calculate standard error
        SE = s / (n ** 0.5)
        # Degrees of freedom
        df = n - 1
        # Confidence level (e.g., 95%)
        confidence_level = 0.95
        alpha = 1 - confidence_level
        # Calculate critical t-value
        t_value = stats.t.ppf(1 - alpha/2, df)
        # Calculate margin of error
        ME = t_value * SE
        # Calculate confidence interval
        ci_lower = average - ME
        ci_upper = average + ME
        # Append confidence interval to the message
        message += f"95% confidence interval for the average: ({ci_lower:.2f}, {ci_upper:.2f})"
    else:
        # Not enough data to compute confidence interval
        message += "Not enough data to compute confidence interval for the average."
    
    return message

def generate_plot(guesses):
    if len(guesses) < 2:
        return None  # Not enough data to plot

    # Convert the list of guesses into a Pandas DataFrame
    df = pd.DataFrame({'Guess': guesses})

    # Histogram
    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
    )

    # CDF
    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
    )

    # Combine the two charts vertically
    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")  # Plot component for Altair charts
        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()