Spaces:
Sleeping
Sleeping
Download builders/chart_builder.py from Shivam4096/Financial2API: direct link, hf CLI and curl.
- Browser
- Download file 4.39 kB
-
https://huggingface.co/spaces/Shivam4096/Financial2API/resolve/main/builders/chart_builder.py
- Command line
-
hf download hf://spaces/Shivam4096/Financial2API/builders/chart_builder.py
-
curl -L -o chart_builder.py https://huggingface.co/spaces/Shivam4096/Financial2API/resolve/main/builders/chart_builder.py
4.39 kB
| import io | |
| import matplotlib | |
| matplotlib.use('Agg') # Headless mode | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| import pandas as pd | |
| import numpy as np | |
| # Set seaborn theme for professional looks | |
| sns.set_theme(style="whitegrid", palette="muted") | |
| plt.rcParams['font.family'] = 'sans-serif' | |
| plt.rcParams['font.sans-serif'] = ['Arial', 'Helvetica', 'DejaVu Sans'] | |
| def _create_bytes_img(fig): | |
| buf = io.BytesIO() | |
| fig.savefig(buf, format='png', bbox_inches='tight', dpi=150) | |
| buf.seek(0) | |
| plt.close(fig) | |
| return buf | |
| def generate_revenue_net_income_chart(data: dict) -> io.BytesIO: | |
| years = data.get("years", []) | |
| if not years: | |
| return None | |
| rev = data.get("income_statement", {}).get("revenue", []) | |
| ni = data.get("income_statement", {}).get("net_income", []) | |
| # Pad to match years | |
| rev = (rev + [0]*len(years))[:len(years)] | |
| ni = (ni + [0]*len(years))[:len(years)] | |
| # Fill None with 0 for plotting | |
| rev = [r if r is not None else 0 for r in rev] | |
| ni = [n if n is not None else 0 for n in ni] | |
| fig, ax1 = plt.subplots(figsize=(8, 4.5)) | |
| x = np.arange(len(years)) | |
| width = 0.35 | |
| ax1.bar(x - width/2, rev, width, label='Revenue', color='#1F4E78') | |
| ax1.bar(x + width/2, ni, width, label='Net Income', color='#549E39') | |
| ax1.set_ylabel(f"Amount ({data.get('currency', 'INR')} {data.get('units_label', 'Crores')})") | |
| ax1.set_title("Revenue & Net Income Trend") | |
| ax1.set_xticks(x) | |
| ax1.set_xticklabels(years) | |
| ax1.legend() | |
| return _create_bytes_img(fig) | |
| def generate_margins_chart(data: dict) -> io.BytesIO: | |
| years = data.get("years", []) | |
| if not years: | |
| return None | |
| ratios = data.get("ratios", {}) | |
| gm = ratios.get("gross_margin", []) | |
| om = ratios.get("operating_margin", []) | |
| nm = ratios.get("net_margin", []) | |
| gm = [(g*100) if g is not None else 0 for g in (gm + [0]*len(years))[:len(years)]] | |
| om = [(o*100) if o is not None else 0 for o in (om + [0]*len(years))[:len(years)]] | |
| nm = [(n*100) if n is not None else 0 for n in (nm + [0]*len(years))[:len(years)]] | |
| fig, ax = plt.subplots(figsize=(8, 4.5)) | |
| x = np.arange(len(years)) | |
| ax.plot(x, gm, marker='o', linewidth=2, label='Gross Margin %', color='#1F4E78') | |
| ax.plot(x, om, marker='s', linewidth=2, label='Operating Margin %', color='#455F51') | |
| ax.plot(x, nm, marker='^', linewidth=2, label='Net Margin %', color='#549E39') | |
| ax.set_ylabel("Margin (%)") | |
| ax.set_title("Profitability Margins Trend") | |
| ax.set_xticks(x) | |
| ax.set_xticklabels(years) | |
| # Add value labels | |
| for i in range(len(years)): | |
| if nm[i] != 0: | |
| ax.annotate(f"{nm[i]:.1f}%", (x[i], nm[i]), textcoords="offset points", xytext=(0,10), ha='center') | |
| ax.legend() | |
| return _create_bytes_img(fig) | |
| def generate_cash_flow_chart(data: dict) -> io.BytesIO: | |
| years = data.get("years", []) | |
| if not years: | |
| return None | |
| cf = data.get("cash_flow", {}) | |
| ocf = cf.get("cash_from_operations", []) | |
| capex = cf.get("capex", []) | |
| fcf = cf.get("free_cash_flow", []) | |
| ocf = [o if o is not None else 0 for o in (ocf + [0]*len(years))[:len(years)]] | |
| # Capex is usually negative, let's plot absolute value for magnitude comparison | |
| capex = [abs(c) if c is not None else 0 for c in (capex + [0]*len(years))[:len(years)]] | |
| fcf = [f if f is not None else 0 for f in (fcf + [0]*len(years))[:len(years)]] | |
| fig, ax = plt.subplots(figsize=(8, 4.5)) | |
| x = np.arange(len(years)) | |
| width = 0.25 | |
| ax.bar(x - width, ocf, width, label='Operating Cash Flow', color='#1F4E78') | |
| ax.bar(x, capex, width, label='CAPEX (Abs)', color='#C00000') | |
| ax.bar(x + width, fcf, width, label='Free Cash Flow', color='#549E39') | |
| ax.set_ylabel(f"Amount ({data.get('currency', 'INR')} {data.get('units_label', 'Crores')})") | |
| ax.set_title("Cash Flow & CAPEX Overview") | |
| ax.set_xticks(x) | |
| ax.set_xticklabels(years) | |
| ax.legend() | |
| return _create_bytes_img(fig) | |
| def generate_all_charts(data: dict) -> dict: | |
| """Returns a dict mapping chart names to BytesIO pngs.""" | |
| return { | |
| "revenue_net_income": generate_revenue_net_income_chart(data), | |
| "margins": generate_margins_chart(data), | |
| "cash_flow": generate_cash_flow_chart(data) | |
| } | |