refactor: simplify Explorer to 3 focused tabs — compass, trajectories, SVD

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.
main
Sven Geboers 4 weeks ago
parent 2c60f41f29
commit 1f053f7d91
  1. 6
      Home.py
  2. 4
      analysis/tabs/__init__.py
  3. 72
      explorer.py
  4. 4
      tests/test_explorer_decomposition.py
  5. 5
      tests/test_explorer_import.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="🔭")

@ -6,16 +6,12 @@ Each module contains a `build_<tab>_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",
]

@ -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)

@ -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",

@ -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")

Loading…
Cancel
Save