Spaces:
Sleeping
Sleeping
| """Plot helpers used by the Shiny app. | |
| The app is responsible for data filtering and column selection; these helpers only | |
| turn a prepared DataFrame into Plotly figures. If the input DataFrame is empty, | |
| the helpers return an empty figure to keep the UI responsive. | |
| """ | |
| from __future__ import annotations | |
| from typing import Sequence | |
| import pandas as pd | |
| import plotly.express as px | |
| from plotly.graph_objects import Figure | |
| def format_metric_value(value: float) -> str: | |
| if pd.isna(value): | |
| return "N/A" | |
| if 0 <= value <= 1: | |
| return f"{value:.0%}" | |
| return f"{value:.2f}" | |
| def format_raw_value(value: float) -> str: | |
| if pd.isna(value): | |
| return "N/A" | |
| return f"{value:.3f}" | |
| def build_trend_plot( | |
| df: pd.DataFrame, | |
| *, | |
| metric_col: str, | |
| metric_label: str, | |
| title: str, | |
| order: Sequence[str] = (), | |
| ) -> Figure: | |
| """Line chart: metric over time for each occupation label.""" | |
| if df.empty: | |
| return px.line() | |
| fig = px.line( | |
| df, | |
| x="year", | |
| y=metric_col, | |
| color="label", | |
| markers=True, | |
| category_orders={"label": list(order)}, | |
| labels={ | |
| "label": "Occupation", | |
| "year": "Year", | |
| metric_col: metric_label, | |
| }, | |
| ) | |
| fig.update_layout( | |
| hovermode="x unified", | |
| title=title, | |
| xaxis_showgrid=True, | |
| yaxis_showgrid=True, | |
| template="plotly_white", | |
| ) | |
| return fig | |
| def build_bar_plot( | |
| df: pd.DataFrame, | |
| *, | |
| percentile_col: str, | |
| raw_col: str, | |
| metric_label: str, | |
| title: str, | |
| order: Sequence[str] = (), | |
| ) -> Figure: | |
| """Horizontal bar chart: percentile ranks for the latest year.""" | |
| if df.empty: | |
| return px.bar() | |
| # Always compare within the latest year available in the filtered data. | |
| latest = df["year"].max() | |
| latest_df = df[df["year"] == latest] | |
| order_list = list(order) | |
| if order_list: | |
| latest_df = latest_df.set_index("label").loc[order_list].reset_index() | |
| latest_df = latest_df.copy() | |
| latest_df["bar_label"] = latest_df.apply( | |
| lambda row: f"{format_raw_value(row[raw_col])} | {format_metric_value(row[percentile_col])}", | |
| axis=1, | |
| ) | |
| fig = px.bar( | |
| latest_df, | |
| x=percentile_col, | |
| y="label", | |
| orientation="h", | |
| text="bar_label", | |
| category_orders={"label": order_list}, | |
| labels={ | |
| "label": "Occupation", | |
| percentile_col: f"{metric_label} (percentile rank)", | |
| }, | |
| ) | |
| fig.update_layout( | |
| title=title, | |
| xaxis_showgrid=True, | |
| yaxis_showgrid=True, | |
| template="plotly_white", | |
| ) | |
| fig.update_traces(textposition="inside") | |
| fig.update_xaxes(range=[0, 1], tickformat=".0%") | |
| return fig | |