import os import gradio as gr import numpy as np import pandas as pd import datetime import plotly.express as px import plotly.graph_objects as go import datasets ##### GPU PLOT ##### def split_multi_users(dfs): df = dfs.copy() df["usernames"] = df["username"].apply(lambda x: x.split(", ")) df["count"] = 1 new_df = [] for row in df.to_dict(orient="records"): gpu_users_num = len(row["usernames"]) for username in row["usernames"]: new_row = row.copy() new_row["count"] = 1 / gpu_users_num new_row["username"] = username new_df.append(new_row) df = pd.DataFrame(new_df) return df def plot_gpus(): ### Load Data dfs = datasets.load_dataset("pluslab/PLUS_Lab_GPUs_Data", data_files="gpus.csv", download_mode='force_redownload')["train"].to_pandas() dfs = dfs.drop(columns=["Unnamed: 0"]) dfs = dfs.fillna("FREE") dfs_plot = split_multi_users(dfs) fig = px.bar( dfs_plot, x="count", y="server", color="username", title=f"Last Updated {min(dfs['timestamp'])}", color_discrete_map={ "FREE": "black", }, text=dfs_plot['username'].astype(str) + "
" + dfs_plot['device'].astype(str), ) fig.update_layout( yaxis={'categoryorder': 'array', 'categoryarray': dfs_plot["server"].unique()[::-1]}, barcornerradius=5, ) fig.update_traces(textposition='inside', insidetextanchor='middle') # print(dfs_plot) return fig, dfs ##### DISK PLOT ##### def _pick_col(df, candidates): norm = {c.strip().lower(): c for c in df.columns} for cand in candidates: cand = cand.strip().lower() if cand in norm: return norm[cand] return None def _kblocks_to_tib(kblocks): # shown as "TB" per your convention return kblocks / (1024**3) def _kblocks_to_gib(kblocks): # shown as "GB" return kblocks / (1024**2) def plot_disks(alert_threshold_pct=99.0): df = datasets.load_dataset( "pluslab/PLUS_Lab_GPUs_Data", data_files="disks.csv", download_mode="force_redownload", )["train"].to_pandas() if "Unnamed: 0" in df.columns: df = df.drop(columns=["Unnamed: 0"]) df = pd.concat([df[df['Mounted'] != '/data2'], df[df['Mounted'] == '/data2'].drop_duplicates(subset=['Mounted'])]) # Keep one of /data2 server_col = _pick_col(df, ["server"]) fs_col = _pick_col(df, ["filesystem"]) blocks_col = _pick_col(df, ["1k-blocks", "1k blocks", "blocks"]) used_col = _pick_col(df, ["used"]) avail_col = _pick_col(df, ["available", "avail"]) mount_col = _pick_col(df, ["mounted", "mounted on", "mount", "mountpoint"]) required = [server_col, fs_col, blocks_col, used_col, avail_col] if any(c is None for c in required): raise ValueError(f"Missing required columns. Found: {list(df.columns)}") for c in [blocks_col, used_col, avail_col]: df[c] = pd.to_numeric(df[c], errors="coerce") # Label if mount_col is not None: df["Label"] = df[server_col].astype(str) + " • " + df[mount_col].astype(str) else: df["Label"] = df[server_col].astype(str) + " • " + df[fs_col].astype(str) # Totals & pct df["Total_kb"] = df[used_col] + df[avail_col] df["Used_pct"] = (df[used_col] / df["Total_kb"]) * 100.0 df["Used_pct"] = df["Used_pct"].clip(0, 100) df["Avail_pct"] = (100.0 - df["Used_pct"]).clip(0, 100) # Sizes df["Used_TB"] = _kblocks_to_tib(df[used_col]) df["Total_TB"] = _kblocks_to_tib(df["Total_kb"]) df["Avail_GB"] = _kblocks_to_gib(df[avail_col]) # <-- GB for hovers # Alerts df["ALERT"] = df["Used_pct"] > alert_threshold_pct # Sort # df = df.sort_values("Total_kb", ascending=False).reset_index(drop=True) df = df.sort_values("Mounted", ascending=False).reset_index(drop=True) y_labels = np.where(df["ALERT"].to_numpy(), "⚠ " + df["Label"], df["Label"]) used_text = [f"{u:.2f} TB ({p:.0f}%)" for u, p in zip(df["Used_TB"], df["Used_pct"])] total_annot = [f"{t:.2f} TB" for t in df["Total_TB"]] avail_gb_0 = [f"{g:.0f} GB" for g in df["Avail_GB"]] # Colors COLOR_TOTAL = "#CBD5E1" COLOR_USED = "#2563EB" COLOR_FREE = "#94A3B8" COLOR_ALERT = "#F59E0B" used_colors = np.where(df["ALERT"].to_numpy(), COLOR_ALERT, COLOR_USED) fig = go.Figure() # Gray background hover: Available in GB (0dp) fig.add_trace( go.Bar( y=y_labels, x=[100] * len(df), base=0, orientation="h", marker=dict(color=COLOR_TOTAL), opacity=0.40, hovertemplate="%{y}
Available: %{customdata}
", customdata=avail_gb_0, showlegend=False, ) ) # Used hover: Available in GB (0dp) too fig.add_trace( go.Bar( y=y_labels, x=df["Used_pct"], base=0, name=f"Used (>{alert_threshold_pct:.0f}% highlighted)", orientation="h", marker=dict(color=used_colors), text=used_text, textposition="inside", insidetextanchor="middle", hovertemplate=( "%{y}
" "Used: %{customdata[0]} (%{customdata[3]:.2f}%)
" "Available: %{customdata[1]}
" "Total: %{customdata[2]}
" "" ), customdata=np.stack( [ df["Used_TB"].map(lambda v: f"{v:.2f} TB").to_numpy(), df["Avail_GB"].map(lambda v: f"{v:.0f} GB").to_numpy(), # <-- changed df["Total_TB"].map(lambda v: f"{v:.2f} TB").to_numpy(), df["Used_pct"].to_numpy(), ], axis=1, ), ) ) # Available hover: Available in GB (0dp) fig.add_trace( go.Bar( y=y_labels, x=df["Avail_pct"], base=df["Used_pct"], name="Available", orientation="h", marker=dict(color=COLOR_FREE), hovertemplate=( "%{y}
" "Available: %{customdata[0]}
" "Used: %{customdata[1]}
" "Total: %{customdata[2]}
" "" ), customdata=np.stack( [ df["Avail_GB"].map(lambda v: f"{v:.0f} GB").to_numpy(), # <-- changed df["Used_TB"].map(lambda v: f"{v:.2f} TB").to_numpy(), df["Total_TB"].map(lambda v: f"{v:.2f} TB").to_numpy(), ], axis=1, ), ) ) # Total annotation (TB, 2dp) for y, ttxt, is_alert in zip(y_labels, total_annot, df["ALERT"].to_numpy()): fig.add_annotation( x=100, y=y, text=ttxt, showarrow=False, xanchor="left", yanchor="middle", xshift=6, font=dict(color=("#B45309" if is_alert else "#334155")), ) fig.update_layout( barmode="overlay", template="plotly_white", title=f"Disk usage (alerts: Used > {alert_threshold_pct:.0f}%)", xaxis=dict(range=[0, 100], ticksuffix="%", title="Percent of total"), yaxis_title="", height=max(420, 28 * len(df)), margin=dict(l=280, r=120, t=60, b=40), legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), barcornerradius=4, ) fig.update_yaxes(autorange="reversed") return fig, df ##### PLOT ALL ##### def plot_figs(): fig_gpus, df_gpus = plot_gpus() fig_disks, df_disks = plot_disks() return fig_gpus, fig_disks, df_gpus, df_disks demo = gr.Interface( fn=plot_figs, inputs = [ ], outputs = [ gr.Plot(label="GPU Status", elem_classes="plotcss"), gr.Plot(label="Disk Status", elem_classes="plotcss"), gr.Dataframe(label="GPU Status Details"), gr.Dataframe(label="Disk Status Details"), ], live=True, flagging_options=[], css=".plotcss {max-width: 820px !important;}", delete_cache=(1, 1) ) if __name__ == "__main__": demo.launch(debug=False)