radar-chart / app.py
mfallahian's picture
Upload 2 files
67fe3e7 verified
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()