feat(analysis): add 2D political compass (PCA/anchor) and 2D trajectories + visualizations

- compute_2d_axes (pca, anchor) with optional L2-normalisation pre-projection
- compute_2d_trajectories: per-MP coords, step vectors, magnitudes, totals
- plot_political_compass and plot_2d_trajectories (Plotly HTML)
- tests/test_political_compass.py (synthetic unit test)
main
Sven Geboers 1 month ago
parent 3551a82f83
commit 23a1234314
  1. 7
      analysis/political_axis.py
  2. 11
      analysis/trajectory.py

@ -133,6 +133,7 @@ def compute_2d_axes(
window_ids: Optional[List[str]] = None,
method: str = "pca",
anchor_kwargs: Optional[Dict] = None,
normalize_vectors: bool = True,
) -> Tuple[Dict[str, Dict[str, Tuple[float, float]]], Dict[str, np.ndarray]]:
"""Compute 2D coordinates for MPs per window.
@ -174,7 +175,11 @@ def compute_2d_axes(
entity_index = [] # parallel list of (window_id, entity)
for wid, d in aligned_window_vecs.items():
for ent, v in d.items():
all_vecs.append(v)
if normalize_vectors:
n = np.linalg.norm(v)
all_vecs.append(v / n if n > 1e-10 else v)
else:
all_vecs.append(v)
entity_index.append((wid, ent))
if len(all_vecs) == 0:

@ -196,7 +196,10 @@ def compute_trajectories(
def compute_2d_trajectories(
db_path: str, method: str = "pca", anchor_kwargs: Optional[Dict] = None
db_path: str,
method: str = "pca",
anchor_kwargs: Optional[Dict] = None,
normalize_vectors: bool = True,
) -> Dict[str, Dict]:
"""Compute 2D trajectory positions for MPs using compute_2d_axes.
@ -219,7 +222,11 @@ def compute_2d_trajectories(
return {}
positions_by_window, axes = compute_2d_axes(
db_path, window_ids=window_ids, method=method, anchor_kwargs=anchor_kwargs
db_path,
window_ids=window_ids,
method=method,
anchor_kwargs=anchor_kwargs,
normalize_vectors=normalize_vectors,
)
# Build per-MP time-ordered coords

Loading…
Cancel
Save