modelflowib 2.73__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- modelBLfunk.py +180 -0
- model_Excel.py +332 -0
- model_cvx.py +139 -0
- model_dynare.py +173 -0
- model_financial_stability.py +88 -0
- model_latex.py +497 -0
- model_latex_class.py +808 -0
- model_parquet_mixin.py +424 -0
- modelclass.py +9828 -0
- modelconstruct.py +1496 -0
- modelconstruct_estimation.py +2872 -0
- modeldash.py +265 -0
- modeldashboot.py +202 -0
- modeldashsidebar.py +456 -0
- modeldekom.py +651 -0
- modeldiff.py +561 -0
- modeldisplay.py +550 -0
- modelestimation.py +1776 -0
- modelestimator_new.py +2613 -0
- modelflowib-2.73.dist-info/METADATA +156 -0
- modelflowib-2.73.dist-info/RECORD +44 -0
- modelflowib-2.73.dist-info/WHEEL +5 -0
- modelflowib-2.73.dist-info/licenses/license.md +10 -0
- modelflowib-2.73.dist-info/top_level.txt +39 -0
- modelgrab.py +318 -0
- modelgrabgdx.py +584 -0
- modelgrabwf2.py +1107 -0
- modelhelp.py +543 -0
- modelhtml.py +606 -0
- modelinvert.py +250 -0
- modeljupyter.py +824 -0
- modeljupytermagic.py +813 -0
- modelmacrograb.py +98 -0
- modelmanipulation.py +1461 -0
- modelmf.py +349 -0
- modelnet.py +114 -0
- modelnewton.py +2178 -0
- modelnormalize.py +430 -0
- modelpattern.py +428 -0
- modelreport.py +2187 -0
- modeluserfunk.py +97 -0
- modelvis.py +1038 -0
- modelwidget.py +718 -0
- modelwidget_input.py +1933 -0
modelwidget.py
ADDED
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon Aug 9 14:46:11 2021
|
|
4
|
+
|
|
5
|
+
To define Jupyter widgets show variables.
|
|
6
|
+
@author: Ib
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import ipywidgets as widgets
|
|
11
|
+
|
|
12
|
+
# try:
|
|
13
|
+
# from ipysheet import sheet, cell, current
|
|
14
|
+
# from ipysheet.pandas_loader import from_dataframe, to_dataframe
|
|
15
|
+
# except:
|
|
16
|
+
# ...
|
|
17
|
+
# print('No ipysheet ')
|
|
18
|
+
from IPython.display import display, clear_output,Latex, Markdown
|
|
19
|
+
from dataclasses import dataclass,field
|
|
20
|
+
import matplotlib.pylab as plt
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from ipydatagrid import DataGrid
|
|
24
|
+
except Exception as e:
|
|
25
|
+
...
|
|
26
|
+
# print( 'no update sheets',e)
|
|
27
|
+
|
|
28
|
+
from modelclass import insertModelVar
|
|
29
|
+
from modelclass import model
|
|
30
|
+
from modeljupyter import jupviz
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class basewidget:
|
|
35
|
+
''' basis for widget updating in jupyter'''
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
datachildren : list = field(default_factory=list) # list of children widgets
|
|
39
|
+
|
|
40
|
+
def update_df(self,df,current_per):
|
|
41
|
+
''' will update container widgets'''
|
|
42
|
+
for w in self.datachildren:
|
|
43
|
+
w.update_df(df,current_per)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class tabwidget:
|
|
48
|
+
'''A widget to create tab or acordium contaners'''
|
|
49
|
+
|
|
50
|
+
tabdefdict : dict # = field(default_factory = lambda: ({}))
|
|
51
|
+
tab : bool = True
|
|
52
|
+
selected_index :any = None
|
|
53
|
+
|
|
54
|
+
def __post_init__(self):
|
|
55
|
+
|
|
56
|
+
thiswidget = widgets.Tab if self.tab else widgets.Accordion
|
|
57
|
+
self.datachildren = [tabcontent
|
|
58
|
+
for tabcontent in self.tabdefdict.values()]
|
|
59
|
+
self.datawidget = thiswidget([child.datawidget for child in self.datachildren],
|
|
60
|
+
selected_index = self.selected_index,
|
|
61
|
+
layout={'height': 'max-content'})
|
|
62
|
+
|
|
63
|
+
for i,key in enumerate(self.tabdefdict.keys()):
|
|
64
|
+
self.datawidget.set_title(i,key)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def update_df(self,df,current_per):
|
|
68
|
+
''' will update container widgets'''
|
|
69
|
+
for w in self.datachildren:
|
|
70
|
+
w.update_df(df,current_per)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def reset(self,g):
|
|
74
|
+
''' will reset container widgets'''
|
|
75
|
+
for w in self.datachildren:
|
|
76
|
+
w.reset(g)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class sheetwidget:
|
|
81
|
+
''' Class defining a widget with a data grid (using ipydatagrid) '''
|
|
82
|
+
df_var: pd.DataFrame = field(default_factory=pd.DataFrame)
|
|
83
|
+
trans: any = lambda x: x # Translation of variable names
|
|
84
|
+
transpose: bool = False # If the dataframe should be transposed
|
|
85
|
+
heading: str = ""
|
|
86
|
+
|
|
87
|
+
def __post_init__(self):
|
|
88
|
+
newnamedf = self.df_var.copy().rename(columns=self.trans)
|
|
89
|
+
self.org_df_var = newnamedf.T if self.transpose else newnamedf
|
|
90
|
+
|
|
91
|
+
column_widths = {col: max(len(col), 10) * 9 for col in self.org_df_var.columns} # Adjust column width dynamically
|
|
92
|
+
self.data_grid = DataGrid(pd.DataFrame(self.org_df_var),
|
|
93
|
+
column_widths=column_widths, enable_filters=False,enable_sort=False,
|
|
94
|
+
editable=True, index_name = 'year')
|
|
95
|
+
self.org_values = self.org_df_var.copy()
|
|
96
|
+
|
|
97
|
+
self.datawidget = widgets.VBox([widgets.Label(value=self.heading), self.data_grid]) if len(self.heading) else self.data_grid
|
|
98
|
+
|
|
99
|
+
def update_df(self, df, current_per=None):
|
|
100
|
+
updated_df = pd.DataFrame(self.data_grid.data)
|
|
101
|
+
if self.transpose:
|
|
102
|
+
updated_df = updated_df.T
|
|
103
|
+
|
|
104
|
+
updated_df.columns = self.df_var.columns
|
|
105
|
+
updated_df.index = self.df_var.index
|
|
106
|
+
df.loc[updated_df.index, updated_df.columns] = df.loc[updated_df.index, updated_df.columns] + updated_df
|
|
107
|
+
return df
|
|
108
|
+
|
|
109
|
+
def reset(self, g):
|
|
110
|
+
self.data_grid.data = pd.DataFrame(self.org_values)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
class slidewidget:
|
|
115
|
+
''' class defefining a widget with lines of slides '''
|
|
116
|
+
slidedef : dict # definition
|
|
117
|
+
altname : str = 'Alternative'
|
|
118
|
+
basename : str = 'Baseline'
|
|
119
|
+
expname : str = "Carbon tax rate, US$ per tonn "
|
|
120
|
+
def __post_init__(self):
|
|
121
|
+
...
|
|
122
|
+
# plt.ioff()
|
|
123
|
+
wexp = widgets.Label(value = self.expname,layout={'width':'54%'})
|
|
124
|
+
walt = widgets.Label(value = self.altname,layout={'width':'8%', 'border':"hide"})
|
|
125
|
+
wbas = widgets.Label(value = self.basename,layout={'width':'10%', 'border':"hide"})
|
|
126
|
+
whead = widgets.HBox([wexp,walt,wbas])
|
|
127
|
+
#
|
|
128
|
+
self.wset = [widgets.FloatSlider(description=des,
|
|
129
|
+
min=cont['min'],
|
|
130
|
+
max=cont['max'],
|
|
131
|
+
value=cont['value'],
|
|
132
|
+
step=cont.get('step',0.01),
|
|
133
|
+
layout={'width':'60%'},style={'description_width':'40%'},
|
|
134
|
+
readout_format = f":>,.{cont.get('dec',2)}f",
|
|
135
|
+
continuous_update=False
|
|
136
|
+
)
|
|
137
|
+
for des,cont in self.slidedef.items()]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
for w in self.wset:
|
|
141
|
+
w.observe(self.set_slide_value,names='value',type='change')
|
|
142
|
+
|
|
143
|
+
waltval= [widgets.Label(
|
|
144
|
+
value=f"{cont['value']:>,.{cont.get('dec',2)}f}",
|
|
145
|
+
layout=widgets.Layout(display="flex", justify_content="center", width="10%", border="hide"))
|
|
146
|
+
for des,cont in self.slidedef.items()
|
|
147
|
+
|
|
148
|
+
]
|
|
149
|
+
self.wslide = [widgets.HBox([s,v]) for s,v in zip(self.wset,waltval)]
|
|
150
|
+
self.slidewidget = widgets.VBox([whead] + self.wslide)
|
|
151
|
+
self.datawidget = widgets.VBox([whead] + self.wslide)
|
|
152
|
+
|
|
153
|
+
# define the result object
|
|
154
|
+
self.current_values = {des:
|
|
155
|
+
{key : v.split() if key=='var' else v for key,v in cont.items() if key in {'value','var','op'}}
|
|
156
|
+
for des,cont in self.slidedef.items()}
|
|
157
|
+
|
|
158
|
+
def reset(self,g):
|
|
159
|
+
for i,(des,cont) in enumerate(self.slidedef.items()):
|
|
160
|
+
self.wset[i].value = cont['value']
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def update_df(self,df,current_per):
|
|
165
|
+
''' updates a dataframe with the values from the widget'''
|
|
166
|
+
for i,(des,cont) in enumerate(self.current_values.items()):
|
|
167
|
+
op = cont.get('op','=')
|
|
168
|
+
value = cont['value']
|
|
169
|
+
for var in cont['var']:
|
|
170
|
+
if op == '+':
|
|
171
|
+
df.loc[current_per,var] = df.loc[current_per,var] + value
|
|
172
|
+
elif op == '+impulse':
|
|
173
|
+
df.loc[current_per[0],var] = df.loc[current_per[0],var] + value
|
|
174
|
+
elif op == '=start-':
|
|
175
|
+
startindex = df.index.get_loc(current_per[0])
|
|
176
|
+
varloc = df.columns.get_loc(var)
|
|
177
|
+
df.iloc[:startindex,varloc] = value
|
|
178
|
+
elif op == '=':
|
|
179
|
+
df.loc[current_per,var] = value
|
|
180
|
+
elif op == '=impulse':
|
|
181
|
+
df.loc[current_per[0],var] = value
|
|
182
|
+
elif op == '%':
|
|
183
|
+
df.loc[current_per,var] = df.loc[current_per,var] * (1-value/100)
|
|
184
|
+
else:
|
|
185
|
+
print(f'Wrong operator in {cont}.\nNot updated')
|
|
186
|
+
assert 1==3,'wRONG OPERATOR'
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def set_slide_value(self,g):
|
|
190
|
+
''' updates the new values to the self.current_vlues
|
|
191
|
+
will be used in update_df
|
|
192
|
+
'''
|
|
193
|
+
line_des = g['owner'].description
|
|
194
|
+
if 0:
|
|
195
|
+
print()
|
|
196
|
+
for k,v in g.items():
|
|
197
|
+
print(f'{k}:{v}')
|
|
198
|
+
|
|
199
|
+
self.current_values[line_des]['value'] = g['new']
|
|
200
|
+
|
|
201
|
+
@dataclass
|
|
202
|
+
class sumslidewidget:
|
|
203
|
+
''' class defefining a widget with lines of slides '''
|
|
204
|
+
slidedef : dict # definition
|
|
205
|
+
maxsum : any = None
|
|
206
|
+
altname : str = 'Alternative'
|
|
207
|
+
basename : str = 'Baseline'
|
|
208
|
+
expname : str = "Carbon tax rate, US$ per tonn "
|
|
209
|
+
def __post_init__(self):
|
|
210
|
+
...
|
|
211
|
+
|
|
212
|
+
self.first = list(self.slidedef.keys())[:-1]
|
|
213
|
+
self.lastdes = list(self.slidedef.keys())[-1]
|
|
214
|
+
|
|
215
|
+
wexp = widgets.Label(value = self.expname,layout={'width':'54%'})
|
|
216
|
+
walt = widgets.Label(value = self.altname,layout={'width':'8%', 'border':"hide"})
|
|
217
|
+
wbas = widgets.Label(value = self.basename,layout={'width':'10%', 'border':"hide"})
|
|
218
|
+
whead = widgets.HBox([wexp,walt,wbas])
|
|
219
|
+
#
|
|
220
|
+
self.wset = [widgets.FloatSlider(description=des,
|
|
221
|
+
min=cont['min'],
|
|
222
|
+
max=cont['max'],
|
|
223
|
+
value=cont['value'],
|
|
224
|
+
step=cont.get('step',0.01),
|
|
225
|
+
layout={'width':'60%'},style={'description_width':'40%'},
|
|
226
|
+
readout_format = f":>,.{cont.get('dec',2)}f",
|
|
227
|
+
continuous_update=False,
|
|
228
|
+
disabled= False
|
|
229
|
+
)
|
|
230
|
+
for des,cont in self.slidedef.items()]
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
for w in self.wset:
|
|
235
|
+
w.observe(self.set_slide_value,names='value',type='change')
|
|
236
|
+
|
|
237
|
+
waltval= [widgets.Label(
|
|
238
|
+
value=f"{cont['value']:>,.{cont.get('dec',2)}f}",
|
|
239
|
+
layout=widgets.Layout(display="flex", justify_content="center", width="10%", border="hide"))
|
|
240
|
+
for des,cont in self.slidedef.items()
|
|
241
|
+
|
|
242
|
+
]
|
|
243
|
+
self.wslide = [widgets.HBox([s,v]) for s,v in zip(self.wset,waltval)]
|
|
244
|
+
self.slidewidget = widgets.VBox([whead] + self.wslide)
|
|
245
|
+
self.datawidget = widgets.VBox([whead] + self.wslide)
|
|
246
|
+
|
|
247
|
+
# define the result object
|
|
248
|
+
self.current_values = {des:
|
|
249
|
+
{key : v.split() if key=='var' else v for key,v in cont.items() if key in {'value','var','op','min','max'}}
|
|
250
|
+
for des,cont in self.slidedef.items()}
|
|
251
|
+
|
|
252
|
+
def reset(self,g):
|
|
253
|
+
for i,(des,cont) in enumerate(self.slidedef.items()):
|
|
254
|
+
self.wset[i].value = cont['value']
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def update_df(self,df,current_per):
|
|
259
|
+
''' updates a dataframe with the values from the widget'''
|
|
260
|
+
for i,(des,cont) in enumerate(self.current_values.items()):
|
|
261
|
+
op = cont.get('op','=')
|
|
262
|
+
value = cont['value']
|
|
263
|
+
for var in cont['var']:
|
|
264
|
+
if op == '+':
|
|
265
|
+
df.loc[current_per,var] = df.loc[current_per,var] + value
|
|
266
|
+
elif op == '+impulse':
|
|
267
|
+
df.loc[current_per[0],var] = df.loc[current_per[0],var] + value
|
|
268
|
+
elif op == '=start-':
|
|
269
|
+
startindex = df.index.get_loc(current_per[0])
|
|
270
|
+
varloc = df.columns.get_loc(var)
|
|
271
|
+
df.iloc[:startindex,varloc] = value
|
|
272
|
+
elif op == '=':
|
|
273
|
+
df.loc[current_per,var] = value
|
|
274
|
+
elif op == '=impulse':
|
|
275
|
+
df.loc[current_per[0],var] = value
|
|
276
|
+
else:
|
|
277
|
+
print(f'Wrong operator in {cont}.\nNot updated')
|
|
278
|
+
assert 1==3,'wRONG OPERATOR'
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def set_slide_value(self,g):
|
|
282
|
+
''' updates the new values to the self.current_vlues
|
|
283
|
+
will be used in update_df
|
|
284
|
+
'''
|
|
285
|
+
line_des = g['owner'].description
|
|
286
|
+
line_index = list(self.current_values.keys()).index(line_des)
|
|
287
|
+
if 0:
|
|
288
|
+
print()
|
|
289
|
+
for k,v in g.items():
|
|
290
|
+
print(f'{k}:{v}')
|
|
291
|
+
|
|
292
|
+
self.current_values[line_des]['value'] = g['new']
|
|
293
|
+
# print(self.current_values)
|
|
294
|
+
if type(self.maxsum) == float:
|
|
295
|
+
allvalues = [v['value'] for v in self.current_values.values()]
|
|
296
|
+
thissum = sum(allvalues)
|
|
297
|
+
if thissum > self.maxsum:
|
|
298
|
+
# print(f'{allvalues=}')
|
|
299
|
+
# print(f"{self.current_values[self.lastdes]['min']=}")
|
|
300
|
+
newlast = self.maxsum-sum(allvalues[:-1])
|
|
301
|
+
newlast = max(newlast,self.current_values[self.lastdes]['min'])
|
|
302
|
+
# print(f'{newlast=}')
|
|
303
|
+
self.current_values[self.lastdes]['value']= newlast
|
|
304
|
+
|
|
305
|
+
newsum= sum([v['value'] for v in self.current_values.values()])
|
|
306
|
+
# print(f'{newsum=}')
|
|
307
|
+
# print(f'{line_index=}')
|
|
308
|
+
if newsum > self.maxsum:
|
|
309
|
+
self.current_values[line_des]['value']=self.wset[line_index].value-newsum +self.maxsum
|
|
310
|
+
self.wset[line_index].value = self.current_values[line_des]['value']
|
|
311
|
+
|
|
312
|
+
self.wset[-1].value = newlast
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@dataclass
|
|
317
|
+
class updatewidget:
|
|
318
|
+
''' class to input and run a model'''
|
|
319
|
+
|
|
320
|
+
mmodel : any # a model
|
|
321
|
+
a_datawidget : any # a tab to update from
|
|
322
|
+
basename : str ='Business as usual'
|
|
323
|
+
keeppat : str = '*'
|
|
324
|
+
varpat : str ='*'
|
|
325
|
+
showvarpat : bool = True
|
|
326
|
+
exodif : pd.DataFrame = field(default_factory=pd.DataFrame) # definition
|
|
327
|
+
lwrun : bool = True
|
|
328
|
+
lwupdate : bool = False
|
|
329
|
+
lwreset : bool = True
|
|
330
|
+
lwsetbas : bool = True
|
|
331
|
+
lwshow :bool = True
|
|
332
|
+
outputwidget : str = 'jupviz'
|
|
333
|
+
prefix_dict : dict = field(default_factory=dict)
|
|
334
|
+
display_first :any = None
|
|
335
|
+
vline : list = field(default_factory=list)
|
|
336
|
+
relativ_start : int = 0
|
|
337
|
+
short :bool = False
|
|
338
|
+
legend :bool = False
|
|
339
|
+
|
|
340
|
+
def __post_init__(self):
|
|
341
|
+
self.baseline = self.mmodel.basedf.copy()
|
|
342
|
+
wrun = widgets.Button(description="Run scenario")
|
|
343
|
+
wrun.on_click(self.run)
|
|
344
|
+
|
|
345
|
+
wupdate = widgets.Button(description="Update the dataset ")
|
|
346
|
+
wupdate.on_click(self.update)
|
|
347
|
+
|
|
348
|
+
wreset = widgets.Button(description="Reset to start")
|
|
349
|
+
wreset.on_click(self.reset)
|
|
350
|
+
|
|
351
|
+
wshow = widgets.Button(description="Show results")
|
|
352
|
+
wshow.on_click(self.show)
|
|
353
|
+
|
|
354
|
+
wsetbas = widgets.Button(description="Use as baseline")
|
|
355
|
+
wsetbas.on_click(self.setbasis)
|
|
356
|
+
self.experiment = 0
|
|
357
|
+
|
|
358
|
+
lbut = []
|
|
359
|
+
|
|
360
|
+
if self.lwrun: lbut.append(wrun)
|
|
361
|
+
if self.lwshow: lbut.append(wshow)
|
|
362
|
+
if self.lwupdate: lbut.append(wupdate)
|
|
363
|
+
if self.lwreset: lbut.append(wreset)
|
|
364
|
+
if self.lwsetbas : lbut.append(wsetbas)
|
|
365
|
+
|
|
366
|
+
wbut = widgets.HBox(lbut)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
self.wname = widgets.Text(value=self.basename,placeholder='Type something',description='Scenario name:',
|
|
370
|
+
layout={'width':'30%'},style={'description_width':'50%'})
|
|
371
|
+
self.wpat = widgets.Text(value= self.varpat,placeholder='Type something',description='Display variables:',
|
|
372
|
+
layout={'width':'65%'},style={'description_width':'30%'})
|
|
373
|
+
|
|
374
|
+
self.wpat.layout.visibility = 'visible' if self.showvarpat else 'hidden'
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
winputstring = widgets.HBox([self.wname,self.wpat])
|
|
378
|
+
|
|
379
|
+
self.wtotal = widgets.VBox([self.a_datawidget.datawidget,winputstring,wbut])
|
|
380
|
+
|
|
381
|
+
self.mmodel.keep_solutions = {}
|
|
382
|
+
self.mmodel.keep_solutions = {self.wname.value : self.baseline}
|
|
383
|
+
self.mmodel.keep_exodif = {}
|
|
384
|
+
|
|
385
|
+
self.experiment += 1
|
|
386
|
+
self.wname.value = f'Experiment {self.experiment}'
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def update(self,g):
|
|
390
|
+
self.thisexperiment = self.baseline.copy()
|
|
391
|
+
self.a_datawidget.update_df(self.thisexperiment,self.mmodel.current_per)
|
|
392
|
+
self.exodif = self.mmodel.exodif(self.baseline,self.thisexperiment)
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def show(self,g=None):
|
|
396
|
+
if self.outputwidget == 'jupviz':
|
|
397
|
+
clear_output()
|
|
398
|
+
display(self.wtotal)
|
|
399
|
+
|
|
400
|
+
displaydict = {k :v.loc[self.mmodel.current_per,self.wpat.value.split()]
|
|
401
|
+
for k,v in self.mmodel.keep_solutions.items()}
|
|
402
|
+
jupviz(displaydict,legend=0)()
|
|
403
|
+
|
|
404
|
+
elif self.outputwidget == 'keep_viz':
|
|
405
|
+
|
|
406
|
+
selectfrom = [v for v in self.mmodel.vlist(self.wpat.value) if v in
|
|
407
|
+
set(list(self.mmodel.keep_solutions.values())[0].columns)]
|
|
408
|
+
clear_output()
|
|
409
|
+
display(self.wtotal)
|
|
410
|
+
plt.close('all')
|
|
411
|
+
_ = self.mmodel.keep_viz(pat=selectfrom[0],selectfrom=selectfrom,vline=self.vline)
|
|
412
|
+
|
|
413
|
+
elif self.outputwidget == 'keep_viz_prefix':
|
|
414
|
+
|
|
415
|
+
selectfrom = [v for v in self.mmodel.vlist(self.wpat.value) if v in
|
|
416
|
+
set(list(self.mmodel.keep_solutions.values())[0].columns)]
|
|
417
|
+
clear_output()
|
|
418
|
+
if self.display_first:
|
|
419
|
+
display(self.display_first)
|
|
420
|
+
display(self.wtotal)
|
|
421
|
+
plt.close('all')
|
|
422
|
+
with self.mmodel.set_smpl_relative(self.relativ_start,0):
|
|
423
|
+
_ = self.mmodel.keep_viz_prefix(pat=selectfrom[0],
|
|
424
|
+
selectfrom=selectfrom,prefix_dict=self.prefix_dict,vline=self.vline,short=self.short,legend=self.legend)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def run(self,g):
|
|
428
|
+
clear_output(True)
|
|
429
|
+
display(self.wtotal)
|
|
430
|
+
self.update(g)
|
|
431
|
+
self.mmodel(self.thisexperiment,progressbar=1,keep = self.wname.value,
|
|
432
|
+
keep_variables = self.keeppat)
|
|
433
|
+
self.mmodel.keep_exodif[self.wname.value] = self.exodif
|
|
434
|
+
self.mmodel.inputwidget_alternativerun = True
|
|
435
|
+
self.current_experiment = self.wname.value
|
|
436
|
+
self.experiment += 1
|
|
437
|
+
self.wname.value = f'Experiment {self.experiment}'
|
|
438
|
+
self.show(g)
|
|
439
|
+
|
|
440
|
+
def setbasis(self,g):
|
|
441
|
+
clear_output(True)
|
|
442
|
+
display(self.wtotal)
|
|
443
|
+
self.mmodel.keep_solutions={self.current_experiment:self.mmodel.keep_solutions[self.current_experiment]}
|
|
444
|
+
|
|
445
|
+
self.mmodel.keep_exodif[self.current_experiment] = self.exodif
|
|
446
|
+
self.mmodel.inputwidget_alternativerun = True
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def reset(self,g):
|
|
452
|
+
self.a_datawidget.reset(g)
|
|
453
|
+
|
|
454
|
+
def fig_to_image(figs,format='svg'):
|
|
455
|
+
from io import StringIO
|
|
456
|
+
f = StringIO()
|
|
457
|
+
figs.savefig(f,format=format)
|
|
458
|
+
f.seek(0)
|
|
459
|
+
image= f.read()
|
|
460
|
+
if format == 'svg':
|
|
461
|
+
# Make the SVG responsive: matplotlib emits the figure's native size
|
|
462
|
+
# (e.g. width="1440pt" for a wide ncol>1 figure), which overflows the
|
|
463
|
+
# notebook output area so only the left column shows. Drop the fixed
|
|
464
|
+
# pt width/height and let the viewBox drive the aspect ratio so the
|
|
465
|
+
# full figure scales to the container width.
|
|
466
|
+
import re
|
|
467
|
+
def _responsive(m):
|
|
468
|
+
tag = re.sub(r'\s(?:width|height)="[^"]*pt"', '', m.group(0))
|
|
469
|
+
if 'style=' not in tag:
|
|
470
|
+
tag = tag[:-1] + ' style="width:100%;height:auto;">'
|
|
471
|
+
return tag
|
|
472
|
+
image = re.sub(r'<svg\b[^>]*>', _responsive, image, count=1)
|
|
473
|
+
return image
|
|
474
|
+
|
|
475
|
+
@dataclass
|
|
476
|
+
class htmlwidget_df:
|
|
477
|
+
''' class displays a dataframe in a html widget '''
|
|
478
|
+
|
|
479
|
+
mmodel : any # a model
|
|
480
|
+
df_var : pd.DataFrame = field(default_factory=pd.DataFrame) # definition
|
|
481
|
+
trans : any = lambda x : x # renaming of variables
|
|
482
|
+
transpose : bool = False # orientation of dataframe
|
|
483
|
+
expname : str = ""
|
|
484
|
+
percent : bool = False
|
|
485
|
+
style : any = ''
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
def __post_init__(self):
|
|
489
|
+
...
|
|
490
|
+
|
|
491
|
+
self.wexp = widgets.Label(value = self.expname,layout={'width':'54%'})
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
newnamedf = self.df_var.copy().rename(columns=self.trans)
|
|
495
|
+
self.org_df_var = newnamedf.T if self.transpose else newnamedf
|
|
496
|
+
if 0:
|
|
497
|
+
image = self.mmodel.ibsstyle(self.org_df_var,percent = self.percent).to_html()
|
|
498
|
+
else:
|
|
499
|
+
style_html = """
|
|
500
|
+
<style>
|
|
501
|
+
table, th, td {
|
|
502
|
+
border: none;
|
|
503
|
+
border-collapse: collapse;
|
|
504
|
+
padding: 10px; # Adjust padding as needed
|
|
505
|
+
text-align: left;
|
|
506
|
+
}
|
|
507
|
+
</style>
|
|
508
|
+
"""
|
|
509
|
+
if self.style:
|
|
510
|
+
image_html = self.style(self.df_var).to_html()
|
|
511
|
+
else:
|
|
512
|
+
image_html = self.mmodel.ibsstyle(self.org_df_var, percent=self.percent).to_html()
|
|
513
|
+
image = f"{style_html}{image_html}"
|
|
514
|
+
|
|
515
|
+
self.whtml = widgets.HTML(image)
|
|
516
|
+
self.datawidget=widgets.VBox([self.wexp,self.whtml]) if len(self.expname) else self.whtml
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
@property
|
|
521
|
+
def show(self):
|
|
522
|
+
display(self.datawidget)
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
@dataclass
|
|
526
|
+
class htmlwidget_fig:
|
|
527
|
+
''' class displays a dataframe in a html widget '''
|
|
528
|
+
|
|
529
|
+
figs : any # a model
|
|
530
|
+
expname : str = ""
|
|
531
|
+
format : str = "svg"
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
def __post_init__(self):
|
|
535
|
+
...
|
|
536
|
+
# print(f'Create {self.expname}')
|
|
537
|
+
|
|
538
|
+
self.wexp = widgets.Label(value = self.expname,layout={'width':'54%'})
|
|
539
|
+
|
|
540
|
+
image = fig_to_image(self.figs,format=self.format)
|
|
541
|
+
self.whtml = widgets.HTML(image)
|
|
542
|
+
self.datawidget=widgets.VBox([self.wexp,self.whtml]) if len(self.expname) else self.whtml
|
|
543
|
+
|
|
544
|
+
@dataclass
|
|
545
|
+
class htmlwidget_style:
|
|
546
|
+
''' Class that displays text in an HTML widget. '''
|
|
547
|
+
|
|
548
|
+
styler: any = ''
|
|
549
|
+
|
|
550
|
+
def __post_init__(self):
|
|
551
|
+
# Initialize the label widget with the provided text
|
|
552
|
+
style_html = """
|
|
553
|
+
<style>
|
|
554
|
+
table, th, td {
|
|
555
|
+
border: none;
|
|
556
|
+
border-collapse: collapse;
|
|
557
|
+
padding: 10px; # Adjust padding as needed
|
|
558
|
+
line-height: normal; # Ensures normal line spacing
|
|
559
|
+
|
|
560
|
+
text-align: left;
|
|
561
|
+
}
|
|
562
|
+
</style>
|
|
563
|
+
"""
|
|
564
|
+
self.datawidget = widgets.HTML(f'{style_html}{self.styler.to_html()}' )
|
|
565
|
+
|
|
566
|
+
def display(self):
|
|
567
|
+
# Function to display the widget
|
|
568
|
+
display(self.datawidget)
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
@dataclass
|
|
572
|
+
class htmlwidget_label:
|
|
573
|
+
''' class displays a dataframe in a html widget '''
|
|
574
|
+
|
|
575
|
+
expname : str = ""
|
|
576
|
+
format : str = "svg"
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
def __post_init__(self):
|
|
580
|
+
...
|
|
581
|
+
|
|
582
|
+
self.wexp = widgets.Label(value = self.expname,layout={'width':'54%'})
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
self.datawidget=self.wexp
|
|
586
|
+
|
|
587
|
+
@dataclass
|
|
588
|
+
class htmlwidget_text:
|
|
589
|
+
''' Class that displays text in an HTML widget. '''
|
|
590
|
+
|
|
591
|
+
text: str = ""
|
|
592
|
+
format: str = "svg" # This property is included but not used in this example
|
|
593
|
+
|
|
594
|
+
def __post_init__(self):
|
|
595
|
+
# Initialize the label widget with the provided text
|
|
596
|
+
self.datawidget = widgets.HTML(
|
|
597
|
+
value=f"<p style='font-family:sans-serif;'>{self.text}</p>",
|
|
598
|
+
layout={'width': '90%'}
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
def display(self):
|
|
602
|
+
# Function to display the widget
|
|
603
|
+
display(self.data_widget)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
@dataclass
|
|
607
|
+
class visshow:
|
|
608
|
+
mmodel : any # a model
|
|
609
|
+
varpat : str ='*'
|
|
610
|
+
showvarpat : bool = True
|
|
611
|
+
show_on : bool = True # Display when called
|
|
612
|
+
|
|
613
|
+
def __post_init__(self):
|
|
614
|
+
...
|
|
615
|
+
# from IPython import get_ipython
|
|
616
|
+
# get_ipython().magic('matplotlib notebook')
|
|
617
|
+
# print(plt.get_backend())
|
|
618
|
+
# print('hej haj')
|
|
619
|
+
# plt.close('all')
|
|
620
|
+
|
|
621
|
+
# print(f'{self.show_on=}')
|
|
622
|
+
# plt.ioff()
|
|
623
|
+
this_vis = self.mmodel[self.varpat]
|
|
624
|
+
self.out_dict = {}
|
|
625
|
+
self.out_dict['Baseline'] ={'df':this_vis.base}
|
|
626
|
+
self.out_dict['Alternative'] ={'df':this_vis}
|
|
627
|
+
self.out_dict['Difference'] ={'df':this_vis.dif}
|
|
628
|
+
self.out_dict['Diff. pct. level'] ={'df':this_vis.difpctlevel,'percent':True}
|
|
629
|
+
self.out_dict['Base growth'] ={'df':this_vis.base.pct,'percent':True}
|
|
630
|
+
self.out_dict['Alt. growth'] ={'df':this_vis.pct,'percent':True}
|
|
631
|
+
self.out_dict['Diff. in growth'] ={'df':this_vis.difpct,'percent':True}
|
|
632
|
+
|
|
633
|
+
out = widgets.Output()
|
|
634
|
+
self.out_to_data = {key:
|
|
635
|
+
htmlwidget_df(self.mmodel,value['df'].df.T,expname=key,
|
|
636
|
+
|
|
637
|
+
percent=value.get('percent',False))
|
|
638
|
+
for key,value in self.out_dict.items()}
|
|
639
|
+
|
|
640
|
+
with out: # to suppress the display of matplotlib creation
|
|
641
|
+
self.out_to_figs ={key:
|
|
642
|
+
htmlwidget_fig(value['df'].rename().plot(top=1.0,title=''),expname='')
|
|
643
|
+
for key,value in self.out_dict.items() }
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
tabnew = {key: tabwidget({'Charts':self.out_to_figs[key],'Data':self.out_to_data[key]},selected_index=0) for key in self.out_to_figs.keys()}
|
|
647
|
+
# print('tabnew created')
|
|
648
|
+
exodif = self.mmodel.exodif()
|
|
649
|
+
exonames = exodif.columns
|
|
650
|
+
exoindex = exodif.index
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
if 1:
|
|
654
|
+
|
|
655
|
+
if len(exonames):
|
|
656
|
+
exoindexstart = max(self.mmodel.lastdf.index.get_loc(exodif.index[0]),self.mmodel.lastdf.index.get_loc(self.mmodel.current_per[0]))
|
|
657
|
+
exoindexend = min(self.mmodel.lastdf.index.get_loc(exodif.index[-1]),self.mmodel.lastdf.index.get_loc(self.mmodel.current_per[-1]))
|
|
658
|
+
exoindexnew = self.mmodel.lastdf.index[exoindexstart:exoindexend]
|
|
659
|
+
rows,cols =exodif.loc[exoindexnew,:].shape
|
|
660
|
+
exosize = rows*cols
|
|
661
|
+
|
|
662
|
+
if exosize < 2000 :
|
|
663
|
+
exobase = self.mmodel.basedf.loc[exoindexnew,exonames]
|
|
664
|
+
exolast = self.mmodel.lastdf.loc[exoindexnew,exonames]
|
|
665
|
+
|
|
666
|
+
out_exodif = htmlwidget_df(self.mmodel,exodif.loc[exoindexnew,:].T)
|
|
667
|
+
out_exobase = htmlwidget_df(self.mmodel,exobase.T)
|
|
668
|
+
out_exolast = htmlwidget_df(self.mmodel,exolast.T)
|
|
669
|
+
else:
|
|
670
|
+
out_exodif = htmlwidget_label(expname = 'To many to display ')
|
|
671
|
+
out_exobase = htmlwidget_label(expname = 'To many to display ')
|
|
672
|
+
out_exolast = htmlwidget_label(expname = 'To many to display ')
|
|
673
|
+
else:
|
|
674
|
+
out_exodif = htmlwidget_label(expname = 'No difference in exogenous')
|
|
675
|
+
out_exobase = htmlwidget_label(expname = 'No difference in exogenous')
|
|
676
|
+
out_exolast = htmlwidget_label(expname = 'No difference in exogenous')
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
out_tab_info = tabwidget({'Delta exogenous':out_exodif,
|
|
680
|
+
'Baseline exogenous':out_exobase,
|
|
681
|
+
'Alt. exogenous':out_exolast},selected_index=0)
|
|
682
|
+
|
|
683
|
+
tabnew['Exo info'] = out_tab_info
|
|
684
|
+
# print('exo inf created')
|
|
685
|
+
|
|
686
|
+
this = tabwidget(tabnew,selected_index=0)
|
|
687
|
+
# print('this created ')
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
self.datawidget = this.datawidget
|
|
691
|
+
if self.show_on:
|
|
692
|
+
...
|
|
693
|
+
display(self.datawidget)
|
|
694
|
+
|
|
695
|
+
try:
|
|
696
|
+
get_ipython().magic('matplotlib inline')
|
|
697
|
+
except:
|
|
698
|
+
...
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def __repr__(self):
|
|
702
|
+
return ''
|
|
703
|
+
|
|
704
|
+
def _html_repr_(self):
|
|
705
|
+
return self.datawidget
|
|
706
|
+
|
|
707
|
+
@property
|
|
708
|
+
def show(self):
|
|
709
|
+
display(self.datawidget)
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
if __name__ == '__main__':
|
|
713
|
+
# if 'masia' not in locals():
|
|
714
|
+
# print('loading model')
|
|
715
|
+
# masia,baseline = model.modelload('C:/wb Dawn/UNESCAP-/Asia/Asia.pcim',run=0,silent=1)
|
|
716
|
+
# test = slidewidget(masia,{})
|
|
717
|
+
...
|
|
718
|
+
|