mergeron 2024.739087.0__py3-none-any.whl → 2024.739088.1__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.

Potentially problematic release.


This version of mergeron might be problematic. Click here for more details.

mergeron/__init__.py CHANGED
@@ -11,7 +11,7 @@ from numpy.typing import NDArray
11
11
 
12
12
  _PKG_NAME: str = Path(__file__).parent.stem
13
13
 
14
- VERSION = "2024.739087.0"
14
+ VERSION = "2024.739088.1"
15
15
 
16
16
  __version__ = VERSION
17
17
 
@@ -19,19 +19,19 @@
19
19
  Grouped by Entry Conditions and Reporting Period \\[0.5\baselineskip]}
20
20
  \begin{tikzpicture}[auto, font = \sffamily]
21
21
  \begin{pgfonlayer}{background}
22
- \matrix[datatable, nodes = {text width = 27pt,},] (invres_rate_raw) {
22
+ \matrix[datatable, nodes = {text width = 27pt,},] (enf_rate_raw) {
23
23
  \JINVAR{ tmpl_data.invdata_datstr -}
24
24
  };
25
25
  % Horizontal scoring for totals
26
- \draw[color = OBSHDRFill, line width = 1pt] (invres_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-1.north west) -- (invres_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-8.north east);
26
+ \draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-1.north west) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-8.north east);
27
27
  % Vertical scoring for column groups
28
- \draw[color = OBSHDRFill, line width = 1pt] (invres_rate_raw-1-2.north east) -- (invres_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-2.south east);
29
- \draw[color = OBSHDRFill, line width = 1pt] (invres_rate_raw-1-4.north east) -- (invres_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-4.south east);
30
- \draw[color = OBSHDRFill, line width = 1pt] (invres_rate_raw-1-6.north east) -- (invres_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-6.south east);
28
+ \draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-2.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-2.south east);
29
+ \draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-4.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-4.south east);
30
+ \draw[color = OBSHDRFill, line width = 1pt] (enf_rate_raw-1-6.north east) -- (enf_rate_raw-\JINVAR{- tmpl_data.invdata_numrows -}-6.south east);
31
31
  \end{pgfonlayer}
32
32
 
33
33
  \matrix[hrow,
34
- above = 0 pt of invres_rate_raw,
34
+ above = 0 pt of enf_rate_raw,
35
35
  nodes = {minimum height = 33pt, text depth = 10pt, text width = 60pt, align = left, inner sep = 3pt,},
36
36
  ] (hdrrow_raw) {
37
37
  \node[rotate = 90] {Relative \\ Frequency \\}; &
@@ -64,12 +64,12 @@
64
64
  Observed Data \\
65
65
  };
66
66
  % Vertical scoring for column groups
67
- \draw[color = white, line width = 1pt] (descrow_raw_pds1-1-1.north east) -- (invres_rate_raw-1-2.north east);
68
- \draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north east) -- (invres_rate_raw-1-4.north east);
69
- \draw[color = white, line width = 1pt] (descrow_raw_pds2-1-1.north east) -- (invres_rate_raw-1-6.north east);
67
+ \draw[color = white, line width = 1pt] (descrow_raw_pds1-1-1.north east) -- (enf_rate_raw-1-2.north east);
68
+ \draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north east) -- (enf_rate_raw-1-4.north east);
69
+ \draw[color = white, line width = 1pt] (descrow_raw_pds2-1-1.north east) -- (enf_rate_raw-1-6.north east);
70
70
 
71
71
  % Header column - row heads
72
- \matrix[hcol, left = 0pt of invres_rate_raw, nodes = {
72
+ \matrix[hcol, left = 0pt of enf_rate_raw, nodes = {
73
73
  text width = \JINVAR{ tmpl_data.hdrcol_raw_width -},
74
74
  inner xsep = 3 pt,
75
75
  },] (hdrcol_raw) {
@@ -85,7 +85,7 @@
85
85
  (hdrcoldesc_raw.north east)
86
86
  ;
87
87
  ((# % Separator for header column
88
- \draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north west) -- (invres_rate_raw-1-1.north west); #))
88
+ \draw[color = white, line width = 1pt] (descrow_raw_mkt1-1-1.north west) -- (enf_rate_raw-1-1.north west); #))
89
89
 
90
90
  % Notes below table
91
91
  \matrix[anytable,
@@ -37,24 +37,21 @@ def discretemap(colormap: str, hexclrs: Sequence[str]) -> LinearSegmentedColorma
37
37
 
38
38
 
39
39
  class TOLcmaps:
40
- """
41
- Class TOLcmaps definition.
42
-
43
- Attributes
44
- ----------
45
- cmap
46
- A matploltib colormap
47
-
48
- cname
49
- Colormap name
40
+ def __init__(self) -> None:
41
+ """
42
+ Class TOLcmaps definition.
50
43
 
51
- namelist
52
- A list of colormap names
44
+ Attributes
45
+ ----------
46
+ cmap
47
+ A matploltib colormap
53
48
 
54
- """
49
+ cname
50
+ Colormap name
55
51
 
56
- def __init__(self) -> None:
57
- """ """
52
+ namelist
53
+ A list of colormap names
54
+ """
58
55
  # self.cmap: LinearSegmentedColormap | None = None
59
56
  self.cname: str = ""
60
57
  self.namelist: Sequence[str] = (
@@ -21,12 +21,14 @@ from typing import Any, ClassVar
21
21
  import numpy as np
22
22
  import numpy.typing as npt
23
23
  import xlsxwriter # type: ignore
24
- from aenum import Enum, unique # type: ignore
24
+ from aenum import Enum, extend_enum, unique # type: ignore
25
25
 
26
26
  from .. import VERSION # noqa: TID252
27
27
 
28
28
  __version__ = VERSION
29
29
 
30
+ Workbook = xlsxwriter.Workbook
31
+
30
32
 
31
33
  @unique
32
34
  class CFmt(dict, Enum): # type: ignore
@@ -34,7 +36,7 @@ class CFmt(dict, Enum): # type: ignore
34
36
  Initialize cell formats for xlsxwriter.
35
37
 
36
38
  The mappings included here, and unions, etc. of them
37
- and any others added at runtime, will be rendered
39
+ and any others added at runtime, are rendered
38
40
  as xlsxWriter.Workbook.Format objects for writing
39
41
  cell values to formatted cells in a spreadsheet.
40
42
 
@@ -43,6 +45,7 @@ class CFmt(dict, Enum): # type: ignore
43
45
 
44
46
  For more information about xlsxwriter's cell formats,
45
47
  see, https://xlsxwriter.readthedocs.io/format.html
48
+
46
49
  """
47
50
 
48
51
  XL_DEFAULT: ClassVar = {"font_name": "Calibri", "font_size": 11}
@@ -52,28 +55,35 @@ class CFmt(dict, Enum): # type: ignore
52
55
  A_CTR_ACROSS: ClassVar = {"align": "center_across"}
53
56
  A_LEFT: ClassVar = {"align": "left"}
54
57
  A_RIGHT: ClassVar = {"align": "right"}
58
+ V_TOP: ClassVar = {"align": "top"}
59
+ V_BOTTOM: ClassVar = {"align": "bottom"}
60
+ V_CTR: ClassVar = {"align": "vcenter"}
61
+
62
+ TEXT_WRAP: ClassVar = {"text_wrap": True}
63
+ TEXT_ROTATE: ClassVar = {"rotation": 90}
64
+ IND_1: ClassVar = {"indent": 1}
55
65
 
56
66
  BOLD: ClassVar = {"bold": True}
57
67
  BOLD_ITALIC: ClassVar = {"bold": True, "italic": True}
58
68
  ITALIC: ClassVar = {"italic": True}
59
69
  ULINE: ClassVar = {"underline": True}
70
+ SOUT: ClassVar = {"font_strikeout": True}
71
+ # Useful with write_rich_text()
72
+ SUPERSCRIPT: ClassVar = {"font_script": 1}
73
+ SUBSCRIPT: ClassVar = {"font_script": 2}
60
74
 
61
- TEXT_WRAP: ClassVar = {"text_wrap": True}
62
- TEXT_ROTATE: ClassVar = {"rotation": 90}
63
- IND_1: ClassVar = {"indent": 1}
64
-
75
+ AREA_NUM: ClassVar = ({"num_format": "0.00000000"},)
65
76
  DOLLAR_NUM: ClassVar = {"num_format": "[$$-409]#,##0.00"}
66
77
  DT_NUM: ClassVar = {"num_format": "mm/dd/yyyy"}
67
- QTY_NUM: ClassVar = {"num_format": "#,##0.0"}
68
78
  PCT_NUM: ClassVar = {"num_format": "##0%"}
69
79
  PCT2_NUM: ClassVar = {"num_format": "##0.00%"}
70
80
  PCT4_NUM: ClassVar = {"num_format": "##0.0000%"}
71
81
  PCT6_NUM: ClassVar = {"num_format": "##0.000000%"}
72
82
  PCT8_NUM: ClassVar = {"num_format": "##0.00000000%"}
73
- AREA_NUM: ClassVar = {"num_format": "0.00000000"}
83
+ QTY_NUM: ClassVar = {"num_format": "#,##0.0"}
74
84
 
75
85
  BAR_FILL: ClassVar = {"pattern": 1, "bg_color": "dfeadf"}
76
- HDR_FILL: ClassVar = {"pattern": 1, "bg_color": "999999"}
86
+ HDR_FILL: ClassVar = {"pattern": 1, "bg_color": "e9e9e9"}
77
87
 
78
88
  LEFT_BORDER: ClassVar = {"left": 1, "left_color": "000000"}
79
89
  RIGHT_BORDER: ClassVar = {"right": 1, "right_color": "000000"}
@@ -81,6 +91,115 @@ class CFmt(dict, Enum): # type: ignore
81
91
  TOP_BORDER: ClassVar = {"top": 1, "top_color": "000000"}
82
92
  HDR_BORDER: ClassVar = TOP_BORDER | BOT_BORDER
83
93
 
94
+ @classmethod
95
+ def add_new(self, _fmt_name: str, _xlsx_fmt_dict: dict[str, Any], /) -> CFmt:
96
+ """
97
+ Add new CFmt object to instance.
98
+
99
+ Parameters
100
+ ----------
101
+ _fmt_name
102
+ Name of new member to be added to CFmt
103
+ _xlsx_fmt_dict
104
+ Any valid argument to xlsxwriter.Workbook.add_format(), or union of
105
+ same with one or more CFmt objects with same, e.g.,
106
+ CFmt.HDR_BORDER | CFmt.HDR_FILL or
107
+ CFmt.HDR_BORDER | {"pattern": 1, "bg_color": "f2f2f2"}
108
+
109
+ Returns
110
+ -------
111
+ None
112
+
113
+ """
114
+
115
+ return extend_enum(self, _fmt_name, _xlsx_fmt_dict) # type: ignore
116
+
117
+ @classmethod
118
+ def ensure_cell_format_spec_tuple(
119
+ self, _cell_formats: Sequence[CFmt | Sequence[CFmt]], /
120
+ ) -> bool:
121
+ """
122
+ Test that a given format specification is a tuple of CFmt enums
123
+
124
+ Parameters
125
+ ----------
126
+ _cell_formats
127
+ Format specification
128
+
129
+ Raises
130
+ ------
131
+ ValueError
132
+ If format specification is not tuple of CFmt enums
133
+
134
+ Returns
135
+ -------
136
+ True if format specification passes, else False
137
+
138
+ """
139
+
140
+ for _cell_format in _cell_formats:
141
+ if isinstance(_cell_format, tuple):
142
+ self.ensure_cell_format_spec_tuple(_cell_format)
143
+
144
+ if not (isinstance(_cell_format, CFmt),):
145
+ raise ValueError(
146
+ "Improperly specified format tuple for writing array."
147
+ " Must be tuple of CFmt enums."
148
+ )
149
+
150
+ return True
151
+
152
+ @classmethod
153
+ def xl_fmt(
154
+ self,
155
+ _xl_book: xlsxwriter.Workbook,
156
+ _cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
157
+ /,
158
+ ) -> xlsxwriter.format.Format:
159
+ """
160
+ Return :code:`xlsxwriter` `Format` object given a CFmt aenum, or tuple thereof.
161
+
162
+ Parameters
163
+ ----------
164
+ _xl_book
165
+ :code:`xlsxwriter.Workbook` object
166
+
167
+ _cell_fmt
168
+ :code:`CFmt` aenum object, or tuple thereof
169
+
170
+ Raises
171
+ ------
172
+ ValueError
173
+ If format specification is not one of None, a CFmt aenum, or
174
+ a xlsxwriter.format.Format object
175
+
176
+ Returns
177
+ -------
178
+ :code:`xlsxwriter` `Format` object
179
+
180
+ """
181
+
182
+ if isinstance(_cell_fmt, xlsxwriter.format.Format):
183
+ return _cell_fmt
184
+ elif _cell_fmt is None:
185
+ return _xl_book.add_format(CFmt.XL_DEFAULT.value)
186
+
187
+ _cell_fmt_dict: Mapping[str, Any] = {}
188
+ if isinstance(_cell_fmt, Sequence):
189
+ self.ensure_cell_format_spec_tuple(_cell_fmt)
190
+ for _cf in _cell_fmt:
191
+ _cell_fmt_dict = (
192
+ (_cell_fmt_dict | _cfi.value for _cfi in _cf)
193
+ if isinstance(_cf, Sequence)
194
+ else _cell_fmt_dict | _cf.value
195
+ )
196
+ elif isinstance(_cell_fmt, CFmt):
197
+ _cell_fmt_dict = _cell_fmt.value
198
+ else:
199
+ raise ValueError("Improperly specified format specification.")
200
+
201
+ return _xl_book.add_format(_cell_fmt_dict)
202
+
84
203
 
85
204
  def write_header(
86
205
  _xl_sheet: xlsxwriter.worksheet.Worksheet,
@@ -156,7 +275,7 @@ def write_footer(
156
275
  None
157
276
  """
158
277
 
159
- if not any((center_footer, left_footer, right_footer)):
278
+ if any((center_footer, left_footer, right_footer)):
160
279
  _xl_sheet.set_footer(
161
280
  "".join([
162
281
  f"&L{left_footer}" if left_footer else "",
@@ -235,6 +354,17 @@ def array_to_sheet(
235
354
  -------
236
355
  Tuple giving address of cell at right below and after range written
237
356
 
357
+
358
+ Notes
359
+ -----
360
+
361
+ The keyword argument cell_format may be passed a tuple of CFmt enums,
362
+ if, and only if, ragged_flag is False. If cell_format is a tuple, it must
363
+ have length equal to the number of cells in the range to be written. Further,
364
+ members of cell_format must each be a CFmt enum or a tuple of CFmt enums; in
365
+ other words, `CFmt.ensure_cell_format_spec_tuple(_c)` must return True for
366
+ any tuple `_c` passed as `cell_format`.
367
+
238
368
  """
239
369
 
240
370
  if not ragged_flag:
@@ -268,7 +398,7 @@ def array_to_sheet(
268
398
  )
269
399
  elif not len(cell_format) == len(_data_table[0]):
270
400
  raise ValueError("Format tuple does not match data in length.")
271
- ensure_cell_format_spec_tuple(cell_format)
401
+ CFmt.ensure_cell_format_spec_tuple(cell_format)
272
402
  _cell_format: Sequence[CFmt | Sequence[CFmt]] = cell_format
273
403
  elif isinstance(cell_format, CFmt):
274
404
  _cell_format = (cell_format,) * len(_data_table[0])
@@ -276,21 +406,27 @@ def array_to_sheet(
276
406
  _cell_format = (CFmt.XL_DEFAULT,) * len(_data_table[0])
277
407
 
278
408
  # construct vector of xlslwrter.format.Format objects
279
- _wbk_formats = tuple(xl_fmt(_xl_book, _cf) for _cf in _cell_format)
409
+ _wbk_formats = tuple(CFmt.xl_fmt(_xl_book, _cf) for _cf in _cell_format)
280
410
  if _num_rows > 1:
281
411
  _wbk_formats_greened = (
282
- tuple(xl_fmt(_xl_book, (_cf, CFmt.BAR_FILL)) for _cf in _cell_format)
412
+ tuple(
413
+ CFmt.xl_fmt(
414
+ _xl_book,
415
+ (*_cf, CFmt.BAR_FILL)
416
+ if isinstance(_cf, Sequence)
417
+ else (_cf, CFmt.BAR_FILL),
418
+ )
419
+ for _cf in _cell_format
420
+ )
283
421
  if green_bar_flag
284
422
  else _wbk_formats
285
423
  )
286
424
 
287
425
  for _ri, _rv in enumerate(_data_table):
288
- _fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
426
+ _wbk_fmt_tuple = _wbk_formats_greened if _ri % 2 else _wbk_formats
289
427
  for _ci, _cv in enumerate(_rv):
290
- _cell_fmt = _fmt_tuple[_ci]
291
- scalar_to_sheet(
292
- _xl_book, _xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cell_fmt
293
- )
428
+ _cf = _wbk_fmt_tuple[_ci]
429
+ scalar_to_sheet(_xl_sheet, _row_id + _ri, _col_id + _ci, _cv, _cf)
294
430
 
295
431
  _right_column_id = _col_id + _ci + 1 if _ci > _num_cols else _right_column_id
296
432
 
@@ -298,20 +434,17 @@ def array_to_sheet(
298
434
 
299
435
 
300
436
  def scalar_to_sheet(
301
- _xl_book: xlsxwriter.workbook.Workbook,
302
437
  _xl_sheet: xlsxwriter.worksheet.Worksheet,
303
- _cell_addr_0: str | int | float = "A1",
438
+ _cell_addr_0: str | int = "A1",
304
439
  /,
305
440
  *_s2s_args: Any,
441
+ empty_as_blank: bool = True,
306
442
  ) -> None:
307
443
  """
308
444
  Write to a single cell in a worksheet.
309
445
 
310
446
  Parameters
311
447
  ----------
312
- _xl_book
313
- Workbook object
314
-
315
448
  _xl_sheet
316
449
  Worksheet object to which to write the give array
317
450
 
@@ -337,104 +470,41 @@ def scalar_to_sheet(
337
470
 
338
471
  """
339
472
 
473
+ _cell_addr: tuple[int | str, ...] = ()
474
+ _cell_val: Any = None
475
+ _cell_fmt: xlsxwriter.format.Format = CFmt.XL_DEFAULT
476
+
340
477
  if isinstance(_cell_addr_0, str):
341
478
  if len(_s2s_args) not in (1, 2):
342
- raise ValueError("Too many or too few arguments.")
343
- _cell_addr: tuple[int | str, ...] = (_cell_addr_0,)
344
- _cell_val: Any = _s2s_args[0]
345
- _cell_fmt: CFmt | Sequence[CFmt] = _s2s_args[1] if len(_s2s_args) == 2 else None # type: ignore
479
+ raise ValueError("Incorrect number of arguments.")
480
+ _cell_addr = (_cell_addr_0,)
481
+ _cell_val = _s2s_args[0]
482
+ _cell_fmt = _s2s_args[1] if len(_s2s_args) == 2 else None # type: ignore
346
483
  elif isinstance(_cell_addr_0, int):
347
- if len(_s2s_args) not in (2, 3):
348
- raise ValueError("Too many or too few arguments.")
484
+ if len(_s2s_args) not in (2, 3) or not isinstance(_s2s_args[0], int):
485
+ raise ValueError("Incorrect/incomplete specification for Excel cell data.")
349
486
  _cell_addr = (_cell_addr_0, _s2s_args[0])
350
487
  _cell_val = _s2s_args[1]
351
488
  _cell_fmt = _s2s_args[2] if len(_s2s_args) == 3 else None # type: ignore
352
489
  else:
353
490
  raise ValueError("Incorrect/incomplete specification for Excel cell data.")
354
491
 
355
- _xl_fmt = xl_fmt(_xl_book, _cell_fmt)
356
- if isinstance(_cell_val, str):
357
- _xl_sheet.write_string(*_cell_addr, _cell_val, _xl_fmt)
358
- else:
359
- _xl_sheet.write(
360
- *_cell_addr, repr(_cell_val) if np.ndim(_cell_val) else _cell_val, _xl_fmt
361
- )
362
-
363
-
364
- def xl_fmt(
365
- _xl_book: xlsxwriter.Workbook,
366
- _cell_fmt: Sequence[CFmt | Sequence[CFmt]] | CFmt | None,
367
- /,
368
- ) -> xlsxwriter.format.Format:
369
- """
370
- Return :code:`xlsxwriter` `Format` object given a CFmt aenum, or tuple thereof.
371
-
372
- Parameters
373
- ----------
374
- _xl_book
375
- :code:`xlsxwriter.Workbook` object
376
-
377
- _cell_fmt
378
- :code:`CFmt` aenum object, or tuple thereof
379
-
380
- Raises
381
- ------
382
- ValueError
383
- If format specification is not one of None, a CFmt aenum, or
384
- a xlsxwriter.format.Format object
385
-
386
- Returns
387
- -------
388
- :code:`xlsxwriter` `Format` object
389
-
390
- """
391
-
392
- if isinstance(_cell_fmt, xlsxwriter.format.Format):
393
- return _cell_fmt
394
- elif _cell_fmt is None:
395
- return _xl_book.add_format(CFmt.XL_DEFAULT.value)
396
-
397
- _cell_fmt_dict: Mapping[str, Any] = {}
398
- if isinstance(_cell_fmt, Sequence):
399
- ensure_cell_format_spec_tuple(_cell_fmt)
400
- for _cf in _cell_fmt:
401
- _cell_fmt_dict = _cell_fmt_dict | _cf.value
402
- elif isinstance(_cell_fmt, CFmt):
403
- _cell_fmt_dict = _cell_fmt.value
492
+ _write_args = (
493
+ (*_cell_addr, repr(_cell_val))
494
+ if np.ndim(_cell_val) or _cell_val in (np.inf, -np.inf, np.nan)
495
+ else (*_cell_addr, _cell_val)
496
+ )
497
+ _write_args = (*_write_args, _cell_fmt) if _cell_fmt else _write_args
498
+
499
+ if empty_as_blank and (_cell_val is None or _cell_val == ""):
500
+ _xl_sheet.write_blank(*_write_args)
501
+ elif (
502
+ _cell_val is None
503
+ or _cell_val == ""
504
+ or isinstance(_cell_val, str)
505
+ or np.ndim(_cell_val)
506
+ or _cell_val in (np.inf, -np.inf, np.nan)
507
+ ):
508
+ _xl_sheet.write_string(*_write_args)
404
509
  else:
405
- raise ValueError("Improperly specified format specification.")
406
-
407
- return _xl_book.add_format(_cell_fmt_dict)
408
-
409
-
410
- def ensure_cell_format_spec_tuple(
411
- _cell_formats: Sequence[CFmt | Sequence[CFmt]], /
412
- ) -> None:
413
- """
414
- Test that a given format specification is tuple of CFmt enums
415
-
416
- Parameters
417
- ----------
418
- _cell_formats
419
- Format specification
420
-
421
- Raises
422
- ------
423
- ValueError
424
- If format specification is not tuple of CFmt enums
425
-
426
- Returns
427
- -------
428
- True if format specification passes, else False
429
-
430
- """
431
-
432
- for _cell_format in _cell_formats:
433
- if isinstance(_cell_format, tuple):
434
- ensure_cell_format_spec_tuple(_cell_format)
435
-
436
- if not (isinstance(_cell_format, CFmt),):
437
- raise ValueError(
438
- "Improperly specified format tuple for writing array."
439
- " Must be tuple of CFmt enums."
440
- )
510
+ _xl_sheet.write(*_write_args)
@@ -10,6 +10,7 @@ from collections.abc import Mapping, Sequence
10
10
  from importlib import resources
11
11
  from pathlib import Path
12
12
  from types import SimpleNamespace
13
+ from typing import Literal
13
14
 
14
15
  import numpy as np
15
16
  import re2 as re # type: ignore
@@ -82,36 +83,12 @@ moe_tmpl = Template(R"""
82
83
  {% endif %}
83
84
  """)
84
85
 
85
- LTX_ARRAY_LINEEND = R"\\" "\n"
86
- latex_hrdcoldesc_format_str = "{}\n{}\n{}".format(
87
- "".join((
88
- R"\matrix[hcol, above=0pt of {}, nodes = {{",
89
- R"text width={}, text depth=10pt, inner sep=3pt, minimum height=25pt,",
90
- R"}},] ",
91
- R"({}) ",
92
- R"{{",
93
- )),
94
- R"\node[align = {},] {{ {} }}; \\",
95
- R"}};",
96
- )
97
-
98
-
99
- class StatsContainer(SimpleNamespace):
100
- """A container for passing content to jinja2 templates
101
-
102
- Other attributes added later, to fully populate selected jinja2 templates
103
- """
104
-
105
- invdata_hdrstr: str
106
- invdata_datstr: str
107
-
108
-
109
- # Define the latex jinja environment
110
- # http://eosrei.net/articles/2015/11/latex-templates-python-and-jinja2-generate-pdfs
86
+ # Define the LaTeX jinja environment
87
+ # http://eosrei.net/articles/2015/11/LaTeX-templates-python-and-jinja2-generate-pdfs
111
88
  with resources.as_file(
112
89
  resources.files(f"{_PKG_NAME}.data.jinja2_LaTeX_templates")
113
90
  ) as _tmpl_folder:
114
- latex_jinja_env = Environment(
91
+ LaTeX_jinja_env = Environment(
115
92
  block_start_string=R"((*",
116
93
  block_end_string="*))",
117
94
  variable_start_string=R"\JINVAR{",
@@ -126,7 +103,7 @@ with resources.as_file(
126
103
  loader=FileSystemLoader(_tmpl_folder),
127
104
  )
128
105
 
129
- # Place files related to rendering latex in output data directory
106
+ # Place files related to rendering LaTeX in output data directory
130
107
  if not (_out_path := DATA_DIR.joinpath(f"{_PKG_NAME}.cls")).is_file():
131
108
  with resources.as_file(
132
109
  resources.files(f"{_PKG_NAME}.data.jinja2_LaTeX_templates").joinpath(
@@ -146,6 +123,30 @@ if not (_DOTTEX := DATA_DIR / Rf"{_PKG_NAME}_TikZTableSettings.tex").is_file():
146
123
  shutil.copy2(_tex_path, _DOTTEX)
147
124
 
148
125
 
126
+ LTX_ARRAY_LINEEND = R"\\" "\n"
127
+ LaTeX_hrdcoldesc_format_str = "{}\n{}\n{}".format(
128
+ "".join((
129
+ R"\matrix[hcol, above=0pt of {}, nodes = {{",
130
+ R"text width={}, text depth=10pt, inner sep=3pt, minimum height=25pt,",
131
+ R"}},] ",
132
+ R"({}) ",
133
+ R"{{",
134
+ )),
135
+ R"\node[align = {},] {{ {} }}; \\",
136
+ R"}};",
137
+ )
138
+
139
+
140
+ class StatsContainer(SimpleNamespace):
141
+ """A container for passing content to jinja2 templates
142
+
143
+ Other attributes added later, to fully populate selected jinja2 templates
144
+ """
145
+
146
+ invdata_hdrstr: str
147
+ invdata_datstr: str
148
+
149
+
149
150
  # Parameters and functions to interpolate selected HHI and ΔHHI values
150
151
  # recorded in fractions to ranges of values in points on the HHI scale
151
152
  HHI_DELTA_KNOTS = np.array(
@@ -184,21 +185,39 @@ ZONE_VALS = np.unique(
184
185
  )
185
186
 
186
187
  ZONE_STRINGS = {
188
+ 0: R"Green Zone (Safeharbor)",
189
+ 1: R"Yellow Zone",
190
+ 2: R"Red Zone (SLC Presumption)",
191
+ fid.TTL_KEY: R"\node[align = left, fill=OBSHDRFill] {TOTAL};",
192
+ }
193
+ ZONE_DETAIL_STRINGS_HHI = {
194
+ 0: Rf"HHI < {HHI_POST_ZONE_KNOTS[1]} pts.",
195
+ 1: R"HHI ∈ [{}, {}) pts. and ".format(*HHI_POST_ZONE_KNOTS[1:3]),
196
+ 2: Rf"HHI ≥ {HHI_POST_ZONE_KNOTS[2]} pts. and ",
197
+ }
198
+
199
+ ZONE_DETAIL_STRINGS_DELTA = {
200
+ 0: "",
201
+ 1: Rf"ΔHHI < \text{{{HHI_DELTA_KNOTS[1]} pts.}}",
202
+ 2: Rf"ΔHHI ≥ \text{{{HHI_DELTA_KNOTS[1]} pts.}}",
203
+ 3: R"ΔHHI ∈ \text{{[{}, {}) pts.}}".format(*HHI_DELTA_KNOTS[1:3]),
204
+ 4: Rf"ΔHHI ≥ \text{{{HHI_DELTA_KNOTS[2]} pts.}}",
205
+ }
206
+
207
+ ZONE_STRINGS_LATEX = {
187
208
  0: R"\node[align = left, fill=BrightGreen] {Green Zone (Safeharbor)};",
188
209
  1: R"\node[align = left, fill=HiCoYellow] {Yellow Zone};",
189
210
  2: R"\node[align = left, fill=VibrRed] {Red Zone (SLC Presumption)};",
190
211
  fid.TTL_KEY: R"\node[align = left, fill=OBSHDRFill] {TOTAL};",
191
212
  }
192
213
 
193
- ZONE_DETAIL_STRINGS_HHI = {
214
+ ZONE_DETAIL_STRINGS_HHI_LATEX = {
194
215
  0: Rf"HHI_{{post}} < \text{{{HHI_POST_ZONE_KNOTS[1]} pts.}}",
195
- 1: R"HHI_{{post}} \in \text{{[{}, {}) pts. and }} ".format(
196
- *HHI_POST_ZONE_KNOTS[1:3]
197
- ),
216
+ 1: R"HHI_{{post}} \text{{[{}, {}) pts. and }} ".format(*HHI_POST_ZONE_KNOTS[1:3]),
198
217
  2: Rf"HHI_{{post}} \geqslant \text{{{HHI_POST_ZONE_KNOTS[2]} pts. and }} ",
199
218
  }
200
219
 
201
- ZONE_DETAIL_STRINGS_DELTA = {
220
+ ZONE_DETAIL_STRINGS_DELTA_LATEX = {
202
221
  0: "",
203
222
  1: Rf"\Delta HHI < \text{{{HHI_DELTA_KNOTS[1]} pts.}}",
204
223
  2: Rf"\Delta HHI \geqslant \text{{{HHI_DELTA_KNOTS[1]} pts.}}",
@@ -207,13 +226,13 @@ ZONE_DETAIL_STRINGS_DELTA = {
207
226
  }
208
227
 
209
228
 
210
- def invres_stats_output(
229
+ def enf_stats_output(
211
230
  _data_array_dict: fid.INVData,
212
231
  _data_period: str = "1996-2003",
213
232
  _table_ind_group: INDGRPConstants = INDGRPConstants.ALL,
214
233
  _table_evid_cond: EVIDENConstants = EVIDENConstants.UR,
215
234
  _stats_group: StatsGrpSelector = StatsGrpSelector.FC,
216
- _invres_spec: INVResolution = INVResolution.CLRN,
235
+ _enf_spec: INVResolution = INVResolution.CLRN,
217
236
  /,
218
237
  *,
219
238
  return_type_sel: StatsReturnSelector = StatsReturnSelector.RPT,
@@ -228,49 +247,49 @@ def invres_stats_output(
228
247
 
229
248
  match _stats_group:
230
249
  case StatsGrpSelector.ZN:
231
- _latex_tbl_invres_stats_func = latex_tbl_invres_stats_byzone
250
+ _enf_stats_table_func = enf_stats_table_byzone
232
251
  case StatsGrpSelector.FC:
233
- _latex_tbl_invres_stats_func = latex_tbl_invres_stats_1dim
252
+ _enf_stats_table_func = enf_stats_table_1dim
234
253
  case StatsGrpSelector.DL:
235
- _latex_tbl_invres_stats_func = latex_tbl_invres_stats_1dim
254
+ _enf_stats_table_func = enf_stats_table_1dim
236
255
  case _:
237
256
  raise ValueError(
238
257
  'Statistics formatted, "{_stats_group}" not available here.'
239
258
  )
240
259
 
241
- _invres_stats_cnts = invres_stats_cnts_by_group(
260
+ _enf_stats_cnts = enf_stats_listing_by_group(
242
261
  _data_array_dict,
243
262
  _data_period,
244
263
  _table_ind_group,
245
264
  _table_evid_cond,
246
265
  _stats_group,
247
- _invres_spec,
266
+ _enf_spec,
248
267
  )
249
268
 
250
- _invres_stats_hdr_list, _invres_stats_dat_list = _latex_tbl_invres_stats_func(
251
- _invres_stats_cnts, None, return_type_sel=return_type_sel, sort_order=sort_order
269
+ _enf_stats_hdr_list, _enf_stats_dat_list = _enf_stats_table_func(
270
+ _enf_stats_cnts, None, return_type_sel=return_type_sel, sort_order=sort_order
252
271
  )
253
272
 
254
273
  if print_to_screen:
255
274
  print(
256
- f"{_invres_spec.capitalize()} stats ({return_type_sel})",
275
+ f"{_enf_spec.capitalize()} stats ({return_type_sel})",
257
276
  f"for Period: {_data_period}",
258
277
  "\u2014",
259
278
  f"{_table_ind_group};",
260
279
  _table_evid_cond,
261
280
  )
262
- stats_print_rows(_invres_stats_hdr_list, _invres_stats_dat_list)
281
+ stats_print_rows(_enf_stats_hdr_list, _enf_stats_dat_list)
263
282
 
264
- return _invres_stats_hdr_list, _invres_stats_dat_list
283
+ return _enf_stats_hdr_list, _enf_stats_dat_list
265
284
 
266
285
 
267
- def invres_stats_cnts_by_group(
286
+ def enf_stats_listing_by_group(
268
287
  _invdata_array_dict: Mapping[str, Mapping[str, Mapping[str, fid.INVTableData]]],
269
288
  _study_period: str,
270
289
  _table_ind_grp: INDGRPConstants,
271
290
  _table_evid_cond: EVIDENConstants,
272
291
  _stats_group: StatsGrpSelector,
273
- _invres_spec: INVResolution,
292
+ _enf_spec: INVResolution,
274
293
  /,
275
294
  ) -> NDArray[np.int64]:
276
295
  if _stats_group == StatsGrpSelector.HD:
@@ -280,14 +299,14 @@ def invres_stats_cnts_by_group(
280
299
 
281
300
  match _stats_group:
282
301
  case StatsGrpSelector.FC:
283
- _cnts_func = invres_cnts_byfirmcount
284
- _cnts_listing_func = invres_cnts_listing_byfirmcount
302
+ _cnts_func = enf_cnts_byfirmcount
303
+ _cnts_listing_func = enf_cnts_listing_byfirmcount
285
304
  case StatsGrpSelector.DL:
286
- _cnts_func = invres_cnts_bydelta
287
- _cnts_listing_func = invres_cnts_listing_byhhianddelta
305
+ _cnts_func = enf_cnts_bydelta
306
+ _cnts_listing_func = enf_cnts_listing_byhhianddelta
288
307
  case StatsGrpSelector.ZN:
289
- _cnts_func = invres_cnts_byconczone
290
- _cnts_listing_func = invres_cnts_listing_byhhianddelta
308
+ _cnts_func = enf_cnts_byconczone
309
+ _cnts_listing_func = enf_cnts_listing_byhhianddelta
291
310
 
292
311
  return _cnts_func(
293
312
  _cnts_listing_func(
@@ -295,17 +314,17 @@ def invres_stats_cnts_by_group(
295
314
  _study_period,
296
315
  _table_ind_grp,
297
316
  _table_evid_cond,
298
- _invres_spec,
317
+ _enf_spec,
299
318
  )
300
319
  )
301
320
 
302
321
 
303
- def invres_cnts_listing_byfirmcount(
322
+ def enf_cnts_listing_byfirmcount(
304
323
  _data_array_dict: Mapping[str, Mapping[str, Mapping[str, fid.INVTableData]]],
305
324
  _data_period: str = "1996-2003",
306
325
  _table_ind_group: INDGRPConstants = INDGRPConstants.ALL,
307
326
  _table_evid_cond: EVIDENConstants = EVIDENConstants.UR,
308
- _invres_spec: INVResolution = INVResolution.CLRN,
327
+ _enf_spec: INVResolution = INVResolution.CLRN,
309
328
  /,
310
329
  ) -> NDArray[np.int64]:
311
330
  if _data_period not in _data_array_dict:
@@ -322,7 +341,7 @@ def invres_cnts_listing_byfirmcount(
322
341
 
323
342
  _ndim_in = 1
324
343
  _stats_kept_indxs = []
325
- match _invres_spec:
344
+ match _enf_spec:
326
345
  case INVResolution.CLRN:
327
346
  _stats_kept_indxs = [-1, -2]
328
347
  case INVResolution.ENFT:
@@ -336,12 +355,12 @@ def invres_cnts_listing_byfirmcount(
336
355
  ])
337
356
 
338
357
 
339
- def invres_cnts_listing_byhhianddelta(
358
+ def enf_cnts_listing_byhhianddelta(
340
359
  _data_array_dict: Mapping[str, Mapping[str, Mapping[str, fid.INVTableData]]],
341
360
  _data_period: str = "1996-2003",
342
361
  _table_ind_group: INDGRPConstants = INDGRPConstants.ALL,
343
362
  _table_evid_cond: EVIDENConstants = EVIDENConstants.UR,
344
- _invres_spec: INVResolution = INVResolution.CLRN,
363
+ _enf_spec: INVResolution = INVResolution.CLRN,
345
364
  /,
346
365
  ) -> NDArray[np.int64]:
347
366
  if _data_period not in _data_array_dict:
@@ -358,7 +377,7 @@ def invres_cnts_listing_byhhianddelta(
358
377
 
359
378
  _ndim_in = 2
360
379
  _stats_kept_indxs = []
361
- match _invres_spec:
380
+ match _enf_spec:
362
381
  case INVResolution.CLRN:
363
382
  _stats_kept_indxs = [-1, -2]
364
383
  case INVResolution.ENFT:
@@ -398,7 +417,7 @@ def table_no_lku(
398
417
  return _tno
399
418
 
400
419
 
401
- def invres_cnts_byfirmcount(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
420
+ def enf_cnts_byfirmcount(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
402
421
  _ndim_in = 1
403
422
  return np.vstack([
404
423
  np.concatenate([
@@ -409,7 +428,7 @@ def invres_cnts_byfirmcount(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int
409
428
  ])
410
429
 
411
430
 
412
- def invres_cnts_bydelta(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
431
+ def enf_cnts_bydelta(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
413
432
  _ndim_in = 2
414
433
  return np.vstack([
415
434
  np.concatenate([
@@ -420,7 +439,7 @@ def invres_cnts_bydelta(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
420
439
  ])
421
440
 
422
441
 
423
- def invres_cnts_byconczone(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
442
+ def enf_cnts_byconczone(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int64]:
424
443
  # Prepare to tag clearance stats by presumption zone
425
444
  _hhi_zone_post_ranged = hhi_zone_post_ranger(_cnts_array[:, 0] / 1e4)
426
445
  _hhi_delta_ranged = hhi_delta_ranger(_cnts_array[:, 1] / 1e4)
@@ -491,23 +510,23 @@ def invres_cnts_byconczone(_cnts_array: NDArray[np.int64], /) -> NDArray[np.int6
491
510
  return _cnts_byconczone[1:]
492
511
 
493
512
 
494
- def latex_tbl_invres_stats_1dim(
513
+ def enf_stats_table_1dim(
495
514
  _inparr: NDArray[np.float64 | np.int64],
496
515
  _totals_row: int | None = None,
497
516
  /,
498
517
  *,
499
518
  return_type_sel: StatsReturnSelector = StatsReturnSelector.CNT,
500
519
  sort_order: SortSelector = SortSelector.UCH,
520
+ print_format: Literal["text", "LaTeX"] = "text",
501
521
  ) -> tuple[list[str], list[list[str]]]:
502
522
  _ndim_in: int = 1
503
523
  _dim_hdr_dict = {
504
- _v: (_k if _k == "TOTAL" else f"{{{_k}}}")
505
- for _k, _v in fid.CNT_FCOUNT_DICT.items()
524
+ _v: (_k if _k == "TOTAL" else f"{_k}") for _k, _v in fid.CNT_FCOUNT_DICT.items()
506
525
  } | {
507
526
  _v: (
508
- "{[2500, 5000]}"
527
+ "[2500, 5000]"
509
528
  if _k == "2,500 +"
510
- else f"{{[{_k.replace(",", "").replace(" - ", ", ")})}}"
529
+ else f"[{_k.replace(",", "").replace(" - ", ", ")})"
511
530
  )
512
531
  for _k, _v in fid.CONC_DELTA_DICT.items()
513
532
  if _k != "TOTAL"
@@ -531,7 +550,10 @@ def latex_tbl_invres_stats_1dim(
531
550
 
532
551
  _stats_hdr_list, _stats_dat_list = [], []
533
552
  for _stats_row in _inparr:
534
- _stats_hdr_list += [_dim_hdr_dict[_stats_row[0]]]
553
+ _stats_hdr_str = _dim_hdr_dict[_stats_row[0]]
554
+ _stats_hdr_list += [
555
+ f"{{{_stats_hdr_str}}}" if print_format == "LaTeX" else _stats_hdr_str
556
+ ]
535
557
 
536
558
  _stats_cnt = _stats_row[_ndim_in:]
537
559
  _stats_tot = np.concatenate((
@@ -543,17 +565,20 @@ def latex_tbl_invres_stats_1dim(
543
565
  return _stats_hdr_list, _stats_dat_list
544
566
 
545
567
 
546
- def latex_tbl_invres_stats_byzone(
568
+ def enf_stats_table_byzone(
547
569
  _inparr: NDArray[np.float64 | np.int64],
548
570
  _totals_row: int | None = None,
549
571
  /,
550
572
  *,
551
573
  return_type_sel: StatsReturnSelector = StatsReturnSelector.CNT,
552
574
  sort_order: SortSelector = SortSelector.UCH,
575
+ print_format: Literal["text", "LaTeX"] = "text",
553
576
  ) -> tuple[list[str], list[list[str]]]:
554
577
  _ndim_in: int = ZONE_VALS.shape[1]
555
578
 
556
- _zone_str_keys = list(ZONE_STRINGS)
579
+ _zone_str_dict = ZONE_STRINGS_LATEX if print_format == "LaTeX" else ZONE_STRINGS
580
+ _zone_str_keys = list(_zone_str_dict)
581
+
557
582
  if sort_order == SortSelector.REV:
558
583
  _inparr = _inparr[::-1]
559
584
  _zone_str_keys = _zone_str_keys[:-1][::-1] + [_zone_str_keys[-1]]
@@ -570,7 +595,7 @@ def latex_tbl_invres_stats_byzone(
570
595
  _stats_hdr_list, _stats_dat_list = ([], [])
571
596
  for _conc_zone in _zone_str_keys:
572
597
  _stats_byzone_it = _inparr[_inparr[:, 0] == _conc_zone]
573
- _stats_hdr_list += [ZONE_STRINGS[_conc_zone]]
598
+ _stats_hdr_list += [_zone_str_dict[_conc_zone]]
574
599
 
575
600
  _stats_cnt = np.einsum("ij->j", _stats_byzone_it[:, _ndim_in:])
576
601
  _stats_tot = np.concatenate((
@@ -585,18 +610,30 @@ def latex_tbl_invres_stats_byzone(
585
610
  for _stats_byzone_detail in _stats_byzone_it:
586
611
  # Only two sets of subtotals detail, so
587
612
  # a conditional expression will do here
588
- _stats_text_color = "HiCoYellow" if _conc_zone == 1 else "BrightGreen"
589
- _stats_hdr_list += [
590
- R"{} {{ \({}{}\) }};".format(
591
- rf"\node[text = {_stats_text_color}, fill = white, align = right]",
592
- ZONE_DETAIL_STRINGS_HHI[_stats_byzone_detail[1]],
593
- (
594
- ""
595
- if _stats_byzone_detail[2] == 0
596
- else Rf"{ZONE_DETAIL_STRINGS_DELTA[_stats_byzone_detail[2]]}"
597
- ),
598
- )
599
- ]
613
+ if print_format == "LaTeX":
614
+ _stats_text_color = "HiCoYellow" if _conc_zone == 1 else "BrightGreen"
615
+ _stats_hdr_list += [
616
+ R"{} {{ \({}{}\) }};".format(
617
+ rf"\node[text = {_stats_text_color}, fill = white, align = right]",
618
+ ZONE_DETAIL_STRINGS_HHI_LATEX[_stats_byzone_detail[1]],
619
+ (
620
+ ""
621
+ if _stats_byzone_detail[2] == 0
622
+ else Rf"{ZONE_DETAIL_STRINGS_DELTA_LATEX[_stats_byzone_detail[2]]}"
623
+ ),
624
+ )
625
+ ]
626
+ else:
627
+ _stats_hdr_list += [
628
+ R"{}{};".format(
629
+ ZONE_DETAIL_STRINGS_HHI[_stats_byzone_detail[1]],
630
+ (
631
+ ""
632
+ if _stats_byzone_detail[2] == 0
633
+ else Rf"{ZONE_DETAIL_STRINGS_DELTA[_stats_byzone_detail[2]]}"
634
+ ),
635
+ )
636
+ ]
600
637
 
601
638
  _stats_cnt = _stats_byzone_detail[_ndim_in:]
602
639
  _stats_tot = np.concatenate((
@@ -652,31 +689,34 @@ def _stats_formatted_row(
652
689
 
653
690
 
654
691
  def stats_print_rows(
655
- _invres_stats_hdr_list: list[str], _invres_stats_dat_list: list[list[str]]
692
+ _enf_stats_hdr_list: list[str],
693
+ _enf_stats_dat_list: list[list[str]],
694
+ print_format: Literal["text", "LaTeX"] = "text",
656
695
  ) -> None:
657
- for _idx, _hdr in enumerate(_invres_stats_hdr_list):
658
- # _hv = (
659
- # re.match(r"^\\node.*?(\{.*\});?", _hdr)[1]
660
- # if _hdr.startswith(R"\node")
661
- # else _hdr
662
- # )
663
- _hdr_str = (
664
- _hdr if _hdr == "TOTAL" else re.fullmatch(r".*?\{(.*)\};?", _hdr)[1].strip()
665
- )
666
- print(
667
- _hdr_str,
668
- "&",
669
- " & ".join(_invres_stats_dat_list[_idx]),
670
- LTX_ARRAY_LINEEND,
671
- end="",
672
- )
696
+ for _idx, _hdr in enumerate(_enf_stats_hdr_list):
697
+ if print_format == "LaTeX":
698
+ _hdr_str = (
699
+ _hdr
700
+ if _hdr == "TOTAL"
701
+ else re.fullmatch(r".*?\{(.*)\};?", _hdr)[1].strip()
702
+ )
703
+ print(
704
+ _hdr_str,
705
+ " & ",
706
+ " & ".join(_enf_stats_dat_list[_idx]),
707
+ LTX_ARRAY_LINEEND,
708
+ end="",
709
+ )
710
+ else:
711
+ print(_hdr, " | ", " | ".join(_enf_stats_dat_list[_idx]))
712
+
673
713
  print()
674
714
 
675
715
 
676
716
  def render_table_pdf(
677
717
  _table_dottex_pathlist: Sequence[str], _table_coll_path: str, /
678
718
  ) -> None:
679
- _table_collection_design = latex_jinja_env.get_template(
719
+ _table_collection_design = LaTeX_jinja_env.get_template(
680
720
  "mergeron_table_collection_template.tex.jinja2"
681
721
  )
682
722
  _table_collection_content = StatsContainer()
@@ -692,12 +732,12 @@ def render_table_pdf(
692
732
  print("\n", file=_table_coll_file)
693
733
 
694
734
  _run_rc = subprocess.run( # noqa: S603
695
- f"latexmk -f -quiet -synctex=0 -interaction=nonstopmode -file-line-error -pdflua {_table_coll_path}".split(),
735
+ f"LaTeXmk -f -quiet -synctex=0 -interaction=nonstopmode -file-line-error -pdflua {_table_coll_path}".split(),
696
736
  check=True,
697
737
  cwd=DATA_DIR,
698
738
  )
699
739
  if _run_rc:
700
- subprocess.run("latexmk -quiet -c".split(), check=True, cwd=DATA_DIR) # noqa: S603
740
+ subprocess.run("LaTeXmk -quiet -c".split(), check=True, cwd=DATA_DIR) # noqa: S603
701
741
  del _run_rc
702
742
 
703
743
  print(
@@ -12,7 +12,7 @@ from .. import VERSION # noqa: TID252
12
12
  from ..core.guidelines_boundaries import HMGThresholds # noqa: TID252
13
13
  from . import MarketSpec, UPPTestRegime
14
14
  from .data_generation import gen_market_sample
15
- from .upp_tests import SaveData, invres_cnts, save_data_to_hdf5, sim_invres_cnts_ll
15
+ from .upp_tests import SaveData, enf_cnts, save_data_to_hdf5, sim_enf_cnts_ll
16
16
 
17
17
  __version__ = VERSION
18
18
 
@@ -46,9 +46,9 @@ class MarketSample(MarketSpec):
46
46
  save_data_to_file=save_data_to_file,
47
47
  )
48
48
 
49
- def estimate_invres_counts(
49
+ def estimate_enf_counts(
50
50
  self,
51
- _invres_parm_vec: HMGThresholds,
51
+ _enf_parm_vec: HMGThresholds,
52
52
  _upp_test_regime: UPPTestRegime,
53
53
  /,
54
54
  *,
@@ -58,9 +58,9 @@ class MarketSample(MarketSpec):
58
58
  save_data_to_file: SaveData = False,
59
59
  ) -> None:
60
60
  if getattr(self, "market_data_sample", None) is None:
61
- self.invres_counts = sim_invres_cnts_ll(
61
+ self.enf_counts = sim_enf_cnts_ll(
62
62
  self,
63
- _invres_parm_vec,
63
+ _enf_parm_vec,
64
64
  _upp_test_regime,
65
65
  save_data_to_file=save_data_to_file,
66
66
  sample_size=sample_size,
@@ -68,8 +68,8 @@ class MarketSample(MarketSpec):
68
68
  nthreads=nthreads,
69
69
  )
70
70
  else:
71
- self.invres_counts = invres_cnts(
72
- self.data, _invres_parm_vec, _upp_test_regime
71
+ self.enf_counts = enf_cnts(
72
+ self.data, _enf_parm_vec, _upp_test_regime
73
73
  )
74
74
  if save_data_to_file:
75
- save_data_to_hdf5(self.invres_counts, save_data_to_file=save_data_to_file)
75
+ save_data_to_hdf5(self.enf_counts, save_data_to_file=save_data_to_file)
mergeron/gen/upp_tests.py CHANGED
@@ -40,7 +40,7 @@ SaveData: TypeAlias = Literal[False] | tuple[Literal[True], ptb.File, ptb.Group]
40
40
 
41
41
 
42
42
  class INVRESCntsArgs(TypedDict, total=False):
43
- "Keyword arguments of function, :code:`sim_invres_cnts`"
43
+ "Keyword arguments of function, :code:`sim_enf_cnts`"
44
44
 
45
45
  sample_size: int
46
46
  seed_seq_list: list[SeedSequence] | None
@@ -49,9 +49,9 @@ class INVRESCntsArgs(TypedDict, total=False):
49
49
  saved_array_name_suffix: str
50
50
 
51
51
 
52
- def sim_invres_cnts_ll(
52
+ def sim_enf_cnts_ll(
53
53
  _mkt_sample_spec: MarketSpec,
54
- _invres_parm_vec: gbl.HMGThresholds,
54
+ _enf_parm_vec: gbl.HMGThresholds,
55
55
  _sim_test_regime: UPPTestRegime,
56
56
  /,
57
57
  *,
@@ -63,8 +63,8 @@ def sim_invres_cnts_ll(
63
63
  ) -> UPPTestsCounts:
64
64
  """A function to parallelize data-generation and testing
65
65
 
66
- The parameters `_sim_invres_cnts_kwargs` are passed unaltered to
67
- the parent function, `sim_invres_cnts()`, except that, if provided,
66
+ The parameters `_sim_enf_cnts_kwargs` are passed unaltered to
67
+ the parent function, `sim_enf_cnts()`, except that, if provided,
68
68
  `seed_seq_list` is used to spawn a seed sequence for each thread,
69
69
  to assure independent samples in each thread, and `nthreads` defines
70
70
  the number of parallel processes used. The number of draws in
@@ -74,7 +74,7 @@ def sim_invres_cnts_ll(
74
74
  Parameters
75
75
  ----------
76
76
 
77
- _invres_parm_vec
77
+ _enf_parm_vec
78
78
  Guidelines thresholds to test against
79
79
 
80
80
  _mkt_sample_spec
@@ -110,12 +110,12 @@ def sim_invres_cnts_ll(
110
110
 
111
111
  if (
112
112
  _mkt_sample_spec.share_spec.recapture_form != RECConstants.OUTIN
113
- and _mkt_sample_spec.share_spec.recapture_rate != _invres_parm_vec.rec
113
+ and _mkt_sample_spec.share_spec.recapture_rate != _enf_parm_vec.rec
114
114
  ):
115
115
  raise ValueError(
116
116
  "{} {} {}".format(
117
117
  f"Recapture rate from market sample spec, {_mkt_sample_spec.share_spec.recapture_rate}",
118
- f"must match the value, {_invres_parm_vec.rec}",
118
+ f"must match the value, {_enf_parm_vec.rec}",
119
119
  "the guidelines thresholds vector.",
120
120
  )
121
121
  )
@@ -126,18 +126,18 @@ def sim_invres_cnts_ll(
126
126
  zip(*[g.spawn(_iter_count) for g in seed_seq_list], strict=True) # type: ignore
127
127
  )
128
128
 
129
- _sim_invres_cnts_kwargs: INVRESCntsArgs = INVRESCntsArgs({
129
+ _sim_enf_cnts_kwargs: INVRESCntsArgs = INVRESCntsArgs({
130
130
  "sample_size": _subsample_sz,
131
131
  "save_data_to_file": save_data_to_file,
132
132
  "nthreads": nthreads,
133
133
  })
134
134
 
135
135
  _res_list = Parallel(n_jobs=_thread_count, prefer="threads")(
136
- delayed(sim_invres_cnts)(
136
+ delayed(sim_enf_cnts)(
137
137
  _mkt_sample_spec,
138
- _invres_parm_vec,
138
+ _enf_parm_vec,
139
139
  _sim_test_regime,
140
- **_sim_invres_cnts_kwargs,
140
+ **_sim_enf_cnts_kwargs,
141
141
  saved_array_name_suffix=f"{saved_array_name_suffix}_{_iter_id:0{2 + int(np.ceil(np.log10(_iter_count)))}d}",
142
142
  seed_seq_list=_rng_seed_seq_list_ch,
143
143
  )
@@ -162,7 +162,7 @@ def sim_invres_cnts_ll(
162
162
  return upp_test_results
163
163
 
164
164
 
165
- def sim_invres_cnts(
165
+ def sim_enf_cnts(
166
166
  _mkt_sample_spec: MarketSpec,
167
167
  _upp_test_parms: gbl.HMGThresholds,
168
168
  _sim_test_regime: UPPTestRegime,
@@ -195,7 +195,7 @@ def sim_invres_cnts(
195
195
  save_data_to_file=save_data_to_file,
196
196
  )
197
197
 
198
- _upp_test_arrays = invres_cnts(
198
+ _upp_test_arrays = enf_cnts(
199
199
  _market_data_sample, _upp_test_parms, _sim_test_regime
200
200
  )
201
201
 
@@ -208,7 +208,7 @@ def sim_invres_cnts(
208
208
  return _upp_test_arrays
209
209
 
210
210
 
211
- def invres_cnts(
211
+ def enf_cnts(
212
212
  _market_data_sample: MarketDataSample,
213
213
  _upp_test_parms: gbl.HMGThresholds,
214
214
  _upp_test_regime: UPPTestRegime,
@@ -228,12 +228,12 @@ def invres_cnts(
228
228
  if _firm_counts_weights is not None and np.all(_firm_counts_weights >= 0):
229
229
  _max_firm_count = len(_firm_counts_weights)
230
230
 
231
- _invres_cnts_sim_byfirmcount_array = -1 * np.ones(_stats_rowlen, np.int64)
231
+ _enf_cnts_sim_byfirmcount_array = -1 * np.ones(_stats_rowlen, np.int64)
232
232
  for _firm_cnt in 2 + np.arange(_max_firm_count):
233
233
  _firm_count_test = _fcounts == _firm_cnt
234
234
 
235
- _invres_cnts_sim_byfirmcount_array = np.vstack((
236
- _invres_cnts_sim_byfirmcount_array,
235
+ _enf_cnts_sim_byfirmcount_array = np.vstack((
236
+ _enf_cnts_sim_byfirmcount_array,
237
237
  np.array([
238
238
  _firm_cnt,
239
239
  np.einsum("ij->", 1 * _firm_count_test),
@@ -246,21 +246,21 @@ def invres_cnts(
246
246
  ],
247
247
  ]),
248
248
  ))
249
- _invres_cnts_sim_byfirmcount_array = _invres_cnts_sim_byfirmcount_array[1:]
249
+ _enf_cnts_sim_byfirmcount_array = _enf_cnts_sim_byfirmcount_array[1:]
250
250
  else:
251
- _invres_cnts_sim_byfirmcount_array = np.array(
251
+ _enf_cnts_sim_byfirmcount_array = np.array(
252
252
  np.nan * np.empty((1, _stats_rowlen)), np.int64
253
253
  )
254
- _invres_cnts_sim_byfirmcount_array[0] = 2
254
+ _enf_cnts_sim_byfirmcount_array[0] = 2
255
255
 
256
256
  # Clearance/enfrocement counts --- by delta
257
257
  _hhi_delta_ranged = esl.hhi_delta_ranger(_hhi_delta)
258
- _invres_cnts_sim_bydelta_array = -1 * np.ones(_stats_rowlen, np.int64)
258
+ _enf_cnts_sim_bydelta_array = -1 * np.ones(_stats_rowlen, np.int64)
259
259
  for _hhi_delta_lim in esl.HHI_DELTA_KNOTS[:-1]:
260
260
  _hhi_delta_test = _hhi_delta_ranged == _hhi_delta_lim
261
261
 
262
- _invres_cnts_sim_bydelta_array = np.vstack((
263
- _invres_cnts_sim_bydelta_array,
262
+ _enf_cnts_sim_bydelta_array = np.vstack((
263
+ _enf_cnts_sim_bydelta_array,
264
264
  np.array([
265
265
  _hhi_delta_lim,
266
266
  np.einsum("ij->", 1 * _hhi_delta_test),
@@ -273,7 +273,7 @@ def invres_cnts(
273
273
  ]),
274
274
  ))
275
275
 
276
- _invres_cnts_sim_bydelta_array = _invres_cnts_sim_bydelta_array[1:]
276
+ _enf_cnts_sim_bydelta_array = _enf_cnts_sim_bydelta_array[1:]
277
277
 
278
278
  # Clearance/enfrocement counts --- by zone
279
279
  try:
@@ -310,16 +310,16 @@ def invres_cnts(
310
310
  ]),
311
311
  ))
312
312
 
313
- _invres_cnts_sim_byconczone_array = esl.invres_cnts_byconczone(
313
+ _enf_cnts_sim_byconczone_array = esl.enf_cnts_byconczone(
314
314
  _stats_byconczone_sim[1:]
315
315
  )
316
316
  del _stats_byconczone_sim
317
317
  del _hhi_delta, _hhi_post, _fcounts
318
318
 
319
319
  return UPPTestsCounts(
320
- _invres_cnts_sim_byfirmcount_array,
321
- _invres_cnts_sim_bydelta_array,
322
- _invres_cnts_sim_byconczone_array,
320
+ _enf_cnts_sim_byfirmcount_array,
321
+ _enf_cnts_sim_bydelta_array,
322
+ _enf_cnts_sim_byconczone_array,
323
323
  )
324
324
 
325
325
 
@@ -348,7 +348,7 @@ def gen_upp_test_arrays(
348
348
  getattr(_upp_test_parms, _f) for _f in ("guppi", "divr", "cmcr", "ipr")
349
349
  )
350
350
 
351
- _invres_resolution, _guppi_aggregator, _divr_aggregator = (
351
+ _enf_resolution, _guppi_aggregator, _divr_aggregator = (
352
352
  getattr(_sim_test_regime, _f)
353
353
  for _f in ("resolution", "guppi_aggregator", "divr_aggregator")
354
354
  )
@@ -443,7 +443,7 @@ def gen_upp_test_arrays(
443
443
  if _divr_aggregator == UPPAggrSelector.MAX:
444
444
  _divr_test_vector = _market_data.divr_array.max(axis=1, keepdims=True)
445
445
 
446
- if _invres_resolution == INVResolution.ENFT:
446
+ if _enf_resolution == INVResolution.ENFT:
447
447
  _upp_test_arrays = UPPTestsRaw(
448
448
  _guppi_test_vector >= _g_bar,
449
449
  (_guppi_test_vector >= _g_bar) | (_divr_test_vector >= _divr_bar),
@@ -469,7 +469,7 @@ def initialize_hd5(
469
469
  _h5_path.unlink()
470
470
  _h5_file = ptb.open_file(_h5_path, mode="w", title=_h5_title)
471
471
  _save_data_to_file: tuple[Literal[True], ptb.File, str] = (True, _h5_file, "/")
472
- _next_subgroup_name_root = "invres_{}_{}_{}_{}".format(
472
+ _next_subgroup_name_root = "enf_{}_{}_{}_{}".format(
473
473
  _hmg_pub_year,
474
474
  *(getattr(_test_regime, _f.name).name for _f in _test_regime.__attrs_attrs__),
475
475
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.739087.0
3
+ Version: 2024.739088.1
4
4
  Summary: Merger Policy Analysis using Python
5
5
  License: MIT
6
6
  Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
@@ -1,5 +1,5 @@
1
1
  mergeron/License.txt,sha256=7iX-y0EyjkbVJKJLS4ZKzuuE1wd0lryfsD_IytLG8lQ,1246
2
- mergeron/__init__.py,sha256=RlvjvurSVnqu0nq067RItm-S66syA3LWsCIUfb0V5oo,1647
2
+ mergeron/__init__.py,sha256=N1M4Em-y2kRZ9GyNnkPOS0BcJR_BNIL-AbpT4WbfQuQ,1647
3
3
  mergeron/core/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
4
4
  mergeron/core/damodaran_margin_data.py,sha256=pjI1rSK_O1-3Oel5b9KXH6ctnInjX1Vii7fypt00gV8,8541
5
5
  mergeron/core/ftc_merger_investigations_data.py,sha256=ZaV2DO7UZabV8eX0Ubq_ToIor7tIRzcvYC54ADliuTk,27931
@@ -8,7 +8,6 @@ mergeron/core/guidelines_boundary_functions.py,sha256=rXjncqTn7NPgI2KY9Wuv3WNrsj
8
8
  mergeron/core/guidelines_boundary_functions_extra.py,sha256=TYq3M5onfAIAY-35Q_SaSVF0Upa9hCSKIQkY-KCGzwM,11393
9
9
  mergeron/core/proportions_tests.py,sha256=akq0Xhdgtst4RAT42_E5cBD_kATq_V4bQeBznmzRSLg,15267
10
10
  mergeron/core/pseudorandom_numbers.py,sha256=k3sDs_NJ2jXlkIWKQ6iiTB5n_QS0RoJ-sqzvFYkC7pY,9277
11
- mergeron/core/xlsxw_helper.py,sha256=TilTQdrqvAcYB2TDKjcAkIzMwQeEQWBMRUP0DVxntoM,12653
12
11
  mergeron/data/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
13
12
  mergeron/data/damodaran_margin_data.xls,sha256=Qggl1p5nkOMJI8YUXhkwXQRz-OhRSqBTzz57N0JQyYA,79360
14
13
  mergeron/data/damodaran_margin_data_dict.msgpack,sha256=sr6s4L69kposEpzGI7jpPb4ULz0UpY-bEYfeNi6UlRA,57621
@@ -16,21 +15,22 @@ mergeron/data/ftc_invdata.msgpack,sha256=WBFHgi7Ld4R-h2zL2Zc3TOIlKqVrbVFMH1LoI4-
16
15
  mergeron/data/jinja2_LaTeX_templates/clrrate_cis_summary_table_template.tex.jinja2,sha256=ae4JiciU-pt8YAM8mRbsmt4W6ePuN1y1NPCWD95oXIo,4833
17
16
  mergeron/data/jinja2_LaTeX_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2,sha256=ODEurkC0UHuWpjRUiQpeW85njSeUEUJYRdYg8gqoEq0,3642
18
17
  mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summary_table_template.tex.jinja2,sha256=h8_DEE0iskT9tnga5lZtxcoevN7pY4iKF-maErt4UU4,2906
19
- mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2,sha256=Ox0ctiyW_hoOPzoWskOpuygomuV6XWhLeLo40KGRy2U,5224
18
+ mergeron/data/jinja2_LaTeX_templates/ftcinvdata_summarypaired_table_template.tex.jinja2,sha256=aiVJGdKPHpQjHQxuymeH42LrpDl_spvDvho2XdQt6m4,5179
20
19
  mergeron/data/jinja2_LaTeX_templates/mergeron.cls,sha256=AV2mk4-uERvAuMkE95Ka7el6LZsb0JZKP4ieiNCnfMU,4562
21
20
  mergeron/data/jinja2_LaTeX_templates/mergeron_table_collection_template.tex.jinja2,sha256=nr6xUI0_2KHG4Sz9k1JFVQjs2h9qS9BGt1MeE6Tygs8,2429
22
21
  mergeron/data/jinja2_LaTeX_templates/setup_tikz_tables.tex,sha256=1hw3RINDtBrh9ZEToMIiNFIu9rozcPwRly69-5O_0UQ,3207
23
22
  mergeron/demo/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
24
23
  mergeron/demo/visualize_empirical_margin_distribution.py,sha256=v1xFJumBX2Ooye82kSSgly-_GpFVkYSDqBwM__rcmZY,2363
25
24
  mergeron/ext/__init__.py,sha256=KtjBlZOl7jwBCAUhrTJB9PdrN39YLYytNiSUSM_gRmA,62
26
- mergeron/ext/tol_colors.py,sha256=eJUtikxlgR3WjBwpkLh-tvB9QBanSvDXt8kp8pmONXU,22277
25
+ mergeron/ext/tol_colors.py,sha256=QBw8s-ZGpUpIIYOplHbLFZSXVoa6eDDJDtzSScP954E,22303
26
+ mergeron/ext/xlsxw_helper.py,sha256=5ib2IHDf8_evJCxf5HakRyDRSRUQp2FJThKNGMM5CVs,15251
27
27
  mergeron/gen/__init__.py,sha256=mlZn8gud6bxP_XKSQY2c-u-C85A8U7VxUKLiXu2hMw0,16280
28
28
  mergeron/gen/_data_generation_functions.py,sha256=7fP4mSVaN36FBhPKSf1y_TbxfRUe-I7fgqdBt74oaCA,21029
29
29
  mergeron/gen/data_generation.py,sha256=gDvCZYJwGpQnokcygM7IRzHBpE5rYI2J5I8uu0_wQyE,8727
30
- mergeron/gen/enforcement_stats.py,sha256=1Mrx2p2-tXN9RdUQgRyk25xPvwh42EtjUHQgHMdCbmQ,22952
31
- mergeron/gen/market_sample.py,sha256=4AxzF8WYPsfZaWGMtm0LMkLrEPSgRUNXd_z_ddP9-vE,2303
32
- mergeron/gen/upp_tests.py,sha256=U2smV53VBnORIQpn3KCSdneSyegrq4dq-zT_6Eg-PIE,17302
30
+ mergeron/gen/enforcement_stats.py,sha256=kpkpMbhqEGQcY2-oUYDj4N2MJ6tvBPSxVpPJne46WxI,24431
31
+ mergeron/gen/market_sample.py,sha256=ekMA9db2AWvrA-GDbIieu270fovFX0JyynCo5FRAGzk,2270
32
+ mergeron/gen/upp_tests.py,sha256=GQZcXU4vQPJRxdI2DVsY7yX6TPqhntlTH-DOAufWFmM,17197
33
33
  mergeron/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
34
- mergeron-2024.739087.0.dist-info/METADATA,sha256=9krPd_NRWr9mzX62A1wnrCg52SXj6gA11AFlkxlNOLg,8690
35
- mergeron-2024.739087.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
- mergeron-2024.739087.0.dist-info/RECORD,,
34
+ mergeron-2024.739088.1.dist-info/METADATA,sha256=7Z26ghdL28r1u1ve8-rVkYzLzIWxfHVAfssKPOCJi8U,8690
35
+ mergeron-2024.739088.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
36
+ mergeron-2024.739088.1.dist-info/RECORD,,