| """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}%") |
|
|