deploy to server

This commit is contained in:
2026-03-26 22:52:11 +01:00
parent c3f74433b2
commit b5c14d0c65
9 changed files with 1086 additions and 635 deletions
+43 -5
View File
@@ -174,6 +174,20 @@ def compute_2d_axes(
for wid in window_ids:
raw_window_vecs[wid] = _trajectory._load_mp_vectors_for_window(db_path, wid)
# Pad all vectors to the maximum dimension across windows before Procrustes.
# Some windows (e.g. 2017 with only 30 motions) have lower-rank SVD output
# (dim=29 instead of 50). Padding with zeros lets Procrustes treat all vectors
# as the same dimension, preserving the alignment chain.
if raw_window_vecs:
max_dim = max(v.shape[0] for d in raw_window_vecs.values() for v in d.values())
padded: Dict[str, Dict[str, np.ndarray]] = {}
for wid, d in raw_window_vecs.items():
padded[wid] = {
e: np.pad(v, (0, max_dim - v.shape[0])) if v.shape[0] < max_dim else v
for e, v in d.items()
}
raw_window_vecs = padded
aligned_window_vecs = _trajectory._procrustes_align_windows(raw_window_vecs)
# Stack all vectors across windows into a single matrix for PCA if needed
@@ -246,10 +260,27 @@ def compute_2d_axes(
# Ensure consistent left/right and progressive/conservative orientation
# by checking canonical party centroids and flipping axis signs if needed.
try:
right_parties = {"PVV", "VVD", "FVD", "BBB", "JA21"}
left_parties = {"SP", "PvdA", "GroenLinks", "GroenLinks-PvdA", "DENK"}
cons_parties = {"PVV", "VVD", "FVD", "CDA", "SGP", "BBB", "JA21"}
right_parties = {
"PVV",
"VVD",
"FVD",
"BBB",
"JA21",
"Nieuw Sociaal Contract",
}
left_parties = {"SP", "PvdA", "GL", "GroenLinks", "GroenLinks-PvdA", "DENK"}
cons_parties = {
"PVV",
"VVD",
"FVD",
"CDA",
"SGP",
"BBB",
"JA21",
"Nieuw Sociaal Contract",
}
prog_parties = {
"GL",
"GroenLinks",
"PvdA",
"PvdD",
@@ -263,9 +294,12 @@ def compute_2d_axes(
def _centroid_for_party_set(party_set):
vecs = []
# Party-level centroid vectors (entity_id == party name directly).
for p in party_set:
if p in ent_to_vec:
vecs.append(ent_to_vec[p])
# MP-level vectors: mp_metadata stores mp_name in the same
# "Lastname, Initials" format as entity_id in svd_vectors.
try:
conn = duckdb.connect(db_path)
rows = conn.execute(
@@ -295,7 +329,7 @@ def compute_2d_axes(
)
axes["x_axis"] = -axes["x_axis"]
# Y-axis: progressive vs conservative — prefer positive = conservative
# Y-axis: progressive vs conservative — positive Y = progressive
prog_cent = _centroid_for_party_set(prog_parties)
cons_cent = _centroid_for_party_set(cons_parties)
if prog_cent is not None and cons_cent is not None:
@@ -378,7 +412,11 @@ def compute_2d_axes(
cons_centroid = np.mean(np.vstack(cons_vecs), axis=0)
lr = right_centroid - left_centroid
pc = cons_centroid - prog_centroid
# Construct progressive-conservative axis so that positive Y corresponds
# to *progressive* positions (consistent with PCA branch where we flip
# the sign to make progressive > conservative). Use prog - cons so a
# positive dot product means closer to the progressive centroid.
pc = prog_centroid - cons_centroid
# Gram-Schmidt: make pc orthogonal to lr
lr_norm = np.linalg.norm(lr)
+22 -1
View File
@@ -56,7 +56,28 @@ def _procrustes_align_windows(
for wid in window_ids[1:]:
cur = window_vecs[wid]
common = [e for e in cur if e in prev_aligned]
# Only consider common entities whose vectors share the same dimensionality
common = [
e
for e in cur
if e in prev_aligned and cur[e].shape == prev_aligned[e].shape
]
# If there are common entities but their vector dimensions differ between
# the current and previously aligned window, skip Procrustes alignment
# for this window rather than raising an exception in orthogonal_procrustes.
if any(
e
for e in cur
if e in prev_aligned and cur[e].shape != prev_aligned[e].shape
):
_logger.debug(
"Procrustes skipped for %s: vector dimensionality mismatch between windows",
wid,
)
result[wid] = cur
prev_aligned = cur
continue
if len(common) < min_overlap:
_logger.debug(