From 1f053f7d91bff79832da90789c43a65a88250dfc Mon Sep 17 00:00:00 2001 From: Sven Geboers Date: Fri, 1 May 2026 14:46:52 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20simplify=20Explorer=20to=203=20focu?= =?UTF-8?q?sed=20tabs=20=E2=80=94=20compass,=20trajectories,=20SVD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes embedding-heavy search and generic browser tabs from the Explorer. The project does not currently use embeddings meaningfully, so the similarity search and browser features were dead weight. Changes: - explorer.py: Remove search and browser tabs, keep compass/trajectories/SVD - explorer.py: Remove fused_embeddings and similarity_cache stats from sidebar - Home.py: Update Explorer description to match new focused layout - analysis/tabs/__init__.py: Remove search and browser exports - tests: Update decomposition and import tests for new tab set Result: Explorer now has 3 focused analytical tabs instead of 5. --- Home.py | 6 +-- analysis/tabs/__init__.py | 4 -- explorer.py | 72 ++-------------------------- tests/test_explorer_decomposition.py | 4 -- tests/test_explorer_import.py | 5 +- 5 files changed, 10 insertions(+), 81 deletions(-) diff --git a/Home.py b/Home.py index 6b97412..ff0ce30 100644 --- a/Home.py +++ b/Home.py @@ -19,8 +19,8 @@ def main() -> None: st.markdown( "**Motief** brengt de Nederlandse Tweede Kamer in kaart op basis van " "echte stemmingen over moties. Gebruik de Stemwijzer om te ontdekken welke " - "partij het beste bij jouw standpunten past, of verken de politieke ruimte " - "zelf in de Explorer." + "partij het beste bij jouw standpunten past, of verken het politieke landschap " + "in de Explorer: kompas, trajecten en SVD-analyse." ) st.divider() @@ -39,7 +39,7 @@ def main() -> None: st.subheader("🔭 Politiek Explorer") st.markdown( "Verken het politieke kompas, partijtrajecten door de tijd, " - "en zoek vergelijkbare moties op in het archief." + "en de onderliggende SVD-componenten die de assen vormen." ) st.page_link("pages/2_Explorer.py", label="Open Explorer", icon="🔭") diff --git a/analysis/tabs/__init__.py b/analysis/tabs/__init__.py index 3f53722..f6f42a4 100644 --- a/analysis/tabs/__init__.py +++ b/analysis/tabs/__init__.py @@ -6,16 +6,12 @@ Each module contains a `build__tab()` function that implements one tab. from analysis.tabs.compass import build_compass_tab from analysis.tabs.trajectories import build_trajectories_tab -from analysis.tabs.search import build_search_tab -from analysis.tabs.browser import build_browser_tab from analysis.tabs.components import build_svd_components_tab from analysis.tabs.quiz import build_mp_quiz_tab __all__ = [ "build_compass_tab", "build_trajectories_tab", - "build_search_tab", - "build_browser_tab", "build_svd_components_tab", "build_mp_quiz_tab", ] diff --git a/explorer.py b/explorer.py index 7369c85..8fcca51 100644 --- a/explorer.py +++ b/explorer.py @@ -1,10 +1,9 @@ """Parlement Explorer — Streamlit data analysis app. -Four tabs: - 1. Politiek Kompas — 2D scatter of MPs/parties, window slider +Three tabs: + 1. Politiek Kompas — 2D scatter of MPs/parties, window slider 2. Partij Trajectories — party centroid lines over time - 3. Motie Zoeken — text search + similarity lookup - 4. Motie Browser — sortable table + detail panel + 3. SVD Components — component themes, scree plot, party positions Run with: streamlit run explorer.py @@ -408,49 +407,6 @@ def load_motions_df(db_path: str) -> pd.DataFrame: return explorer_data.load_motions_df(db_path) -def query_similar( - db_path: str, - source_motion_id: int, - vector_type: str = "fused", - top_k: int = 10, -) -> pd.DataFrame: - """Return top-k similar motions from similarity_cache (read-only).""" - return explorer_data.query_similar(db_path, source_motion_id, vector_type, top_k) - - -def _window_to_dates(window_id: str) -> tuple[str, str]: - """Return (start_date, end_date) ISO strings for a given window_id.""" - return trajectory.window_to_dates(window_id) - - -def build_compass_tab(*args, **kwargs): - """Build the Politiek Kompas tab.""" - from analysis.tabs.compass import build_compass_tab as _impl - - return _impl(*args, **kwargs) - - -def build_trajectories_tab(*args, **kwargs): - """Build the Partij Trajectories tab.""" - from analysis.tabs.trajectories import build_trajectories_tab as _impl - - return _impl(*args, **kwargs) - - -def build_search_tab(*args, **kwargs): - """Build the Motie Zoeken tab.""" - from analysis.tabs.search import build_search_tab as _impl - - return _impl(*args, **kwargs) - - -def build_browser_tab(*args, **kwargs): - """Build the Motie Browser tab.""" - from analysis.tabs.browser import build_browser_tab as _impl - - return _impl(*args, **kwargs) - - def build_svd_components_tab(*args, **kwargs): """Build the SVD Components tab.""" from analysis.tabs.components import build_svd_components_tab as _impl @@ -476,24 +432,16 @@ def run_app() -> None: st.sidebar.title("Instellingen") db_path = "data/motions.db" window_size = "annual" - show_rejected = st.sidebar.checkbox("Toon verworpen moties", value=False) with st.sidebar.expander("â„šī¸ Over", expanded=False): try: if _DUCKDB_AVAILABLE: con = duckdb.connect(database=db_path, read_only=True) n_motions = con.execute("SELECT COUNT(*) FROM motions").fetchone()[0] - n_fused = con.execute( - "SELECT COUNT(*) FROM fused_embeddings" - ).fetchone()[0] - n_sim = con.execute("SELECT COUNT(*) FROM similarity_cache").fetchone()[ - 0 - ] con.close() st.markdown( f"**Moties:** {n_motions:,} \n" - f"**Fused embeddings:** {n_fused:,} \n" - f"**Similarity cache:** {n_sim:,}" + f"**Vensters:** per jaar + huidig parlement" ) else: st.warning( @@ -505,22 +453,16 @@ def run_app() -> None: tab_labels = [ "🧭 Politiek Kompas", "📈 Trajectories", - "🔍 Motie Zoeken", - "📋 Motie Browser", "đŸ”Ŧ SVD Components", ] if hasattr(st, "tabs") and callable(getattr(st, "tabs")): - tab1, tab2, tab3, tab4, tab5 = st.tabs(tab_labels) + tab1, tab2, tab3 = st.tabs(tab_labels) with tab1: build_compass_tab(db_path, window_size) with tab2: build_trajectories_tab(db_path, window_size) with tab3: - build_search_tab(db_path, show_rejected) - with tab4: - build_browser_tab(db_path, show_rejected) - with tab5: build_svd_components_tab(db_path) else: selection = st.radio("Tab", tab_labels) @@ -528,10 +470,6 @@ def run_app() -> None: build_compass_tab(db_path, window_size) elif selection == tab_labels[1]: build_trajectories_tab(db_path, window_size) - elif selection == tab_labels[2]: - build_search_tab(db_path, show_rejected) - elif selection == tab_labels[3]: - build_browser_tab(db_path, show_rejected) else: build_svd_components_tab(db_path) diff --git a/tests/test_explorer_decomposition.py b/tests/test_explorer_decomposition.py index c8574b5..2c767b9 100644 --- a/tests/test_explorer_decomposition.py +++ b/tests/test_explorer_decomposition.py @@ -27,8 +27,6 @@ class TestExplorerDecomposition: tabs = [ ("analysis/tabs/compass.py", "build_compass_tab"), ("analysis/tabs/trajectories.py", "build_trajectories_tab"), - ("analysis/tabs/search.py", "build_search_tab"), - ("analysis/tabs/browser.py", "build_browser_tab"), ("analysis/tabs/components.py", "build_svd_components_tab"), ("analysis/tabs/quiz.py", "build_mp_quiz_tab"), ] @@ -75,8 +73,6 @@ class TestExplorerDecomposition: tab_modules = [ "analysis/tabs/compass.py", "analysis/tabs/trajectories.py", - "analysis/tabs/search.py", - "analysis/tabs/browser.py", "analysis/tabs/components.py", "analysis/tabs/quiz.py", "analysis/tabs/_rendering.py", diff --git a/tests/test_explorer_import.py b/tests/test_explorer_import.py index 4c3b8be..f519fce 100644 --- a/tests/test_explorer_import.py +++ b/tests/test_explorer_import.py @@ -9,6 +9,5 @@ def test_explorer_importable(): assert callable(mod.run_app) assert hasattr(mod, "load_positions") assert hasattr(mod, "load_motions_df") - assert hasattr(mod, "query_similar") - assert hasattr(mod, "build_compass_tab") - assert hasattr(mod, "build_search_tab") + assert hasattr(mod, "build_svd_components_tab") + assert hasattr(mod, "build_mp_quiz_tab")