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
modeldisplay.py
ADDED
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon Apr 8 14:58:26 2024
|
|
4
|
+
|
|
5
|
+
@author: ibhan
|
|
6
|
+
|
|
7
|
+
The `modeldisplay` module facilitates the generation, management, and display of data visualizations and tables
|
|
8
|
+
derived from ModelFlow models. It is designed to support a wide range of output formats including LaTeX documents,
|
|
9
|
+
HTML, and interactive IPyWidgets, making it highly versatile for different reporting and analysis needs in Jupyter
|
|
10
|
+
notebook environments.
|
|
11
|
+
|
|
12
|
+
This module provides a structured and extendible approach to organizing and rendering data analysis results, enabling users to
|
|
13
|
+
easily convert complex model outputs into digestible visual representations and tables. It is especially useful
|
|
14
|
+
for automating the reporting process in data analysis, financial modeling, and research projects, leveraging Python's
|
|
15
|
+
capabilities for data processing and visualization along with advanced document presentation features.
|
|
16
|
+
|
|
17
|
+
Key Features:
|
|
18
|
+
- Dynamic generation of LaTeX and HTML content for integrating data visualizations and tables into reports and
|
|
19
|
+
presentations.
|
|
20
|
+
- Compatibility with IPyWidgets for creating interactive, widget-based displays that enhance the interactivity of
|
|
21
|
+
Jupyter notebooks.
|
|
22
|
+
- Seamless integration with matplotlib for figure generation and pandas for table formatting, providing a comprehensive
|
|
23
|
+
toolkit for data display.
|
|
24
|
+
- Customizable display options and specifications through dataclasses, allowing for tailored presentation styles
|
|
25
|
+
and formats.
|
|
26
|
+
|
|
27
|
+
Classes:
|
|
28
|
+
- `Options`: Configures display options for managing how data and figures are presented, including naming conventions,
|
|
29
|
+
formatting preferences, and title settings.
|
|
30
|
+
- `Line`: Defines line configurations for table displays, supporting various data representation and difference
|
|
31
|
+
calculations to suit different analysis needs.
|
|
32
|
+
- `DisplaySpec`: Groups display options and line configurations, facilitating the management of complex display setups
|
|
33
|
+
in a structured manner.
|
|
34
|
+
- `DisplayDef`: Base class for display definitions, capable of compiling various display components into cohesive
|
|
35
|
+
specifications for rendering.
|
|
36
|
+
- `LatexRepo`: Handles the generation of LaTeX content, compilation into PDFs, and embedding within Jupyter notebooks,
|
|
37
|
+
supporting both static and dynamic content creation.
|
|
38
|
+
- `DisplayVarTableDef`: Specializes in displaying variable tables, automating the creation and formatting of tables
|
|
39
|
+
from ModelFlow model outputs.
|
|
40
|
+
- `DisplayFigWrapDef`: Focuses on wrapping and adjusting matplotlib figures for inclusion in various display formats,
|
|
41
|
+
ensuring figures are presentation-ready.
|
|
42
|
+
|
|
43
|
+
The `modeldisplay` module bridges the gap between analytical modeling and result presentation, offering a streamlined
|
|
44
|
+
workflow for transforming ModelFlow model outputs into high-quality visual and tabular displays suitable for a wide
|
|
45
|
+
range of purposes.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
import pandas as pd
|
|
53
|
+
import matplotlib.pyplot as plt
|
|
54
|
+
import matplotlib as mpl
|
|
55
|
+
import seaborn as sns
|
|
56
|
+
import fnmatch
|
|
57
|
+
from matplotlib import dates
|
|
58
|
+
import matplotlib.ticker as ticker
|
|
59
|
+
from IPython.display import display
|
|
60
|
+
from dataclasses import dataclass, field
|
|
61
|
+
from typing import Any, List, Dict, Optional
|
|
62
|
+
|
|
63
|
+
from subprocess import run
|
|
64
|
+
from pathlib import Path
|
|
65
|
+
import webbrowser as wb
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class Options:
|
|
69
|
+
"""
|
|
70
|
+
Represents configuration options for data display definitions.
|
|
71
|
+
|
|
72
|
+
Attributes:
|
|
73
|
+
name (str) : name for this display. Default is 'display'
|
|
74
|
+
foot (str) : footer if relevant
|
|
75
|
+
rename (bool): If True, allows renaming of data columns. Default is True.
|
|
76
|
+
decorate (bool): If True, decorates row descriptions based on the showtype. Default is True.
|
|
77
|
+
width (int): Specifies the width for formatting output in characters. Default is 20.
|
|
78
|
+
custom_description (Dict): Custom description to augment or override default descriptions. Empty by default.
|
|
79
|
+
title (str): Text for the title. Default is an empty string.
|
|
80
|
+
chunk_size (int): Specifies the number of columns per chunk in the display output. Default is 5.
|
|
81
|
+
timeslice (List): Specifies the time slice for data display. Empty by default.
|
|
82
|
+
"""
|
|
83
|
+
name : str = 'display'
|
|
84
|
+
foot : str =''
|
|
85
|
+
rename: bool = True
|
|
86
|
+
decorate: bool = True
|
|
87
|
+
width: int = 20
|
|
88
|
+
custom_description: Dict = field(default_factory=dict)
|
|
89
|
+
title : str = ''
|
|
90
|
+
chunk_size : int = 5
|
|
91
|
+
timeslice : List = field(default_factory=list)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def __post_init__(self):
|
|
96
|
+
...
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class Line:
|
|
102
|
+
"""
|
|
103
|
+
A dataclass for representing and validating line configurations for data display.
|
|
104
|
+
|
|
105
|
+
Attributes:
|
|
106
|
+
showtype (str): Specifies the type of data representation. Valid options are 'level', 'growth',
|
|
107
|
+
'change', 'basedf', 'textline', and 'gdppct'. Default is 'level'.
|
|
108
|
+
diftype (str): Specifies the type of difference calculation to apply. Valid options are 'nodif', 'dif',
|
|
109
|
+
'difpct', 'basedf', and 'lastdf'. Default is 'nodif'.
|
|
110
|
+
centertext (str): Center text used when showtype is 'textline'. Default is a space.
|
|
111
|
+
rename (bool): If True, allows renaming of data columns. Default is True.
|
|
112
|
+
dec (int): Specifies the number of decimal places to use for numerical output. Default is 2.
|
|
113
|
+
pat (str): Pattern or identifier used to select data for the line. Default is '#Headline'.
|
|
114
|
+
latexfont (str) : Modifier used in lates for instande r'\textbf'
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
showtype: str = 'level'
|
|
118
|
+
diftype: str = 'nodif'
|
|
119
|
+
centertext : str = ''
|
|
120
|
+
rename: bool = False
|
|
121
|
+
dec: int = 2
|
|
122
|
+
pat : str = '#Headline'
|
|
123
|
+
latexfont :str =''
|
|
124
|
+
|
|
125
|
+
def __post_init__(self):
|
|
126
|
+
valid_showtypes = {'level', 'growth', 'change', 'basedf', 'gdppct' ,'textline'}
|
|
127
|
+
valid_diftypes = {'nodif', 'dif', 'difpct', 'basedf', 'lastdf'}
|
|
128
|
+
|
|
129
|
+
if self.showtype not in valid_showtypes:
|
|
130
|
+
raise ValueError(f"showtype must be one of {valid_showtypes}, got {self.showtype}")
|
|
131
|
+
|
|
132
|
+
if self.diftype not in valid_diftypes:
|
|
133
|
+
raise ValueError(f"diftype must be one of {valid_diftypes}, got {self.diftype}")
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class DisplaySpec:
|
|
138
|
+
"""
|
|
139
|
+
A dataclass to encapsulate display specifications including options and a list of line configurations.
|
|
140
|
+
|
|
141
|
+
Attributes:
|
|
142
|
+
options (Options): An instance of the Options dataclass specifying configuration options.
|
|
143
|
+
lines (List[Line]): A list of Line instances specifying individual line configurations.
|
|
144
|
+
"""
|
|
145
|
+
options: Options = field(default_factory=Options)
|
|
146
|
+
lines: List[Line] = field(default_factory=list)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass
|
|
150
|
+
class DisplayDef:
|
|
151
|
+
mmodel : Any = None
|
|
152
|
+
spec : Options = field(default_factory=DisplaySpec)
|
|
153
|
+
name : str = ''
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def __post_init__(self):
|
|
157
|
+
self.options = self.spec.options
|
|
158
|
+
self.lines = self.spec.lines
|
|
159
|
+
self.name = self.name if self.name else self.options.name
|
|
160
|
+
try:
|
|
161
|
+
self.var_description = self.mmodel.defsub(self.mmodel.var_description | self.options.custom_description )
|
|
162
|
+
except:
|
|
163
|
+
self.var_description = {}
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
self.timeslice = self.options.timeslice if self.options.timeslice else self.mmodel.current_per
|
|
167
|
+
except:
|
|
168
|
+
self.timeslice = []
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def get_rowdes(self,df,showtype,line):
|
|
172
|
+
if self.options.rename or line.rename:
|
|
173
|
+
rowdes = [self.var_description[v] for v in df.index]
|
|
174
|
+
else:
|
|
175
|
+
rowdes = [v for v in df.index]
|
|
176
|
+
|
|
177
|
+
if self.options.decorate :
|
|
178
|
+
match showtype:
|
|
179
|
+
case 'growth':
|
|
180
|
+
rowdes = [f'{des}, % growth' for des in rowdes]
|
|
181
|
+
|
|
182
|
+
case 'gdppct':
|
|
183
|
+
rowdes = [f'{des.split(",")[0].split("mill")[0]}, % of GDP' for des in rowdes]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
case _:
|
|
187
|
+
rowdes = rowdes
|
|
188
|
+
|
|
189
|
+
df.index = rowdes
|
|
190
|
+
return df
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def df_str(self):
|
|
194
|
+
width = self.options.width
|
|
195
|
+
df = self.df.copy( )
|
|
196
|
+
format_decimal = [ line.dec for line,df in zip(self.lines,self.dfs) for row in range(len(df))]
|
|
197
|
+
for i, dec in enumerate(format_decimal):
|
|
198
|
+
df.iloc[i] = df.iloc[i].apply(lambda x: " " * width if pd.isna(x) else f"{x:>{width},.{dec}f}".strip() )
|
|
199
|
+
return df
|
|
200
|
+
|
|
201
|
+
@property
|
|
202
|
+
def df_str_disp(self):
|
|
203
|
+
center = [ (line.showtype == 'textline' and line.centertext !='' ) for line,df in zip(self.lines,self.dfs) for row in range(len(df))]
|
|
204
|
+
center_index = [index+1 for index, value in enumerate(center) if value]
|
|
205
|
+
|
|
206
|
+
width = self.options.width
|
|
207
|
+
rawdata = self.df_str.to_string().split('\n')
|
|
208
|
+
data = center_title_under_years(rawdata,center_index)
|
|
209
|
+
out = '\n'.join(data)
|
|
210
|
+
return out
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def print(self):
|
|
214
|
+
if self.options.title:
|
|
215
|
+
print(self.options.title)
|
|
216
|
+
print(self.df_str_disp)
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def datawidget(self):
|
|
220
|
+
return self.make_html_style(self.displaydf.loc[:,self.timeslice],self.lines )
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def pdf(self,xopen=False,show=True,width=800,height=600):
|
|
227
|
+
repo = LatexRepo(self.latex ,name=self.name)
|
|
228
|
+
return repo.pdf(xopen,show,width,height)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def __floordiv__(self, other):
|
|
232
|
+
if hasattr(other,'latex'):
|
|
233
|
+
# If the other object is an instance of LaTeXHolder, concatenate their LaTeX strings
|
|
234
|
+
return LatexRepo(latex =self.latex + '\n' + other.latex,name=self.name)
|
|
235
|
+
elif isinstance(other, str):
|
|
236
|
+
# If the other object is a string, assume it's a raw LaTeX string and concatenate
|
|
237
|
+
return LatexRepo(latex = self.latex + '\n' + other,name=self.name)
|
|
238
|
+
else:
|
|
239
|
+
# If the other object is neither a LaTeXHolder instance nor a string, raise an error
|
|
240
|
+
raise ValueError("Can only add another LaTeXHolder instance or a raw LaTeX string.")
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def make_html_style(self,df,lines,use_tooltips =True ) :
|
|
245
|
+
out = self.df_str.style.set_table_styles([
|
|
246
|
+
{
|
|
247
|
+
'selector': '.row_heading, .corner',
|
|
248
|
+
'props': [
|
|
249
|
+
('position', 'sticky'),
|
|
250
|
+
('left', '0'),
|
|
251
|
+
('z-index', '3'),
|
|
252
|
+
('background-color', 'white'),
|
|
253
|
+
('width', '300px'), # Set the width of the row headings
|
|
254
|
+
('min-width', '200px'), # Ensure the minimum width is respected
|
|
255
|
+
('max-width', '400px') # Ensure the maximum width is respected
|
|
256
|
+
]
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
'selector': '.col_heading',
|
|
260
|
+
'props': [
|
|
261
|
+
('position', 'sticky'),
|
|
262
|
+
('top', '0'),
|
|
263
|
+
('z-index', '2'),
|
|
264
|
+
('background-color', 'white')
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
'selector': 'th',
|
|
269
|
+
'props': [
|
|
270
|
+
('text-align', 'left') , # Align text to the left
|
|
271
|
+
('background-color', 'white'), # Ensuring headers are not transparent
|
|
272
|
+
('z-index', '2') # Headers z-index on par with column headings
|
|
273
|
+
]
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
'selector': 'td', # Targeting data cells
|
|
277
|
+
'props': [
|
|
278
|
+
('z-index', '1'), # Lower z-index than headers
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
{
|
|
284
|
+
'selector': 'caption',
|
|
285
|
+
'props': [
|
|
286
|
+
('font-size', '16px'), # Make the font larger
|
|
287
|
+
('font-weight', 'bold') # Make the font bold
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
],overwrite=True)
|
|
291
|
+
if use_tooltips:
|
|
292
|
+
tt = pd.DataFrame([[v for v in df.columns ]for t in df.index] ,index=df.index,columns=df.columns)
|
|
293
|
+
try:
|
|
294
|
+
out=out.set_tooltips(tt, props='visibility: hidden; position: absolute; z-index: 1; border: 1px solid #000066;'
|
|
295
|
+
'background-color: white; color: #000066; font-size: 0.8em;width:100%'
|
|
296
|
+
'transform: translate(0px, -24px); padding: 0.6em; border-radius: 0.5em;')
|
|
297
|
+
except Exception as e:
|
|
298
|
+
print(f'no tooltips {e}')
|
|
299
|
+
|
|
300
|
+
out= out.set_caption(self.options.title)
|
|
301
|
+
|
|
302
|
+
return out
|
|
303
|
+
|
|
304
|
+
@property
|
|
305
|
+
def latex(self):
|
|
306
|
+
rowlines = [ line for line,df in zip(self.lines,self.dfs) for row in range(len(df))]
|
|
307
|
+
dfs = [self.df_str.iloc[:, i:i+self.options.chunk_size] for i in range(0, self.df_str.shape[1], self.options.chunk_size)]
|
|
308
|
+
outlist = []
|
|
309
|
+
for i,df in enumerate(dfs):
|
|
310
|
+
ncol=len(df.columns)
|
|
311
|
+
newindex = [fr'&\multicolumn{{{ncol}}}'+'{c}{' + f'{line.latexfont}' + '{' + df.index[i]+'}}'
|
|
312
|
+
if line.showtype == 'textline'
|
|
313
|
+
else df.index[i]
|
|
314
|
+
for i, line in enumerate(rowlines)]
|
|
315
|
+
|
|
316
|
+
df.index = newindex
|
|
317
|
+
tabformat = 'l'+'r'*ncol
|
|
318
|
+
outlist = outlist + [df.style.format(lambda x:x) \
|
|
319
|
+
.set_caption(self.options.title + ('' if i == 0 else ' - continued ')) \
|
|
320
|
+
.to_latex(hrules=True, position='ht', column_format=tabformat).replace('%',r'\%').replace('US$',r'US\$') ]
|
|
321
|
+
|
|
322
|
+
# print(outlist)
|
|
323
|
+
out = r' '.join(outlist)
|
|
324
|
+
|
|
325
|
+
out = '\n'.join(l.replace('& ','') if 'multicolum' in l else l for l in out.split('\n'))
|
|
326
|
+
return out
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def _repr_html_(self):
|
|
330
|
+
return self.datawidget._repr_html_()
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@dataclass
|
|
335
|
+
class LatexRepo:
|
|
336
|
+
latex: str = ""
|
|
337
|
+
name : str ='latex_test'
|
|
338
|
+
|
|
339
|
+
def set_name(self,name):
|
|
340
|
+
self.name = name
|
|
341
|
+
return self
|
|
342
|
+
|
|
343
|
+
def latexwrap(self):
|
|
344
|
+
|
|
345
|
+
latex_pre = r'''\documentclass{article}
|
|
346
|
+
\usepackage{booktabs}
|
|
347
|
+
\usepackage{caption} % Include the caption package
|
|
348
|
+
\captionsetup{justification=raggedright,singlelinecheck=false}
|
|
349
|
+
\usepackage{graphicx}
|
|
350
|
+
\usepackage{pgf}
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
\begin{document}
|
|
354
|
+
|
|
355
|
+
'''
|
|
356
|
+
|
|
357
|
+
latex_post = r'''
|
|
358
|
+
\end{document}
|
|
359
|
+
'''
|
|
360
|
+
out = latex_pre + self.latex + latex_post
|
|
361
|
+
return out
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def pdf(self,xopen=False,show=True,width=800,height=600,morelatex = [] ):
|
|
366
|
+
from IPython.display import IFrame,display
|
|
367
|
+
|
|
368
|
+
latex_dir = Path(f'latex/{self.name}')
|
|
369
|
+
latex_dir.mkdir(parents=True, exist_ok=True)
|
|
370
|
+
|
|
371
|
+
latex_file = latex_dir / f'{self.name}.tex'
|
|
372
|
+
pdf_file = latex_dir / f'{self.name}.pdf'
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
# Now open the file for writing within the newly created directory
|
|
376
|
+
with open(latex_file, 'wt') as f:
|
|
377
|
+
f.write(self.latexwrap()) # Assuming tab.fulllatexwidget is the content you want to write
|
|
378
|
+
xx0 = run(f'latexmk -pdf -dvi- -ps- -f {self.name}.tex' ,cwd = f'{latex_dir}')
|
|
379
|
+
if xx0.returncode:
|
|
380
|
+
wb.open(latex_dir.absolute(), new=1)
|
|
381
|
+
|
|
382
|
+
raise Exception(f'Error creating PDF file, {xx0.returncode}, look in the latex folder')
|
|
383
|
+
|
|
384
|
+
if xopen:
|
|
385
|
+
wb.open(pdf_file , new=2)
|
|
386
|
+
|
|
387
|
+
if show:
|
|
388
|
+
return IFrame(pdf_file, width=width, height=height)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def __floordiv__(self, other):
|
|
392
|
+
if isinstance(other,str):
|
|
393
|
+
other_latex = other
|
|
394
|
+
else:
|
|
395
|
+
if hasattr(other,'latex'):
|
|
396
|
+
other_latex= other.latex
|
|
397
|
+
else:
|
|
398
|
+
raise Exception('Trying to join latex from object without latex content ')
|
|
399
|
+
out = LatexRepo(self.latex + other_latex )
|
|
400
|
+
return out
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def _repr_html_(self):
|
|
404
|
+
self.pdf(show=False)
|
|
405
|
+
pdf_file = f"latex/{self.name}/{self.name}.pdf"
|
|
406
|
+
return f'<iframe src="{pdf_file}" width="800" height="600"></iframe>'
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@dataclass
|
|
411
|
+
class DisplayVarTableDef(DisplayDef):
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def __post_init__(self):
|
|
415
|
+
super().__post_init__() # Call the parent class's __post_init__
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
self.dfs = [self.make_var_df(line) for line in self.lines ]
|
|
420
|
+
self.df = pd.concat( self.dfs )
|
|
421
|
+
self.displaydf = pd.concat( self.dfs )
|
|
422
|
+
return
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def make_var_df(self, line):
|
|
426
|
+
showtype = line.showtype
|
|
427
|
+
diftype = line.diftype
|
|
428
|
+
|
|
429
|
+
with self.mmodel.keepswitch(switch=True):
|
|
430
|
+
|
|
431
|
+
# Pre-process for cases that use linevars and linedes
|
|
432
|
+
if showtype in ['textline']:
|
|
433
|
+
linedf = pd.DataFrame(float('nan'), index=self.mmodel.current_per, columns=[line.centertext]).T
|
|
434
|
+
|
|
435
|
+
else:
|
|
436
|
+
def getline(start_ofset= 0,**kvargs):
|
|
437
|
+
locallinedfdict = self.mmodel.keep_get_plotdict_new(pat=line.pat,showtype=showtype,
|
|
438
|
+
diftype = diftype,keep_dim=False)
|
|
439
|
+
if diftype == 'basedf':
|
|
440
|
+
locallinedf = next(iter((locallinedfdict.values()))).T
|
|
441
|
+
else:
|
|
442
|
+
locallinedf = next(iter(reversed(locallinedfdict.values()))).T
|
|
443
|
+
|
|
444
|
+
return locallinedf.loc[:,self.mmodel.current_per]
|
|
445
|
+
|
|
446
|
+
linedf = getline()
|
|
447
|
+
linedf = self.get_rowdes(linedf,showtype,line)
|
|
448
|
+
|
|
449
|
+
return(linedf)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
@dataclass
|
|
453
|
+
class DisplayFigWrapDef(DisplayDef):
|
|
454
|
+
|
|
455
|
+
figs : Dict = field(default_factory=dict)
|
|
456
|
+
extensions : List[str] = field(default_factory=lambda: ['svg','pgf'])
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def __post_init__(self):
|
|
460
|
+
super().__post_init__() # Call the parent class's __post_init__
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
self.titledic = {chart: fig.axes[0].get_title() for chart,fig in self.figs.items() }
|
|
464
|
+
|
|
465
|
+
self.newfigs= {chart : fig for chart,fig in self.figs.items() }
|
|
466
|
+
for fig in self.newfigs.values():
|
|
467
|
+
fig.axes[0].set_title('')
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
self.mmodel.savefigs(figs=self.newfigs, location = './latex',
|
|
471
|
+
experimentname = self.name ,extensions= self.extensions
|
|
472
|
+
,xopen=False)
|
|
473
|
+
self.charts = list(self.newfigs.keys() )
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
def figwrap(self,chart):
|
|
479
|
+
latex_dir = Path(f'../{self.name}')
|
|
480
|
+
|
|
481
|
+
out = r'''
|
|
482
|
+
\begin{figure}[htbp]
|
|
483
|
+
\centering
|
|
484
|
+
\resizebox{\textwidth}{!}{\input{'''
|
|
485
|
+
out = out + fr'{(latex_dir / chart).as_posix()}.pgf'+'}}'
|
|
486
|
+
out = out + fr'''
|
|
487
|
+
\caption{{{self.titledic[chart]}}}
|
|
488
|
+
\end{{figure}}
|
|
489
|
+
'''
|
|
490
|
+
return out
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def latex(self):
|
|
494
|
+
latex_dir = Path(f'../{self.name}')
|
|
495
|
+
|
|
496
|
+
out = '\n'.join( self.figwrap(chart) for chart in self.charts)
|
|
497
|
+
return out
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def tab_growth(mmodel = None, pat='#Headline',title='Growth',dif=False,custom_description = {},diftext = 'Impact '):
|
|
501
|
+
|
|
502
|
+
if dif==True:
|
|
503
|
+
diftype = 'dif'
|
|
504
|
+
ldiftext = diftext
|
|
505
|
+
else:
|
|
506
|
+
diftype = 'nodif'
|
|
507
|
+
ldiftext = ''
|
|
508
|
+
|
|
509
|
+
tabspec = DisplaySpec(
|
|
510
|
+
options = Options(decorate=False,rename=True,name='A_small_table',
|
|
511
|
+
custom_description=custom_description,title =title,width=5),
|
|
512
|
+
lines = [
|
|
513
|
+
Line(showtype='textline',centertext=f'--- {ldiftext} Percent growth ---'),
|
|
514
|
+
Line(showtype='growth' ,pat=pat,diftype=diftype ) ,
|
|
515
|
+
Line(showtype='textline'),
|
|
516
|
+
]
|
|
517
|
+
)
|
|
518
|
+
tab = DisplayVarTableDef (mmodel=mmodel, spec = tabspec)
|
|
519
|
+
return tab
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def center_title_under_years(data, title_row_index=[1]):
|
|
523
|
+
"""
|
|
524
|
+
Center a title (specified by its index in the list) under the years row in a list of strings.
|
|
525
|
+
|
|
526
|
+
:param data: List of strings representing the data.
|
|
527
|
+
:param title_row_index: Index of the title row in the list. Defaults to 1.
|
|
528
|
+
:return: A new list of strings with the centered title.
|
|
529
|
+
"""
|
|
530
|
+
# Make a shallow copy of the list to avoid modifying the original list
|
|
531
|
+
adjusted_data = data.copy()
|
|
532
|
+
|
|
533
|
+
# Find the start and end indices of the year values in the first row
|
|
534
|
+
year_row = adjusted_data[0]
|
|
535
|
+
start_index = len(year_row) - len(year_row.lstrip())
|
|
536
|
+
end_index = len(year_row.rstrip())
|
|
537
|
+
|
|
538
|
+
# Calculate the total space available for centering
|
|
539
|
+
total_space = end_index - start_index
|
|
540
|
+
|
|
541
|
+
# Center the title within this space
|
|
542
|
+
for row_index in title_row_index:
|
|
543
|
+
title = adjusted_data[row_index].strip() # Remove leading and trailing spaces
|
|
544
|
+
centered_title = title.center(total_space)
|
|
545
|
+
|
|
546
|
+
# Replace the original title in the list with the centered title
|
|
547
|
+
# Ensuring that the centered title is positioned correctly relative to the entire line
|
|
548
|
+
adjusted_data[row_index] = f"{year_row[:start_index]}{centered_title}{year_row[end_index:]}"
|
|
549
|
+
|
|
550
|
+
return adjusted_data
|