Spaces:
Sleeping
Sleeping
| """Gradio dashboard grid component for valuation charts. | |
| This module creates a responsive grid layout for displaying 8-9 fundamental charts | |
| using Gradio's Row and Column components with min_width for automatic wrapping. | |
| """ | |
| import logging | |
| from pathlib import Path | |
| from typing import List, Optional | |
| import gradio as gr | |
| from config.models import ValuationDashboard | |
| logger = logging.getLogger(__name__) | |
| class DashboardComponent: | |
| """Responsive dashboard grid for fundamental charts.""" | |
| def __init__(self): | |
| """Initialize dashboard component.""" | |
| logger.info("DashboardComponent initialized") | |
| def create_desktop_grid(self) -> List[gr.Image]: | |
| """Create 2x4 desktop grid layout with responsive wrapping. | |
| Uses gr.Row() with gr.Column(scale=1, min_width=300) per research.md R2 | |
| to enable automatic wrapping on smaller screens. | |
| Returns: | |
| List of gr.Image components for chart display | |
| """ | |
| chart_components = [] | |
| # Row 1: P/E and P/B | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| pe_chart = gr.Image( | |
| label="P/E Ratio", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(pe_chart) | |
| with gr.Column(scale=1, min_width=300): | |
| pb_chart = gr.Image( | |
| label="P/B Ratio", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(pb_chart) | |
| # Row 2: P/S and EV/EBITDA | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| ps_chart = gr.Image( | |
| label="P/S Ratio", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(ps_chart) | |
| with gr.Column(scale=1, min_width=300): | |
| ev_chart = gr.Image( | |
| label="EV/EBITDA", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(ev_chart) | |
| # Row 3: Profit Margins and ROE | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| margins_chart = gr.Image( | |
| label="Profit Margins", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(margins_chart) | |
| with gr.Column(scale=1, min_width=300): | |
| roe_chart = gr.Image( | |
| label="Return on Equity", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(roe_chart) | |
| # Row 4: Growth and FCF | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| growth_chart = gr.Image( | |
| label="Revenue & Earnings Growth", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(growth_chart) | |
| with gr.Column(scale=1, min_width=300): | |
| fcf_chart = gr.Image( | |
| label="Free Cash Flow", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(fcf_chart) | |
| # Row 5: Debt-to-Equity (centered in single column) | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| debt_chart = gr.Image( | |
| label="Debt-to-Equity", | |
| type="filepath", | |
| show_label=True, | |
| ) | |
| chart_components.append(debt_chart) | |
| # Empty column for balance | |
| with gr.Column(scale=1, min_width=300): | |
| pass | |
| logger.info(f"Created desktop grid with {len(chart_components)} chart slots") | |
| return chart_components | |
| def create_mobile_grid(self) -> List[gr.Image]: | |
| """Create stacked mobile layout (1 column, 8+ rows). | |
| Returns: | |
| List of gr.Image components for chart display | |
| """ | |
| chart_components = [] | |
| with gr.Accordion("📊 Valuation Dashboard", open=True): | |
| # All charts stacked vertically | |
| pe_chart = gr.Image(label="P/E Ratio", type="filepath") | |
| chart_components.append(pe_chart) | |
| pb_chart = gr.Image(label="P/B Ratio", type="filepath") | |
| chart_components.append(pb_chart) | |
| ps_chart = gr.Image(label="P/S Ratio", type="filepath") | |
| chart_components.append(ps_chart) | |
| ev_chart = gr.Image(label="EV/EBITDA", type="filepath") | |
| chart_components.append(ev_chart) | |
| margins_chart = gr.Image(label="Profit Margins", type="filepath") | |
| chart_components.append(margins_chart) | |
| roe_chart = gr.Image(label="Return on Equity", type="filepath") | |
| chart_components.append(roe_chart) | |
| growth_chart = gr.Image(label="Revenue & Earnings Growth", type="filepath") | |
| chart_components.append(growth_chart) | |
| fcf_chart = gr.Image(label="Free Cash Flow", type="filepath") | |
| chart_components.append(fcf_chart) | |
| debt_chart = gr.Image(label="Debt-to-Equity", type="filepath") | |
| chart_components.append(debt_chart) | |
| return chart_components | |
| def extract_chart_paths(dashboard: ValuationDashboard) -> List[Optional[str]]: | |
| """Extract file paths from dashboard charts in display order. | |
| Args: | |
| dashboard: Generated ValuationDashboard object | |
| Returns: | |
| List of 9 file paths (or None for unavailable charts) | |
| """ | |
| from config.models import ChartType | |
| chart_order = [ | |
| ChartType.PE_RATIO, | |
| ChartType.PB_RATIO, | |
| ChartType.PS_RATIO, | |
| ChartType.EV_EBITDA, | |
| ChartType.PROFIT_MARGINS, | |
| ChartType.ROE, | |
| ChartType.REVENUE_EARNINGS_GROWTH, | |
| ChartType.FREE_CASH_FLOW, | |
| ChartType.DEBT_TO_EQUITY, | |
| ] | |
| paths = [] | |
| for chart_type in chart_order: | |
| chart = next((c for c in dashboard.charts if c.chart_type == chart_type), None) | |
| if chart: | |
| # Find the actual file path (this is a placeholder - need to track paths) | |
| # For now, return None as charts don't store file paths yet | |
| paths.append(None) | |
| else: | |
| paths.append(None) | |
| return paths | |