blog

git clone https://git.ce9e.org/blog.git

commit
61a54e14b4f542fa8dc0bc542417dd06eb75b8ad
parent
f327b687fe7d58dc8c2b6833f1d3fdc9a6847bbc
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2025-05-16 20:50
add post on tax curves

Diffstat

M _content/posts/2022-08-06-basic-income/index.md 2 +-
A _content/posts/2025-05-16-tax-curves/curves.py 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A _content/posts/2025-05-16-tax-curves/index.md 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A _content/posts/2025-05-16-tax-curves/linear.png 0
A _content/posts/2025-05-16-tax-curves/log.png 0
A _content/posts/2025-05-16-tax-curves/pow.png 0

6 files changed, 195 insertions, 1 deletions


diff --git a/_content/posts/2022-08-06-basic-income/index.md b/_content/posts/2022-08-06-basic-income/index.md

@@ -1,7 +1,7 @@
    1     1 ---
    2     2 title: Basic income is not about redistribution of money
    3     3 date: 2022-08-06
    4    -1 tags: [politics]
   -1     4 tags: [politics, economics]
    5     5 description: The discourse around basic income annoys me.
    6     6 ---
    7     7 

diff --git a/_content/posts/2025-05-16-tax-curves/curves.py b/_content/posts/2025-05-16-tax-curves/curves.py

@@ -0,0 +1,69 @@
   -1     1 from matplotlib import pyplot as plt
   -1     2 from matplotlib.ticker import FuncFormatter
   -1     3 import numpy as np
   -1     4 
   -1     5 n = 300_000
   -1     6 
   -1     7 
   -1     8 def linear(x, a, b):
   -1     9     return a * x + b
   -1    10 
   -1    11 
   -1    12 def linear_marginal_rate(x, a, b):
   -1    13     return np.ones(len(x)) * a
   -1    14 
   -1    15 
   -1    16 def log(x, a, b):
   -1    17     return a * np.log(x / a + 1) + b
   -1    18 
   -1    19 
   -1    20 def log_marginal_rate(x, a, b):
   -1    21     return 1 / (x / a + 1)
   -1    22 
   -1    23 
   -1    24 def pow(x, a, b):
   -1    25     return np.pow(x / (a * b) + 1, a) * b
   -1    26 
   -1    27 
   -1    28 def pow_marginal_rate(x, a, b):
   -1    29     return np.pow(x / (a * b) + 1, a - 1)
   -1    30 
   -1    31 
   -1    32 def render(f, marginal_rate, a, b):
   -1    33     euro_formatter = FuncFormatter(lambda x, pos: f'{x:.0f}€')
   -1    34     percent_formatter = FuncFormatter(lambda x, pos: f'{x:.0%}')
   -1    35 
   -1    36     x = income = np.linspace(0, n, 500)
   -1    37 
   -1    38     fig, axes = plt.subplots(1, 2, sharex='row', figsize=(10, 5))
   -1    39     axes[0].plot(x, x, color='grey', linestyle='dotted')
   -1    40 
   -1    41     for i, aa in enumerate(a):
   -1    42         y = f(x, aa, b)
   -1    43         m = 1 - marginal_rate(x, aa, b)
   -1    44         av = (x - y) / x
   -1    45         color = ['blue', 'green', 'red'][i]
   -1    46         axes[0].plot(x, y, color=color)
   -1    47         axes[1].plot(x, m, color=color)
   -1    48         axes[1].plot(x, av, color=color, linestyle='dashed')
   -1    49 
   -1    50     axes[0].set_title('After Taxes')
   -1    51     axes[0].xaxis.set_major_formatter(euro_formatter)
   -1    52     axes[0].yaxis.set_major_formatter(euro_formatter)
   -1    53     axes[0].set_xlim([0, n])
   -1    54     axes[0].set_ylim([0, n])
   -1    55     axes[0].grid()
   -1    56 
   -1    57     axes[1].set_title('Marginal/Average Tax Rate')
   -1    58     axes[1].yaxis.set_major_formatter(percent_formatter)
   -1    59     axes[1].set_ylim([-0.2, 1])
   -1    60     axes[1].grid()
   -1    61 
   -1    62     plt.tight_layout()
   -1    63     plt.savefig(f'{f.__name__}.png')
   -1    64 
   -1    65 
   -1    66 if __name__ == '__main__':
   -1    67     render(linear, linear_marginal_rate, [0.3, 0.5, 0.7], 10_000)
   -1    68     render(log, log_marginal_rate, [30_000, 90_000, 400_000], 10_000)
   -1    69     render(pow, pow_marginal_rate, [0.5, 0.7, 0.9], 10_000)

diff --git a/_content/posts/2025-05-16-tax-curves/index.md b/_content/posts/2025-05-16-tax-curves/index.md

@@ -0,0 +1,125 @@
   -1     1 ---
   -1     2 title: Finding the ideal tax curve
   -1     3 date: 2025-05-16
   -1     4 tags: [economics, math]
   -1     5 description: "Having fun by finding better alternatives to those absurd piecewise-defined tax curves"
   -1     6 ---
   -1     7 
   -1     8 I recently tried to figure out income taxes and came across one of those absurd
   -1     9 [piecewise-defined](https://en.wikipedia.org/wiki/File:Income_Tax_Germany_2010.png)
   -1    10 tax curves. So I thought it might be a fun activity to figure out better
   -1    11 options for tax curves, without any claim to real-world merit.
   -1    12 
   -1    13 ## Basics
   -1    14 
   -1    15 We will look at functions where <math><mi>x</mi></math> is the income before
   -1    16 taxes and <math><mi>f</mi><mo>(</mo><mi>x</mi><mo>)</mo></math> is the
   -1    17 income after taxes.
   -1    18 
   -1    19 I am a big fan of folding some form of social security into the tax system, so
   -1    20 <math><mi>b</mi></math> will be the level of basic income everyone should have.
   -1    21 
   -1    22 All functions will have a single additional parameter <math><mi>a</mi></math>
   -1    23 that can be used to adjust the system to the current economic situation,
   -1    24 basically raising or lowering taxes.
   -1    25 
   -1    26 ## Linear
   -1    27 
   -1    28 The simplest model is a flat tax rate with basic income:
   -1    29 
   -1    30 <math>
   -1    31     <mi>𝑓</mi><mo>(</mo><mi>π‘₯</mi><mo>)</mo>
   -1    32     <mo>=</mo>
   -1    33     <mi>π‘Ž</mi>
   -1    34     <mo>&InvisibleTimes;</mo>
   -1    35     <mi>π‘₯</mi>
   -1    36     <mo>+</mo>
   -1    37     <mi>𝑏</mi>
   -1    38 </math>
   -1    39 
   -1    40 ![](./linear.png)
   -1    41 
   -1    42 With this system, the marginal tax rate is constant, but the average tax rate
   -1    43 starts out [negative](https://en.wikipedia.org/wiki/Negative_income_tax) and
   -1    44 then quickly grows towards the marginal tax rate.
   -1    45 
   -1    46 ## Logarithmic
   -1    47 
   -1    48 Most real-world economies have progressive tax rates. That means: the higher
   -1    49 your income, the higher your marginal tax rate. The classic mathematical
   -1    50 function that grows to infinity but slows down while doing so is the logarithm:
   -1    51 
   -1    52 <math>
   -1    53     <mi>𝑓</mi><mo>(</mo><mi>π‘₯</mi><mo>)</mo>
   -1    54     <mo>=</mo>
   -1    55     <mi>π‘Ž</mi>
   -1    56     <mo>&InvisibleTimes;</mo>
   -1    57     <mi>ln</mi>
   -1    58     <mo>(</mo>
   -1    59     <mrow>
   -1    60         <mfrac>
   -1    61             <mi>x</mi>
   -1    62             <mi>a</mi>
   -1    63         </mfrac>
   -1    64         <mo>+</mo>
   -1    65         <mn>1</mn>
   -1    66     </mrow>
   -1    67     <mo>)</mo>
   -1    68     <mo>+</mo>
   -1    69     <mi>𝑏</mi>
   -1    70 </math>
   -1    71 
   -1    72 ![](log.png)
   -1    73 
   -1    74 Now the marginal tax rate starts at 0% and grows towards 100%.
   -1    75 
   -1    76 The marginal tax rate is what you have to pay on any additional income you
   -1    77 make. The common believe is that a high marginal tax rate will disincentivize
   -1    78 people from earning more (=Β being more productive). That is why I wanted to
   -1    79 start with 0%.
   -1    80 
   -1    81 On the other end of the spectrum, I don't see any reason to stop the
   -1    82 progression at some arbitrary value. If a single person has some astronomical
   -1    83 income, sure, let them pay 99.9% marginal tax. They will still have much more
   -1    84 money than everyone else.
   -1    85 
   -1    86 ## Power
   -1    87 
   -1    88 Another type of functions that go up to infinity but slow down on the way are
   -1    89 power functions like this one:
   -1    90 
   -1    91 <math>
   -1    92     <mi>𝑓</mi><mo>(</mo><mi>π‘₯</mi><mo>)</mo>
   -1    93     <mo>=</mo>
   -1    94     <msup>
   -1    95         <mrow>
   -1    96             <mo>(</mo>
   -1    97             <mrow>
   -1    98                 <mfrac>
   -1    99                     <mi>x</mi>
   -1   100                     <mrow>
   -1   101                         <mi>a</mi>
   -1   102                         <mo>&InvisibleTimes;</mo>
   -1   103                         <mi>b</mi>
   -1   104                     <mrow>
   -1   105                 </mfrac>
   -1   106                 <mo>+</mo>
   -1   107                 <mn>1</mn>
   -1   108             </mrow>
   -1   109             <mo>)</mo>
   -1   110         </mrow>
   -1   111         <mi>a</mi>
   -1   112     </msup>
   -1   113     <mo>&InvisibleTimes;</mo>
   -1   114     <mi>𝑏</mi>
   -1   115 </math>
   -1   116 
   -1   117 ![](pow.png)
   -1   118 
   -1   119 Like with the logarithm, the marginal tax rate starts at 0% and grows towards
   -1   120 100%. However, it doesn't grow as quickly, which puts it somewhere in between
   -1   121 the logarithmic and linear versions. So this feels the most balanced.
   -1   122 
   -1   123 I also like that <math><mi>a</mi></math> has an intuitive interpretation (how
   -1   124 curved to curve is). So if I were ever going to be minister of finance, this
   -1   125 would probably be the version that my advisors would have to talk me out of.

diff --git a/_content/posts/2025-05-16-tax-curves/linear.png b/_content/posts/2025-05-16-tax-curves/linear.png

Binary files differ.

diff --git a/_content/posts/2025-05-16-tax-curves/log.png b/_content/posts/2025-05-16-tax-curves/log.png

Binary files differ.

diff --git a/_content/posts/2025-05-16-tax-curves/pow.png b/_content/posts/2025-05-16-tax-curves/pow.png

Binary files differ.