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

Files changed (30) hide show
  1. mergeron/core/__init__.py +1 -1
  2. mergeron/core/guidelines_standards.py +247 -57
  3. mergeron/core/proportions_tests.py +19 -19
  4. mergeron/core/pseudorandom_numbers.py +30 -29
  5. mergeron/examples/__init__.py +1 -1
  6. mergeron/examples/concentration_as_diversion.py +75 -88
  7. mergeron/examples/investigations_stats_obs_tables.py +119 -111
  8. mergeron/examples/investigations_stats_sim_tables.py +108 -87
  9. mergeron/examples/plotSafeHarbs_symbolically.py +2 -2
  10. mergeron/examples/safeharbor_boundaries_for_mergers_with_asymmetric_shares.py +35 -28
  11. mergeron/examples/safeharbor_boundaries_for_symmetric_firm_mergers.py +6 -13
  12. mergeron/examples/sound_guppi_safeharbor.py +23 -18
  13. mergeron/examples/testIntrinsicClearanceRates.py +5 -5
  14. mergeron/examples/visualize_empirical_margin_distribution.py +1 -1
  15. mergeron/examples/{visualize_guidelines_tests_scatterplots.py → visualize_guidelines_tests.py} +42 -48
  16. mergeron/ext/__init__.py +1 -1
  17. mergeron/gen/__init__.py +1 -1
  18. mergeron/gen/data_generation.py +25 -24
  19. mergeron/gen/guidelines_tests.py +47 -47
  20. mergeron/gen/investigations_stats.py +98 -46
  21. mergeron/jinja_LaTex_templates/clrrate_cis_summary_table_template.tex.jinja2 +2 -3
  22. mergeron/jinja_LaTex_templates/ftcinvdata_byhhianddelta_table_template.tex.jinja2 +2 -3
  23. mergeron/jinja_LaTex_templates/ftcinvdata_summary_table_template.tex.jinja2 +1 -2
  24. mergeron/jinja_LaTex_templates/ftcinvdata_summarypaired_table_template.tex.jinja2 +13 -14
  25. mergeron/jinja_LaTex_templates/mergeron.cls +161 -0
  26. mergeron/jinja_LaTex_templates/mergeron_table_collection_template.tex.jinja2 +90 -0
  27. {mergeron-2024.738930.0.dist-info → mergeron-2024.738936.2.dist-info}/METADATA +15 -18
  28. mergeron-2024.738936.2.dist-info/RECORD +41 -0
  29. mergeron-2024.738930.0.dist-info/RECORD +0 -39
  30. {mergeron-2024.738930.0.dist-info → mergeron-2024.738936.2.dist-info}/WHEEL +0 -0
@@ -21,7 +21,8 @@ import numpy as np
21
21
  from numpy.random import PCG64DXSM, Generator, SeedSequence
22
22
  from numpy.typing import NBitBase, NDArray
23
23
 
24
- T = TypeVar("T", bound=NBitBase)
24
+ TF = TypeVar("TF", bound=NBitBase)
25
+ TI = TypeVar("TI", bound=NBitBase)
25
26
 
26
27
  NTHREADS = 2 * cpu_count()
27
28
  DIST_PARMS_DEFAULT = np.array([0.0, 1.0], np.float64)
@@ -77,8 +78,7 @@ def gen_seed_seq_list_default(
77
78
 
78
79
  References
79
80
  ----------
80
- *See*,
81
- https://numpy.org/doc/stable/reference/random/parallel.html
81
+ *See*, https://numpy.org/doc/stable/reference/random/parallel.html
82
82
 
83
83
 
84
84
  """
@@ -113,6 +113,30 @@ def gen_seed_seq_list_default(
113
113
 
114
114
 
115
115
  class MultithreadedRNG:
116
+ """Fill given array on demand with pseudo-random numbers as specified.
117
+
118
+ Random number generation is multithreaded, using twice
119
+ the number of threads as available CPU cores by default.
120
+ If a seed sequence is provided, it is used in a thread-safe way
121
+ to generate repeatable i.i.d. draws. All arguments are validated
122
+ before commencing multithreaded random number generation.
123
+
124
+ Parameters
125
+ ----------
126
+ _out_array
127
+ The output array to which generated data are written.
128
+ Its dimensions define the size of the sample.
129
+ dist_type
130
+ Distribution for the generated random numbers
131
+ dist_parms
132
+ Parameters, if any, for tailoring random number generation
133
+ seed_sequence
134
+ SeedSequence object for generating repeatable draws.
135
+ nthreads
136
+ Number of threads to spawn for random number generation.
137
+
138
+ """
139
+
116
140
  def __init__(
117
141
  self,
118
142
  _out_array: NDArray[np.float64],
@@ -121,33 +145,10 @@ class MultithreadedRNG:
121
145
  dist_type: Literal[
122
146
  "Beta", "Dirichlet", "Gaussian", "Normal", "Random", "Uniform"
123
147
  ] = "Uniform",
124
- dist_parms: NDArray[np.floating[T]] = DIST_PARMS_DEFAULT,
148
+ dist_parms: NDArray[np.floating[TF]] | None = DIST_PARMS_DEFAULT,
125
149
  seed_sequence: SeedSequence | None = None,
126
150
  nthreads: int = NTHREADS,
127
151
  ):
128
- """Fill given array on demand with pseudo-random numbers as specified.
129
-
130
- Random number generation is multithreaded, using twice
131
- the number of threads as available CPU cores by default.
132
- If a seed sequence is provided, it is used in a thread-safe way
133
- to generate repeatable i.i.d. draws. All arguments are validated
134
- before commencing multithreaded random number generation.
135
-
136
- Parameters
137
- ----------
138
- _out_array
139
- The output array to which generated data are written.
140
- Its dimensions define the size of the sample.
141
- dist_type
142
- Distribution for the generated random numbers
143
- dist_parms
144
- Parameters, if any, for tailoring random number generation
145
- seed_sequence
146
- SeedSequence object for generating repeatable draws.
147
- nthreads
148
- Number of threads to spawn for random number generation.
149
-
150
- """
151
152
  self.thread_count = nthreads
152
153
 
153
154
  _seed_sequence = seed_sequence or SeedSequence(pool_size=8)
@@ -171,7 +172,7 @@ class MultithreadedRNG:
171
172
 
172
173
  self.dist_type = dist_type
173
174
 
174
- if np.array_equal(dist_parms, DIST_PARMS_DEFAULT):
175
+ if dist_parms is None or np.array_equal(dist_parms, DIST_PARMS_DEFAULT):
175
176
  match dist_type:
176
177
  case "Uniform":
177
178
  self.dist_type = "Random"
@@ -210,7 +211,7 @@ class MultithreadedRNG:
210
211
  def _fill(
211
212
  _rng: np.random.Generator,
212
213
  _dist_type: str,
213
- _dist_parms: NDArray[np.floating[T]],
214
+ _dist_parms: NDArray[np.floating[TF]],
214
215
  _out: NDArray[np.float64],
215
216
  _first: int,
216
217
  _last: int,
@@ -1,5 +1,5 @@
1
1
  from importlib.metadata import version
2
2
 
3
- from .. import _PKG_NAME
3
+ from .. import _PKG_NAME # noqa: TID252
4
4
 
5
5
  __version__ = version(_PKG_NAME)
@@ -20,7 +20,6 @@ systems.
20
20
 
21
21
  from __future__ import annotations
22
22
 
23
- from collections import OrderedDict
24
23
  from collections.abc import Mapping, Sequence
25
24
  from datetime import datetime
26
25
  from math import sqrt
@@ -35,101 +34,99 @@ from xlsxwriter import Workbook
35
34
  import mergeron.core.excel_helper as xlh
36
35
  import mergeron.core.guidelines_standards as gsf
37
36
  import mergeron.ext.tol_colors as ptcolor
37
+ from mergeron import DATA_DIR
38
38
 
39
- mod_path = Path(__file__)
40
- data_path = Path.home() / mod_path.parents[1].stem
39
+ PROG_PATH = Path(__file__)
41
40
 
42
- recapture_spec = "inside-out"
41
+ RECAPTURE_SPEC = "inside-out"
43
42
  # Map boundary forms to titles and generating-function names, with
44
43
  # additional parameters as relevant
45
- bdry_specs_dict: Mapping[str, Mapping[str, Any]] = OrderedDict({
44
+ BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
46
45
  "ΔHHI": {
47
- "title_str": "ΔHHI boundary boundary",
46
+ "title_str": "ΔHHI boundary",
47
+ "sheet_name": "ΔHHI",
48
48
  "func_str": R"\Delta HHI",
49
49
  "func": gsf.delta_hhi_boundary,
50
50
  },
51
51
  "OSWAG Own-shr-wtd Div Ratio Index": {
52
52
  "title_str": "Aggregated-diversion-ratio boundary, own-share wtd. avg.",
53
+ "sheet_name": "OSWAG, wtd avg",
53
54
  "func_str": R"(s_1 d_{12} + s_2 d_{21}) / s_M",
54
55
  "func": gsf.shrratio_mgnsym_boundary_wtd_avg,
55
- "func_kwargs": {"wgtng_policy": "own-share", "recapture_spec": recapture_spec},
56
+ "func_kwargs": {"wgtng_policy": "own-share", "recapture_spec": RECAPTURE_SPEC},
56
57
  },
57
58
  "OSWAG Own-shr-wtd Div Ratio Distance": {
58
59
  "title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. distance",
60
+ "sheet_name": "OSWAG, distance",
59
61
  "func_str": R"\surd (s_1 d_{12}^2 / s_M + s_2 d_{21}^2 / s_M)",
60
62
  "func": gsf.shrratio_mgnsym_boundary_wtd_avg,
61
63
  "func_kwargs": {
62
64
  "wgtng_policy": "own-share",
63
- "recapture_spec": recapture_spec,
64
- "avg_method": "root-mean-square",
65
- },
66
- },
67
- "OSWAG Own-shr-wtd Div Ratio Real Distance": {
68
- "title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. (really) distance ",
69
- "func_str": R"\surd (d_{12}^{s_1 / s_M} + d_{21}^{s_2 / s_M})",
70
- "func": gsf.shrratio_mgnsym_boundary_wtd_avg,
71
- "func_kwargs": {
72
- "wgtng_policy": "own-share",
73
- "recapture_spec": recapture_spec,
65
+ "recapture_spec": RECAPTURE_SPEC,
74
66
  "avg_method": "distance",
75
67
  },
76
68
  },
77
69
  "OSWAG Min Div Ratio": {
78
70
  "title_str": "Aggregated-diversion-ratio boundary, minimum",
71
+ "sheet_name": "OSWAG, minimum",
79
72
  "func_str": R"\min (d_{12}, d_{21})",
80
73
  "func": gsf.shrratio_mgnsym_boundary_min,
81
- "func_kwargs": {"recapture_spec": recapture_spec},
74
+ "func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
82
75
  },
83
76
  "SAG Combined Share": {
84
77
  "title_str": "Combined Share boundary",
78
+ "sheet_name": "SAG, combined-share",
85
79
  "func_str": R"s_M",
86
80
  "func": gsf.combined_share_boundary,
87
81
  },
88
82
  "SAG Div Ratio Distance": {
89
83
  "title_str": "Aggregated-diversion-ratio boundary, distance",
84
+ "sheet_name": "SAG, distance",
90
85
  "func_str": R"\surd (d_{12}^2 / 2 + d_{21}^2 / 2)",
91
86
  "func": gsf.shrratio_mgnsym_boundary_avg,
92
- "func_kwargs": {
93
- "recapture_spec": recapture_spec,
94
- "avg_method": "root-mean-square",
95
- },
87
+ "func_kwargs": {"recapture_spec": RECAPTURE_SPEC, "avg_method": "distance"},
96
88
  },
97
89
  "SAG Average Div Ratio": {
98
90
  "title_str": "Aggregated-diversion-ratio boundary, simple average",
91
+ "sheet_name": "SAG, average",
99
92
  "func_str": R"(d_{12} + d_{21}) / 2",
100
93
  "func": gsf.shrratio_mgnsym_boundary_xact_avg,
101
- "func_kwargs": {"recapture_spec": recapture_spec},
94
+ "func_kwargs": {"recapture_spec": RECAPTURE_SPEC},
102
95
  },
103
96
  "CPSWAG Premerger HHI-contribution": {
104
97
  "title_str": "Premerger HHI-contribution boundary",
98
+ "sheet_name": "CPSWAG, HHI-contrib-pre",
105
99
  "func_str": R"HHI_M^{pre}",
106
100
  "func": gsf.hhi_pre_contrib_boundary,
107
101
  },
108
102
  "CPSWAG Cross-product-shr-wtd Div Ratio Index": {
109
103
  "title_str": "Aggregated-diversion-ratio boundary, cross-product-share wtd. avg.",
104
+ "sheet_name": "CPSWAG, wtd avg",
110
105
  "func_str": R"(s_2 d_{12} / s_M + s_1 d_{21} / s_M)",
111
106
  "func": gsf.shrratio_mgnsym_boundary_wtd_avg,
112
107
  "func_kwargs": {
113
108
  "wgtng_policy": "cross-product-share",
114
- "recapture_spec": recapture_spec,
109
+ "recapture_spec": RECAPTURE_SPEC,
115
110
  },
116
111
  },
117
112
  "CPSWAG Cross-product-shr-wtd Div Ratio Distance": {
118
113
  "title_str": "Aggregated-diversion-ratio boundary, cross-prod-shr. wtd. distance",
114
+ "sheet_name": "CPSWAG, distance",
119
115
  "func_str": R"\surd (s_2 d_{12}^2 / s_M + s_1 d_{21}^2 / s_M)",
120
116
  "func": gsf.shrratio_mgnsym_boundary_wtd_avg,
121
117
  "func_kwargs": {
122
118
  "wgtng_policy": "cross-product-share",
123
- "recapture_spec": recapture_spec,
124
- "avg_method": "root-mean-square",
119
+ "recapture_spec": RECAPTURE_SPEC,
120
+ "avg_method": "distance",
125
121
  },
126
122
  },
127
123
  "CPSWAG Max Div Ratio": {
128
124
  "title_str": "Aggregated-diversion-ratio boundary, maximum",
125
+ "sheet_name": "CPSWAG, maximum",
129
126
  "func_str": R"\max (d_{12}, d_{21})",
130
127
  "func": gsf.shrratio_mgnsym_boundary_max,
131
128
  },
132
- })
129
+ }
133
130
 
134
131
 
135
132
  def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
@@ -142,7 +139,9 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
142
139
 
143
140
  """
144
141
  gso = gsf.GuidelinesStandards(_gpubyr)
145
- _dhhi_val, _, _r_val, _g_val, *_ = gso.presumption
142
+ _dhhi_val, _r_val, _g_val = (
143
+ getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
144
+ )
146
145
 
147
146
  _dhhi_seq = (
148
147
  (0.01, 0.02, 0.03125, 0.05, _dhhi_val)
@@ -153,7 +152,7 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
153
152
  _bdry_approx_data_dict = {
154
153
  "Criterion": {
155
154
  _k: R"\({} < {}\)".format(
156
- bdry_specs_dict[_k]["func_str"],
155
+ BDRY_SPECS_DICT[_k]["func_str"],
157
156
  R"\safeharb{d}"
158
157
  if "Div Ratio" in _k
159
158
  else (
@@ -162,7 +161,7 @@ def tabulate_boundary_stats(_gpubyr: Literal[1992, 2010, 2023], /) -> None:
162
161
  else R"\safeharb{H}"
163
162
  ),
164
163
  )
165
- for _k in bdry_specs_dict
164
+ for _k in BDRY_SPECS_DICT
166
165
  if not _k.endswith("Distance")
167
166
  }
168
167
  }
@@ -209,7 +208,7 @@ def _dhhi_stats(
209
208
 
210
209
  _bdry_stats = Parallel(n_jobs=cpu_count() // 2)(
211
210
  delayed(_bdry_stats_col)(_bdry_spec, _dhhi_val, _delta_val, _r_val)
212
- for _bdry_spec in bdry_specs_dict
211
+ for _bdry_spec in BDRY_SPECS_DICT
213
212
  )
214
213
 
215
214
  _bounds_string = R"{{ {} \\ {} }}".format(
@@ -234,9 +233,9 @@ def _bdry_stats_col(
234
233
  case "CPSWAG Premerger HHI-contribution":
235
234
  return _bdry_spec, f"{_hhi_m_pre_prob:6.5f}"
236
235
  case _ if "Div Ratio" in _bdry_spec:
237
- _gbd_func = bdry_specs_dict[_bdry_spec]["func"]
236
+ _gbd_func = BDRY_SPECS_DICT[_bdry_spec]["func"]
238
237
  _, _within_bdry_area = _gbd_func(
239
- _delta_val, _r_val, **bdry_specs_dict[_bdry_spec].get("func_kwargs", {})
238
+ _delta_val, _r_val, **BDRY_SPECS_DICT[_bdry_spec].get("func_kwargs", {})
240
239
  )
241
240
  _within_bdry_prob = 2 * _within_bdry_area
242
241
  _within_conc_bdry_prob = (
@@ -261,10 +260,11 @@ def plot_and_save_boundary_coords(
261
260
  ) -> None:
262
261
  gso = gsf.GuidelinesStandards(_gpubyr)
263
262
 
264
- _hmg_standards_strings = {
263
+ _hmg_standards_strings_dict = {
265
264
  "distributed": ("presumption", "inferred presumption", "safeharbor"),
266
265
  "collected": ("safeharbor", "inferred_presumption", "presumption"),
267
- }.get(layout, ())
266
+ }
267
+ _hmg_standards_strings = _hmg_standards_strings_dict.get(layout, ())
268
268
  if not _hmg_standards_strings:
269
269
  raise ValueError(
270
270
  f"Layout parameter value, {layout!r} is invalid. "
@@ -279,7 +279,7 @@ def plot_and_save_boundary_coords(
279
279
  for _divr_agg_method, _hmg_standards_str in zip(
280
280
  _divr_agg_methods, _hmg_standards_strings, strict=True
281
281
  ):
282
- _r_bar, _g_bar = gso.presumption[2:4]
282
+ _r_bar, _g_bar = (getattr(gso.presumption, _f) for _f in ("rec", "guppi"))
283
283
  _dhhi_val = getattr(gso, _hmg_standards_str)[0]
284
284
  _divr_val = (
285
285
  _g_bar
@@ -301,36 +301,22 @@ def plot_and_save_boundary_coords(
301
301
  str, Sequence[tuple[float]]
302
302
  ] = {} #: Container for boundary coordinates data, by boundary
303
303
 
304
- for _bdry_spec_key in bdry_specs_dict:
305
- _bdry_spec = (_bdry_spec_key, bdry_specs_dict[_bdry_spec_key])
304
+ for _bdry_spec_key in BDRY_SPECS_DICT:
305
+ _bdry_spec = (_bdry_spec_key, BDRY_SPECS_DICT[_bdry_spec_key])
306
306
 
307
307
  if _bdry_spec_key == "ΔHHI":
308
- if any((
309
- _hmg_standards_str == "inferred_presumption",
310
- _hmg_standards_str == "safeharbor" and layout == "collected",
311
- _hmg_standards_str == "presumption" and _divr_agg_method != "OSWAG",
312
- )):
308
+ if _hmg_standards_str != _hmg_standards_strings_dict[layout][0]:
313
309
  continue
314
310
 
315
311
  _dh_s1, _dh_s2 = gen_plot_boundary(
316
312
  _bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
317
313
  )
318
314
 
319
- if _hmg_standards_str == "safeharbor":
320
- _ax1.fill_between(
321
- (0, *tuple(_dh_s1), 1),
322
- (1, *tuple(_dh_s2), 0),
323
- edgecolor=None,
324
- facecolor="#64bb64", # "#64ff64"
325
- alpha=0.7,
326
- rasterized=True,
327
- )
328
-
329
315
  del _dh_s1, _dh_s2
330
316
 
331
317
  elif _bdry_spec_key.startswith(
332
318
  _divr_agg_method
333
- ) and not _bdry_spec_key.endswith("Distance"):
319
+ ): # and not _bdry_spec_key.endswith("Distance"):
334
320
  gen_plot_boundary(
335
321
  _bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
336
322
  )
@@ -346,8 +332,8 @@ def plot_and_save_boundary_coords(
346
332
  _fig_leg.set_in_layout(False)
347
333
 
348
334
  for _bndry_name in _bndry_data_dict:
349
- if _bndry_name == "ΔHHI": # _divr_agg_method != "OSWAG" and
350
- continue
335
+ # if _bndry_name == "ΔHHI": # and _divr_agg_method != "OSWAG" and
336
+ # continue
351
337
 
352
338
  boundary_data_to_worksheet(
353
339
  _bndry_name,
@@ -358,7 +344,7 @@ def plot_and_save_boundary_coords(
358
344
  _xl_book,
359
345
  )
360
346
 
361
- _fig_savepath = data_path / rf"{mod_path.stem}_{_gpubyr}.pdf"
347
+ _fig_savepath = DATA_DIR / rf"{PROG_PATH.stem}_{_gpubyr}.pdf"
362
348
  _my_fig1.savefig(_fig_savepath)
363
349
  print()
364
350
  del _divr_agg_method
@@ -406,10 +392,14 @@ def gen_plot_boundary(
406
392
  _pt_mdco: ptcolor.Mcset = ptcolor.tol_cset("medium-contrast") # type: ignore
407
393
 
408
394
  _plot_line_width = 1.0
395
+ _plot_line_alpha = 0.8
409
396
  _plot_line_color = _pt_mdco.black
410
397
  _plot_line_style = {"OSWAG": "-", "SAG": "-.", "CPSWAG": "--"}.get(
411
398
  _bdry_spec_str.split(" ")[0], "-"
412
399
  )
400
+ if _bdry_spec_str.startswith("ΔHHI"):
401
+ _plot_line_width = 0.5
402
+ _plot_line_alpha = 1.0
413
403
  _zrdr = 5
414
404
 
415
405
  if not _bdry_spec_str.startswith("ΔHHI"):
@@ -425,12 +415,12 @@ def gen_plot_boundary(
425
415
  case _:
426
416
  _plot_line_color = _pt_mdco.dark_red
427
417
 
428
- _dh_bar = _gso.safeharbor[0]
429
- _g_val = _gso.safeharbor[3]
418
+ _dh_bar = _gso.safeharbor.divr
419
+ _g_val = _gso.safeharbor.guppi
430
420
 
431
- _r_bar = _gso.presumption[2]
421
+ _r_bar = _gso.presumption.rec
432
422
 
433
- _dhhi_val = getattr(_gso, _gs_str)[0] # _gso.presumption[0]
423
+ _dhhi_val = getattr(_gso, _gs_str).delta
434
424
  _s_mid = sqrt(_dhhi_val / 2)
435
425
  _delta_val = _g_val / _r_bar if _gs_str == "safeharbor" else _s_mid / (1 - _s_mid)
436
426
 
@@ -456,7 +446,9 @@ def gen_plot_boundary(
456
446
  _plot_label_uom,
457
447
  )
458
448
 
459
- _bndry_data_dict |= {_bdry_spec_str: (_bdry_data, _bdry_area)} # type: ignore
449
+ _bndry_data_dict |= {
450
+ _bdry_spec_str: (_bdry_spec_dict["sheet_name"], _bdry_data, _bdry_area)
451
+ } # type: ignore
460
452
  _bdry_s1, _bdry_s2 = zip(*_bdry_data, strict=True)
461
453
 
462
454
  _ax1.plot(
@@ -466,30 +458,26 @@ def gen_plot_boundary(
466
458
  color=_plot_line_color,
467
459
  linestyle=_plot_line_style,
468
460
  linewidth=_plot_line_width,
461
+ alpha=_plot_line_alpha,
469
462
  zorder=_zrdr,
470
463
  )
471
464
 
472
465
  print("\t", _bdry_spec_str, f"{_bdry_s2[0]:.1%}")
473
- match _bdry_spec_str:
474
- case "ΔHHI":
475
- _plot_annotator(
476
- _ax1,
477
- f"({_bdry_s1[0]:.1%}, {_bdry_s2[0]:.1%})",
478
- (_bdry_s1[0], _bdry_s2[0]),
479
- (0.005, 0),
480
- "left",
481
- )
482
- case _ if _bdry_spec_str.startswith("SAG") or _bdry_spec_str in (
483
- "CPSWAG Premerger HHI-contribution",
484
- "CPSWAG Max Div Ratio",
485
- ):
486
- _plot_annotator(
487
- _ax1,
488
- f"{_bdry_s2[0]:.1%}",
489
- (_bdry_s1[0], _bdry_s2[0]),
490
- (-0.005, 0),
491
- "right",
492
- )
466
+ if _bdry_spec_str.startswith(("ΔHHI", "OSWAG Min")):
467
+ _plot_annotator(
468
+ _ax1,
469
+ f"({_bdry_s1[1]:.1%}, {_bdry_s2[1]:.1%})",
470
+ (_bdry_s1[1], _bdry_s2[1]),
471
+ (0.005, 0),
472
+ "left",
473
+ )
474
+ elif _bdry_spec_str.startswith("SAG") or _bdry_spec_str in (
475
+ "CPSWAG Premerger HHI-contribution",
476
+ "CPSWAG Max Div Ratio",
477
+ ):
478
+ _plot_annotator(
479
+ _ax1, f"{_bdry_s2[0]:.1%}", (_bdry_s1[0], _bdry_s2[0]), (-0.005, 0), "right"
480
+ )
493
481
 
494
482
  return _bdry_s1, _bdry_s2
495
483
 
@@ -546,9 +534,9 @@ def boundary_data_to_worksheet(
546
534
  Specified Excel Workbook
547
535
 
548
536
  """
549
- _xl_sheet = _xl_book.add_worksheet(
550
- f"{_bndry_name.replace('Boundary', '').strip()}"[:31]
551
- )
537
+ _sheet_name, _bndry_points, _bndry_area = _bndry_data_dict[_bndry_name]
538
+
539
+ _xl_sheet = _xl_book.add_worksheet(_sheet_name)
552
540
 
553
541
  _xl_sheet.write("A1", "Sound GUPPI Safeharbor")
554
542
  _xl_sheet.write("A2", "Merger Screens for Unilateral Effects")
@@ -574,7 +562,6 @@ def boundary_data_to_worksheet(
574
562
  )
575
563
  _xl_sheet.set_footer(f"&L{_left_footer}")
576
564
 
577
- _bndry_points, _bndry_area = _bndry_data_dict[_bndry_name]
578
565
  xlh.scalar_to_sheet(_xl_book, _xl_sheet, "B7", _bndry_area, xlh.CFmt.AREA_NUM)
579
566
 
580
567
  _results_header_row = 9
@@ -613,7 +600,7 @@ if __name__ == "__main__":
613
600
 
614
601
  # Initiliaze workbook for saving boundary coordinates
615
602
  with Workbook(
616
- data_path.joinpath(rf"{mod_path.stem}_{gpubyr}_BoundaryCoordinates.xlsx")
603
+ DATA_DIR / rf"{PROG_PATH.stem}_{gpubyr}_BoundaryCoordinates.xlsx"
617
604
  ) as xl_book:
618
605
  # tabulate_boundary_stats(gpubyr)
619
606
  plot_and_save_boundary_coords(gpubyr, xl_book, layout="collected") # type: ignore