My_Agent / sheet_tool.py
Pawan Patil
Add matplotlib dependency and fix pivot column flattening
6cf5d7d
# sheet_tool.py
from google.oauth2.service_account import Credentials
import gspread
import pandas as pd
import matplotlib.pyplot as plt
import io
import base64
from typing import Tuple
# CONFIG - change these
CREDENTIALS_FILE = "credentials.json" # path to your service account JSON
SHEET_ID = "1nOekWGmPsjoHj9T-MFjlNGSFyKPRogVbEjFNRxGgxuM" # replace with your sheet id
WORKSHEET_INDEX = 0 # first sheet
SCOPES = [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive",
]
def authorize_gs():
creds = Credentials.from_service_account_file(CREDENTIALS_FILE, scopes=SCOPES)
client = gspread.authorize(creds)
return client
def fetch_sheet_as_df(sheet_id: str = SHEET_ID, worksheet_index: int = WORKSHEET_INDEX) -> pd.DataFrame:
client = authorize_gs()
sh = client.open_by_key(sheet_id)
worksheet = sh.get_worksheet(worksheet_index)
data = worksheet.get_all_values()
if not data:
return pd.DataFrame()
df = pd.DataFrame(data[1:], columns=data[0])
# try to convert numeric columns where possible
for col in df.columns:
df[col] = pd.to_numeric(df[col], errors="ignore")
return df
def create_pivot(df: pd.DataFrame, index: list, columns: list, values: list, aggfunc: str = "sum") -> pd.DataFrame:
if df.empty:
return pd.DataFrame()
# Create pivot table
pivot = pd.pivot_table(df, index=index, columns=columns, values=values, aggfunc=aggfunc, fill_value=0)
# Flatten multi-index columns for readability
pivot = pivot.reset_index()
pivot.columns = [
" ".join(map(str, c)).strip() if isinstance(c, tuple) else str(c).strip()
for c in pivot.columns
]
return pivot
def summary_stats(df: pd.DataFrame, numeric_only: bool = True) -> pd.DataFrame:
if df.empty:
return pd.DataFrame()
return df.describe(include="all") if not numeric_only else df.describe()
def plot_dataframe(df: pd.DataFrame, kind: str = "bar", x: str = None, y: list = None, title: str = None, figsize=(8,5)) -> str:
"""
Creates a matplotlib plot and returns a base64 PNG data URI.
"""
if df.empty:
raise ValueError("DataFrame is empty")
plt.close('all')
fig, ax = plt.subplots(figsize=figsize)
if kind == "bar":
if x is None or y is None:
df.plot(kind="bar", ax=ax)
else:
df.plot(kind="bar", x=x, y=y, ax=ax)
elif kind == "line":
df.plot(kind="line", x=x, y=y, ax=ax)
elif kind == "pie":
df.set_index(x)[y].plot(kind="pie", ax=ax, autopct='%1.1f%%')
else:
df.plot(kind=kind, x=x, y=y, ax=ax)
if title:
ax.set_title(title)
ax.grid(True)
buf = io.BytesIO()
fig.tight_layout()
fig.savefig(buf, format="png")
buf.seek(0)
b64 = base64.b64encode(buf.read()).decode("utf-8")
return "data:image/png;base64," + b64
def df_to_csv_bytes(df: pd.DataFrame) -> bytes:
return df.to_csv(index=False).encode("utf-8")