1
+ import plotly .graph_objects as go
2
+
3
+ from plotly .offline import plot
1
4
from econtools .budget import Budget
2
5
from econtools .utility import CobbDouglas
3
- from entities .person import Person
4
6
5
7
6
8
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
+ """
8
13
def __init__ (
9
14
self ,
10
15
old_budget : Budget ,
11
16
new_budget : Budget ,
12
17
utility_function : CobbDouglas # need to replace with utility superclass
13
18
):
14
19
self .old_budget = old_budget
20
+ self .old_budget .name = 'Old Budget'
15
21
self .new_budget = new_budget
22
+ self .new_budget .name = 'New Budget'
16
23
self .utility = utility_function
17
24
18
- self .old_consumption = self .utility .optimal_bundle (
25
+ self .old_bundle = self .utility .optimal_bundle (
19
26
self .old_budget .good_x .price ,
20
27
self .old_budget .good_y .price ,
21
28
self .old_budget .income
@@ -24,20 +31,29 @@ def __init__(
24
31
self .pivoted_budget = self .calculate_pivoted_budget ()
25
32
self .substitution_bundle = self .calculate_substitution_bundle ()
26
33
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 ()
28
37
29
38
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
+ """
30
42
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
32
44
pivoted_income = self .old_budget .income + delta_m
33
45
pivoted_budget = Budget (
34
- self .old_budget .good_x ,
46
+ self .new_budget .good_x ,
35
47
self .old_budget .good_y ,
36
- pivoted_income
48
+ pivoted_income ,
49
+ 'Pivoted Budget'
37
50
)
38
51
return pivoted_budget
39
52
40
53
def calculate_substitution_bundle (self ):
54
+ """
55
+ Return the bundle consumed after pivoting the budget line
56
+ """
41
57
substitution_bundle = self .utility .optimal_bundle (
42
58
self .pivoted_budget .good_x .price ,
43
59
self .pivoted_budget .good_y .price ,
@@ -46,22 +62,146 @@ def calculate_substitution_bundle(self):
46
62
return substitution_bundle
47
63
48
64
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 ]
50
66
return substitution_effect
51
67
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 ())
53
101
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
55
125
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
+ )
59
140
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
+ # ))
62
191
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
64
205
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