| | """UI component functions for the financial dashboard.""" |
| |
|
| | import streamlit as st |
| | import pandas as pd |
| | import sys |
| | import os |
| |
|
| | |
| | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
| |
|
| | from utils.formatters import format_financial_value |
| | from components.data_sources import get_profitability_metrics |
| |
|
| |
|
| | def display_price_metrics(metrics: dict): |
| | """Display key price metrics in columns.""" |
| | st.markdown('<div class="section-title">π Price Metrics</div>', unsafe_allow_html=True) |
| |
|
| | col1, col2, col3, col4 = st.columns(4) |
| |
|
| | with col1: |
| | st.metric("Current Price", f"${metrics['current_price']:.2f}", |
| | f"{metrics['price_change']:+.2f}", delta_color="normal") |
| |
|
| | with col2: |
| | st.metric("Day Change %", f"{metrics['price_change_pct']:+.2f}%", |
| | None, delta_color="normal") |
| |
|
| | with col3: |
| | st.metric("52W High", f"${metrics['high_52w']:.2f}") |
| |
|
| | with col4: |
| | st.metric("52W Low", f"${metrics['low_52w']:.2f}") |
| |
|
| |
|
| | def display_company_info(profile_info): |
| | """Display company information.""" |
| | st.markdown('<div class="section-title">π Company Information</div>', unsafe_allow_html=True) |
| |
|
| | if profile_info: |
| | info_col1, info_col2 = st.columns(2) |
| | with info_col1: |
| | st.write(f"**Company Name:** {getattr(profile_info, 'name', 'N/A')}") |
| | st.write(f"**Sector:** {getattr(profile_info, 'sector', 'N/A')}") |
| | st.write(f"**Industry:** {getattr(profile_info, 'industry', 'N/A')}") |
| |
|
| | with info_col2: |
| | st.write(f"**Country:** {getattr(profile_info, 'country', 'N/A')}") |
| | st.write(f"**Exchange:** {getattr(profile_info, 'exchange', 'N/A')}") |
| | st.write(f"**Website:** {getattr(profile_info, 'website', 'N/A')}") |
| |
|
| |
|
| | def display_financial_metrics(income_stmt: pd.DataFrame): |
| | """Display financial metrics from income statement.""" |
| | st.markdown('<div class="section-title">π° Financial Metrics</div>', unsafe_allow_html=True) |
| |
|
| | latest_income = income_stmt.iloc[0] if len(income_stmt) > 0 else None |
| |
|
| | if latest_income is not None: |
| | |
| | fin_col1, fin_col2, fin_col3, fin_col4 = st.columns(4) |
| |
|
| | with fin_col1: |
| | revenue = latest_income.get('total_revenue', 0) |
| | if pd.notna(revenue) and revenue > 0: |
| | st.metric("Total Revenue", format_financial_value(revenue)) |
| | else: |
| | st.metric("Total Revenue", "N/A") |
| |
|
| | with fin_col2: |
| | net_income = latest_income.get('net_income', 0) |
| | if pd.notna(net_income) and net_income > 0: |
| | st.metric("Net Income", format_financial_value(net_income)) |
| | else: |
| | st.metric("Net Income", "N/A") |
| |
|
| | with fin_col3: |
| | gross_profit = latest_income.get('gross_profit', 0) |
| | if pd.notna(gross_profit) and gross_profit > 0: |
| | st.metric("Gross Profit", format_financial_value(gross_profit)) |
| | else: |
| | st.metric("Gross Profit", "N/A") |
| |
|
| | with fin_col4: |
| | operating_income = latest_income.get('operating_income', 0) |
| | if pd.notna(operating_income) and operating_income > 0: |
| | st.metric("Operating Income", format_financial_value(operating_income)) |
| | else: |
| | st.metric("Operating Income", "N/A") |
| |
|
| | |
| | fin_col5, fin_col6, fin_col7, fin_col8 = st.columns(4) |
| |
|
| | with fin_col5: |
| | eps = latest_income.get('diluted_earnings_per_share', 0) |
| | if pd.notna(eps): |
| | st.metric("EPS (Diluted)", f"${eps:.2f}") |
| | else: |
| | st.metric("EPS (Diluted)", "N/A") |
| |
|
| | with fin_col6: |
| | ebitda = latest_income.get('ebitda', 0) |
| | if pd.notna(ebitda) and ebitda > 0: |
| | st.metric("EBITDA", format_financial_value(ebitda)) |
| | else: |
| | st.metric("EBITDA", "N/A") |
| |
|
| | with fin_col7: |
| | cogs = latest_income.get('cost_of_revenue', 0) |
| | if pd.notna(cogs) and cogs > 0: |
| | st.metric("Cost of Revenue", format_financial_value(cogs)) |
| | else: |
| | st.metric("Cost of Revenue", "N/A") |
| |
|
| | with fin_col8: |
| | rd_expense = latest_income.get('research_and_development_expense', 0) |
| | if pd.notna(rd_expense) and rd_expense > 0: |
| | st.metric("R&D Expense", format_financial_value(rd_expense)) |
| | else: |
| | st.metric("R&D Expense", "N/A") |
| |
|
| |
|
| | def display_income_statement(income_stmt: pd.DataFrame): |
| | """Display formatted income statement table.""" |
| | st.markdown("### Income Statement") |
| |
|
| | if not income_stmt.empty: |
| | display_columns = [ |
| | 'period_ending', |
| | 'total_revenue', |
| | 'cost_of_revenue', |
| | 'gross_profit', |
| | 'operating_income', |
| | 'net_income', |
| | 'diluted_earnings_per_share', |
| | 'ebitda' |
| | ] |
| |
|
| | available_cols = [col for col in display_columns if col in income_stmt.columns] |
| | financial_display = income_stmt[available_cols].copy() |
| |
|
| | for col in financial_display.columns: |
| | if col != 'period_ending': |
| | financial_display[col] = financial_display[col].apply( |
| | lambda x: format_financial_value(x) |
| | ) |
| |
|
| | st.dataframe(financial_display, use_container_width=True, hide_index=True) |
| |
|
| |
|
| | def display_profitability_metrics(income_stmt: pd.DataFrame): |
| | """Display profitability metrics.""" |
| | st.markdown("### Profitability Metrics") |
| |
|
| | prof_col1, prof_col2 = st.columns(2) |
| | latest_data = income_stmt.iloc[0] |
| | metrics = get_profitability_metrics(latest_data) |
| |
|
| | with prof_col1: |
| | if "gross_margin" in metrics: |
| | st.metric("Gross Margin", f"{metrics['gross_margin']:.2f}%") |
| | if "net_margin" in metrics: |
| | st.metric("Net Profit Margin", f"{metrics['net_margin']:.2f}%") |
| |
|
| | with prof_col2: |
| | if "operating_margin" in metrics: |
| | st.metric("Operating Margin", f"{metrics['operating_margin']:.2f}%") |
| |
|
| | if len(income_stmt) > 1: |
| | prev_revenue = income_stmt.iloc[1].get('total_revenue', 0) |
| | total_rev = latest_data.get('total_revenue', 0) |
| | if prev_revenue and prev_revenue > 0: |
| | revenue_growth = ((total_rev - prev_revenue) / prev_revenue) * 100 |
| | st.metric("Revenue Growth (YoY)", f"{revenue_growth:+.2f}%") |
| |
|