deploy to server
This commit is contained in:
@@ -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
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user