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
modelmf.py
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
This is a module for extending pandas dataframes with the modelflow toolbox
|
|
5
|
+
|
|
6
|
+
Created on Sat March 2019
|
|
7
|
+
|
|
8
|
+
@author: hanseni
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import fnmatch
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
from modelclass import model
|
|
17
|
+
from modelhelp import debug_var
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if not hasattr(pd.DataFrame,'mfcalc'):
|
|
21
|
+
|
|
22
|
+
@pd.api.extensions.register_dataframe_accessor("mfcalc")
|
|
23
|
+
class mfcalc():
|
|
24
|
+
'''
|
|
25
|
+
Used to carry out calculation specified as equations
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
eq (TYPE): Equations one on each line. can be started with <start end> to control calculation sample .
|
|
29
|
+
start (TYPE, optional): DESCRIPTION. Defaults to ''.
|
|
30
|
+
end (TYPE, optional): DESCRIPTION. Defaults to ''.
|
|
31
|
+
showeq (TYPE, optional): If True the equations will be printed. Defaults to False.
|
|
32
|
+
**kwargs (TYPE): Here all solve options can be provided.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Dataframe.
|
|
36
|
+
|
|
37
|
+
'''
|
|
38
|
+
def __init__(self, pandas_obj):
|
|
39
|
+
# self._validate(pandas_obj)
|
|
40
|
+
self._obj = pandas_obj
|
|
41
|
+
# print(self._obj)
|
|
42
|
+
|
|
43
|
+
def __call__(self,eq,start='',end='',showeq=False, **kwargs):
|
|
44
|
+
'''
|
|
45
|
+
This call performs the calculation
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
eq (TYPE): Equations one on each line. can be started with <start end> to control calculation sample .
|
|
49
|
+
start (TYPE, optional): DESCRIPTION. Defaults to ''.
|
|
50
|
+
end (TYPE, optional): DESCRIPTION. Defaults to ''.
|
|
51
|
+
showeq (TYPE, optional): If True the equations will be printed. Defaults to False.
|
|
52
|
+
**kwargs (TYPE): Here all solve options can be provided.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Dataframe.
|
|
56
|
+
|
|
57
|
+
'''
|
|
58
|
+
|
|
59
|
+
# print({**kwargs,**{'start':start,'end':end}})
|
|
60
|
+
if (l0 := eq.strip()).startswith('<'):
|
|
61
|
+
timesplit = l0.split('>', 1)
|
|
62
|
+
if len(timesplit) != 2:
|
|
63
|
+
raise Exception(f'Malformed time specification\nOffending: "{l0}"')
|
|
64
|
+
|
|
65
|
+
time_options = timesplit[0].replace('<', '').replace(',', ' ').replace(':', ' ').replace('/', ' ').split()
|
|
66
|
+
|
|
67
|
+
if len(time_options) == 1:
|
|
68
|
+
start = time_options[0]
|
|
69
|
+
end = time_options[0]
|
|
70
|
+
elif len(time_options) == 2:
|
|
71
|
+
start, end = time_options
|
|
72
|
+
else:
|
|
73
|
+
raise Exception(f'Too many times\nOffending: "{l0}"')
|
|
74
|
+
|
|
75
|
+
xeq = timesplit[1]
|
|
76
|
+
blanksmpl = False
|
|
77
|
+
|
|
78
|
+
offending = [line.strip() for line in xeq.splitlines() if line.strip().startswith('<')]
|
|
79
|
+
if offending:
|
|
80
|
+
offending_text = "\n".join(offending)
|
|
81
|
+
raise Exception(
|
|
82
|
+
'More than one time specification is not allowed\n'
|
|
83
|
+
'Offending lines:\n'
|
|
84
|
+
f'{offending_text}'
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
xeq = eq
|
|
88
|
+
blanksmpl = True
|
|
89
|
+
|
|
90
|
+
mmodel = model.from_eq(xeq,modelname='MFCalc', **kwargs)
|
|
91
|
+
|
|
92
|
+
res = mmodel(self._obj,**{**{'silent':True},**kwargs,**{'start':start,'end':end,}})
|
|
93
|
+
|
|
94
|
+
# print('jddd')
|
|
95
|
+
if blanksmpl:
|
|
96
|
+
if mmodel.maxlag or mmodel.maxlead:
|
|
97
|
+
print(f'* Take care. Lags or leads in the equations, mfcalc run for {mmodel.current_per[0]} to {mmodel.current_per[-1]}')
|
|
98
|
+
if showeq:
|
|
99
|
+
print(mmodel.equations)
|
|
100
|
+
return res
|
|
101
|
+
|
|
102
|
+
@pd.api.extensions.register_dataframe_accessor("mfupdate")
|
|
103
|
+
class mfupdate():
|
|
104
|
+
'''Extend a dataframe to update with values from another dataframe'''
|
|
105
|
+
def __init__(self, pandas_obj):
|
|
106
|
+
# self._validate(pandas_obj)
|
|
107
|
+
self._obj = pandas_obj
|
|
108
|
+
# print(self._obj)
|
|
109
|
+
|
|
110
|
+
def second(self,df,safe=True):
|
|
111
|
+
this = self._obj.copy(deep=True)
|
|
112
|
+
col=df.columns
|
|
113
|
+
index = df.index
|
|
114
|
+
if safe: # if dooing many experiments, we dont want this to pappen
|
|
115
|
+
assert 0 == len(set(index) - set(this.index)), 'Index in update not in dataframe'
|
|
116
|
+
assert 0 == len(set(col) - set(this.columns)),'Column in update not in dataframe'
|
|
117
|
+
this.loc[index,col] = df.loc[index,col]
|
|
118
|
+
return this
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def __call__(self,df):
|
|
122
|
+
return self.second(df)
|
|
123
|
+
|
|
124
|
+
@pd.api.extensions.register_dataframe_accessor("ibloc")
|
|
125
|
+
class ibloc():
|
|
126
|
+
'''Extend a dataframe with a slice method which accepot wildcards in column selection.
|
|
127
|
+
|
|
128
|
+
The method just juse the method vlist from modelclass.model class '''
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def __init__(self, pandas_obj):
|
|
132
|
+
# self._validate(pandas_obj)
|
|
133
|
+
self._obj = pandas_obj
|
|
134
|
+
# print(self._obj)
|
|
135
|
+
|
|
136
|
+
def __getitem__(self, select):
|
|
137
|
+
m = model()
|
|
138
|
+
m.lastdf = self._obj
|
|
139
|
+
# print(select)
|
|
140
|
+
vars = m.vlist(select)
|
|
141
|
+
return self._obj.loc[:,vars]
|
|
142
|
+
|
|
143
|
+
def __call__(self):
|
|
144
|
+
''' Not in use'''
|
|
145
|
+
print('hello from ibloc')
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
def mfquery_0(pat, df):
|
|
149
|
+
'''
|
|
150
|
+
Returns a DataFrame with columns matching the pattern(s), case-insensitive.
|
|
151
|
+
The pattern can be a string or a list of patterns.
|
|
152
|
+
Wildcards: * and ?
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
pat (string or list of strings)
|
|
156
|
+
df (DataFrame)
|
|
157
|
+
Returns:
|
|
158
|
+
DataFrame subset
|
|
159
|
+
'''
|
|
160
|
+
if isinstance(pat, list):
|
|
161
|
+
patterns = pat
|
|
162
|
+
else:
|
|
163
|
+
patterns = [pat]
|
|
164
|
+
|
|
165
|
+
# Lowercase lookup for case-insensitive matching
|
|
166
|
+
col_map = {str(c) .lower(): c for c in df.columns}
|
|
167
|
+
lower_cols = list(col_map.keys())
|
|
168
|
+
|
|
169
|
+
seen = set()
|
|
170
|
+
names = []
|
|
171
|
+
|
|
172
|
+
for p in patterns:
|
|
173
|
+
for up in p.lower().split():
|
|
174
|
+
for v in fnmatch.filter(lower_cols, up):
|
|
175
|
+
orig = col_map[v]
|
|
176
|
+
if orig not in seen:
|
|
177
|
+
seen.add(orig)
|
|
178
|
+
names.append(orig)
|
|
179
|
+
|
|
180
|
+
return df.loc[:, names]
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@pd.api.extensions.register_dataframe_accessor("mfquery")
|
|
184
|
+
class mfquery:
|
|
185
|
+
def __init__(self, pandas_obj):
|
|
186
|
+
self._obj = pandas_obj
|
|
187
|
+
|
|
188
|
+
def __call__(self, pat):
|
|
189
|
+
return mfquery_0(pat, self._obj)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def f(a):
|
|
193
|
+
return 42
|
|
194
|
+
|
|
195
|
+
from functools import wraps
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def as_df_method_simple(func):
|
|
200
|
+
"""Register a function as a method directly on ``pandas.DataFrame``.
|
|
201
|
+
|
|
202
|
+
The decorated function must take a DataFrame as its first argument.
|
|
203
|
+
It becomes callable as ``df.<func_name>(...)`` and remains callable
|
|
204
|
+
as a plain function.
|
|
205
|
+
|
|
206
|
+
Refuses to overwrite pandas built-ins. Methods previously registered
|
|
207
|
+
by this decorator are silently re-registered on module reload, which
|
|
208
|
+
keeps notebook workflows smooth.
|
|
209
|
+
|
|
210
|
+
Raises
|
|
211
|
+
------
|
|
212
|
+
AttributeError
|
|
213
|
+
If the function's name collides with a pandas built-in attribute.
|
|
214
|
+
|
|
215
|
+
Examples
|
|
216
|
+
--------
|
|
217
|
+
>>> @as_df_method
|
|
218
|
+
... def top_n(df, col, n=5):
|
|
219
|
+
... return df.nlargest(n, col)
|
|
220
|
+
>>> df.top_n('Z', n=2)
|
|
221
|
+
"""
|
|
222
|
+
# Store the registry on DataFrame itself so it survives module reloads.
|
|
223
|
+
# If we kept it on the decorator function, re-importing would wipe the
|
|
224
|
+
# set and our previously-attached methods would look like built-ins.
|
|
225
|
+
REGISTRY_ATTR = "_as_df_method_registered"
|
|
226
|
+
if not hasattr(pd.DataFrame, REGISTRY_ATTR):
|
|
227
|
+
setattr(pd.DataFrame, REGISTRY_ATTR, set())
|
|
228
|
+
registered = getattr(pd.DataFrame, REGISTRY_ATTR)
|
|
229
|
+
|
|
230
|
+
name = func.__name__
|
|
231
|
+
|
|
232
|
+
# If the name exists on DataFrame but wasn't added by us, it's a
|
|
233
|
+
# pandas built-in (or another extension). Refuse to shadow it.
|
|
234
|
+
if hasattr(pd.DataFrame, name) and name not in registered:
|
|
235
|
+
raise AttributeError(
|
|
236
|
+
f"{name!r} is already an attribute of pandas.DataFrame "
|
|
237
|
+
f"(likely a built-in). Refusing to overwrite it — pick a "
|
|
238
|
+
f"different name."
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
@wraps(func)
|
|
242
|
+
def method(self, *args, **kwargs):
|
|
243
|
+
return func(self, *args, **kwargs)
|
|
244
|
+
|
|
245
|
+
setattr(pd.DataFrame, name, method)
|
|
246
|
+
registered.add(name)
|
|
247
|
+
return func
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
import warnings
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def as_df_method(name=None):
|
|
256
|
+
"""Register ``func(df, *args, **kwargs)`` as a callable DataFrame method.
|
|
257
|
+
|
|
258
|
+
Usable as ``@as_df_method`` or ``@as_df_method("custom_name")``.
|
|
259
|
+
After registration, ``df.<name>(...)`` calls ``func(df, ...)``. The
|
|
260
|
+
function also remains callable directly.
|
|
261
|
+
|
|
262
|
+
Re-running the decorator (e.g. on notebook reload) updates the
|
|
263
|
+
registered function in place without re-registering the accessor,
|
|
264
|
+
avoiding pandas' "already registered" warning.
|
|
265
|
+
|
|
266
|
+
If ``name`` is already bound on ``pd.DataFrame`` by something other
|
|
267
|
+
than this decorator, a warning is issued and the existing attribute
|
|
268
|
+
is shadowed.
|
|
269
|
+
"""
|
|
270
|
+
# Bare usage: @as_df_method (name is actually the function)
|
|
271
|
+
if callable(name):
|
|
272
|
+
func, name = name, None
|
|
273
|
+
return as_df_method(name)(func)
|
|
274
|
+
|
|
275
|
+
def decorator(func):
|
|
276
|
+
accessor_name = name or func.__name__
|
|
277
|
+
|
|
278
|
+
# Registry lives on DataFrame so it survives module reloads in
|
|
279
|
+
# notebooks. Note: this is shared across all modules using this
|
|
280
|
+
# decorator — last writer wins.
|
|
281
|
+
REGISTRY_ATTR = "_as_df_method_registry"
|
|
282
|
+
if not hasattr(pd.DataFrame, REGISTRY_ATTR):
|
|
283
|
+
setattr(pd.DataFrame, REGISTRY_ATTR, {})
|
|
284
|
+
registry = getattr(pd.DataFrame, REGISTRY_ATTR)
|
|
285
|
+
|
|
286
|
+
if hasattr(pd.DataFrame, accessor_name) and accessor_name not in registry:
|
|
287
|
+
warnings.warn(
|
|
288
|
+
f"{accessor_name!r} is already bound on pandas.DataFrame; "
|
|
289
|
+
"shadowing it. Pick another name if this is unintentional.",
|
|
290
|
+
stacklevel=2,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# Fast path: already registered. Swap the underlying function on
|
|
294
|
+
# the existing accessor class so reloads pick up code changes
|
|
295
|
+
# without pandas complaining about duplicate registration.
|
|
296
|
+
if accessor_name in registry:
|
|
297
|
+
accessor_cls = registry[accessor_name]
|
|
298
|
+
accessor_cls._func = staticmethod(func)
|
|
299
|
+
accessor_cls.__doc__ = func.__doc__
|
|
300
|
+
return func
|
|
301
|
+
|
|
302
|
+
class _Accessor:
|
|
303
|
+
__doc__ = func.__doc__
|
|
304
|
+
_func = staticmethod(func)
|
|
305
|
+
|
|
306
|
+
def __init__(self, pandas_obj):
|
|
307
|
+
self._obj = pandas_obj
|
|
308
|
+
|
|
309
|
+
def __call__(self, *args, **kwargs):
|
|
310
|
+
# Read _func off the class so reloads are picked up.
|
|
311
|
+
return type(self)._func(self._obj, *args, **kwargs)
|
|
312
|
+
|
|
313
|
+
_Accessor.__name__ = f"{func.__name__}_method"
|
|
314
|
+
_Accessor.__qualname__ = _Accessor.__name__
|
|
315
|
+
|
|
316
|
+
pd.api.extensions.register_dataframe_accessor(accessor_name)(_Accessor)
|
|
317
|
+
registry[accessor_name] = _Accessor
|
|
318
|
+
return func
|
|
319
|
+
|
|
320
|
+
return decorator
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
if __name__ == '__main__':
|
|
324
|
+
#this is for testing
|
|
325
|
+
df2 = pd.DataFrame({'Z':[1., 22., 33,43] , 'TY':[10.,20.,30.,40.] ,'YD':[10.,20.,30.,40.]},index=[2017,2018,2019,2020])
|
|
326
|
+
df3 = pd.DataFrame({'Z':[1., 22., 33,43] , 'TY':[10.,20.,30.,40.] ,'YD':[10.,20.,30.,40.]},index=[2017,2018,2019,2020])
|
|
327
|
+
df4 = pd.DataFrame({'Z':[ 223., 333] , 'TY':[203.,303.] },index=[2018,2019])
|
|
328
|
+
ftest = '''
|
|
329
|
+
ii = x+z
|
|
330
|
+
c=0.8*yd
|
|
331
|
+
i = ii+iy
|
|
332
|
+
x = f(2)
|
|
333
|
+
y = c + i + x+ i(-1)
|
|
334
|
+
yX = 0.02
|
|
335
|
+
dogplace = y *4 '''
|
|
336
|
+
assert 1==1
|
|
337
|
+
#%%
|
|
338
|
+
df2.mfcalc(ftest,funks=[f],showeq=1)
|
|
339
|
+
df4 = pd.DataFrame({'Z':[ 223., 333] , 'YD':[203.,303.] },index=[2018,2019])
|
|
340
|
+
x = df2.mfupdate(df4)
|
|
341
|
+
#%% test graph
|
|
342
|
+
df2
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@as_df_method
|
|
346
|
+
def top_n(df, col, n=5):
|
|
347
|
+
return df.nlargest(n, col)
|
|
348
|
+
|
|
349
|
+
df2.top_n('Z',n=2)
|
modelnet.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Wed Oct 15 14:30:44 2014
|
|
4
|
+
|
|
5
|
+
Displays an adjencacy matrix
|
|
6
|
+
.
|
|
7
|
+
@author: ibh
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import print_function
|
|
12
|
+
import networkx as nx
|
|
13
|
+
from itertools import groupby, chain
|
|
14
|
+
from collections import OrderedDict,Counter
|
|
15
|
+
import numpy as np
|
|
16
|
+
from matplotlib import pyplot, patches
|
|
17
|
+
import matplotlib.pyplot as plt
|
|
18
|
+
import matplotlib as mpl
|
|
19
|
+
import pandas as pd
|
|
20
|
+
import seaborn as sns
|
|
21
|
+
from matplotlib import colors
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def draw_adjacency_matrix(G, node_order=None, partitions=None,type=False,title='Structure',size=(10,10)):
|
|
25
|
+
"""
|
|
26
|
+
- G is a netorkx graph
|
|
27
|
+
- node_order (optional) is a list of nodes, where each node in G
|
|
28
|
+
appears exactly once
|
|
29
|
+
- partitions is a list of node lists, where each node in G appears
|
|
30
|
+
in exactly one node list
|
|
31
|
+
|
|
32
|
+
- type is a list of saying "simultaneous" or something else, has to have same length as partitions
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
df = nx.to_pandas_adjacency(G,nodelist=node_order).T
|
|
36
|
+
|
|
37
|
+
fig, ax = plt.subplots(figsize=size)
|
|
38
|
+
plt.title(title,fontsize=20)
|
|
39
|
+
cmap1 = colors.ListedColormap(['white','blue'])
|
|
40
|
+
norm1 = colors.BoundaryNorm([0.,0.3,30], cmap1.N)
|
|
41
|
+
sns.heatmap(df,ax=ax,cbar=False,square=True,cmap=cmap1,norm=norm1)
|
|
42
|
+
plt.xlabel('This variable is input to', fontsize=18)
|
|
43
|
+
plt.ylabel('The formular for this variable', fontsize=18)
|
|
44
|
+
|
|
45
|
+
color = 'blue'
|
|
46
|
+
current_idx = 0
|
|
47
|
+
if partitions:
|
|
48
|
+
for i,module in enumerate(partitions):
|
|
49
|
+
if type:
|
|
50
|
+
if len(type[i]) and type[i].startswith('Simultaneous'):
|
|
51
|
+
ax.add_patch(patches.Rectangle((current_idx, current_idx),
|
|
52
|
+
len(module), # Width
|
|
53
|
+
len(module), # Height
|
|
54
|
+
facecolor=[1.,0,0,0.5]))
|
|
55
|
+
elif len(type[i]) and type[i] == 'Recursiv':
|
|
56
|
+
ax.add_patch(patches.Polygon([(current_idx, current_idx),
|
|
57
|
+
(current_idx, current_idx+len(module)),
|
|
58
|
+
(current_idx+len(module), current_idx+len(module))],
|
|
59
|
+
facecolor=[0,1,0,0.5]))
|
|
60
|
+
elif len(type[i]) and type[i] == 'Endogeneous':
|
|
61
|
+
ax.add_patch(patches.Rectangle((current_idx, current_idx),
|
|
62
|
+
len(module), # Width
|
|
63
|
+
len(module), # Height
|
|
64
|
+
facecolor=[1.,0,0,0.5]))
|
|
65
|
+
elif len(type[i]) and type[i] == 'Exogeneous':
|
|
66
|
+
ax.add_patch(patches.Rectangle(( current_idx,0),
|
|
67
|
+
len(module), # Width
|
|
68
|
+
current_idx, # Height
|
|
69
|
+
facecolor=[1.,1,0,0.5]))
|
|
70
|
+
else:
|
|
71
|
+
ax.add_patch(patches.Rectangle((current_idx, current_idx),
|
|
72
|
+
len(module), # Width
|
|
73
|
+
len(module), # Height
|
|
74
|
+
facecolor=[1.,0,0,0.5]))
|
|
75
|
+
current_idx += len(module)
|
|
76
|
+
if 'Recursiv' in type or 'Simultaneous' in type :
|
|
77
|
+
firkant = patches.Rectangle((0,0),1,1,facecolor=[1.,0,0,1], label='Feedback block')
|
|
78
|
+
trekant = patches.Polygon([(0, 0),(0, 1),(1, 3)],facecolor=[0,1,0,1], label='No feedback block')
|
|
79
|
+
ax.legend(handles=[firkant,trekant],loc=1,fontsize=18)
|
|
80
|
+
|
|
81
|
+
if 'Endogeneous' in type or 'Exogeneous' in type :
|
|
82
|
+
firkant = patches.Rectangle((0,0),1,1,facecolor=[1.,0,0,1], label='Endogeneous variables')
|
|
83
|
+
trekant = patches.Polygon([(0, 0),(0, 1),(1, 3)],facecolor=[1,1,0,1], label='Exogeneous variables')
|
|
84
|
+
ax.legend(handles=[firkant,trekant],loc=3,fontsize=18)
|
|
85
|
+
return fig
|
|
86
|
+
|
|
87
|
+
def drawendoexo(model,size=(6.,6.)):
|
|
88
|
+
''' Draw dependency including exogeneous. Used for illustrating for small models'''
|
|
89
|
+
fig = draw_adjacency_matrix(model.totgraph_nolag,
|
|
90
|
+
list(chain(model.endogene,model.exogene)),[model.endogene,model.exogene],
|
|
91
|
+
['Endogeneous','Exogeneous'], title = 'Dependencies' ,size=size)
|
|
92
|
+
return fig
|
|
93
|
+
|
|
94
|
+
if __name__ == '__main__' :
|
|
95
|
+
#%%
|
|
96
|
+
ftest = ''' FRMl <> y = c + i + x $
|
|
97
|
+
FRMl <> yd = 0.6 * y + y0 $
|
|
98
|
+
FRMl <> c= 0.6 * yd + 0.2 *yd(-1) $
|
|
99
|
+
FRMl <> i = I0 $
|
|
100
|
+
FRMl <> ii = i *2 $
|
|
101
|
+
FRMl <> x = 2 $
|
|
102
|
+
frml <> dog = y $'''
|
|
103
|
+
import modelclass as mc
|
|
104
|
+
mtest = mc.model(ftest)
|
|
105
|
+
draw_adjacency_matrix(mtest.totgraph_nolag)
|
|
106
|
+
plt.show()
|
|
107
|
+
draw_adjacency_matrix(mtest.endograph,mtest.strongorder,mtest.strongblock,mtest.strongtype)
|
|
108
|
+
plt.show()
|
|
109
|
+
#%%
|
|
110
|
+
mtest.draw('Y')
|
|
111
|
+
mtest.drawmodel()
|
|
112
|
+
#%%
|
|
113
|
+
|
|
114
|
+
drawendoexo(mtest)
|