#!/usr/bin/env python3 """Sincroniza el diccionario de variables que manda el club con nuestros metadatos. El club manda un xlsx con cuatro columnas: ``Categoría`` (categoría de estilo de juego), ``Categoria_2`` (subcategoría), ``Nombre`` (nombre de uso) y ``Nombre Columna`` (nombre en el dataset). Este script lo compara con lo que tenemos y actualiza: scripts/feature_groups.json ....... agrega (nunca borra) las variables que el club asigna a una categoría y a nosotros nos faltaba el grupo scripts/feature_subgroups.json .... columna → subcategoría (``Categoria_2``), info nueva scripts/var_labels_extra.json ..... se poda: quedan solo los nombres que el club NO da Después hay que re-correr, en este orden: python scripts/build_var_dict.py python webapp-static/build_data.py python scripts/gen_diccionario_variables.py python scripts/gen_referencia.py El xlsx **no está versionado** (`*.xlsx` está en .gitignore porque el repo es público): guardá el que manda el club en la raíz de racing-reports/ antes de correr esto. Uso: python scripts/sync_club_dictionary.py [ruta.xlsx] [--dry-run] """ from __future__ import annotations import json import sys from pathlib import Path import pandas as pd ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT / "src")) from racing_reports import team_vars # noqa: E402 DEFAULT_XLSX = ROOT / "diccionario_variables_2.xlsx" GROUPS = ROOT / "scripts" / "feature_groups.json" SUBGROUPS = ROOT / "scripts" / "feature_subgroups.json" EXTRA = ROOT / "scripts" / "var_labels_extra.json" # Categoría del club → nombre del grupo tal como se ve en la app. CAT_TO_GRUPO = { "Balón Parado": "Balón parado", "Balón Parado – Defensivo": "Balón parado (rival)", "Build-up / Posesión": "Build-up / Posesión", "Defensiva": "Defensiva", "Defensiva – Presión": "Defensiva – Presión", "Disciplina / Control": "Disciplina / Control", "Ofensiva – Creación": "Ofensiva – Creación", "Transiciones – Defensivas": "Transiciones – Defensivas", "Transiciones – Ofensivas": "Transiciones – Ofensivas", # ESTRATEGIA (formacion / formacion_rival) no entra: no son métricas, van como metadato. } def main() -> None: args = [a for a in sys.argv[1:] if not a.startswith("--")] dry = "--dry-run" in sys.argv xlsx = Path(args[0]) if args else DEFAULT_XLSX dic = pd.read_excel(xlsx, sheet_name=0) dic["col"] = dic["Nombre Columna"].astype(str).str.strip().str.lower() dic = dic.rename(columns={"Categoría": "cat", "Categoria_2": "sub", "Nombre": "nombre"}) nuestras = {c.lower() for c in team_vars.variables()} groups = json.loads(GROUPS.read_text(encoding="utf-8")) if GROUPS.exists() else {} extra = json.loads(EXTRA.read_text(encoding="utf-8")) if EXTRA.exists() else {} print(f"[sync] {xlsx.name}: {len(dic)} filas · nuestras variables: {len(nuestras)}") fuera = dic[~dic["col"].isin(nuestras)] if len(fuera): print(f"\n {len(fuera)} variables del club que NO existen en team_stats_agg:") for r in fuera.itertuples(): print(f" {r.col:32} ({r.nombre})") # ── grupos: unión ───────────────────────────────────────────────────────── add, nuevos_grupos = 0, set() for r in dic[dic["col"].isin(nuestras)].itertuples(): g = CAT_TO_GRUPO.get(str(r.cat).strip()) if not g: continue cur = groups.setdefault(r.col, []) if g not in cur: cur.append(g) cur.sort() add += 1 if g not in {x for v in groups.values() for x in v if v is not cur}: nuevos_grupos.add(g) sin_grupo = sorted(c for c in nuestras if not groups.get(c)) print(f"\n grupos agregados: {add}") print(f" variables sin ningún grupo: {len(sin_grupo)}" + (f" → {sin_grupo}" if sin_grupo else "")) por_grupo = {} for c, gs in groups.items(): for g in gs: por_grupo[g] = por_grupo.get(g, 0) + 1 print(" grupos resultantes:") for g in sorted(por_grupo): print(f" {g:34} {por_grupo[g]:3}") # ── subcategorías ───────────────────────────────────────────────────────── subs = {r.col: str(r.sub).strip() for r in dic[dic["col"].isin(nuestras)].itertuples()} print(f"\n subcategorías (Categoria_2): {len(subs)} variables · " f"{len(set(subs.values()))} valores distintos") # ── labels: podar var_labels_extra ──────────────────────────────────────── nombrados = set(dic["col"]) sobran = sorted(k for k in extra if k.lower() in nombrados) quedan = {k: v for k, v in extra.items() if k.lower() not in nombrados} print(f"\n var_labels_extra: {len(extra)} → {len(quedan)} " f"({len(sobran)} ya los nombra el club)") if quedan: print(f" quedan a mano: {sorted(quedan)}") if dry: print("\n[sync] --dry-run: no se escribió nada") return GROUPS.write_text(json.dumps(groups, ensure_ascii=False, indent=1), encoding="utf-8") SUBGROUPS.write_text(json.dumps(dict(sorted(subs.items())), ensure_ascii=False, indent=1), encoding="utf-8") EXTRA.write_text(json.dumps(quedan, ensure_ascii=False, indent=1), encoding="utf-8") print(f"\n[sync] escrito: {GROUPS.name}, {SUBGROUPS.name}, {EXTRA.name}") if __name__ == "__main__": main()