Spaces:
Sleeping
Sleeping
File size: 2,799 Bytes
eec71cb f6d385f eec71cb f6d385f eec71cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | """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
|