trading-tools / web /components /dashboard_grid.py
Deploy Bot
Deploy Trading Analysis Platform to HuggingFace Spaces
a1bf219
"""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