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,493 +0,0 @@
1
- """
2
-
3
- Draw boundaries for various standards from U.S. Horizontal Merger Guidelines.
4
- """
5
-
6
- from itertools import product as iterprod
7
- from pathlib import Path
8
- from typing import Literal, TypedDict
9
-
10
- import matplotlib.axis
11
- from matplotlib import cm as colormgr
12
- from matplotlib import colormaps
13
- from matplotlib import colors as mcolors
14
- from matplotlib.ticker import StrMethodFormatter
15
- from numpy import arange, arctan, array, hsplit, insert, rad2deg, round, sqrt, vstack
16
-
17
- import mergeron.core.guidelines_boundaries as gbl
18
- from mergeron import DATA_DIR, UPPAggrSelector
19
- from mergeron.core import UPPBoundarySpec
20
-
21
- PROG_PATH = Path(__file__)
22
-
23
-
24
- class _CMAPArgs(TypedDict):
25
- cmap: mcolors.Colormap
26
- norm: mcolors.Normalize
27
-
28
-
29
- _color_kwargs = _CMAPArgs(cmap=colormaps["cividis"], norm=mcolors.Normalize(0, 1.0))
30
-
31
-
32
- def plot_delta_boundaries(
33
- _guppi_bench_key: str,
34
- _print_guppi_max_bndry_envs_flag: bool,
35
- _recapture_spec: Literal["inside-out", "proportional"],
36
- _color_kwargs: _CMAPArgs = _color_kwargs,
37
- /,
38
- ) -> None:
39
- _print_guppi_max_bndry_envs_flag = _print_guppi_max_bndry_envs_flag or False
40
-
41
- print("ΔHHI safeharbor boundary")
42
- _plt, _my_fig1, _ax1, _ = gbl.boundary_plot()
43
-
44
- _hmg_thresholds = get_hmg_thresholds_by_key(_guppi_bench_key)
45
- _dh_bar, _r_bar, _guppi_bench, _divr_bench = (
46
- getattr(_hmg_thresholds, _f) for _f in ("delta", "rec", "guppi", "divr")
47
- )
48
-
49
- print("Contour map of selected ∆HHI boundaries")
50
-
51
- for _dh_bound in 100, 200, 300, 500, 800, 1200, 2500:
52
- if _dh_bound in (300, 500):
53
- continue
54
-
55
- _dh_boundary = gbl.delta_hhi_boundary(_dh_bound / 1e4)
56
- _dh_dat_x, _dh_dat_y = (_z.T[0] for _z in hsplit(_dh_boundary.coordinates, 2))
57
- if _dh_bound == 100:
58
- _lwval, _lsval = 0.75, "-"
59
- else:
60
- _lwval, _lsval = 0.5, ":"
61
-
62
- _ax1.plot(
63
- _dh_dat_x,
64
- _dh_dat_y,
65
- linewidth=_lwval,
66
- linestyle=_lsval,
67
- color="black",
68
- zorder=3,
69
- )
70
-
71
- if _print_guppi_max_bndry_envs_flag:
72
- _symshr = gbl.round_cust(sqrt(_dh_bound / 2e4))
73
- _dstar = gbl.round_cust(_symshr / (1 - _symshr))
74
- _m_star = _guppi_bench / (_dstar * _r_bar)
75
- print(_symshr, _dstar, _m_star, _r_bar, _guppi_bench, "...", end="")
76
-
77
- _guppi_bdry_env_xs = (0, _symshr, 1)
78
- if _recapture_spec == "inside-out":
79
- # ## Plot envelope of GUPPI boundaries with
80
- # r_k = r_bar if s_k = min(_s_1, _s_2)
81
- # ## See (s_i, s_j) in equation~(44), or thereabouts, in paper
82
- _smin_nr = _dstar * (1 - _r_bar)
83
- _smax_nr = 1 - _dstar * _r_bar
84
- _guppi_bdry_env_dr = _smin_nr + _smax_nr
85
- _guppi_bdry_env_xs = ( # type: ignore
86
- 0,
87
- _smin_nr / _guppi_bdry_env_dr,
88
- _symshr,
89
- _smax_nr / _guppi_bdry_env_dr,
90
- 1,
91
- )
92
- del _guppi_bdry_env_dr
93
- print(_guppi_bdry_env_xs[1], _guppi_bdry_env_xs[-2], end="")
94
- print()
95
-
96
- _ax1.plot(
97
- _guppi_bdry_env_xs,
98
- _guppi_bdry_env_xs[::-1],
99
- linewidth=0.5,
100
- linestyle="--",
101
- color=_color_kwargs["cmap"](_m_star),
102
- zorder=3,
103
- )
104
- del _symshr, _dstar, _m_star
105
-
106
- if _recapture_spec == "inside-out" and _dh_bound not in (200, 300, 500):
107
- _ax1.annotate(
108
- rf"$\Delta HHI$ = {_dh_bound:,d} pts.",
109
- xy=(_dh_dat_x[1], _dh_dat_y[1]),
110
- xytext=(_dh_dat_x[1], _dh_dat_y[1]),
111
- textcoords="data",
112
- ha="left",
113
- va="center",
114
- fontsize=5,
115
- zorder=5.1,
116
- )
117
- del _guppi_bdry_env_xs
118
-
119
- if _dh_bound == 100:
120
- _ax1.fill_between(
121
- _dh_dat_x,
122
- _dh_dat_y,
123
- 0,
124
- edgecolor=None,
125
- facecolor="#64bb64",
126
- alpha=0.7,
127
- rasterized=True,
128
- )
129
- del (_dh_boundary, _dh_dat_x, _dh_dat_y) # , _dh_dat_x_pla, _dh_dat_y_pla
130
-
131
- _my_fig1.savefig((DATA_DIR / f"{PROG_PATH.stem}_DH100_deltaHHI_only.pdf"), dpi=600)
132
-
133
- del _plt, _my_fig1, _ax1
134
-
135
-
136
- def plot_guppi_boundaries( # noqa PLR0915
137
- _guppi_bench_key: str,
138
- _pcm_same_flag: bool,
139
- _recapture_spec: Literal["proportional", "inside-out"],
140
- _color_kwargs: _CMAPArgs = _color_kwargs,
141
- /,
142
- ) -> None:
143
- if recapture_spec not in (_recspecs := ("inside-out", "proportional")):
144
- raise ValueError(f"Recapture specification must be one of, {_recspecs!r}")
145
-
146
- _hmg_thresholds = get_hmg_thresholds_by_key(_guppi_bench_key)
147
- _dh_bar, _r_bar, _guppi_bench, _divr_bench = (
148
- getattr(_hmg_thresholds, _f) for _f in ("delta", "rec", "guppi", "divr")
149
- )
150
-
151
- # First we get the data for the ΔHHI benchmark we want to plot
152
- _dh_boundary = gbl.delta_hhi_boundary(_dh_bar)
153
- _dh_dat_x, _dh_dat_y = (_z.T[0] for _z in hsplit(_dh_boundary.coordinates, 2))
154
-
155
- _plt, _, _, _set_axis_def = gbl.boundary_plot()
156
-
157
- _my_fig1 = _plt.figure(figsize=(5.5, 5.0))
158
-
159
- _fig1_grid = _my_fig1.add_gridspec(
160
- nrows=1,
161
- ncols=2,
162
- figure=_my_fig1,
163
- width_ratios=[5, 0.5],
164
- height_ratios=[1.0],
165
- wspace=0.0,
166
- )
167
- _ax1 = _my_fig1.add_subplot(_fig1_grid[0, 0])
168
- _ax1 = _set_axis_def(_ax1, mktshares_plot_flag=True, mktshares_axlbls_flag=True)
169
-
170
- _ax1.plot(_dh_dat_x, _dh_dat_y, linewidth=0.75, color="black", zorder=3)
171
- _ax1.fill_between(
172
- _dh_dat_x,
173
- _dh_dat_y,
174
- 0,
175
- edgecolor=None,
176
- facecolor="#64bb64",
177
- alpha=0.7,
178
- rasterized=True,
179
- )
180
-
181
- # GUPPI boundary-of-boundaries for symmetric-firm mergers
182
- _step_size = 10**-5
183
- _m_lim = _guppi_bench / _r_bar
184
- _mst_vec = arange(_m_lim, 1.00 + _step_size, _step_size)
185
- _sym_shr_vec = (_dst_vec := _m_lim / _mst_vec) / (1 + _dst_vec)
186
- # _sym_shr_vec = np.arange(gbl.shr_from_gbd(g_bar), 0.5 + step_size, step_size)
187
- # _mst_vec = (g_bar / r_bar) * (1 - sym_shr_vec) / sym_shr_vec
188
- # https://stackoverflow.com/questions/39753282/
189
- _ax1.scatter(
190
- _sym_shr_vec,
191
- _sym_shr_vec,
192
- label=r"$\overline{g}$ = 6%; $\overline{d}$ = 20%",
193
- marker=",",
194
- s=(0.25 * 72.0 / _my_fig1.dpi) ** 2,
195
- edgecolor=None,
196
- c=_mst_vec,
197
- **_color_kwargs,
198
- rasterized=True,
199
- zorder=3,
200
- )
201
-
202
- for _m_star in arange(1.00, _m_lim - 0.10, -0.10):
203
- _m_star, _delta_star, _s_mid = (
204
- round(_s, 4)
205
- for _s in (_m_star, _m_lim / _m_star, _m_lim / (_m_star + _m_lim))
206
- )
207
-
208
- _s2_vals = (_delta_star, _s_mid, 0.0)
209
- if _pcm_same_flag:
210
- _s1_vals = _s2_vals[::-1]
211
- _ax1.plot(
212
- _s1_vals,
213
- _s2_vals,
214
- linestyle="--",
215
- linewidth=0.75,
216
- color=_color_kwargs["cmap"](_m_star),
217
- zorder=3,
218
- )
219
- else:
220
- _s1_vals = (0.0, _s_mid, 1.0)
221
- if _recapture_spec == "inside-out":
222
- _s_1_i2, _s_2_i2 = array([
223
- (_x := _guppi_bench - _m_star),
224
- (_y := _guppi_bench - _m_lim),
225
- ]) / (_x + _y)
226
- del _x, _y
227
-
228
- _s1_vals = insert(_s1_vals, [-1], [_s_1_i2])
229
- _s2_vals = insert(_s2_vals, [-1], [_s_2_i2])
230
-
231
- # Print Outer boundary, color-coded m_2
232
- _ax1.plot(
233
- _s1_vals,
234
- _s2_vals,
235
- linestyle="--",
236
- linewidth=0.5,
237
- color=colormaps["cividis"](_m_star),
238
- zorder=3,
239
- )
240
- # Print inner boundary, color-coded m_1
241
- _ax1.plot(
242
- _s2_vals[::-1],
243
- _s1_vals[::-1],
244
- linestyle="--",
245
- linewidth=0.5,
246
- color=colormaps["cividis"](_m_star),
247
- zorder=3,
248
- )
249
-
250
- # skip labeling a few
251
- if _m_star >= 0.70:
252
- continue
253
-
254
- # Place boundary labels along each boundary-line segment
255
- _bndry_grad = grad_est(_ax1, (0, _s_mid), (_delta_star, _s_mid))
256
- _bndry_angle = rad2deg(arctan(_bndry_grad))
257
-
258
- _x_shft_pts = 0.001
259
- _y_shft_pts = 0.015
260
-
261
- _m1_lbl_str, _m2_lbl_str = (
262
- r"${0} = {1:3.{2}f}\%$".format(
263
- ("m^*" if _pcm_same_flag else f"m_{_k}"),
264
- (_pcmv := _m_star * 100),
265
- 2 * int(_pcmv % 1 > 0),
266
- )
267
- for _k in (1, 2)
268
- )
269
- _ax1.annotate(
270
- _m2_lbl_str,
271
- xy=(0, _delta_star),
272
- xytext=(0 + _x_shft_pts, _delta_star + _y_shft_pts),
273
- textcoords="data",
274
- rotation=_bndry_angle,
275
- ha="left",
276
- va="top",
277
- fontsize=4,
278
- zorder=5.1,
279
- )
280
- _ax1.annotate(
281
- _m1_lbl_str,
282
- xy=(_delta_star, 0),
283
- xytext=(0 + _x_shft_pts, _delta_star + _y_shft_pts)[::-1],
284
- textcoords="data",
285
- rotation=-90 - _bndry_angle,
286
- ha="right",
287
- va="bottom",
288
- fontsize=4,
289
- zorder=5.1,
290
- )
291
-
292
- # Examples of hypothetical combinations
293
- if not _pcm_same_flag:
294
- if _guppi_bench_key == "DH50":
295
- _xco, _yco, _lval = zip(
296
- *([0.15, 0.10, "A"], [0.27, 0.15, "B"]), strict=True
297
- )
298
- else:
299
- _xco, _yco, _lval = zip(
300
- *([0.20, 0.135, "A"], [0.27, 0.15, "B"]), strict=True
301
- )
302
-
303
- _ax1.scatter(_xco, _yco, s=1, c="black", zorder=4.5)
304
- for lid, lvl in enumerate(_lval):
305
- _ax1.annotate(
306
- f"${lvl}$",
307
- xy=(_xco[lid], _yco[lid]),
308
- xytext=(_xco[lid] - 0.025, _yco[lid] - 0.01),
309
- fontsize=8,
310
- zorder=4.6,
311
- )
312
-
313
- # print("Diversion ratio bound")
314
- if _divr_bench < _r_bar:
315
- _m_star_bench = _guppi_bench / _divr_bench
316
- _s_mid_bench = gbl.shr_from_gbd(
317
- _guppi_bench, m_star=_m_star_bench, r_bar=_r_bar
318
- )
319
- _delta_star = gbl.critical_shrratio(
320
- _guppi_bench, m_star=_m_star_bench, r_bar=_r_bar
321
- )
322
- guppi_boundary = gbl.shrratio_boundary(
323
- UPPBoundarySpec(_delta_star, _r_bar, agg_method=UPPAggrSelector.MAX)
324
- )
325
- _x_drt, _y_drt = zip(*guppi_boundary.coordinates, strict=True)
326
-
327
- _ax1.plot(
328
- _x_drt,
329
- _y_drt,
330
- linestyle="-",
331
- linewidth=0.75,
332
- color=_color_kwargs["cmap"](_m_star_bench),
333
- zorder=4,
334
- )
335
-
336
- _drt_grad = grad_est(_ax1, _x_drt[:2], _y_drt[:2])
337
- _drt_angle = rad2deg(arctan(_drt_grad))
338
-
339
- _dl_xshift = 0.015 if _divr_bench < 0.20 else -0.01
340
- _dl_yshift = 0.0075 if _divr_bench < 0.20 else 0.005
341
-
342
- _dr_labelstr = R"$\symbf{{\overline{{d}} = {0:3.{1}f}\%}}$".format(
343
- (_dbch := _divr_bench * 100), 1 * (_dbch % 1 > 0)
344
- )
345
-
346
- _ax1.annotate(
347
- _dr_labelstr,
348
- xy=(_s_mid_bench, _s_mid_bench),
349
- xytext=(_s_mid_bench + _dl_xshift, _s_mid_bench + _dl_yshift),
350
- rotation=_drt_angle,
351
- ha="right",
352
- va="bottom",
353
- fontsize=5,
354
- zorder=4.1,
355
- )
356
- _ax1.annotate(
357
- _dr_labelstr,
358
- xy=(_s_mid_bench, _s_mid_bench),
359
- xytext=(_s_mid_bench + _dl_xshift, _s_mid_bench + _dl_yshift)[::-1],
360
- textcoords="data",
361
- rotation=-90 - _drt_angle,
362
- ha="left",
363
- va="top",
364
- fontsize=5,
365
- zorder=4.1,
366
- )
367
-
368
- del _x_drt, _y_drt, _drt_grad, _drt_angle
369
-
370
- # Drop in a point for the Farrell/Shapiro example
371
- # Generate the points and error bars
372
- _ex_divratio = 1.0
373
- _ex_shr_from_divratio = round(_ex_divratio / (1 + _ex_divratio), 3)
374
- _ebar_array = vstack([_ex_shr_from_divratio, 0.0 * _ex_shr_from_divratio])
375
- _ebar_plot = _ax1.errorbar(
376
- _ex_shr_from_divratio,
377
- _ex_shr_from_divratio,
378
- xerr=_ebar_array,
379
- yerr=_ebar_array,
380
- fmt=".",
381
- mfc=_color_kwargs["cmap"](_guppi_bench / _r_bar),
382
- mec="None",
383
- alpha=0.9,
384
- zorder=5,
385
- )
386
- # Set linestyle for errorbars
387
- # https://stackoverflow.com/questions/22995797/
388
- for _ix in range(2):
389
- _ebar_plot[-1][_ix].set(
390
- color=_color_kwargs["cmap"](_guppi_bench / _r_bar),
391
- linestyle="--",
392
- linewidth=0.5,
393
- alpha=0.9,
394
- zorder=2,
395
- )
396
-
397
- # Annotate the point
398
- _ax1.annotate(
399
- rf"$d={_r_bar * 100:3.0f}\%$",
400
- xy=(_ex_shr_from_divratio, _ex_shr_from_divratio),
401
- xytext=(_ex_shr_from_divratio + 0.01, _ex_shr_from_divratio - 0.008),
402
- fontsize=5,
403
- zorder=5.1,
404
- )
405
-
406
- # Colorbar
407
- ax1_cb = _my_fig1.add_subplot(_fig1_grid[0, 1], frameon=False)
408
- ax1_cb.axis("off")
409
- _cm_plot = _my_fig1.colorbar(
410
- colormgr.ScalarMappable(**_color_kwargs),
411
- use_gridspec=True,
412
- ax=ax1_cb,
413
- orientation="vertical",
414
- fraction=0.75,
415
- ticks=arange(0, 1.5, 0.1),
416
- format=StrMethodFormatter("{x:>3.0%}"),
417
- pad=0.0,
418
- )
419
- _cm_plot.set_label(label="Price-Cost Margin", fontsize=8)
420
- _cm_plot.ax.tick_params(length=5, width=0.5, labelsize=6)
421
- _cm_plot.ax.set_ylim(0, 1.0)
422
- _cm_plot.outline.set_visible(False)
423
-
424
- _fig1_savename = "_".join((
425
- f"{PROG_PATH.stem}",
426
- f"pcmSame{_pcm_same_flag}",
427
- f"{_guppi_bench_key}",
428
- f"rbar{_recapture_spec.upper()}",
429
- ))
430
- _my_fig1.savefig((DATA_DIR / f"{_fig1_savename}.pdf"), dpi=600)
431
- del _my_fig1, _ax1, _ebar_plot, _fig1_savename
432
- del _dh_dat_x, _dh_dat_y
433
-
434
-
435
- def grad_est(
436
- _ax: matplotlib.axis.Axis, _pt_xs: tuple[float, ...], _pt_ys: tuple[float, ...]
437
- ) -> float:
438
- if (_pt_len := max(len(_pt_xs), len(_pt_ys))) > 2:
439
- raise ValueError(
440
- "Expecting only 2 points for calculation of line-gradient; got {_pt_len}."
441
- )
442
- _pt1, _pt2 = (
443
- _ax.transData.transform_point((_pt_xs[_i], _pt_ys[_i])) # type: ignore
444
- for _i in range(2)
445
- )
446
- _grad: float = (_pt2[1] - _pt1[1]) / (_pt2[0] - _pt1[0])
447
- return _grad
448
-
449
-
450
- def get_hmg_thresholds_by_key(_guppi_bench_key: str, /) -> gbl.HMGThresholds:
451
- match _guppi_bench_key:
452
- case "DOJATR":
453
- return gbl.HMGThresholds(
454
- (_tmp := gbl.GuidelinesThresholds(2010).safeharbor).delta,
455
- _tmp.rec,
456
- 0.05,
457
- _tmp.divr,
458
- _tmp.cmcr,
459
- _tmp.ipr,
460
- )
461
- case "DH100":
462
- return gbl.GuidelinesThresholds(2010).safeharbor
463
- case "DH50":
464
- return gbl.GuidelinesThresholds(1992).safeharbor
465
- case _:
466
- raise ValueError(
467
- f"GUPPI benchmark key must be one of, {guppi_benchmark_keys!r}"
468
- )
469
-
470
-
471
- if __name__ == "__main__":
472
- print("Define parameters for GUPPI safeharbor plots")
473
-
474
- guppi_benchmark_keys = ("DH50", "DH100", "DOJATR")
475
-
476
- print("Plot countour-maps of ∆HHI boundaries and GUPPI safeharbor boundaries")
477
-
478
- pcm_same_flag: bool = True
479
- recapture_spec: Literal["inside-out", "proportional"] = "inside-out"
480
- plot_delta_boundaries("DH100", pcm_same_flag, recapture_spec, _color_kwargs)
481
-
482
- print("GUPPI safeharbor boundaries, by precentage price-cost margin")
483
- for pcm_same_flag, recapture_spec in iterprod(
484
- (False, True), ("inside-out", "proportional")
485
- ):
486
- if pcm_same_flag and recapture_spec == "inside-out":
487
- continue
488
-
489
- print(f"Symmetric margins: {pcm_same_flag!r}; recapture: '{recapture_spec}'")
490
- for guppi_bench_key in guppi_benchmark_keys:
491
- plot_guppi_boundaries(
492
- guppi_bench_key, pcm_same_flag, recapture_spec, _color_kwargs
493
- )
@@ -1,206 +0,0 @@
1
- """
2
- Draw GUPPI safe harbor boundary for symmetric firm mergers
3
-
4
- This boundary is limited to share-margin space, given restrictions from symmetry
5
- """
6
-
7
- from pathlib import Path
8
-
9
- import matplotlib as mpl
10
- import numpy as np
11
- from matplotlib import cm as colormgr
12
- from matplotlib import colors as mcolors
13
- from matplotlib.ticker import AutoMinorLocator, MultipleLocator, StrMethodFormatter
14
-
15
- import mergeron.core.guidelines_boundaries as gbl
16
- from mergeron import DATA_DIR
17
-
18
- PROG_PATH = Path(__file__)
19
-
20
-
21
- def _main() -> None:
22
- plt, _, _, set_axis_def = gbl.boundary_plot()
23
- # plt.delaxes(ax1)
24
- # del my_fig1, ax1
25
- # del ax1
26
-
27
- pcm_colornorm = mcolors.Normalize(0, 1.0)
28
- cmap_kwargs = {"cmap": "cividis", "norm": pcm_colornorm}
29
-
30
- my_fig1 = plt.figure(figsize=(5.5, 5.0), dpi=600)
31
-
32
- fig1_grid = my_fig1.add_gridspec(
33
- nrows=1,
34
- ncols=2,
35
- figure=my_fig1,
36
- width_ratios=[5, 0.5],
37
- height_ratios=[1.0],
38
- wspace=0.0,
39
- )
40
- ax1 = my_fig1.add_subplot(fig1_grid[0, 0])
41
- ax1 = set_axis_def(ax1, mktshares_plot_flag=False)
42
-
43
- print("Generate data for plots")
44
- # Mgn coords, and div-ratio coords
45
- g_bar, r_bar, dr_bar = 0.06, 0.80, 0.20
46
-
47
- step_size = 10**-5
48
- sym_shr_vec = np.arange(gbl.shr_from_gbd(g_bar), 0.5 + step_size, step_size)
49
- mst_vec = (g_bar / r_bar) * (1 - sym_shr_vec) / sym_shr_vec
50
-
51
- print("Setup basic figure and axes for plots of safe harbor boundaries.")
52
-
53
- # Diversion-ratio boundary, in calibrated 6 percent safe-harbor
54
- ax1.plot(
55
- [np.sqrt(0.01 / 2) for _ in range(2)],
56
- [0.0, 1.0],
57
- label=r"$\Delta HHI = $100 points",
58
- linestyle="-",
59
- linewidth=0.5,
60
- color="black",
61
- zorder=5,
62
- )
63
- ax1.fill_between(
64
- [0.0, np.sqrt(0.01 / 2)],
65
- (1.0, 1.0),
66
- 0,
67
- edgecolor=None,
68
- facecolor="#64bb64",
69
- alpha=0.7,
70
- zorder=2,
71
- )
72
-
73
- # Proposed GUPPI safe harbor
74
- ax1.scatter(
75
- sym_shr_vec,
76
- mst_vec,
77
- label=r"$\overline{g} = $6%; $\overline{d} = $20%",
78
- marker=",",
79
- s=(0.25 * 72.0 / my_fig1.dpi) ** 2,
80
- edgecolor=None,
81
- c=mst_vec,
82
- **cmap_kwargs,
83
- rasterized=True,
84
- zorder=9,
85
- )
86
- ax1.scatter(
87
- sym_shr_vec,
88
- 0 * mst_vec,
89
- label=r"Projection, $\overline{g} = $6%; $\overline{d} = $20%",
90
- marker="o",
91
- s=(2.0 * 72.0 / my_fig1.dpi) ** 2,
92
- edgecolor=None,
93
- c=mst_vec,
94
- **cmap_kwargs,
95
- rasterized=True,
96
- zorder=11,
97
- )
98
-
99
- # Drop in a point for the Farrell/Shapiro example
100
- # Generate the points and error bars
101
- dr_bar_mgn = np.array([g_bar / d for d in (dr_bar, r_bar)])
102
- dr_bar_shr = np.round((dst_vec := g_bar / (r_bar * dr_bar_mgn)) / (1 + dst_vec), 3)
103
- ax1.scatter(
104
- dr_bar_shr,
105
- dr_bar_mgn,
106
- s=(5.0 * 72.0 / my_fig1.dpi) ** 2,
107
- marker=".",
108
- edgecolor=None,
109
- c=dr_bar_mgn,
110
- **cmap_kwargs,
111
- )
112
- ax1.plot(
113
- [dr_bar_shr[0] for _ in range(2)],
114
- [0, dr_bar_mgn[0]],
115
- label=r"$\overline{d} = $20%",
116
- linestyle="-",
117
- linewidth=0.75,
118
- alpha=1,
119
- color=mpl.colormaps["cividis"](dr_bar_mgn[0]),
120
- zorder=5.5,
121
- )
122
-
123
- # Annotate diversion ratio limit
124
- ax1.annotate(
125
- r"$\overline{d}$ = 20%",
126
- xy=(0.20, 0.30),
127
- xytext=(0.20, 0.30 - 0.03), # (0.20 + 0.005, 0.30 + 0.005),
128
- horizontalalignment="right",
129
- fontsize=8,
130
- zorder=5,
131
- )
132
- # Annotate diversion ratio limit
133
- ax1.annotate(
134
- r"$\overline{d}$ = 80%",
135
- xy=(0.50, 0.075),
136
- xytext=(0.5, 0.075 - 0.03),
137
- fontsize=8,
138
- horizontalalignment="right",
139
- zorder=5,
140
- )
141
- # Annotate \Deltah{} boundary
142
- ax1.annotate(
143
- r"$\Delta HHI$ = 100 points",
144
- xy=(0.07, 0.250),
145
- xytext=(0.07 + 0.005, 0.40 + 0.01),
146
- fontsize=8,
147
- rotation=90,
148
- zorder=5,
149
- )
150
- # Annotate GUPPI boundary
151
- ax1.annotate(
152
- r"$\overline{g}$ = 6%",
153
- xy=(0.10, 0.70),
154
- xytext=(0.10 + 0.004, 0.70 + 0.01),
155
- fontsize=8,
156
- zorder=5,
157
- )
158
-
159
- # Axis scale and labels
160
- # x-axis
161
- ax1.set_xlim(0.0, 0.5)
162
- ax1.set_xlabel("Symmetric Firm Share, $s$", fontsize=10)
163
- ax1.xaxis.set_label_coords(0.75, -0.1)
164
- # y-axis
165
- ax1.set_ylim(0.0, 1.0)
166
- ax1.set_ylabel("Price-Cost Margin, $m^*$", fontsize=10)
167
- ax1.yaxis.set_label_coords(-0.1, 0.75)
168
-
169
- _minorLocator = AutoMinorLocator(5)
170
- _majorLocator = MultipleLocator(0.05)
171
- for _axs in ax1.xaxis, ax1.yaxis:
172
- _majorticklabels_rot = 45 if _axs == ax1.xaxis else 0
173
- # x-axis
174
- _axs.set_major_locator(_majorLocator)
175
- _axs.set_minor_locator(_minorLocator)
176
- _axs.set_major_formatter(StrMethodFormatter("{x:>3.0%}"))
177
-
178
- plt.setp(_axs.get_majorticklabels(), fontsize=6)
179
- plt.setp(_axs.get_majorticklabels(), rotation=_majorticklabels_rot)
180
-
181
- for axl in ax1.get_xticklabels(), ax1.get_yticklabels():
182
- plt.setp(axl[::2], visible=False)
183
-
184
- # Colorbar
185
- ax1_cb = my_fig1.add_subplot(fig1_grid[0, 1], frameon=False)
186
- ax1_cb.axis("off")
187
- cm_plot = my_fig1.colorbar(
188
- colormgr.ScalarMappable(**cmap_kwargs),
189
- use_gridspec=True,
190
- ax=ax1_cb,
191
- orientation="vertical",
192
- fraction=0.75,
193
- ticks=np.arange(0, 1.5, 0.1),
194
- format=StrMethodFormatter("{x:>3.0%}"),
195
- pad=0.0,
196
- )
197
- cm_plot.set_label(label="Price-Cost Margin", fontsize=8)
198
- cm_plot.ax.tick_params(length=5, width=0.5, labelsize=6)
199
- cm_plot.ax.set_ylim(0, 1.0)
200
- cm_plot.outline.set_visible(False)
201
-
202
- plt.savefig(DATA_DIR / PROG_PATH.with_suffix(".pdf").name)
203
-
204
-
205
- if __name__ == "__main__":
206
- _main()