Skip to content

Instantly share code, notes, and snippets.

@miguel9554
Last active January 21, 2026 22:18
Show Gist options
  • Select an option

  • Save miguel9554/4afdde0e8030e47db3aae795c822977e to your computer and use it in GitHub Desktop.

Select an option

Save miguel9554/4afdde0e8030e47db3aae795c822977e to your computer and use it in GitHub Desktop.
Plot de carga fiscal del monotributo
import pandas as pd
import plotly.graph_objects as go
import numpy as np
df = pd.DataFrame({
"Categoria": list("ABCDEFGHIJK"),
"Ingreso_anual": [
10277988.13, 15058447.71, 21113696.52, 26212853.42,
30833964.37, 38642048.36, 46211109.37, 70113407.33,
78479211.62, 89872640.30, 108357084.05,
],
"Total_servicios": [
42386.74, 48250.78, 56501.85, 72414.10, 102537.97,
129045.32, 197108.23, 447346.93, 824802.26,
999007.65, 1381687.90,
],
"Total_bienes": [
42386.74, 48250.78, 55227.06, 70661.26, 92658.35,
111198.27, 135918.34, 272063.40, 406512.05,
497059.41, 600879.51,
],
})
df["Ingreso_mensual"] = df["Ingreso_anual"] / 12
# 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
def crear_escalones(df, columna_total):
"""Crear datos para escalones (gasto constante por categoría, en millones)"""
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_mill = df[columna_total].iloc[i] / 1e6
y_escalon.extend([y_mill, y_mill])
return x_escalon, y_escalon
def crear_porcentaje(df, columna_total, min_ingreso_mill=4.0):
"""Crear datos interpolados para porcentaje (varía continuamente)"""
x_continuo = []
y_porcentaje = []
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]
n_puntos = 50
for j in range(n_puntos):
ingreso = inicio + (fin - inicio) * j / (n_puntos - 1)
ingreso_mill = ingreso / 1e6
if ingreso_mill >= min_ingreso_mill:
x_continuo.append(ingreso_mill)
porcentaje = (df[columna_total].iloc[i] * 12) / ingreso * 100
y_porcentaje.append(porcentaje)
return x_continuo, y_porcentaje
# Crear datos para servicios
x_escalon_serv, y_escalon_serv = crear_escalones(df, "Total_servicios")
x_cont_serv, y_pct_serv = crear_porcentaje(df, "Total_servicios")
# Crear datos para bienes
x_escalon_bien, y_escalon_bien = crear_escalones(df, "Total_bienes")
x_cont_bien, y_pct_bien = crear_porcentaje(df, "Total_bienes")
fig = go.Figure()
color_servicios = "#1f77b4" # azul
color_bienes = "#ff7f0e" # naranja
# === SERVICIOS ===
# Escalones para gasto mensual servicios (dashed)
fig.add_trace(go.Scatter(
x=x_escalon_serv,
y=y_escalon_serv,
mode="lines",
name="Servicios [ARS]",
line=dict(shape='hv', color=color_servicios, dash="dash"),
yaxis="y1",
xaxis="x",
))
# Puntos y etiquetas en los límites de categoría (servicios)
fig.add_trace(go.Scatter(
x=df["Ingreso_anual_mill_round"],
y=df["Total_servicios"] / 1e6,
mode="markers+text",
text=df["Categoria"],
textposition="bottom right",
marker=dict(size=8, color=color_servicios),
showlegend=False,
yaxis="y1",
xaxis="x",
))
# Línea continua para porcentaje servicios (solid)
fig.add_trace(go.Scatter(
x=x_cont_serv,
y=y_pct_serv,
mode="lines",
name="Servicios [%]",
line=dict(color=color_servicios),
yaxis="y2",
xaxis="x",
))
# === BIENES ===
# Escalones para gasto mensual bienes (dashed)
fig.add_trace(go.Scatter(
x=x_escalon_bien,
y=y_escalon_bien,
mode="lines",
name="Bienes [ARS]",
line=dict(shape='hv', color=color_bienes, dash="dash"),
yaxis="y1",
xaxis="x",
))
# Puntos y etiquetas en los límites de categoría (bienes)
fig.add_trace(go.Scatter(
x=df["Ingreso_anual_mill_round"],
y=df["Total_bienes"] / 1e6,
mode="markers+text",
text=df["Categoria"],
textposition="bottom right",
marker=dict(size=8, color=color_bienes),
showlegend=False,
yaxis="y1",
xaxis="x",
))
# Línea continua para porcentaje bienes (solid)
fig.add_trace(go.Scatter(
x=x_cont_bien,
y=y_pct_bien,
mode="lines",
name="Bienes [%]",
line=dict(color=color_bienes),
yaxis="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/02/2026",
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 [millones de ARS]",
range=[0, 1.7],
dtick=0.25,
),
yaxis2=dict(
title="Gasto mensual [%]",
overlaying="y",
side="right",
range=[0, 20.4],
dtick=3,
showgrid=False,
),
legend=dict(
x=0.01,
y=0.99,
xanchor="left",
yanchor="top",
bgcolor="rgba(255,255,255,0.8)",
),
hovermode="x unified",
)
fig.show()
# Exportar a PNG para compartir en web (1200x800 px, escala 2x para buena resolución)
fig.write_image("monotributo.png", width=1200, height=800, scale=2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment