mergeron 2024.738953.0__py3-none-any.whl → 2024.738953.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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mergeron
3
- Version: 2024.738953.0
3
+ Version: 2024.738953.1
4
4
  Summary: Analysis of standards defined in Horizontal Merger Guidelines
5
5
  License: MIT
6
6
  Keywords: merger policy analysis,merger guidelines,merger screening,policy presumptions,concentration standards,upward pricing pressure,GUPPI
@@ -10,20 +10,6 @@ mergeron/core/guidelines_boundaries.py,sha256=eOEzbfgNQn-XKFZ72pql1xfBaLApQIdbfm
10
10
  mergeron/core/guidelines_boundaries_specialized_functions.py,sha256=zrnqaPd7a_jIO1qtM9VXhiiADZRMpg6Y-e2m0od4_JM,10448
11
11
  mergeron/core/proportions_tests.py,sha256=tCrbya1el5u1OFOXphODP6yWOGywuNY6z9LBTsNRKzM,15320
12
12
  mergeron/core/pseudorandom_numbers.py,sha256=uBK_fnhkOSkqnK4gEU8b3r_9B6r-vKmXZ64HViraTK8,9446
13
- mergeron/examples/__init__.py,sha256=iyfxkX3-SoMS4ZQZKHKPn8JEMN536vpty9oSZf0LHv8,115
14
- mergeron/examples/concentration_as_diversion.py,sha256=_RPId16pVGs1GxW5cZl1U1F0gIN8c0NPDvO2O7DbFGU,21505
15
- mergeron/examples/enforcement_boundaries_for_mergers_with_asymmetric_shares.py,sha256=GhczLXtv1R7GtAJRngDTwda8fBKeX1Hdf6FZDlvqw60,16241
16
- mergeron/examples/enforcement_boundaries_for_symmetric_firm_mergers.py,sha256=DAljm5NJquE56f-x4pLXzKCdhYQyVpWaM8uGlD6rIEs,5779
17
- mergeron/examples/example_parameterizations.py,sha256=VP-hi7L0j30ffcEzmJ3P8mOj1VjwEWKCTZSx_CaVQxA,4197
18
- mergeron/examples/guidelines_enforcement_patterns.py,sha256=iHGUaWCidVwIywI60ZNB4AnvzpTe60az1H7AzB3ddl0,2255
19
- mergeron/examples/investigations_stats_obs_tables.py,sha256=RLJ7Y6tHgJ3ik2m2b7hsVwz-I8GzDBUtU0JQpRCjhtc,18017
20
- mergeron/examples/investigations_stats_sim_tables.py,sha256=72oNhfp-rkLVf-pgFejWgW4kvs3hb0gIy9zgd7kJtto,14907
21
- mergeron/examples/plotSafeHarbs_symbolically.py,sha256=YuuZd0zs1-icZKJnocbfRYqR2n5yHrbxjxtr2h5rYQo,1613
22
- mergeron/examples/sound_guppi_safeharbor.py,sha256=0IGeFAJzkvpJEt-MnVkUcNCppj1FiRfUWf2FyKjV9Qo,6085
23
- mergeron/examples/summarize_ftc_investigations_data.py,sha256=447vtwlAsfc3Po8wFcKRHC4Ur-zvKc5dwBjtu4M49ig,1360
24
- mergeron/examples/testIntrinsicClearanceRates.py,sha256=T0-6m-SEPVy-mY8gZY2HlJO4ncBa47r87bERhhANLFs,5378
25
- mergeron/examples/visualize_empirical_margin_distribution.py,sha256=eMTWgNJ1eSTZBgwojZXAYMfuzgMGM2UU999axNjBip4,2918
26
- mergeron/examples/visualize_guidelines_tests.py,sha256=2ZE7GRkGjVzvcwXkNAzGUKRGcf5Pb4ty-lQv0V1_LKU,9357
27
13
  mergeron/ext/__init__.py,sha256=iyfxkX3-SoMS4ZQZKHKPn8JEMN536vpty9oSZf0LHv8,115
28
14
  mergeron/ext/tol_colors.py,sha256=wFOHZXWZonbp9mhmSGu9mVujBYhdTsvx9_WikMpoCmo,22229
29
15
  mergeron/gen/__init__.py,sha256=nVvHJiUuTzTcT0mhX1BmneAiLkC1sg3I4X9xdu7OKJg,16248
@@ -39,6 +25,6 @@ mergeron/jinja_LaTex_templates/mergeron.cls,sha256=AV2mk4-uERvAuMkE95Ka7el6LZsb0
39
25
  mergeron/jinja_LaTex_templates/mergeron_table_collection_template.tex.jinja2,sha256=nr6xUI0_2KHG4Sz9k1JFVQjs2h9qS9BGt1MeE6Tygs8,2429
40
26
  mergeron/jinja_LaTex_templates/setup_tikz_tables.tex.jinja2,sha256=WKVxtp3eoMchfGliQAJMj4w2FtBkWG5z2V3-hBYUYUQ,3292
41
27
  mergeron/py.typed,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
42
- mergeron-2024.738953.0.dist-info/METADATA,sha256=ia6SKqwsWVDqQHyIzFyPRzwtO50QoJvFggv7RHRhnsw,6330
43
- mergeron-2024.738953.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
44
- mergeron-2024.738953.0.dist-info/RECORD,,
28
+ mergeron-2024.738953.1.dist-info/METADATA,sha256=_rIDqv_IzGJMoR3TXh-kun4PEgow1U6smCToxX8qnSY,6330
29
+ mergeron-2024.738953.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
30
+ mergeron-2024.738953.1.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- from importlib.metadata import version
2
-
3
- from .. import _PKG_NAME # noqa: TID252
4
-
5
- __version__ = version(_PKG_NAME)
@@ -1,625 +0,0 @@
1
- R"""
2
-
3
- Demonstrates the correspondence between concentration standards and
4
- diversion ratio standards, graphically
5
-
6
- Here, *correspondence* is defined as the close approximation of
7
- boundaries for sets of mergers meeting a guidelines concentration
8
- standard to boundaries for sets of mergers meeting a
9
- matching diversion ratio. Separate demonstrations based on
10
- 1992 Guidelines concentration standards and 2010 Guidelines concentration
11
- standards are generated as,
12
- 1.) Plots of the boundaries write to separate PDF files
13
- 2.) Tables of boundary coordinates written to separate Excel files
14
-
15
- Output is written in the `mergeron` sub-folder within a user's home directory,
16
- i.e., `%USERPROFILE%\mergeron` on Windows, or `~/mergeron/` on Unix-like
17
- systems.
18
-
19
- """
20
-
21
- from __future__ import annotations
22
-
23
- from collections.abc import Mapping, Sequence
24
- from datetime import datetime
25
- from math import sqrt
26
- from pathlib import Path
27
- from typing import Any, Literal
28
-
29
- import matplotlib.axes as mpa
30
- from jinja2 import FileSystemLoader
31
- from joblib import Parallel, cpu_count, delayed # type: ignore
32
- from numpy import pi
33
- from xlsxwriter import Workbook # type: ignore
34
-
35
- import mergeron.core.excel_helper as xlh
36
- import mergeron.core.guidelines_boundaries as gbl
37
- import mergeron.ext.tol_colors as ptcolor
38
- import mergeron.gen.investigations_stats as isl
39
- from mergeron import DATA_DIR, RECConstants, UPPAggrSelector
40
- from mergeron.core import UPPBoundarySpec
41
-
42
- PROG_PATH = Path(__file__)
43
-
44
- RECAPTURE_SPEC = RECConstants.INOUT
45
- # Map boundary forms to titles and generating-function names, with
46
- # additional parameters as relevant
47
- BDRY_SPECS_DICT: Mapping[str, Mapping[str, Any]] = {
48
- "ΔHHI": {
49
- "title_str": "ΔHHI boundary",
50
- "sheet_name": "ΔHHI",
51
- "func_str": R"\Delta HHI",
52
- "func": gbl.delta_hhi_boundary,
53
- },
54
- "OSWAG Own-shr-wtd Div Ratio Index": {
55
- "title_str": "Aggregated-diversion-ratio boundary, own-share wtd. avg.",
56
- "sheet_name": "OSWAG, wtd avg",
57
- "func_str": R"(s_1 d_{12} + s_2 d_{21}) / s_M",
58
- "agg_method": UPPAggrSelector.OSA,
59
- "recapture_spec": RECAPTURE_SPEC,
60
- },
61
- "OSWAG Own-shr-wtd Div Ratio Distance": {
62
- "title_str": "Aggregated-diversion-ratio boundary, own-shr. wtd. distance",
63
- "sheet_name": "OSWAG, distance",
64
- "func_str": R"\surd (s_1 d_{12}^2 / s_M + s_2 d_{21}^2 / s_M)",
65
- "agg_method": UPPAggrSelector.OSD,
66
- "recapture_spec": RECAPTURE_SPEC,
67
- },
68
- "OSWAG Min Div Ratio": {
69
- "title_str": "Aggregated-diversion-ratio boundary, minimum",
70
- "sheet_name": "OSWAG, minimum",
71
- "func_str": R"\min (d_{12}, d_{21})",
72
- "agg_method": UPPAggrSelector.MIN,
73
- "recapture_spec": RECAPTURE_SPEC,
74
- },
75
- "SAG Combined Share": {
76
- "title_str": "Combined Share boundary",
77
- "sheet_name": "SAG, combined-share",
78
- "func_str": R"s_M",
79
- "func": gbl.combined_share_boundary,
80
- },
81
- "SAG Average Div Ratio": {
82
- "title_str": "Aggregated-diversion-ratio boundary, simple average",
83
- "sheet_name": "SAG, average",
84
- "func_str": R"(d_{12} + d_{21}) / 2",
85
- "agg_method": UPPAggrSelector.AVG,
86
- "recapture_spec": RECAPTURE_SPEC,
87
- },
88
- "SAG Div Ratio Distance": {
89
- "title_str": "Aggregated-diversion-ratio boundary, distance",
90
- "sheet_name": "SAG, distance",
91
- "func_str": R"\surd (d_{12}^2 / 2 + d_{21}^2 / 2)",
92
- "agg_method": UPPAggrSelector.DIS,
93
- "recapture_spec": RECAPTURE_SPEC,
94
- },
95
- "CPSWAG Premerger HHI-contribution": {
96
- "title_str": "Premerger HHI-contribution boundary",
97
- "sheet_name": "CPSWAG, HHI-contrib-pre",
98
- "func_str": R"HHI_M^{pre}",
99
- "func": gbl.hhi_pre_contrib_boundary,
100
- },
101
- "CPSWAG Cross-product-shr-wtd Div Ratio Index": {
102
- "title_str": "Aggregated-diversion-ratio boundary, cross-product-share wtd. avg.",
103
- "sheet_name": "CPSWAG, wtd avg",
104
- "func_str": R"(s_2 d_{12} / s_M + s_1 d_{21} / s_M)",
105
- "agg_method": UPPAggrSelector.CPA,
106
- "recapture_spec": RECAPTURE_SPEC,
107
- },
108
- "CPSWAG Cross-product-shr-wtd Div Ratio Distance": {
109
- "title_str": "Aggregated-diversion-ratio boundary, cross-prod-shr. wtd. distance",
110
- "sheet_name": "CPSWAG, distance",
111
- "func_str": R"\surd (s_2 d_{12}^2 / s_M + s_1 d_{21}^2 / s_M)",
112
- "agg_method": UPPAggrSelector.CPD,
113
- "recapture_spec": RECAPTURE_SPEC,
114
- },
115
- "CPSWAG Max Div Ratio": {
116
- "title_str": "Aggregated-diversion-ratio boundary, maximum",
117
- "sheet_name": "CPSWAG, maximum",
118
- "func_str": R"\max (d_{12}, d_{21})",
119
- "agg_method": UPPAggrSelector.MAX,
120
- "recapture_spec": RECAPTURE_SPEC,
121
- },
122
- }
123
-
124
-
125
- def tabulate_boundary_stats(_gpubyr: gbl.HMGPubYear, /) -> None:
126
- """
127
- Parameters
128
- ----------
129
- _gpubyr
130
- Guidelines version (year of publication) from which concentration standards
131
- are drawn
132
-
133
- """
134
- _invres_rate_table_content = isl.StatsContainer()
135
-
136
- gso = gbl.GuidelinesThresholds(_gpubyr)
137
- _dhhi_val, _r_val, _g_val = (
138
- getattr(gso.presumption, _f) for _f in ("delta", "rec", "guppi")
139
- )
140
-
141
- _dhhi_seq = (
142
- (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
143
- if _gpubyr == 2010
144
- else (0.005, 0.01, 0.02, gso.imputed_presumption.delta, 0.08)
145
- )
146
-
147
- _bdry_approx_data_dict = {
148
- "Criterion": {
149
- _k: R"\({} < {}\)".format(
150
- BDRY_SPECS_DICT[_k]["func_str"],
151
- R"\safeharb{d}"
152
- if "Div Ratio" in _k
153
- else (
154
- R"\surd (2 \safeharb{H})"
155
- if _k.endswith("Combined Share")
156
- else R"\safeharb{H}"
157
- ),
158
- )
159
- for _k in BDRY_SPECS_DICT
160
- # if not _k.endswith("Distance")
161
- }
162
- }
163
- _bdry_approx_data_dict |= {
164
- R"{ \safeharb{H} \\ \safeharb{d} }": {
165
- _k: R"{}" for _k in _bdry_approx_data_dict["Criterion"]
166
- }
167
- }
168
-
169
- _bdry_data = Parallel(n_jobs=-1)(
170
- delayed(_dhhi_stats)(_dhhi_val, _r_val) for _dhhi_val in _dhhi_seq
171
- )
172
- _bdry_approx_data_dict |= dict(_bdry_data)
173
-
174
- _data_str = ""
175
- _data_str = "{} \\\\ \n".format(
176
- " & ".join(
177
- _k.replace("Criterion", R"{\text{} \\ Criterion}") # \phantom{Criterion}
178
- for _k in _bdry_approx_data_dict
179
- )
180
- )
181
- for _sk in _bdry_approx_data_dict["Criterion"]:
182
- _data_str += "{} \\\\ \n".format(
183
- " & ".join(_bdry_approx_data_dict[_k][_sk] for _k in _bdry_approx_data_dict)
184
- )
185
- print(_data_str)
186
-
187
- _invres_rate_table_content.data_str = _data_str
188
-
189
- _j2_env = isl.latex_jinja_env
190
- _j2_env.loader = FileSystemLoader(str(PROG_PATH.parent / "templates"))
191
- _j2_templ = _j2_env.get_template(
192
- "concentration_as_diversion_intrinsic_enforcement_rates.tex.jinja2"
193
- )
194
- PROG_PATH.parents[1].joinpath(
195
- f"{PROG_PATH.stem}_intrinsic_enforcement_rates_{_gpubyr}.tex"
196
- ).write_text(_j2_templ.render(tmpl_data=_invres_rate_table_content))
197
-
198
-
199
- def _dhhi_stats(_dhhi_val: float, _r_val: float) -> tuple[str, dict[str, str]]:
200
- _dhhi_val = round(_dhhi_val, 5)
201
-
202
- _divr_val = gbl.gbd_from_dsf(_dhhi_val, r_bar=_r_val)
203
- _delta_val = gbl.critical_shrratio(_divr_val, r_bar=_r_val)
204
- # _s_mid = sqrt(_dhhi_val / 2)
205
-
206
- # _delta_val = _s_mid / (1 - _s_mid)
207
- # if _dhhi_val * 1e4 in (50, 100, 200):
208
- # _delta_val = gbl.critical_shrratio()(_r_val * _delta_val) / _r_val
209
- # _divr_val = _r_val * _delta_val
210
-
211
- print(
212
- "Processing data for ΔHHI = {0:.{1}f} points;".format(
213
- _dhhi_val * 1e4, 1 * (_dhhi_val * 1e4 % 1 > 1e-8)
214
- ),
215
- f"diversion ratio = {_divr_val:.{1 * (_divr_val * 1e2 % 1 > 1e-8)}%};",
216
- )
217
-
218
- _bdry_stats = Parallel(n_jobs=cpu_count() // 2)(
219
- delayed(_bdry_stats_col)(_bdry_spec, _dhhi_val, _delta_val, _r_val)
220
- for _bdry_spec in BDRY_SPECS_DICT
221
- )
222
-
223
- _bounds_string = R"{{ {} \\ {} }}".format(
224
- Rf"{_dhhi_val * 1e4:.{1 * (_dhhi_val * 1e4 % 1 > 1e-8)}f} points",
225
- Rf"{_divr_val * 1e2:.{2 * (_divr_val * 1e2 % 1 > 1e-8)}f}\%",
226
- )
227
- return _bounds_string, dict(_bdry_stats)
228
-
229
-
230
- def _bdry_stats_col(
231
- _bdry_spec: str, _dhhi_val: float, _delta_val: float, _r_val: float, /
232
- ) -> tuple[str, str]:
233
- _dhhi_prob = 2 * gbl.dh_area(_dhhi_val)
234
- _cs_prob = 2 * _dhhi_val
235
- _hhi_m_pre_prob = pi * _dhhi_val / 2
236
-
237
- match _bdry_spec:
238
- case "ΔHHI":
239
- return _bdry_spec, f"{_dhhi_prob:6.5f}"
240
- case "SAG Combined Share":
241
- return _bdry_spec, f"{_cs_prob:6.5f}"
242
- case "CPSWAG Premerger HHI-contribution":
243
- return _bdry_spec, f"{_hhi_m_pre_prob:6.5f}"
244
- case _ if "Div Ratio" in _bdry_spec:
245
- _within_bdry_area = gbl.shrratio_boundary(
246
- UPPBoundarySpec(
247
- _delta_val,
248
- _r_val,
249
- agg_method=BDRY_SPECS_DICT[_bdry_spec]["agg_method"],
250
- recapture_spec=BDRY_SPECS_DICT[_bdry_spec]["recapture_spec"],
251
- )
252
- ).area
253
- _within_bdry_prob = 2 * _within_bdry_area
254
- if _bdry_spec.startswith("CPSWAG"):
255
- _within_conc_bdry_prob = _hhi_m_pre_prob
256
- elif _bdry_spec.startswith("SAG"):
257
- _within_conc_bdry_prob = _cs_prob
258
- else:
259
- _within_conc_bdry_prob = _dhhi_prob
260
-
261
- return _bdry_spec, R"{{ {:6.5f} \\ {:.2f}\% }}".format( # noqa: UP032
262
- _within_bdry_prob,
263
- 100 * (1 - (_within_conc_bdry_prob / _within_bdry_prob)),
264
- )
265
- case _:
266
- raise ValueError(f'Unexpected specification, "{_bdry_spec}"?')
267
-
268
-
269
- def plot_and_save_boundary_coords(
270
- _gpubyr: gbl.HMGPubYear,
271
- _xl_book: Workbook,
272
- /,
273
- layout: Literal["collected", "distributed"] = "collected",
274
- ) -> None:
275
- gso = gbl.GuidelinesThresholds(_gpubyr)
276
-
277
- _hmg_standards_strings_dict = {
278
- "distributed": ("presumption", "inferred presumption", "safeharbor"),
279
- "collected": ("safeharbor", "imputed_presumption", "presumption"),
280
- }
281
- _hmg_standards_strings = _hmg_standards_strings_dict.get(layout, ())
282
- if not _hmg_standards_strings:
283
- raise ValueError(
284
- f"Layout parameter value, {layout!r} is invalid. "
285
- f'Must be one of, ("collected", "distributed"). '
286
- )
287
-
288
- # Initialize plot area
289
- _plt, _my_fig1, _ax1, _set_axis_def = gbl.boundary_plot()
290
-
291
- _divr_agg_methods = ("OSWAG", "SAG", "CPSWAG")
292
-
293
- for _divr_agg_method, _hmg_standards_str in zip(
294
- _divr_agg_methods, _hmg_standards_strings, strict=True
295
- ):
296
- _r_bar, _g_bar = (getattr(gso.presumption, _f) for _f in ("rec", "guppi"))
297
- _dhhi_val = getattr(gso, _hmg_standards_str).delta
298
- _divr_val = (
299
- _g_bar
300
- if _hmg_standards_str == "safeharbor"
301
- else _r_bar * sqrt(_dhhi_val / 2) / (1 - sqrt(_dhhi_val / 2))
302
- )
303
-
304
- _dhhi_val_str = "{0:.{1}f} points".format(
305
- _dhhi_val * 1e4, 1 * (_dhhi_val * 1e4 % 1 > 1e-8)
306
- )
307
- _divr_val_str = f"{_divr_val:.{1 * (_divr_val * 1e2 % 1 > 1e-8)}%}"
308
-
309
- print(
310
- f"Processing data for ΔHHI = {_dhhi_val_str},",
311
- f"diversion ratio = {_divr_val_str}:",
312
- )
313
-
314
- _bndry_data_dict: dict[
315
- str, Sequence[tuple[float]]
316
- ] = {} #: Container for boundary coordinates data, by boundary
317
-
318
- for _bdry_spec_key in BDRY_SPECS_DICT:
319
- _bdry_spec = (_bdry_spec_key, BDRY_SPECS_DICT[_bdry_spec_key])
320
-
321
- if _bdry_spec_key == "ΔHHI":
322
- if _hmg_standards_str != _hmg_standards_strings_dict[layout][0]:
323
- continue
324
-
325
- _dh_s1, _dh_s2 = gen_plot_boundary(
326
- _bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
327
- )
328
-
329
- del _dh_s1, _dh_s2
330
-
331
- elif _bdry_spec_key.startswith(
332
- _divr_agg_method
333
- ): # and not _bdry_spec_key.endswith("Distance"):
334
- gen_plot_boundary(
335
- _bndry_data_dict, gso, _hmg_standards_str, _bdry_spec, _ax1
336
- )
337
-
338
- _fig_leg = _ax1.legend(
339
- loc="upper right",
340
- bbox_to_anchor=(0.995, 0.999),
341
- shadow=True,
342
- fancybox=False,
343
- frameon=False,
344
- fontsize=8,
345
- )
346
- _fig_leg.set_in_layout(False)
347
-
348
- for _bndry_name in _bndry_data_dict:
349
- boundary_data_to_worksheet(
350
- _bndry_name,
351
- _dhhi_val_str,
352
- _divr_val_str,
353
- _r_bar,
354
- _bndry_data_dict,
355
- _xl_book,
356
- )
357
-
358
- _fig_savepath = DATA_DIR / rf"{PROG_PATH.stem}_{_gpubyr}.pdf"
359
- _my_fig1.savefig(_fig_savepath)
360
- print()
361
-
362
-
363
- def gen_plot_boundary(
364
- _bndry_data_dict: Mapping[str, Sequence[tuple[float]]],
365
- _gso: gbl.GuidelinesThresholds,
366
- _gs_str: str,
367
- _bdry_spec: tuple[str, Mapping[str, Any]],
368
- _ax1: mpa.Axes,
369
- /,
370
- ) -> tuple[tuple[float], tuple[float]]:
371
- """
372
- Utility function to plot boundaries given a dict of relevant parms.
373
-
374
- Parameters
375
- ----------
376
- _bndry_data_dict
377
- mapping for storing boundary coordinates for each plotted boundary
378
- _gso
379
- gbl.GuidelinesStandards instance of tuples listing
380
- concentration standard, default recapture-rate, GUPPI bound,
381
- and diversion ratio bound for "safeharbor", "weak presumption",
382
- and "presumption", where "weak presumption" represents an alternative
383
- interpretation of the enforcement margin for the Guidelines presumption
384
- _gs_str
385
- safeharbor, presumption, or overt_presumption
386
- _bdry_spec
387
- tuple of a string specifying boundary function to plot and
388
- a mapping detailing the boundary function specification including
389
- boundary function name and keyword parameters
390
- _ax1
391
- matplotlib Axes object for plots
392
-
393
- Returns
394
- -------
395
- tuples of boundary coordinates - Firm 1 shares and Firm 2 shares along
396
- boundary for Guidelines standard
397
- """
398
-
399
- _bdry_spec_str, _bdry_spec_dict = _bdry_spec
400
- print(_bdry_spec_dict["title_str"])
401
-
402
- _pt_mdco: ptcolor.Mcset = ptcolor.tol_cset("medium-contrast") # type: ignore
403
- _pt_vbco: ptcolor.Vcset = ptcolor.tol_cset("vibrant") # type: ignore
404
-
405
- _plot_line_width = 1.0
406
- _plot_line_alpha = 0.8
407
- _plot_line_color = _pt_vbco.black
408
- _plot_line_style = {"OSWAG": "-", "SAG": "-.", "CPSWAG": "--"}.get(
409
- _bdry_spec_str.split(" ")[0], "-"
410
- )
411
- if _bdry_spec_str.startswith("ΔHHI"):
412
- _plot_line_width = 0.5
413
- _plot_line_alpha = 1.0
414
- _zrdr = 5
415
-
416
- if not _bdry_spec_str.startswith("ΔHHI"):
417
- match _bdry_spec_str:
418
- case _ if _bdry_spec_str.startswith(("SAG Combined", "CPSWAG Premerger")):
419
- _zrdr = 2
420
- case _ if "Distance" in _bdry_spec_str:
421
- _plot_line_color = _pt_vbco.blue
422
- _zrdr = 3
423
- case _ if "shr-wtd" in _bdry_spec_str or "Mean" in _bdry_spec_str:
424
- _plot_line_color = _pt_vbco.teal
425
- _zrdr = 3
426
- case _:
427
- _plot_line_color = _pt_vbco.red
428
-
429
- _g_val = _gso.safeharbor.guppi
430
-
431
- _r_bar = _gso.presumption.rec
432
-
433
- _dhhi_val = getattr(_gso, _gs_str).delta
434
- _s_mid = sqrt(_dhhi_val / 2)
435
- _delta_val = _g_val / _r_bar if _gs_str == "safeharbor" else _s_mid / (1 - _s_mid)
436
-
437
- _bdry_func = _bdry_spec_dict.get("func", gbl.shrratio_boundary)
438
- if "Div Ratio" in _bdry_spec_str:
439
- _bdry_boundary = gbl.shrratio_boundary(
440
- UPPBoundarySpec(
441
- _delta_val,
442
- _r_bar,
443
- agg_method=_bdry_spec_dict["agg_method"],
444
- recapture_spec=_bdry_spec_dict["recapture_spec"],
445
- )
446
- )
447
- _plot_label_mag, _plot_label_uom = _r_bar * _delta_val * 1e2, "%"
448
- elif _bdry_spec_str.endswith("Combined Share"):
449
- _bdry_boundary = _bdry_func(2 * _s_mid)
450
- _plot_label_mag, _plot_label_uom = 2 * _s_mid * 1e2, "%"
451
- else:
452
- _bdry_boundary = _bdry_func(_dhhi_val)
453
- _plot_label_mag, _plot_label_uom = _dhhi_val * 1e4, " points"
454
-
455
- _plot_label = R"${0}$ = {1:.{2}f}{3}".format(
456
- _bdry_spec_dict["func_str"],
457
- _plot_label_mag,
458
- 1 * (_plot_label_mag % 1 > 1e-8),
459
- _plot_label_uom,
460
- )
461
-
462
- _bndry_data_dict |= {
463
- _bdry_spec_str: (
464
- _bdry_spec_dict["sheet_name"],
465
- _bdry_boundary.coordinates,
466
- _bdry_boundary.area,
467
- )
468
- } # type: ignore
469
- _bdry_s1, _bdry_s2 = zip(*_bdry_boundary.coordinates, strict=True)
470
-
471
- _ax1.plot(
472
- _bdry_s1,
473
- _bdry_s2,
474
- label=_plot_label,
475
- color=_plot_line_color,
476
- linestyle=_plot_line_style,
477
- linewidth=_plot_line_width,
478
- alpha=_plot_line_alpha,
479
- zorder=_zrdr,
480
- )
481
-
482
- print("\t", _bdry_spec_str, f"{_bdry_s2[0]:.1%}")
483
- if _bdry_spec_str.startswith(("ΔHHI", "OSWAG Min")):
484
- _plot_annotator(
485
- _ax1,
486
- f"({_bdry_s1[1]:.1%}, {_bdry_s2[1]:.1%})",
487
- (_bdry_s1[1], _bdry_s2[1]),
488
- (0.005, 0),
489
- "left",
490
- )
491
- elif _bdry_spec_str.startswith("SAG") or _bdry_spec_str in (
492
- "CPSWAG Premerger HHI-contribution",
493
- "CPSWAG Max Div Ratio",
494
- ):
495
- _plot_annotator(
496
- _ax1, f"{_bdry_s2[0]:.1%}", (_bdry_s1[0], _bdry_s2[0]), (-0.005, 0), "right"
497
- )
498
-
499
- return _bdry_s1, _bdry_s2
500
-
501
-
502
- def _plot_annotator(
503
- _ax: mpa.Axes,
504
- _a_str: str,
505
- _data_pt: tuple[float, float],
506
- _note_offset: tuple[float, float],
507
- _h_align: str,
508
- _v_align: str = "bottom",
509
- _font_sz: int = 3,
510
- _z_order: float = 5.0,
511
- /,
512
- ) -> None:
513
- _ax.annotate(
514
- "" if _data_pt[1] * 10 % 1 < 1e-8 else _a_str,
515
- xy=_data_pt,
516
- xytext=(_data_pt[0] + _note_offset[0], _data_pt[1] + _note_offset[1]),
517
- textcoords="data",
518
- ha=_h_align,
519
- va=_v_align,
520
- fontsize=_font_sz,
521
- zorder=_z_order,
522
- )
523
-
524
-
525
- def boundary_data_to_worksheet(
526
- _bndry_name: str,
527
- _dhhi_val_str: str,
528
- _divr_val_str: str,
529
- _r_bar: float,
530
- _bndry_data_dict: Mapping[str, Sequence[tuple[Any]]],
531
- _xl_book: Workbook,
532
- /,
533
- ) -> None:
534
- """
535
- Write boundary data to worksheet in specified Excel workbook
536
-
537
- Parameters
538
- ----------
539
- _bndry_name
540
- Name of concentration or diversion boundary
541
- _dhhi_val_str
542
- ∆HHI value as a formatted string
543
- _divr_val_str
544
- Diversion ratio value as a formatted string
545
- _r_bar
546
- Specified recapture rate
547
- _bndry_data_dict
548
- Container with boundary coordinates data for various concentration and
549
- diversion boundaries
550
- _xl_book
551
- Specified Excel Workbook
552
-
553
- """
554
- _sheet_name, _bndry_points, _bndry_area = _bndry_data_dict[_bndry_name]
555
-
556
- _xl_sheet = _xl_book.add_worksheet(_sheet_name)
557
-
558
- _xl_sheet.write("A1", "Sound GUPPI Safeharbor")
559
- _xl_sheet.write("A2", "Merger Screens for Unilateral Effects")
560
- _xl_sheet.write("A3", f"Share Coordinates Defining {_bndry_name}")
561
- if "Div Ratio" in _bndry_name:
562
- _xl_sheet.write(
563
- "A4",
564
- "Boundary parameters: {}; {}".format(
565
- f"diversion ratio = {_divr_val_str}", f"recapture rate = {_r_bar:3.0%}"
566
- ),
567
- )
568
- _xl_sheet.write("A6", "Area Under Boundary (Simpson's Rule)")
569
- else:
570
- _xl_sheet.write("A4", f"Boundary parameters: ΔHHI = {_dhhi_val_str}")
571
- _xl_sheet.write("A6", "Area Under Boundary (Closed Form)")
572
-
573
- # Write and format the data
574
- _left_footer = "{}, {} on {}.\n{}".format(
575
- "Generated by Python module",
576
- ".".join(Path(__file__).parts[-3:]).rstrip(".py"),
577
- datetime.now().strftime("%A, %d %B %Y"),
578
- "© S. Murthy Kambhampaty, 2017-2023. License: CC-BY-NC-SA-4.0.",
579
- )
580
- _xl_sheet.set_footer(f"&L{_left_footer}")
581
-
582
- xlh.scalar_to_sheet(_xl_book, _xl_sheet, "B7", _bndry_area, xlh.CFmt.AREA_NUM)
583
-
584
- _results_header_row = 9
585
- for _cell_addr_col in range(2):
586
- xlh.scalar_to_sheet(
587
- _xl_book,
588
- _xl_sheet,
589
- _results_header_row,
590
- _cell_addr_col,
591
- f"Firm {_cell_addr_col + 1}",
592
- (xlh.CFmt.HDR_BORDER, xlh.CFmt.A_RIGHT),
593
- )
594
- # set column widths
595
- _xl_sheet.set_column(0, 1, 15)
596
-
597
- _results_top_row = 11
598
- _last_written_row, _last_written_col = xlh.matrix_to_sheet(
599
- _xl_book,
600
- _xl_sheet,
601
- _bndry_points,
602
- _results_top_row,
603
- cell_format=xlh.CFmt.PCT_NUM, # type: ignore
604
- )
605
-
606
- # Draw a bottom border
607
- _cell_row = _last_written_row
608
- for _cell_col in range(_last_written_col):
609
- xlh.scalar_to_sheet(
610
- _xl_book, _xl_sheet, _cell_row, _cell_col, "", xlh.CFmt.BOT_BORDER
611
- )
612
-
613
-
614
- if __name__ == "__main__":
615
- gpubyrs: list[gbl.HMGPubYear] = [1992, 2010, 2023]
616
- for gpubyr in gpubyrs[2:][:1]:
617
- tabulate_boundary_stats(gpubyr)
618
-
619
- # Initiliaze workbook for saving boundary coordinates
620
- with Workbook(
621
- DATA_DIR / rf"{PROG_PATH.stem}_{gpubyr}_BoundaryCoordinates.xlsx"
622
- ) as xl_book:
623
- # tabulate_boundary_stats(gpubyr)
624
- plot_and_save_boundary_coords(gpubyr, xl_book, layout="collected") # type: ignore
625
- xl_book.worksheets()[0].activate()