from pathlib import Path
import json,html
from reportlab.platypus import SimpleDocTemplate,Paragraph,Spacer,Table,TableStyle,KeepTogether
from reportlab.lib.styles import getSampleStyleSheet,ParagraphStyle
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.units import cm
P=Path(__file__).resolve().parent;d=json.loads((P/'resultados.json').read_text());J=json.dumps(d,ensure_ascii=False).replace('</','<\\/')
site=r'''<!DOCTYPE html><html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="Investigación econométrica sobre ingresos laborales en Argentina con microdatos EPH 2025 T4, por Nahuel Iván López."><title>Educación e ingresos laborales | Nahuel Iván López</title><style>
:root{color-scheme:dark;--bg:#08121e;--panel:#102337;--line:#294359;--ink:#edf5fa;--muted:#a9becc;--aqua:#65e2cf;--blue:#78aaff;font-family:Inter,system-ui,Arial,sans-serif}*{box-sizing:border-box}html{scroll-behavior:smooth}body{background:var(--bg);color:var(--ink);margin:0}a{color:var(--aqua)}header,main,footer{max-width:1160px;margin:auto;padding:24px}header{display:flex;justify-content:space-between;align-items:center;gap:12px;border-bottom:1px solid var(--line);flex-wrap:wrap}header a{font-size:13px}nav{display:flex;gap:16px;flex-wrap:wrap}nav a{text-decoration:none;color:var(--muted)}h1{font-size:clamp(36px,5.8vw,66px);line-height:1.09;letter-spacing:-.04em;max-width:900px;margin:20px 0}h2{font-size:clamp(22px,3vw,30px);margin:50px 0 14px;letter-spacing:-.02em}h3{margin:0 0 10px;font-size:17px}p{line-height:1.65}.muted{color:var(--muted)}.eyebrow{font-size:12px;letter-spacing:.15em;color:var(--aqua);font-weight:700}.lead{max-width:840px;color:#c5d8e3;font-size:18px}.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:15px}.panel{border:1px solid var(--line);border-radius:17px;background:var(--panel);padding:22px}.metric{font-size:clamp(24px,3vw,35px);font-weight:800;letter-spacing:-.03em;margin:8px 0}.sub{font-size:12px;color:var(--muted)}.insight{border-left:3px solid var(--aqua);padding-left:18px;max-width:850px}.controls{display:flex;flex-wrap:wrap;gap:9px;margin:15px 0}button,.btn{background:#1a3950;color:var(--ink);border:1px solid #44647a;padding:10px 14px;border-radius:9px;cursor:pointer;font:inherit;font-size:13px;text-decoration:none;display:inline-block}button.active{background:#147e81;border-color:#52cfbb}.chartrow{display:grid;grid-template-columns:180px 1fr 130px;gap:12px;align-items:center;margin:13px 0}.track{height:22px;background:#21364a;border-radius:5px;overflow:hidden}.fill{height:100%;background:linear-gradient(90deg,#438ebd,#62dcca);border-radius:5px}.chartrow .value{text-align:right;font-variant-numeric:tabular-nums}.small{font-size:13px}.coef{display:grid;grid-template-columns:200px 1fr 100px;gap:12px;align-items:center;margin:15px 0}.axis{height:25px;position:relative;background:linear-gradient(90deg,transparent 49.9%,#58748a 50%,transparent 50.1%)}.ci{position:absolute;top:11px;height:3px;background:var(--aqua)}.dot{position:absolute;top:6px;width:12px;height:12px;background:var(--aqua);border-radius:50%;transform:translateX(-50%)}.coef .value{text-align:right}.scroll{overflow-x:auto}table{border-collapse:collapse;width:100%}td,th{border-bottom:1px solid var(--line);text-align:left;padding:11px;font-size:13px}footer{border-top:1px solid var(--line);color:var(--muted);font-size:13px;margin-top:40px}strong{color:white}@media(max-width:730px){.grid{grid-template-columns:1fr}.chartrow{grid-template-columns:105px 1fr 90px;gap:7px;font-size:12px}.coef{grid-template-columns:120px 1fr 68px;gap:5px;font-size:11px}header,main,footer{padding:18px}.panel{padding:16px}nav{gap:10px}}
</style></head><body><header><div><strong>NAHUEL IVÁN LÓPEZ</strong><div class="sub">Economía · Portfolio de análisis cuantitativo</div></div><nav><a href="#hallazgos">Hallazgos</a><a href="#explorador">Explorador</a><a href="#modelo">Econometría</a><a href="#metodologia">Metodología</a></nav></header><main><div class="eyebrow">PROYECTO 02 · EPH / INDEC · 2025 T4</div><h1>Educación e <span style="color:var(--aqua)">ingresos laborales</span> en Argentina</h1><p class="lead">¿Qué diferencias de ingresos se observan entre niveles educativos y cuánto persisten al controlar por edad, sexo y región? Investigación reproducible con microdatos de la Encuesta Permanente de Hogares.</p><div class="controls"><a class="btn" href="Informe_Econometrico.pdf" download>↓ Informe en PDF</a><a class="btn" href="analisis.py" download>↓ Código Python</a><a class="btn" href="resultados.json" download>↓ Resultados agregados</a></div><section class="grid"><div class="panel"><div class="sub">Muestra analítica</div><div class="metric" id="n"></div><div class="sub">Personas ocupadas, 18–65 años, ingreso positivo</div></div><div class="panel"><div class="sub">R² · modelo principal</div><div class="metric" id="r2"></div><div class="sub">Logaritmo del ingreso mensual</div></div><div class="panel"><div class="sub">R² · especificación ampliada</div><div class="metric" id="r2b"></div><div class="sub">Incluye horas y categoría ocupacional; muestra distinta</div></div></section><section id="hallazgos"><h2>01 / Resultados principales</h2><div class="grid"><div class="panel"><div class="sub">Superior completo vs. secundaria completa</div><div class="metric" id="premium"></div><p class="small muted">Diferencia condicional estimada en ingreso mensual; no es retorno causal de la educación.</p></div><div class="panel"><div class="sub">Mujeres vs. varones</div><div class="metric" id="female"></div><p class="small muted">Asociación condicional; no equivale a brecha salarial por hora ni a discriminación identificada.</p></div><div class="panel"><div class="sub">Ingreso medio, superior completo</div><div class="metric" id="income"></div><p class="small muted">Promedio ponderado de P21; pesos corrientes de 2025 T4.</p></div></div><div class="panel" style="margin-top:16px"><h3>Lectura económica</h3><p class="insight">Los datos muestran una asociación positiva entre educación superior completa e ingreso de la ocupación principal, aun después de controlar por características observables. La estimación no permite atribuir causalmente la diferencia a la educación: influyen selección, horas trabajadas, ocupación y factores no medidos.</p></div></section><section id="explorador"><h2>02 / Explorador de ingresos</h2><div class="panel"><div class="controls" id="dimension"><button data-d="educacion" class="active">Educación</button><button data-d="sexo">Sexo</button><button data-d="region">Región</button></div><div class="controls" id="measure"><button data-m="media" class="active">Media ponderada</button><button data-m="mediana">Mediana ponderada</button></div><div id="bars" aria-live="polite"></div><p class="small muted">Ingresos mensuales de la ocupación principal (P21), ponderados con PONDIIO. La media es sensible a valores elevados; la mediana representa el punto central ponderado.</p></div></section><section id="modelo"><h2>03 / Estimación econométrica</h2><div class="panel"><h3>Modelo principal</h3><p class="muted small">ln(P21) = β₀ + educación + edad + edad² + mujer + región + ε. Referencia educativa: secundaria completa. Mínimos cuadrados ponderados (PONDIIO) y errores agrupados por hogar como aproximación, no inferencia de diseño muestral completo.</p><h3 style="margin-top:25px">Coeficientes educativos e indicador mujer</h3><p class="sub">Efectos porcentuales transformados como 100 × [exp(β) − 1]. Las barras representan intervalos de confianza del 95% transformados.</p><div id="coefchart"></div><div class="scroll"><table><thead><tr><th>Variable</th><th>Coef. log</th><th>IC 95% (log)</th><th>Valor p</th></tr></thead><tbody id="coeftable"></tbody></table></div></div><h2>04 / Pruebas de robustez</h2><div class="grid"><div class="panel"><h3>Modelo principal ponderado</h3><div class="metric" id="mainr"></div><div class="sub" id="mainn"></div></div><div class="panel"><h3>Sin ponderación</h3><div class="metric" id="unwr"></div><div class="sub" id="unwn"></div></div><div class="panel"><h3>Con horas y categoría ocupacional</h3><div class="metric" id="hourr"></div><div class="sub" id="hourn"></div></div></div><p class="muted small">El modelo ampliado incorpora log(horas trabajadas en todas las ocupaciones, PP3E_TOT) y categoría ocupacional (CAT_OCUP), restringiendo a 1–100 horas. No se trata de un modelo de salario por hora de la ocupación principal. Comparar R² no identifica el efecto individual de cada control y la muestra cambia.</p><div class="panel"><h3>Comparación de coeficientes seleccionados</h3><div class="scroll"><table><thead><tr><th>Variable</th><th>Principal</th><th>Sin ponderar</th><th>Con horas/categoría</th></tr></thead><tbody id="robust"></tbody></table></div></div></section><section id="metodologia"><h2>05 / Fuente, metodología y límites</h2><div class="panel"><p><strong>Fuente:</strong> INDEC, Encuesta Permanente de Hogares (EPH), microdatos individuales, cuarto trimestre de 2025. <a href="https://www.indec.gob.ar/indec/web/Institucional-Indec-BasesDeDatos-8" target="_blank" rel="noopener noreferrer">Repositorio oficial</a>.</p><p class="muted small"><strong>Selección:</strong> ocupados entre 18 y 65 años, P21 positivo, ponderador PONDIIO positivo, sexo codificado y NIVEL_ED entre 1 y 6. Se excluyen ingresos nulos, negativos o no declarados. No representa a toda la población ocupada. Los resultados se refieren a los aglomerados urbanos de la EPH y no a la totalidad territorial argentina.</p><p class="muted small"><strong>Inferencia:</strong> errores estándar agrupados por hogar, sin reconstrucción integral de estratos y unidades primarias del diseño de encuesta. Los intervalos deben interpretarse como aproximaciones. Estudio transversal observacional: correlaciones, no efectos causales. El ingreso mensual mezcla remuneración y horas trabajadas; educación y empleo pueden ser endógenos. Las ponderaciones y la no respuesta condicionan la interpretación.</p><p class="muted small"><strong>Reproducibilidad:</strong> se publican script Python, CSV agregados y resultados JSON. No se publican registros individuales de los encuestados.</p><p class="muted small"><strong>Herramientas:</strong> Python · pandas · NumPy · statsmodels · regresión ponderada · inferencia agrupada · visualización interactiva · HTML/CSS/JavaScript.</p></div></section></main><footer>© Nahuel Iván López · Portfolio académico y profesional · Análisis económico basado en datos</footer><script>const d=__DATA__;const fmt=x=>Number(x).toLocaleString('es-AR',{maximumFractionDigits:1});const money=x=>'$'+Math.round(x).toLocaleString('es-AR');const pct=x=>(x>0?'+':'')+fmt(x)+'%';document.querySelector('#n').textContent=fmt(d.muestra);document.querySelector('#r2').textContent=fmt(d.modelo.r2);document.querySelector('#r2b').textContent=fmt(d.con_horas_categoria.r2);document.querySelector('#premium').textContent=pct(d.principal_superior.efecto_pct);document.querySelector('#female').textContent=pct(d.principal_mujer.efecto_pct);document.querySelector('#income').textContent=money(d.educacion.find(x=>x.codigo===6).media);let dim='educacion',measure='media';function bars(){const rows=d[dim],mx=Math.max(...rows.map(x=>x[measure]));document.querySelector('#bars').innerHTML=rows.map(x=>{const lab=x.educacion||x.grupo;return `<div class="chartrow"><div>${lab}</div><div class="track"><div class="fill" style="width:${Math.max(1,100*x[measure]/mx)}%"></div></div><div class="value">${money(x[measure])}</div></div>`}).join('')}bars();document.querySelectorAll('#dimension button').forEach(b=>b.onclick=()=>{dim=b.dataset.d;document.querySelectorAll('#dimension button').forEach(z=>z.classList.toggle('active',z===b));bars()});document.querySelectorAll('#measure button').forEach(b=>b.onclick=()=>{measure=b.dataset.m;document.querySelectorAll('#measure button').forEach(z=>z.classList.toggle('active',z===b));bars()});const labels={'C(educ, Treatment(reference=4))[T.1]':'Primaria incompleta','C(educ, Treatment(reference=4))[T.2]':'Primaria completa','C(educ, Treatment(reference=4))[T.3]':'Secundaria incompleta','C(educ, Treatment(reference=4))[T.5]':'Superior incompleto','C(educ, Treatment(reference=4))[T.6]':'Superior completo','mujer':'Mujeres'};const co=d.modelo.coeficientes.filter(x=>labels[x.variable]);const lo=-70,hi=140,scale=x=>Math.max(0,Math.min(100,100*(x-lo)/(hi-lo)));document.querySelector('#coefchart').innerHTML=co.map(x=>{let l=100*Math.expm1(x.li),u=100*Math.expm1(x.ls),v=x.efecto_pct;return `<div class="coef"><div>${labels[x.variable]}</div><div class="axis"><div class="ci" style="left:${scale(l)}%;width:${Math.max(1,scale(u)-scale(l))}%"></div><div class="dot" style="left:${scale(v)}%"></div></div><div class="value">${pct(v)}</div></div>`}).join('');document.querySelector('#coeftable').innerHTML=d.modelo.coeficientes.filter(x=>x.variable!=='Intercept').map(x=>`<tr><td>${labels[x.variable]||x.variable.replace('C(region)','Región')}</td><td>${x.coef.toFixed(3)}</td><td>[${x.li.toFixed(3)}, ${x.ls.toFixed(3)}]</td><td>${x.p<.001?'&lt; 0,001':fmt(x.p)}</td></tr>`).join('');[['mainr',d.modelo.r2],['unwr',d.sin_ponderar.r2],['hourr',d.con_horas_categoria.r2]].forEach(([id,v])=>document.getElementById(id).textContent=fmt(v));[['mainn',d.modelo.n],['unwn',d.sin_ponderar.n],['hourn',d.con_horas_categoria.n]].forEach(([id,v])=>document.getElementById(id).textContent=fmt(v)+' observaciones');function val(model,key){const x=model.coeficientes.find(x=>x.variable===key);return x?pct(x.efecto_pct):'—'}document.querySelector('#robust').innerHTML=['C(educ, Treatment(reference=4))[T.6]','mujer'].map(k=>`<tr><td>${labels[k]}</td><td>${val(d.modelo,k)}</td><td>${val(d.sin_ponderar,k)}</td><td>${val(d.con_horas_categoria,k)}</td></tr>`).join('');</script></body></html>'''.replace('__DATA__',J)
(P/'index.html').write_text(site,encoding='utf-8')
styles=getSampleStyleSheet();styles.add(ParagraphStyle(name='CoverX',parent=styles['Title'],fontName='Helvetica-Bold',fontSize=22,leading=28,textColor=colors.HexColor('#10283e'),spaceAfter=15));styles.add(ParagraphStyle(name='HeadingX',parent=styles['Heading2'],fontSize=13,textColor=colors.HexColor('#0d5b67'),spaceBefore=17,spaceAfter=8));styles.add(ParagraphStyle(name='BodyX',parent=styles['BodyText'],fontSize=9.5,leading=15,spaceAfter=9));doc=SimpleDocTemplate(str(P/'Informe_Econometrico.pdf'),pagesize=(21*cm,29.7*cm),rightMargin=2*cm,leftMargin=2*cm,topMargin=2*cm,bottomMargin=2*cm);story=[]
def para(s,style='BodyX'):story.append(Paragraph(html.escape(s),styles[style]))
para('Educación e ingresos laborales en Argentina','CoverX');para('Nahuel Iván López | Investigación econométrica | EPH, cuarto trimestre de 2025');para('Resumen ejecutivo','HeadingX');para(f"La muestra analítica comprende {d['muestra']:,} personas ocupadas de 18 a 65 años con ingreso positivo en la ocupación principal. El modelo principal ponderado presenta R² = {d['modelo']['r2']:.4f}.");para(f"Respecto de secundaria completa, educación superior completa se asocia con un ingreso mensual {d['principal_superior']['efecto_pct']:.1f}% mayor, condicionado por edad, sexo y región (IC 95% para el coeficiente logarítmico: [{d['principal_superior']['li']:.3f}, {d['principal_superior']['ls']:.3f}]). La variable mujer presenta una asociación de {d['principal_mujer']['efecto_pct']:.1f}% respecto de varones, manteniendo constantes los controles del modelo.");para('Pregunta y datos','HeadingX');para('¿Cómo se relacionan el nivel educativo, la edad, el sexo y la región con el ingreso mensual de la ocupación principal? Se utiliza el archivo individual de la EPH del INDEC correspondiente al cuarto trimestre de 2025, con cobertura de aglomerados urbanos. La variable dependiente es ln(P21), con P21 positivo.');para('Diseño de estimación','HeadingX');para('Modelo principal: ln(P21) = intercepto + categorías de educación + edad + edad al cuadrado + mujer + efectos fijos regionales + error. La categoría educativa de referencia es secundaria completa. Se utilizan mínimos cuadrados ponderados por PONDIIO y errores agrupados por hogar como aproximación; no se implementa el diseño muestral complejo completo.');para('Ingresos por nivel educativo','HeadingX')
t=[['Educación','N','Media ponderada ($)','Mediana ponderada ($)']]+[[r['educacion'],str(r['n']),f"{r['media']:,}",f"{r['mediana']:,}"] for r in d['educacion']];tab=Table(t,colWidths=[5.3*cm,1.4*cm,4.5*cm,4.5*cm],repeatRows=1);tab.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),colors.HexColor('#143b54')),('TEXTCOLOR',(0,0),(-1,0),colors.white),('FONTSIZE',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),7),('ROWBACKGROUNDS',(0,1),(-1,-1),[colors.whitesmoke,colors.white]),('LINEBELOW',(0,-1),(-1,-1),.5,colors.lightgrey)]));story.append(tab)
para('Robustez','HeadingX');para(f"Se compararon (a) modelo principal ponderado: N={d['modelo']['n']}, R²={d['modelo']['r2']:.4f}; (b) modelo no ponderado: N={d['sin_ponderar']['n']}, R²={d['sin_ponderar']['r2']:.4f}; (c) modelo con log de horas trabajadas en todas las ocupaciones y categoría ocupacional: N={d['con_horas_categoria']['n']}, R²={d['con_horas_categoria']['r2']:.4f}. El tercer modelo restringe PP3E_TOT a 1–100 horas; por ello los tamaños muestrales difieren.")
para('Alcances y limitaciones','HeadingX');para('Este estudio es transversal y observacional. Las asociaciones estimadas no identifican retornos causales a la educación ni discriminación. P21 mide ingreso mensual de la ocupación principal, no remuneración por hora. El modelo principal no controla horas trabajadas, ocupación ni selección al empleo; las variables omitidas pueden afectar los coeficientes. La submuestra de ingreso positivo excluye a ocupados sin ingreso declarado o positivo. Los errores agrupados por hogar no reemplazan la inferencia que incorpora el diseño complejo de la EPH. La cobertura se limita a aglomerados urbanos relevados.');para('Reproducibilidad y fuente','HeadingX');para('INDEC, Encuesta Permanente de Hogares, microdatos individuales, 4º trimestre de 2025. Los scripts Python, los resultados agregados en CSV y el JSON acompañan este informe. No se redistribuyen microdatos individuales en el sitio público. Fuente: https://www.indec.gob.ar/indec/web/Institucional-Indec-BasesDeDatos-8');doc.build(story)
print('HTML',len(site),'PDF', (P/'Informe_Econometrico.pdf').stat().st_size)
