"""Dash elements.""" import pandas as pd import plotly.graph_objs as go from cachetools import TTLCache, cached from dash import dash_table, dcc, html from sqlalchemy.engine import Engine from sqlalchemy.orm import Session from aki_prj23_transparenzregister.ui.archive.networkx_dash import networkx_component from aki_prj23_transparenzregister.utils.sql import entities COLORS = { "light": "#edefef", "lavender-blush": "#f3e8ee", "ash-gray": "#bacdb0", "cambridge-blue": "#729b79", "paynes-gray": "#475b63", "raisin-black": "#2e2c2f", } def get_company_data(session: Session) -> pd.DataFrame: """Creates a session to the database and get's all available company data. Args: session: A session connecting to the database. Returns: A dataframe containing all available company data including the corresponding district court. """ query_company = session.query(entities.Company, entities.DistrictCourt.name).join( entities.DistrictCourt ) engine = session.bind if not isinstance(engine, Engine): raise TypeError return pd.read_sql(str(query_company), engine, index_col="company_id") def get_finance_data(session: Session) -> pd.DataFrame: """Collects all available company data. Args: session: A session connecting to the database. Returns: A dataframe containing all financial data of all companies. """ query_finance = session.query( entities.AnnualFinanceStatement, entities.Company.name, entities.Company.id ).join(entities.Company) engine = session.bind if not isinstance(engine, Engine): raise TypeError return pd.read_sql(str(query_finance), engine) @cached( # type: ignore cache=TTLCache(maxsize=1, ttl=300), key=lambda session: 0 if session is None else str(session.bind), ) def get_options(session: Session | None) -> dict[int, str]: """Collects the search options for the companies. Args: session: A session connecting to the database. Returns: A dict containing the company id as key and its name. """ if not session: return {} return get_company_data(session)["company_name"].to_dict() def create_header(options: dict) -> html: """Creates header for dashboard. Args: options: A dictionary with company names and ids for the dropdown. Returns: The html div to create the page's header including the name of the page and the search for companies. """ return html.Div( className="header-wrapper", children=[ html.Div( className="header-title", children=[ html.I( id="home-button", n_clicks=0, className="bi-house-door-fill", ), html.H1( className="header-title-text", children="Transparenzregister für Kapitalgesellschaften", ), ], ), html.Div( className="header-search", children=[ html.Div( className="header-search-dropdown", children=[ dcc.Dropdown( id="select_company", options=[ {"label": o, "value": key} for key, o in options.items() ], placeholder="Suche nach Unternehmen oder Person", ), ], ), ], ), ], ) def create_company_header(selected_company_name: str) -> html: """Create company header based on selected company. Args: selected_company_name: The company name that has been chosen in the dropdown. Returns: The html div to create the company header. """ return html.Div( className="company-header", children=[ html.H1( className="company-header-title", id="id-company-header-title", children=selected_company_name, ), ], ) def create_company_stats(selected_company_data: pd.Series) -> html: """Create company stats. Args: selected_company_data: A series containing all company information of the selected company. Returns: The html div to create the company stats table and the three small widgets. """ company_data = { "col1": ["Unternehmen", "Straße", "Stadt"], "col2": [ selected_company_data["company_name"], selected_company_data["company_street"], str( selected_company_data["company_zip_code"] + " " + selected_company_data["company_city"] ), ], "col3": ["Branche", "Amtsgericht", "Gründungsjahr"], "col4": [ selected_company_data["company_sector"], selected_company_data["district_court_name"], "xxx", ], } df_company_data = pd.DataFrame(data=company_data) return html.Div( className="stats-wrapper", children=[ html.Div( className="widget-large", children=[ html.H3( className="widget-title", children="Stammdaten", ), dash_table.DataTable( df_company_data.to_dict("records"), [{"name": i, "id": i} for i in df_company_data.columns], style_table={ "width": "90%", "marginLeft": "auto", "marginRight": "auto", "paddingBottom": "20px", "color": COLORS["raisin-black"], }, # hide header of table css=[ { "selector": "tr:first-child", "rule": "display: none", }, ], style_cell={"textAlign": "center"}, style_cell_conditional=[ {"if": {"column_id": c}, "fontWeight": "bold"} for c in ["col1", "col3"] ], style_data={ "whiteSpace": "normal", "height": "auto", }, ), ], ), html.Div( className="widget-small", children=[ html.H3( className="widget-title", children="Stimmung", ), ], ), html.Div( className="widget-small", children=[ html.H3( className="widget-title", children="Aktienkurs", ), html.H1( className="widget-content", children="123", ), ], ), html.Div( className="widget-small", children=[ html.H3( className="widget-title", children="Umsatz", ), html.H1( className="widget-content", children="1234", ), ], ), ], ) def create_tabs(selected_company_id: int, selected_finance_df: pd.DataFrame) -> html: """Create tabs for more company information. Args: selected_company_id: Id of the chosen company in the dropdown. selected_finance_df: A dataframe containing all available finance information of the companies. Returns: The html div to create the tabs of the company page. """ return html.Div( className="tabs", children=[ dcc.Tabs( id="tabs", value="tab-1", children=[ dcc.Tab( label="Kennzahlen", value="tab-1", className="tab-style", selected_className="selected-tab-style", children=[kennzahlen_layout(selected_finance_df)], ), dcc.Tab( label="Beteiligte Personen", value="tab-2", className="tab-style", selected_className="selected-tab-style", ), dcc.Tab( label="Stimmung", value="tab-3", className="tab-style", selected_className="selected-tab-style", ), dcc.Tab( label="Verflechtungen", value="tab-4", className="tab-style", selected_className="selected-tab-style", children=[network_layout(selected_company_id)], ), ], ), html.Div(id="tabs-example-content-1"), ], ) def kennzahlen_layout(selected_finance_df: pd.DataFrame) -> html: """Create metrics tab. Args: selected_company_id: Id of the chosen company in the dropdown. selected_finance_df: A dataframe containing all available finance information of the companies. Returns: The html div to create the metrics tab of the company page. """ return html.Div( [ dcc.Graph( figure=financials_figure( selected_finance_df, "annual_finance_statement_ebit" ) ) ] ) def financials_figure(selected_finance_df: pd.DataFrame, metric: str) -> go.Figure: """Creates plotly line chart for a specific company and a metric. Args: selected_finance_df: A dataframe containing all finance information of the selected company. metric: The metric that should be visualized. Returns: A plotly figure showing the available metric data of the company. """ # create figure fig_line = go.Figure() # add trace for company 1 fig_line.add_trace( go.Scatter( x=selected_finance_df["annual_finance_statement_date"], y=selected_finance_df[metric], line_color=COLORS["raisin-black"], marker_color=COLORS["raisin-black"], ) ) # set title and labels fig_line.update_layout( title=metric, xaxis_title="Jahr", yaxis_title="in Mio.€", plot_bgcolor=COLORS["light"], ) return fig_line def network_layout(selected_company_id: int) -> html: """Create network tab. Args: selected_company_id: Id of the chosen company in the dropdown. Returns: The html div to create the network tab of the company page. """ return networkx_component(selected_company_id)