Spaces:
Running
Running
| from pathlib import Path | |
| import gradio as gr | |
| import pandas as pd | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| CSV_PATH = Path("metrics.csv") | |
| def load_data() -> pd.DataFrame: | |
| df = pd.read_csv(CSV_PATH) | |
| # Normalize/parse columns | |
| if "date" not in df.columns: | |
| raise ValueError("Expected a 'date' column in metrics.csv") | |
| df["date"] = pd.to_datetime(df["date"], errors="coerce") | |
| df = df.sort_values("date").reset_index(drop=True) | |
| # Ensure numeric columns are numeric | |
| for c in df.columns: | |
| if c == "date": | |
| continue | |
| df[c] = pd.to_numeric(df[c], errors="coerce") | |
| return df | |
| def line_figure(df: pd.DataFrame, cols: list[str], title: str, yaxis_title: str = "") -> go.Figure: | |
| if not cols: | |
| # Empty placeholder so the UI doesn't error | |
| fig = go.Figure() | |
| fig.update_layout(title=f"{title} (no series selected)") | |
| return fig | |
| fig = px.line( | |
| df, | |
| x="date", | |
| y=cols, | |
| markers=True, | |
| title=title, | |
| ) | |
| # Improve layout for time series | |
| fig.update_layout( | |
| legend_title_text="Series", | |
| xaxis_title="Date", | |
| yaxis_title=yaxis_title, | |
| hovermode="x unified", | |
| margin={"l": 50, "r": 20, "t": 50, "b": 40}, | |
| ) | |
| return fig | |
| TAB_SPEC = { | |
| "Docstrings": [ | |
| "docstring coverage", | |
| "docstring missing", | |
| ], | |
| "Size (Lines/Statements/Expressions/Parameters)": [ | |
| "lines mean", | |
| "lines max", | |
| "lines 90th-percentile", | |
| "statements mean", | |
| "statements max", | |
| "statements 90th-percentile", | |
| "expressions mean", | |
| "expressions max", | |
| "expressions 90th-percentile", | |
| "parameters mean", | |
| "parameters max", | |
| "parameters 90th-percentile", | |
| ], | |
| "Complexity": [ | |
| "cyclomatic_complexity mean", | |
| "cyclomatic_complexity max", | |
| "cyclomatic_complexity 90th-percentile", | |
| ], | |
| "Typing": [ | |
| "type_coverage mean", | |
| "type_coverage min", | |
| "type_coverage 50th-percentile", | |
| ], | |
| "Duplication": [ | |
| "duplication.score mean", | |
| "duplication.score max", | |
| "duplication.score 90th-percentile", | |
| "duplication.score 50th-percentile", | |
| "duplication.duplicated-lines total", | |
| ], | |
| "TODOs": [ | |
| "todo_comments total", | |
| ], | |
| "CLOC (Repository scope)": [ | |
| "files", | |
| "lines blank", | |
| "lines comment", | |
| "lines code", | |
| ], | |
| } | |
| Y_LABELS = { | |
| "Docstrings": "value", | |
| "Size (Lines/Statements/Expressions/Parameters)": "count", | |
| "Complexity": "complexity", | |
| "Typing": "fraction / coverage", | |
| "Duplication": "score / lines", | |
| "TODOs": "count", | |
| "CLOC (Repository scope)": "lines / files", | |
| } | |
| DF = load_data() | |
| with gr.Blocks(title="Code Metrics β Time Series", fill_height=True) as demo: | |
| gr.Markdown( | |
| "## PEFT Code Metrics Over Time\n" | |
| f"Loaded **{CSV_PATH}** with {len(DF)} rows spanning " | |
| f"{DF['date'].min().date()} β {DF['date'].max().date()}.\n\n" | |
| "Use each tab to pick the series you want to plot." | |
| ) | |
| with gr.Tabs(): | |
| tab_controls = [] | |
| tab_plots = [] | |
| for tab_name, series in TAB_SPEC.items(): | |
| available = [s for s in series if s in DF.columns] # guard against missing cols | |
| with gr.Tab(tab_name): | |
| with gr.Row(): | |
| sel = gr.CheckboxGroup( | |
| choices=available, | |
| value=available, | |
| label="Series", | |
| ) | |
| plot = gr.Plot( | |
| value=line_figure(DF, available, tab_name, Y_LABELS.get(tab_name, "")), | |
| show_label=False, | |
| ) | |
| sel.change( | |
| fn=lambda cols, t=tab_name: line_figure(DF, cols, t, Y_LABELS.get(t, "")), | |
| inputs=sel, | |
| outputs=plot, | |
| ) | |
| tab_controls.append(sel) | |
| tab_plots.append(plot) | |
| if __name__ == "__main__": | |
| demo.launch() | |