Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- app.py +84 -32
- radar_data.json +56 -0
app.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
import plotly.graph_objects as go
|
|
@@ -5,6 +8,9 @@ import plotly.io as pio
|
|
| 5 |
|
| 6 |
pio.templates.default = "plotly_white"
|
| 7 |
|
|
|
|
|
|
|
|
|
|
| 8 |
def plot_spyder(scores: dict, title: str = "Group Chart", range_max: float | None = None) -> go.Figure:
|
| 9 |
if not scores:
|
| 10 |
raise ValueError("scores dict is empty")
|
|
@@ -38,69 +44,115 @@ def plot_spyder(scores: dict, title: str = "Group Chart", range_max: float | Non
|
|
| 38 |
|
| 39 |
return fig
|
| 40 |
|
|
|
|
| 41 |
def build_scores(df: pd.DataFrame) -> dict:
|
| 42 |
df = df.dropna(subset=["label", "value"])
|
| 43 |
df["label"] = df["label"].astype(str).str.strip()
|
| 44 |
df = df[df["label"] != ""]
|
| 45 |
return dict(zip(df["label"], df["value"].astype(float)))
|
| 46 |
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
rm = None if range_max <= 0 else range_max
|
| 49 |
-
return (
|
| 50 |
-
plot_spyder(build_scores(df1), t1, rm),
|
| 51 |
-
plot_spyder(build_scores(df2), t2, rm),
|
| 52 |
-
plot_spyder(build_scores(df3), t3, rm),
|
| 53 |
-
plot_spyder(build_scores(df4), t4, rm),
|
| 54 |
-
)
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
"
|
| 59 |
-
"
|
| 60 |
-
"
|
|
|
|
|
|
|
| 61 |
],
|
| 62 |
-
"value": [9, 2, 8, 3, 6, 6, 5, 4],
|
| 63 |
}
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
with gr.Blocks() as demo:
|
| 67 |
gr.Markdown("## Radar Chart Builder — All 4 Groups together")
|
| 68 |
|
| 69 |
-
range_input = gr.Number(value=
|
| 70 |
|
| 71 |
with gr.Row():
|
| 72 |
with gr.Column():
|
| 73 |
-
|
| 74 |
-
value=
|
| 75 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 76 |
column_count=(2, "fixed"), interactive=True, label="Chart 1 Data"
|
| 77 |
)
|
| 78 |
-
|
| 79 |
with gr.Column():
|
| 80 |
-
|
| 81 |
-
value=
|
| 82 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 83 |
column_count=(2, "fixed"), interactive=True, label="Chart 2 Data"
|
| 84 |
)
|
| 85 |
-
|
| 86 |
|
| 87 |
with gr.Row():
|
| 88 |
with gr.Column():
|
| 89 |
-
|
| 90 |
-
value=
|
| 91 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 92 |
column_count=(2, "fixed"), interactive=True, label="Chart 3 Data"
|
| 93 |
)
|
| 94 |
-
|
| 95 |
with gr.Column():
|
| 96 |
-
|
| 97 |
-
value=
|
| 98 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 99 |
column_count=(2, "fixed"), interactive=True, label="Chart 4 Data"
|
| 100 |
)
|
| 101 |
-
|
| 102 |
|
| 103 |
-
|
|
|
|
| 104 |
|
| 105 |
with gr.Row():
|
| 106 |
out1 = gr.Plot(label="Chart 1")
|
|
@@ -109,10 +161,10 @@ with gr.Blocks() as demo:
|
|
| 109 |
out3 = gr.Plot(label="Chart 3")
|
| 110 |
out4 = gr.Plot(label="Chart 4")
|
| 111 |
|
| 112 |
-
|
| 113 |
-
fn=
|
| 114 |
-
inputs=[
|
| 115 |
-
outputs=[out1, out2, out3, out4],
|
| 116 |
)
|
| 117 |
|
| 118 |
demo.launch()
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
import gradio as gr
|
| 5 |
import pandas as pd
|
| 6 |
import plotly.graph_objects as go
|
|
|
|
| 8 |
|
| 9 |
pio.templates.default = "plotly_white"
|
| 10 |
|
| 11 |
+
DATA_PATH = Path("radar_data.json")
|
| 12 |
+
|
| 13 |
+
|
| 14 |
def plot_spyder(scores: dict, title: str = "Group Chart", range_max: float | None = None) -> go.Figure:
|
| 15 |
if not scores:
|
| 16 |
raise ValueError("scores dict is empty")
|
|
|
|
| 44 |
|
| 45 |
return fig
|
| 46 |
|
| 47 |
+
|
| 48 |
def build_scores(df: pd.DataFrame) -> dict:
|
| 49 |
df = df.dropna(subset=["label", "value"])
|
| 50 |
df["label"] = df["label"].astype(str).str.strip()
|
| 51 |
df = df[df["label"] != ""]
|
| 52 |
return dict(zip(df["label"], df["value"].astype(float)))
|
| 53 |
|
| 54 |
+
|
| 55 |
+
def load_state(path: Path):
|
| 56 |
+
with path.open("r", encoding="utf-8") as f:
|
| 57 |
+
raw = json.load(f)
|
| 58 |
+
return raw
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def save_state(path: Path, payload: dict):
|
| 62 |
+
with path.open("w", encoding="utf-8") as f:
|
| 63 |
+
json.dump(payload, f, indent=2)
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def state_to_ui(state: dict):
|
| 67 |
+
range_max = state.get("range_max", 10)
|
| 68 |
+
charts = state.get("charts", [])
|
| 69 |
+
|
| 70 |
+
def to_df(ch):
|
| 71 |
+
return pd.DataFrame({"label": list(ch["scores"].keys()), "value": list(ch["scores"].values())})
|
| 72 |
+
|
| 73 |
+
df1 = to_df(charts[0])
|
| 74 |
+
df2 = to_df(charts[1])
|
| 75 |
+
df3 = to_df(charts[2])
|
| 76 |
+
df4 = to_df(charts[3])
|
| 77 |
+
|
| 78 |
+
t1 = charts[0]["title"]
|
| 79 |
+
t2 = charts[1]["title"]
|
| 80 |
+
t3 = charts[2]["title"]
|
| 81 |
+
t4 = charts[3]["title"]
|
| 82 |
+
|
| 83 |
+
return df1, t1, df2, t2, df3, t3, df4, t4, range_max
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def ui_to_state(df1, t1, df2, t2, df3, t3, df4, t4, range_max):
|
| 87 |
rm = None if range_max <= 0 else range_max
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
payload = {
|
| 90 |
+
"range_max": range_max,
|
| 91 |
+
"charts": [
|
| 92 |
+
{"title": t1, "scores": build_scores(df1)},
|
| 93 |
+
{"title": t2, "scores": build_scores(df2)},
|
| 94 |
+
{"title": t3, "scores": build_scores(df3)},
|
| 95 |
+
{"title": t4, "scores": build_scores(df4)},
|
| 96 |
],
|
|
|
|
| 97 |
}
|
| 98 |
+
|
| 99 |
+
figs = (
|
| 100 |
+
plot_spyder(payload["charts"][0]["scores"], t1, rm),
|
| 101 |
+
plot_spyder(payload["charts"][1]["scores"], t2, rm),
|
| 102 |
+
plot_spyder(payload["charts"][2]["scores"], t3, rm),
|
| 103 |
+
plot_spyder(payload["charts"][3]["scores"], t4, rm),
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
save_state(DATA_PATH, payload)
|
| 107 |
+
return (*figs, gr.update(value="Saved ✓"))
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
# ---- App bootstrapping ----
|
| 111 |
+
if not DATA_PATH.exists():
|
| 112 |
+
raise FileNotFoundError(f"Missing {DATA_PATH}. Create it using the sample JSON below.")
|
| 113 |
+
|
| 114 |
+
state = load_state(DATA_PATH)
|
| 115 |
+
df1, t1, df2, t2, df3, t3, df4, t4, range_max = state_to_ui(state)
|
| 116 |
|
| 117 |
with gr.Blocks() as demo:
|
| 118 |
gr.Markdown("## Radar Chart Builder — All 4 Groups together")
|
| 119 |
|
| 120 |
+
range_input = gr.Number(value=range_max, label="Shared Range Max (0 = auto)")
|
| 121 |
|
| 122 |
with gr.Row():
|
| 123 |
with gr.Column():
|
| 124 |
+
df1_input = gr.Dataframe(
|
| 125 |
+
value=df1, headers=["label", "value"],
|
| 126 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 127 |
column_count=(2, "fixed"), interactive=True, label="Chart 1 Data"
|
| 128 |
)
|
| 129 |
+
t1_input = gr.Textbox(value=t1, label="Chart 1 Title")
|
| 130 |
with gr.Column():
|
| 131 |
+
df2_input = gr.Dataframe(
|
| 132 |
+
value=df2, headers=["label", "value"],
|
| 133 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 134 |
column_count=(2, "fixed"), interactive=True, label="Chart 2 Data"
|
| 135 |
)
|
| 136 |
+
t2_input = gr.Textbox(value=t2, label="Chart 2 Title")
|
| 137 |
|
| 138 |
with gr.Row():
|
| 139 |
with gr.Column():
|
| 140 |
+
df3_input = gr.Dataframe(
|
| 141 |
+
value=df3, headers=["label", "value"],
|
| 142 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 143 |
column_count=(2, "fixed"), interactive=True, label="Chart 3 Data"
|
| 144 |
)
|
| 145 |
+
t3_input = gr.Textbox(value=t3, label="Chart 3 Title")
|
| 146 |
with gr.Column():
|
| 147 |
+
df4_input = gr.Dataframe(
|
| 148 |
+
value=df4, headers=["label", "value"],
|
| 149 |
datatype=["str", "number"], row_count=(8, "dynamic"),
|
| 150 |
column_count=(2, "fixed"), interactive=True, label="Chart 4 Data"
|
| 151 |
)
|
| 152 |
+
t4_input = gr.Textbox(value=t4, label="Chart 4 Title")
|
| 153 |
|
| 154 |
+
save_plot_button = gr.Button("Save & Plot")
|
| 155 |
+
status = gr.Textbox(value="", label="Status", interactive=False)
|
| 156 |
|
| 157 |
with gr.Row():
|
| 158 |
out1 = gr.Plot(label="Chart 1")
|
|
|
|
| 161 |
out3 = gr.Plot(label="Chart 3")
|
| 162 |
out4 = gr.Plot(label="Chart 4")
|
| 163 |
|
| 164 |
+
save_plot_button.click(
|
| 165 |
+
fn=ui_to_state,
|
| 166 |
+
inputs=[df1_input, t1_input, df2_input, t2_input, df3_input, t3_input, df4_input, t4_input, range_input],
|
| 167 |
+
outputs=[out1, out2, out3, out4, status],
|
| 168 |
)
|
| 169 |
|
| 170 |
demo.launch()
|
radar_data.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"range_max": 10,
|
| 3 |
+
"charts": [
|
| 4 |
+
{
|
| 5 |
+
"title": "Group 1 Chart",
|
| 6 |
+
"scores": {
|
| 7 |
+
"Affordability": 9.0,
|
| 8 |
+
"Control": 2.0,
|
| 9 |
+
"Difficulty": 8.0,
|
| 10 |
+
"Energy Efficiency Gains": 3.0,
|
| 11 |
+
"Partnership Effort": 6.0,
|
| 12 |
+
"Risk Reduction": 6.0,
|
| 13 |
+
"Scale": 5.0,
|
| 14 |
+
"Adverse Outcome": 4.0
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"title": "Group 2 Chart",
|
| 19 |
+
"scores": {
|
| 20 |
+
"Affordability": 6.0,
|
| 21 |
+
"Control": 4.0,
|
| 22 |
+
"Difficulty": 7.0,
|
| 23 |
+
"Energy Efficiency Gains": 5.0,
|
| 24 |
+
"Partnership Effort": 7.0,
|
| 25 |
+
"Risk Reduction": 5.0,
|
| 26 |
+
"Scale": 6.0,
|
| 27 |
+
"Adverse Outcome": 3.0
|
| 28 |
+
}
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"title": "Group 3 Chart",
|
| 32 |
+
"scores": {
|
| 33 |
+
"Affordability": 5.0,
|
| 34 |
+
"Control": 6.0,
|
| 35 |
+
"Difficulty": 4.0,
|
| 36 |
+
"Energy Efficiency Gains": 5.0,
|
| 37 |
+
"Partnership Effort": 4.0,
|
| 38 |
+
"Risk Reduction": 7.0,
|
| 39 |
+
"Adverse Outcome": 6.0
|
| 40 |
+
}
|
| 41 |
+
},
|
| 42 |
+
{
|
| 43 |
+
"title": "Group 4 Chart",
|
| 44 |
+
"scores": {
|
| 45 |
+
"Affordability": 7.0,
|
| 46 |
+
"Control": 2.0,
|
| 47 |
+
"Difficulty": 6.0,
|
| 48 |
+
"Energy Efficiency Gains": 4.0,
|
| 49 |
+
"Partnership Effort": 6.0,
|
| 50 |
+
"Risk Reduction": 5.0,
|
| 51 |
+
"Scale": 7.0,
|
| 52 |
+
"Adverse Outcome": 2.0
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
]
|
| 56 |
+
}
|