# app.py import asyncio asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy()) import gradio as gr import mcp_tools from mcp_tools import posthoc_tests, assumption_checks import spaces @spaces.GPU def init_gpu(): return "GPU initialized" import json, tempfile, os def save_json_to_file(data, filename): path = os.path.join(tempfile.gettempdir(), filename) with open(path, "w") as f: json.dump(data, f) return path import base64 def save_png_to_file(img, filename): if img is None: return None img.save(filename, format="PNG") return filename from io import BytesIO from PIL import Image import matplotlib.pyplot as plt def ui_plot(groups_str): # Parse semicolon-separated groups groups = [] for g in groups_str.split(";"): nums = [float(x) for x in g.split(",")] groups.append(nums) # Example plot: boxplot of groups fig, ax = plt.subplots() ax.boxplot(groups) ax.set_title("Group Plot") ax.set_xlabel("Group") ax.set_ylabel("Value") buf = BytesIO() fig.savefig(buf, format="png") buf.seek(0) return Image.open(buf) # ----------------------------- # UI helper wrappers # ----------------------------- def ui_welch(g1, g2, alt): return mcp_tools.welch_t_test(g1, g2, alt) def ui_student(g1, g2, alt): return mcp_tools.student_t_test(g1, g2, alt) def ui_paired(g1, g2, alt): return mcp_tools.paired_t_test(g1, g2, alt) #def ui_one_sample(g, mu, alt): # return mcp_tools.one_sample_t_test(g, mu, alt) def parse_group(text): # Split on commas, strip whitespace, convert to float return [float(x.strip()) for x in text.split(",") if x.strip()] def ui_os(g, mu, alternative): import numpy as np import pingouin as pg g = np.array(parse_group(g), dtype=float) if mu is None: mu = 0 mu = float(mu) adjusted = g - mu result = pg.ttest(adjusted, y=None, alternative=alternative) print("DEBUG ui_os:", g, mu, alternative) return { "T": float(result["T"].iloc[0]), "dof": int(result["dof"].iloc[0]), "alternative": alternative, "p_val": float(result["p-val"].iloc[0]), "CI95": [float(result["CI95%"].iloc[0][0]), float(result["CI95%"].iloc[0][1])], "cohen_d": float(result["cohen-d"].iloc[0]), "power": float(result["power"].iloc[0]), "BF10": str(result["BF10"].iloc[0]) } def ui_anova(groups): return mcp_tools.one_way_anova(groups) # ----------------------------- # Modern Light Theme # ----------------------------- theme = gr.themes.Soft( primary_hue="blue", secondary_hue="gray", neutral_hue="gray", ) # ----------------------------- # Main UI # ----------------------------- with gr.Blocks(title="Stat3001 — Statistical Tests") as demo: gr.Markdown( """ # 📊 Stat3001 — Statistical Analysis Toolkit Clean, modern, and powered by **Pingouin** for robust statistical results. """ ) groups_input = gr.Textbox( label="Groups (semicolon-separated)", placeholder="Example: 1,2,3; 4,5,6; 7,8,9", value="1,2,3; 4,5,6; 7,8,9" ) load_example = gr.Button("Load example") load_example.click(lambda: "1,2,3; 4,5,6; 7,8,9", None, groups_input) # Shared input for both ANOVA and post-hoc # ----------------------------------------- # SHARED COMPONENTS (define BEFORE tabs) # ----------------------------------------- # Shared input area # --------------------------------------------------- # Welch t-test # --------------------------------------------------- with gr.Tab("Welch t-test"): with gr.Column(): gr.Markdown("### Compare two independent groups (unequal variances).") g1 = gr.Textbox(label="Group 1 (comma-separated numbers)") g2 = gr.Textbox(label="Group 2 (comma-separated numbers)") alt = gr.Radio(["two-sided", "less", "greater"], value="two-sided", label="Alternative hypothesis") run = gr.Button("Run Welch t-test", variant="primary") out = gr.JSON(label="Results") download_welch = gr.DownloadButton("Download results") #run.click(lambda *args: ui_welch(*args), inputs=[g1, g2, alt], outputs=[out]) run.click(ui_welch, inputs=[g1, g2, alt], outputs=out) run.click( lambda r: save_json_to_file(r, "welch_results.json"), inputs=[out], outputs=[download_welch] ) example_welch = "23,25,28,30,32", "18,20,22,25,27" example_anova = "1,2,3; 2,3,4; 3,4,5" load_example = gr.Button("Load example") load_example.click( lambda: example_welch, None, [g1, g2] ) # --------------------------------------------------- # Student t-test # --------------------------------------------------- with gr.Tab("Student t-test"): gr.Markdown("### Compare two independent groups (equal variances).") with gr.Column(): g1_s = gr.Textbox(label="Group 1 (comma-separated numbers)") g2_s = gr.Textbox(label="Group 2 (comma-separated numbers)") alt_s = gr.Radio(["two-sided", "less", "greater"], value="two-sided", label="Alternative hypothesis") example_student = ("10,12,14,15,16", "9,11,13,14,15") load_example_student = gr.Button("Load example") load_example_student.click(lambda: example_student, None, [g1_s, g1_s]) run_s = gr.Button("Run Student t-test", variant="primary") out_s = gr.JSON(label="Results") download_student = gr.DownloadButton("Download results") run_s.click(ui_student, inputs=[g1_s, g1_s, alt_s], outputs=[out_s]) run_s.click( lambda r: save_json_to_file(r, "student_results.json"), inputs=[out_s], outputs=[download_student] ) #run.click(lambda *args: ui_welch(*args), inputs=[g1, g2, alt], outputs=[out]) #run.click(lambda r: ("results.json", json.dumps(r)), inputs=[out], outputs=[download]) # --------------------------------------------------- # Paired t-test # --------------------------------------------------- with gr.Tab("Paired t-test"): gr.Markdown("### Compare two related measurements (same subjects).") with gr.Column(): g1_p = gr.Textbox(label="Group 1 (comma-separated numbers)") g2_p = gr.Textbox(label="Group 2 (comma-separated numbers)") alt_p = gr.Radio(["two-sided", "less", "greater"], value="two-sided", label="Alternative hypothesis") example_paired = ("5,6,7,8,9", "6,7,8,9,10") load_example_paired = gr.Button("Load example") load_example_paired.click(lambda: example_paired, None, [g1_p, g2_p]) run_p = gr.Button("Run Paired t-test", variant="primary") out_p = gr.JSON(label="Results") download_paired = gr.DownloadButton("Download results") run_p.click(ui_paired, inputs=[g1_p, g2_p, alt_p], outputs=[out_p]) run_p.click( lambda r: save_json_to_file(r, "paired_results.json"), inputs=[out_p], outputs=[download_paired] ) #run.click(lambda *args: ui_welch(*args), inputs=[g1, g2, alt], outputs=[out]) #run.click(lambda r: ("results.json", json.dumps(r)), inputs=[out], outputs=[download]) #run_p.click(ui_paired, inputs=[g1_p, g2_p, alt_p], outputs=out_p) # --------------------------------------------------- # One-sample t-test # --------------------------------------------------- with gr.Tab("One-sample t-test"): with gr.Column(): g_os = gr.Textbox(label="Sample values (comma-separated)") mu_os = gr.Number(label="Population mean", value=0) alt_one = gr.Radio(["two-sided", "less", "greater"], value="two-sided") out_os = gr.JSON(label="Results") run_os = gr.Button("Run One-sample t-test", variant="primary") download_os = gr.DownloadButton("Download results") example_one_sample = "5,6,7,8,9" load_example_one = gr.Button("Load example") load_example_one.click(lambda: example_one_sample, None, [g_os]) run_os.click(ui_os, inputs=[g_os, mu_os, alt_one], outputs=[out_os]) run_os.click( lambda r: save_json_to_file(r, "one_sample_results.json"), inputs=[out_os], outputs=[download_os] ) # --------------------------------------------------- # One-way ANOVA # --------------------------------------------------- # ----------------------------------------- # ANOVA TAB # ----------------------------------------- with gr.Tab("ANOVA"): with gr.Column(): run_anova = gr.Button("Run ANOVA") out_anova = gr.JSON(label="Results") run_anova.click(ui_anova, inputs=[groups_input], outputs=[out_anova]) # ----------------------------------------- # POST-HOC TAB # ----------------------------------------- with gr.Tab("Post-hoc"): with gr.Column(): method = gr.Radio(["games-howell", "tukey"], value="games-howell") run_post = gr.Button("Run post-hoc tests") out_post = gr.JSON(label="Results") download_post = gr.DownloadButton("Download results") run_post.click(lambda g, m: posthoc_tests(g, m), inputs=[groups_input, method], outputs=[out_post]) run_post.click(lambda r: save_json_to_file(r, "posthoc.json"), inputs=[out_post], outputs=[download_post]) # --------------------------------------------------- # Assumption Checks # --------------------------------------------------- with gr.Tab("Assumption Checks"): with gr.Column(): gr.Markdown("### Normality & Homogeneity") run_assump = gr.Button("Run assumption checks", variant="primary") out_assump = gr.JSON(label="Results") download_assump = gr.DownloadButton("Download results") # Use the shared groups_input run_assump.click( lambda g: assumption_checks(g), inputs=[groups_input], outputs=[out_assump] ) run_assump.click( lambda r: save_json_to_file(r, "assumption_checks.json"), inputs=[out_assump], outputs=[download_assump] ) # --------------------------------------------------- # Plots # --------------------------------------------------- with gr.Tab("Plot"): with gr.Column(): run_plot = gr.Button("Generate Plot") plot_output = gr.Image(type="pil", label="Plot") download_plot = gr.DownloadButton("Download plot") run_plot.click(ui_plot, inputs=[groups_input], outputs=[plot_output]) download_plot.click( lambda img: save_png_to_file(img, "plot.png"), inputs=[plot_output], outputs=[download_plot] ) # Main execution if __name__ == "__main__": demo.launch( theme=theme, server_name="0.0.0.0", server_port=7860 )