Last active
December 17, 2025 02:07
-
-
Save miguel9554/4afdde0e8030e47db3aae795c822977e to your computer and use it in GitHub Desktop.
Plot de carga fiscal del monotributo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import pandas as pd | |
| import plotly.graph_objects as go | |
| import numpy as np | |
| df = pd.DataFrame({ | |
| "Categoria": list("ABCDEFGHIJK"), | |
| "Ingreso_anual": [ | |
| 8992597.87, 13175201.52, 18473166.15, 22934610.05, | |
| 26977793.60, 33809379.57, 40431835.35, 61344853.64, | |
| 68664410.05, 78632948.76, 94805682.90, | |
| ], | |
| "Total_mensual": [ | |
| 37085.74, 42216.41, 49435.58, 63357.80, 89714.31, | |
| 112906.59, 172457.38, 391400.62, 721650.46, | |
| 874069.29, 1208890.60, | |
| ], | |
| }) | |
| df["Ingreso_mensual"] = df["Ingreso_anual"] / 12 | |
| df["Total_anual"] = df["Total_mensual"] * 12 | |
| df["Porcentaje_ingreso"] = df["Total_anual"] / df["Ingreso_anual"] * 100 | |
| # Convertir a millones | |
| df["Ingreso_anual_mill"] = df["Ingreso_anual"] / 1e6 | |
| df["Ingreso_mensual_mill"] = df["Ingreso_mensual"] / 1e6 | |
| # Redondear a 3 cifras significativas SOLO para el eje X anual | |
| df["Ingreso_anual_mill_round"] = df["Ingreso_anual_mill"].apply(lambda x: round(x, 3 - len(str(int(x))))) | |
| # Calcular mensual como anual_redondeado / 12 | |
| df["Ingreso_mensual_mill_round"] = df["Ingreso_anual_mill_round"] / 12 | |
| # Crear datos para escalones (gasto constante por categoría) | |
| x_escalon = [] | |
| y_escalon = [] | |
| for i in range(len(df)): | |
| if i == 0: | |
| x_escalon.extend([0, df["Ingreso_anual_mill_round"].iloc[i]]) | |
| else: | |
| x_escalon.extend([df["Ingreso_anual_mill_round"].iloc[i-1], df["Ingreso_anual_mill_round"].iloc[i]]) | |
| y_escalon.extend([df["Total_mensual"].iloc[i], df["Total_mensual"].iloc[i]]) | |
| # Crear datos interpolados para porcentaje (varía continuamente) | |
| # Solo a partir de 4 millones | |
| x_continuo = [] | |
| y_porcentaje = [] | |
| min_ingreso_mill = 4.0 # Mínimo en millones | |
| for i in range(len(df)): | |
| if i == 0: | |
| inicio = df["Ingreso_anual"].iloc[i] * 0.001 | |
| else: | |
| inicio = df["Ingreso_anual"].iloc[i-1] | |
| fin = df["Ingreso_anual"].iloc[i] | |
| # Generar puntos intermedios | |
| n_puntos = 50 | |
| for j in range(n_puntos): | |
| ingreso = inicio + (fin - inicio) * j / (n_puntos - 1) | |
| ingreso_mill = ingreso / 1e6 | |
| # Solo agregar si es >= 4 millones | |
| if ingreso_mill >= min_ingreso_mill: | |
| x_continuo.append(ingreso_mill) | |
| porcentaje = (df["Total_mensual"].iloc[i] * 12) / ingreso * 100 | |
| y_porcentaje.append(porcentaje) | |
| # 👇 Hardcodeado: 1,500,000 ARS = 20% | |
| max_ars = 1500000 | |
| max_porcentaje = 20 | |
| fig = go.Figure() | |
| # Escalones para gasto mensual (constante por categoría) | |
| fig.add_trace(go.Scatter( | |
| x=x_escalon, | |
| y=y_escalon, | |
| mode="lines", | |
| name="Gasto mensual [ARS]", | |
| line=dict(shape='hv'), | |
| yaxis="y1", | |
| xaxis="x", | |
| )) | |
| # Puntos y etiquetas en los límites de categoría (ABAJO del punto) | |
| fig.add_trace(go.Scatter( | |
| x=df["Ingreso_anual_mill_round"], | |
| y=df["Total_mensual"], | |
| mode="markers+text", | |
| text=df["Categoria"], | |
| textposition="bottom center", | |
| marker=dict(size=8), | |
| showlegend=False, | |
| yaxis="y1", | |
| xaxis="x", | |
| )) | |
| # Línea continua para porcentaje - AHORA EN Y2 con valores originales | |
| fig.add_trace(go.Scatter( | |
| x=x_continuo, | |
| y=y_porcentaje, # 👈 Valores originales de porcentaje | |
| mode="lines", | |
| name="Gasto mensual [%]", | |
| yaxis="y2", # 👈 Ahora va en y2 | |
| xaxis="x", | |
| )) | |
| # Traza invisible para forzar xaxis2 | |
| fig.add_trace(go.Scatter( | |
| x=df["Ingreso_anual_mill_round"], | |
| y=[None] * len(df), | |
| xaxis="x2", | |
| yaxis="y", | |
| showlegend=False, | |
| hoverinfo="skip", | |
| )) | |
| fig.update_layout( | |
| title=f"Carga fiscal del monotributo con categorías del 1/08/2025", | |
| xaxis=dict( | |
| title="Ingreso bruto anual [millones de ARS]", | |
| tickvals=df["Ingreso_anual_mill_round"], | |
| ticktext=[f"{v:.3g}" for v in df["Ingreso_anual_mill_round"]], | |
| side="bottom", | |
| ), | |
| xaxis2=dict( | |
| title="Ingreso bruto mensual [millones de ARS]", | |
| overlaying="x", | |
| side="top", | |
| tickvals=df["Ingreso_anual_mill_round"], | |
| ticktext=[f"{v:.3g}" for v in df["Ingreso_mensual_mill_round"]], | |
| showgrid=False, | |
| ), | |
| yaxis=dict( | |
| title="Gasto mensual [ARS]", | |
| tickformat="$,.0f", | |
| ), | |
| yaxis2=dict( | |
| title="Gasto mensual [%]", | |
| overlaying="y", | |
| side="right", | |
| tickformat=".2f", | |
| ), | |
| legend=dict( | |
| x=0.01, | |
| y=0.99, | |
| xanchor="left", | |
| yanchor="top", | |
| bgcolor="rgba(255,255,255,0.8)", | |
| ), | |
| hovermode="x unified", | |
| ) | |
| fig.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment