Spaces:
Sleeping
Sleeping
| import json | |
| from pathlib import Path | |
| import gradio as gr | |
| import pandas as pd | |
| import plotly.graph_objects as go | |
| import plotly.io as pio | |
| pio.templates.default = "plotly_white" | |
| DATA_PATH = Path("radar_data.json") | |
| def plot_spyder(scores: dict, title: str = "Group Chart", range_max: float | None = None) -> go.Figure: | |
| if not scores: | |
| raise ValueError("scores dict is empty") | |
| labels = list(scores.keys()) | |
| values = list(scores.values()) | |
| labels_loop = labels + [labels[0]] | |
| values_loop = values + [values[0]] | |
| fig = go.Figure( | |
| data=go.Scatterpolar( | |
| r=values_loop, | |
| theta=labels_loop, | |
| fill="toself", | |
| name=title, | |
| line=dict(width=3), | |
| ) | |
| ) | |
| fig.update_layout( | |
| title=title, | |
| polar=dict( | |
| radialaxis=dict( | |
| visible=True, | |
| range=[0, range_max if range_max is not None else max(values)], | |
| ) | |
| ), | |
| showlegend=False, | |
| ) | |
| return fig | |
| def build_scores(df: pd.DataFrame) -> dict: | |
| df = df.dropna(subset=["label", "value"]) | |
| df["label"] = df["label"].astype(str).str.strip() | |
| df = df[df["label"] != ""] | |
| return dict(zip(df["label"], df["value"].astype(float))) | |
| def load_state(path: Path): | |
| with path.open("r", encoding="utf-8") as f: | |
| raw = json.load(f) | |
| return raw | |
| def save_state(path: Path, payload: dict): | |
| with path.open("w", encoding="utf-8") as f: | |
| json.dump(payload, f, indent=2) | |
| def state_to_ui(state: dict): | |
| range_max = state.get("range_max", 5) | |
| charts = state.get("charts", []) | |
| def to_df(ch): | |
| return pd.DataFrame({"label": list(ch["scores"].keys()), "value": list(ch["scores"].values())}) | |
| df1 = to_df(charts[0]) | |
| df2 = to_df(charts[1]) | |
| df3 = to_df(charts[2]) | |
| df4 = to_df(charts[3]) | |
| t1 = charts[0]["title"] | |
| t2 = charts[1]["title"] | |
| t3 = charts[2]["title"] | |
| t4 = charts[3]["title"] | |
| return df1, t1, df2, t2, df3, t3, df4, t4, range_max | |
| def ui_to_state(df1, t1, df2, t2, df3, t3, df4, t4, range_max): | |
| rm = None if range_max <= 0 else range_max | |
| payload = { | |
| "range_max": range_max, | |
| "charts": [ | |
| {"title": t1, "scores": build_scores(df1)}, | |
| {"title": t2, "scores": build_scores(df2)}, | |
| {"title": t3, "scores": build_scores(df3)}, | |
| {"title": t4, "scores": build_scores(df4)}, | |
| ], | |
| } | |
| figs = ( | |
| plot_spyder(payload["charts"][0]["scores"], t1, rm), | |
| plot_spyder(payload["charts"][1]["scores"], t2, rm), | |
| plot_spyder(payload["charts"][2]["scores"], t3, rm), | |
| plot_spyder(payload["charts"][3]["scores"], t4, rm), | |
| ) | |
| save_state(DATA_PATH, payload) | |
| return (*figs, gr.update(value="Saved ✓")) | |
| # ---- App bootstrapping ---- | |
| if not DATA_PATH.exists(): | |
| raise FileNotFoundError(f"Missing {DATA_PATH}. Create it using the sample JSON below.") | |
| state = load_state(DATA_PATH) | |
| df1, t1, df2, t2, df3, t3, df4, t4, range_max = state_to_ui(state) | |
| with gr.Blocks() as demo: | |
| gr.Markdown("## Radar Chart Builder — All 4 Groups together") | |
| range_input = gr.Number(value=range_max, label="Shared Range Max (0 = auto)") | |
| with gr.Row(): | |
| with gr.Column(): | |
| df1_input = gr.Dataframe( | |
| value=df1, headers=["label", "value"], | |
| datatype=["str", "number"], row_count=(8, "dynamic"), | |
| column_count=(2, "fixed"), interactive=True, label="Chart 1 Data" | |
| ) | |
| t1_input = gr.Textbox(value=t1, label="Chart 1 Title") | |
| with gr.Column(): | |
| df2_input = gr.Dataframe( | |
| value=df2, headers=["label", "value"], | |
| datatype=["str", "number"], row_count=(8, "dynamic"), | |
| column_count=(2, "fixed"), interactive=True, label="Chart 2 Data" | |
| ) | |
| t2_input = gr.Textbox(value=t2, label="Chart 2 Title") | |
| with gr.Row(): | |
| with gr.Column(): | |
| df3_input = gr.Dataframe( | |
| value=df3, headers=["label", "value"], | |
| datatype=["str", "number"], row_count=(8, "dynamic"), | |
| column_count=(2, "fixed"), interactive=True, label="Chart 3 Data" | |
| ) | |
| t3_input = gr.Textbox(value=t3, label="Chart 3 Title") | |
| with gr.Column(): | |
| df4_input = gr.Dataframe( | |
| value=df4, headers=["label", "value"], | |
| datatype=["str", "number"], row_count=(8, "dynamic"), | |
| column_count=(2, "fixed"), interactive=True, label="Chart 4 Data" | |
| ) | |
| t4_input = gr.Textbox(value=t4, label="Chart 4 Title") | |
| save_plot_button = gr.Button("Save & Plot") | |
| status = gr.Textbox(value="", label="Status", interactive=False) | |
| with gr.Row(): | |
| out1 = gr.Plot(label="Chart 1") | |
| out2 = gr.Plot(label="Chart 2") | |
| with gr.Row(): | |
| out3 = gr.Plot(label="Chart 3") | |
| out4 = gr.Plot(label="Chart 4") | |
| save_plot_button.click( | |
| fn=ui_to_state, | |
| inputs=[df1_input, t1_input, df2_input, t2_input, df3_input, t3_input, df4_input, t4_input, range_input], | |
| outputs=[out1, out2, out3, out4, status], | |
| ) | |
| demo.launch() |