Files
datatools-dev/src/gui/pages/6_Outlier_Detector.py
Michael 904356f4e8 feat(gui): inline Help popover next to every tool's title
Adds a contextual Help button on each detail page, right of the title.
Clicking it opens a Streamlit popover with a one-shot how-to: when to
use, numbered steps, before→after examples, and an optional one-line
tip. Designed to be scannable — no paragraph prose.

Implementation:
- New ``render_tool_header(tool_id)`` helper in components replaces the
  bare ``st.title(...) + st.caption(...)`` block on each of the 11 tool
  pages. Title in the wide column, popover in a narrow right column;
  caption sits on its own line beneath.
- Help content is one markdown blob per tool stored in i18n under
  ``tools.<id>.help_md`` (en + es). Editors can tweak copy without
  touching Python.
- ``help.button_label`` and ``help.missing_body`` keys added to both
  packs for the popover trigger and the empty-tool fallback.

All 11 tool pages now use the same header pattern — including the
PDF Extractor and Reconciler which previously had hardcoded title/
caption pairs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 17:21:55 +00:00

100 lines
3.1 KiB
Python

"""DataTools Find Unusual Values — stub page."""
from __future__ import annotations
import sys
from pathlib import Path
import streamlit as st
_project_root = Path(__file__).resolve().parent.parent.parent.parent
if str(_project_root) not in sys.path:
sys.path.insert(0, str(_project_root))
from src.gui.components import (
back_to_home_link,
render_sticky_footer,
render_tool_header,
hide_streamlit_chrome,
require_feature_or_render_upgrade,
)
from src.i18n import t
from src.license import FeatureFlag
hide_streamlit_chrome()
render_sticky_footer()
back_to_home_link()
from src.audit import log_page_open
log_page_open("6_Outlier_Detector")
require_feature_or_render_upgrade(FeatureFlag.OUTLIER_DETECTOR)
# ---------------------------------------------------------------------------
# Header
# ---------------------------------------------------------------------------
render_tool_header("06_outlier_detector")
st.info("This tool is under development.")
# ---------------------------------------------------------------------------
# What this tool will do
# ---------------------------------------------------------------------------
st.markdown("""
**Features:**
- Z-score detection (configurable threshold)
- IQR (interquartile range) detection
- MAD (median absolute deviation) detection
- Domain-rule violations (e.g., age < 0, price > $1M)
- Visual outlier highlighting in data preview
- Handling: flag only, remove, cap/winsorize to bounds
""")
st.divider()
# ---------------------------------------------------------------------------
# File upload (functional)
# ---------------------------------------------------------------------------
uploaded = st.file_uploader(
"Import CSV or Excel file",
type=["csv", "tsv", "xlsx", "xls"],
help="Import a file to preview. Processing is not yet available.",
key="outlier_file_upload",
)
if uploaded is not None:
import pandas as pd
try:
if uploaded.name.endswith((".xlsx", ".xls")):
df = pd.read_excel(uploaded)
else:
df = pd.read_csv(uploaded)
st.subheader(f"Preview: {uploaded.name}")
st.caption(f"{len(df)} rows, {len(df.columns)} columns")
st.dataframe(df.head(10), width="stretch")
except Exception as e:
from src.core.errors import format_for_user
st.error(
f"**Could not read `{uploaded.name}`**\n\n"
f"```\n{format_for_user(e)}\n```"
)
# ---------------------------------------------------------------------------
# Placeholder options
# ---------------------------------------------------------------------------
st.subheader("Detection Method")
st.selectbox("Method", ["Z-Score", "IQR (Interquartile Range)", "MAD (Median Absolute Deviation)"], disabled=True)
st.slider("Z-Score threshold", 1.0, 5.0, 3.0, 0.1, disabled=True)
st.slider("IQR multiplier", 1.0, 3.0, 1.5, 0.1, disabled=True)
st.subheader("Handling")
st.selectbox("Action", ["Flag only (add column)", "Remove outlier rows", "Cap / Winsorize to bounds"], disabled=True)
st.divider()
st.button("Detect Outliers", type="primary", width="stretch", disabled=True)