Skip to content

Commit eba1c12

Browse files
committed
Slutsky decomposition substitution and income effects, added plotting
1 parent b6b46c5 commit eba1c12

File tree

1 file changed

+159
-19
lines changed

1 file changed

+159
-19
lines changed

mies/econtools/slutsky.py

+159-19
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1+
import plotly.graph_objects as go
2+
3+
from plotly.offline import plot
14
from econtools.budget import Budget
25
from econtools.utility import CobbDouglas
3-
from entities.person import Person
46

57

68
class Slutsky:
7-
9+
"""
10+
Implementation of the Slutsky equation, accepts two budgets, a utility function, and calculates
11+
the income and substitution effects
12+
"""
813
def __init__(
914
self,
1015
old_budget: Budget,
1116
new_budget: Budget,
1217
utility_function: CobbDouglas # need to replace with utility superclass
1318
):
1419
self.old_budget = old_budget
20+
self.old_budget.name = 'Old Budget'
1521
self.new_budget = new_budget
22+
self.new_budget.name = 'New Budget'
1623
self.utility = utility_function
1724

18-
self.old_consumption = self.utility.optimal_bundle(
25+
self.old_bundle = self.utility.optimal_bundle(
1926
self.old_budget.good_x.price,
2027
self.old_budget.good_y.price,
2128
self.old_budget.income
@@ -24,20 +31,29 @@ def __init__(
2431
self.pivoted_budget = self.calculate_pivoted_budget()
2532
self.substitution_bundle = self.calculate_substitution_bundle()
2633
self.substitution_effect = self.calculate_substitution_effect()
27-
self.final_budget = None
34+
self.new_bundle = self.calculate_new_bundle()
35+
self.income_effect = self.calculate_income_effect()
36+
self.plot = self.get_slutsky_plot()
2837

2938
def calculate_pivoted_budget(self):
39+
"""
40+
Pivot the budget line at the new price so the consumer can still afford their old bundle
41+
"""
3042
delta_p = self.new_budget.good_x.price - self.old_budget.good_x.price
31-
delta_m = self.old_consumption[0] * delta_p
43+
delta_m = self.old_bundle[0] * delta_p
3244
pivoted_income = self.old_budget.income + delta_m
3345
pivoted_budget = Budget(
34-
self.old_budget.good_x,
46+
self.new_budget.good_x,
3547
self.old_budget.good_y,
36-
pivoted_income
48+
pivoted_income,
49+
'Pivoted Budget'
3750
)
3851
return pivoted_budget
3952

4053
def calculate_substitution_bundle(self):
54+
"""
55+
Return the bundle consumed after pivoting the budget line
56+
"""
4157
substitution_bundle = self.utility.optimal_bundle(
4258
self.pivoted_budget.good_x.price,
4359
self.pivoted_budget.good_y.price,
@@ -46,22 +62,146 @@ def calculate_substitution_bundle(self):
4662
return substitution_bundle
4763

4864
def calculate_substitution_effect(self):
49-
substitution_effect = self.substitution_bundle[0] - self.old_consumption[0]
65+
substitution_effect = self.substitution_bundle[0] - self.old_bundle[0]
5066
return substitution_effect
5167

52-
my_person = Person(1)
68+
def calculate_new_bundle(self):
69+
"""
70+
Shift the budget line outward
71+
"""
72+
new_bundle = self.utility.optimal_bundle(
73+
self.new_budget.good_x.price,
74+
self.new_budget.good_y.price,
75+
self.new_budget.income
76+
)
77+
return new_bundle
78+
79+
def calculate_income_effect(self):
80+
income_effect = self.new_bundle[0] - self.substitution_bundle[0]
81+
return income_effect
82+
83+
def get_slutsky_plot(self):
84+
max_x_int = max(
85+
self.old_budget.income / self.old_budget.good_x.price,
86+
self.pivoted_budget.income / self.pivoted_budget.good_x.price,
87+
self.new_budget.income / self.new_budget.good_x.price
88+
) * 1.2
89+
90+
max_y_int = max(
91+
self.old_budget.income,
92+
self.pivoted_budget.income,
93+
self.new_budget.income,
94+
) * 1.2
95+
fig = go.Figure()
96+
97+
# budget lines
98+
fig.add_trace(self.old_budget.get_line())
99+
fig.add_trace(self.pivoted_budget.get_line())
100+
fig.add_trace(self.new_budget.get_line())
53101

54-
my_person.data
102+
# utility curves
103+
fig.add_trace(
104+
self.utility.trace(
105+
k=self.old_bundle[2],
106+
m=max_x_int,
107+
name='Old Utility'
108+
)
109+
)
110+
fig.add_trace(
111+
self.utility.trace(
112+
k=self.substitution_bundle[2],
113+
m=max_x_int,
114+
name='Pivoted Utility'
115+
)
116+
)
117+
fig.add_trace(
118+
self.utility.trace(
119+
k=self.new_bundle[2],
120+
m=max_x_int,
121+
name='New Utility'
122+
)
123+
)
124+
# consumption bundles
55125

56-
my_person.get_policy_history()
57-
my_person.policy_history
58-
my_person.get_policy('company_1', 1)
126+
fig.add_trace(
127+
go.Scatter(
128+
x=[self.old_bundle[0]],
129+
y=[self.old_bundle[1]],
130+
mode='markers+text',
131+
text=['Old Bundle'],
132+
textposition='top center',
133+
marker=dict(
134+
size=[15],
135+
color=[1]
136+
),
137+
showlegend=False
138+
)
139+
)
59140

60-
my_person.policy
61-
my_person.premium
141+
fig.add_trace(
142+
go.Scatter(
143+
x=[self.substitution_bundle[0]],
144+
y=[self.substitution_bundle[1]],
145+
mode='markers+text',
146+
text=['Pivoted Bundle'],
147+
textposition='top center',
148+
marker=dict(
149+
size=[15],
150+
color=[2]
151+
),
152+
showlegend=False
153+
)
154+
)
155+
156+
fig.add_trace(
157+
go.Scatter(
158+
x=[self.new_bundle[0]],
159+
y=[self.new_bundle[1]],
160+
mode='markers+text',
161+
text=['New Bundle'],
162+
textposition='top center',
163+
marker=dict(
164+
size=[15],
165+
color=[3]
166+
),
167+
showlegend=False
168+
)
169+
)
170+
# Substitution and income effect interval lines
171+
# fig.add_shape(
172+
# type='line',
173+
# xref='x',
174+
# yref='y',
175+
# x0=self.substitution_bundle[0] - self.substitution_effect,
176+
# y0=max_y_int / 10,
177+
# x1=self.substitution_bundle[0],
178+
# y1=max_y_int / 10,
179+
# line=dict(
180+
# color='LightSeaGreen',
181+
# dash='dashdot'
182+
# )
183+
# )
184+
# fig.add_trace(go.Scatter(
185+
# x=[self.substitution_bundle[0] * .5],
186+
# y=[max_y_int / 10],
187+
# text=['Substitution Effect'],
188+
# mode='text',
189+
# textposition='top center'
190+
# ))
62191

63-
my_person.get_budget()
192+
fig['layout'].update({
193+
'title': 'Slutsky Decomposition',
194+
'title_x': 0.5,
195+
'xaxis': {
196+
'title': 'Amount of Insurance',
197+
'range': [0, max_x_int]
198+
},
199+
'yaxis': {
200+
'title': 'Amount of All Other Goods',
201+
'range': [0, max_y_int]
202+
}
203+
})
204+
return fig
64205

65-
my_person.get_consumption()
66-
my_person.get_consumption_figure()
67-
my_person.show_consumption()
206+
def show_plot(self):
207+
plot(self.plot)

0 commit comments

Comments
 (0)