Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges
1from typing import Callable 2from copy import deepcopy 3import matplotlib.gridspec 4import matplotlib.pyplot as plt 5from matplotlib.ticker import FixedLocator 6from matplotlib.patches import Rectangle 7 8import Fumagalli_Motta_Tarantino_2020.Models as Models 9from Fumagalli_Motta_Tarantino_2020.Models.Types import * 10from Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize import * 11 12 13class AssetRange(IVisualize): 14 """ 15 Visualizes the outcomes over an assets range for a specific model. 16 """ 17 18 def __init__(self, model: Models.OptimalMergerPolicy, **kwargs) -> None: 19 super(AssetRange, self).__init__(model, **kwargs) 20 self.labels: list[str] = [] 21 self.colors: dict[str, dict] = {} 22 self._thresholds: list[Models.ThresholdItem] = self._get_essential_thresholds() 23 self._check_thresholds() 24 self._label_colors: dict[str:dict] = self._init_label_colors() 25 26 @staticmethod 27 def _init_label_colors() -> dict[str, dict]: 28 o = PossibleOutcomes 29 d = {} 30 vis_success = 1.0 31 vis_fail = 0.7 32 vis_no_att = 0.4 33 for i in [ 34 (o.NoTakeoversSuccessfulDevelopment, 0, vis_success), 35 (o.NoTakeoversFailedDevelopment, 0, vis_fail), 36 (o.NoTakeoversDevelopmentNotAttempted, 0, vis_no_att), 37 (o.RejectedEarlySeparatingUnsuccessfulDevelopment, 1, vis_success), 38 (o.RejectedEarlySeparatingSuccessfulDevelopment, 1, vis_fail), 39 (o.EarlySeparatingSuccessfulDevelopment, 2, vis_success), 40 (o.EarlySeparatingUnsuccessfulDevelopment, 2, vis_fail), 41 (o.EarlySeparatingDevelopmentNotAttempted, 2, vis_no_att), 42 (o.EarlyPoolingSuccessfulDevelopment, 3, vis_success), 43 (o.EarlyPoolingUnsuccessfulDevelopment, 3, vis_fail), 44 (o.EarlyPoolingDevelopmentNotAttempted, 3, vis_no_att), 45 (o.LatePooling, 4, vis_success), 46 (o.LatePoolingRejectedEarlySeparating, 4, vis_fail), 47 ]: 48 d.update( 49 AssetRange._init_label_color( 50 outcome_type=i[0], color_id=i[1], opacity=i[2] 51 ), 52 ) 53 return d 54 55 @staticmethod 56 def _init_label_color( 57 outcome_type: Models.PossibleOutcomes, color_id: int, opacity: float 58 ) -> dict[dict]: 59 return { 60 IVisualize._get_summary_latex(outcome_type.outcome): { 61 "color": IVisualize.COLORS[color_id], 62 "opacity": opacity, 63 } 64 } 65 66 @staticmethod 67 def plot_label_colors(show_plot=False) -> plt.Axes: 68 """ 69 Plots the colors used in the legend for asset ranges matched to the outcome. 70 71 Returns 72 ------- 73 plt.Axes 74 Axis containing the plot. 75 """ 76 label_colors = AssetRange._init_label_colors() 77 fig, ax = plt.subplots() 78 ax.set_axis_off() 79 height = 0.1 80 width = 0.1 81 ax.set_ylim(bottom=0, top=len(label_colors) * height) 82 ax.set_xlim(left=0, right=width * 1.05 + 0.02) 83 for i, label in enumerate(label_colors): 84 ax.text( 85 width * 1.1, 86 (i + 0.5) * height, 87 label, 88 horizontalalignment="left", 89 verticalalignment="center", 90 ) 91 92 ax.add_patch( 93 Rectangle( 94 xy=(0, i * height), 95 width=width, 96 height=height, 97 facecolor=label_colors[label]["color"], 98 alpha=label_colors[label]["opacity"], 99 ) 100 ) 101 fig.tight_layout() 102 if show_plot: 103 fig.show() 104 return ax 105 106 def _check_thresholds(self) -> None: 107 assert ( 108 self._thresholds is not None and len(self._thresholds) >= 2 109 ), "Essential thresholds are not valid" 110 111 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 112 super(AssetRange, self).set_model(model) 113 self._thresholds = self._get_essential_thresholds() 114 self._check_thresholds() 115 116 def _get_outcomes_asset_range( 117 self, 118 ) -> list[Models.OptimalMergerPolicySummary]: 119 """ 120 Generates a list with all essential threshold concerning the assets of a start-up and an additional list with 121 summaries of the outcomes of the model in between the thresholds. 122 123 Returns 124 ------- 125 (list[Fumagalli_Motta_Tarantino_2020.FMT20.ThresholdItem], list[Fumagalli_Motta_Tarantino_2020.FMT20.OptimalMergerPolicySummary]) 126 List containing the essential asset thresholds in the model and list containing the summaries of the outcomes of the model. 127 """ 128 original_assets = self.model.startup_assets 129 summaries: list[Models.OptimalMergerPolicySummary] = [] 130 for i in range(len(self._thresholds) - 1): 131 self._set_model_startup_assets(self._thresholds[i], self._thresholds[i + 1]) 132 summaries.append(self.model.summary()) 133 self.model.startup_assets = original_assets 134 return summaries 135 136 def _set_model_startup_assets( 137 self, 138 lower_threshold: Models.ThresholdItem, 139 upper_threshold: Models.ThresholdItem, 140 ) -> None: 141 self.model.startup_assets = ( 142 self._get_inverse_asset_distribution_value(lower_threshold.value) 143 + self._get_inverse_asset_distribution_value(upper_threshold.value) 144 ) / 2 145 146 def _get_essential_thresholds(self) -> list[Models.ThresholdItem]: 147 """ 148 Generates a list with all essential threshold concerning the assets of a start-up. 149 150 Returns 151 ------- 152 list[Fumagalli_Motta_Tarantino_2020.FMT20.ThresholdItem] 153 List containing the essential asset thresholds in the model. 154 """ 155 thresholds = self._get_available_thresholds() 156 essential_thresholds: list[Models.ThresholdItem] = [] 157 for threshold in thresholds: 158 if self._valid_x_tick(threshold): 159 essential_thresholds.append(threshold) 160 thresholds = sorted(essential_thresholds, key=lambda x: x.value) 161 return thresholds 162 163 def _get_available_thresholds(self) -> list[Models.ThresholdItem]: 164 return [ 165 Models.ThresholdItem("$F(0)$", self._get_x_min(), include=True), 166 Models.ThresholdItem( 167 "$F(K)$", 168 self._get_x_max(), 169 include=True, 170 ), 171 Models.ThresholdItem( 172 "$\\Gamma$", self.model.asset_distribution_threshold_welfare 173 ), 174 Models.ThresholdItem( 175 "$\\Phi$", 176 self.model.asset_distribution_threshold_profitable_without_late_takeover, 177 ), 178 Models.ThresholdItem( 179 "$\\Phi^T$", self.model.asset_distribution_threshold_with_late_takeover 180 ), 181 Models.ThresholdItem( 182 "$\\Phi^{\\prime}$", 183 self.model.asset_distribution_threshold_unprofitable_without_late_takeover, 184 ), 185 Models.ThresholdItem("$F(\\bar{A})$", self.model.asset_threshold_cdf), 186 Models.ThresholdItem( 187 "$F(\\bar{A}^T)$", self.model.asset_threshold_late_takeover_cdf 188 ), 189 Models.ThresholdItem( 190 "$\\Lambda(\\cdot)$", 191 self.model.asset_distribution_threshold_shelving_approved, 192 ), 193 ] 194 195 def _get_x_labels_ticks(self) -> (list[float], list[str]): 196 """ 197 Generates the locations of the ticks on the x-axis and the corresponding labels on the x-axis. 198 199 Returns 200 ------- 201 (list[float], list[str]) 202 A list containing the ticks on the x-axis and a list containing the labels on the x-axis. 203 """ 204 x_ticks: list[float] = [] 205 x_labels: list[str] = [] 206 for threshold in self._thresholds: 207 x_ticks.append(threshold.value) 208 x_labels.append(threshold.name) 209 return x_ticks, x_labels 210 211 def _set_x_axis(self, **kwargs) -> None: 212 x_ticks, x_labels = self._get_x_labels_ticks() 213 self._set_x_locators(x_ticks) 214 self._set_x_labels(x_labels) 215 self._set_x_ticks() 216 self.ax.set_xlabel( 217 kwargs.get("x_label", "Cumulative Distribution Value of Assets $F(A)$") 218 ) 219 220 def _set_x_ticks(self) -> None: 221 self.ax.tick_params( 222 which="minor", 223 bottom=False, 224 top=True, 225 labelbottom=False, 226 labeltop=True, 227 axis="x", 228 pad=0, 229 ) 230 self.ax.tick_params(which="major", top=False, pad=3, axis="x") 231 self.ax.tick_params(which="both", length=2, axis="x") 232 233 def _set_x_labels(self, x_labels: list[str]) -> None: 234 self.ax.set_xticklabels(x_labels[::2], fontsize=IVisualize.fontsize) 235 self.ax.set_xticklabels( 236 x_labels[1::2], minor=True, fontsize=IVisualize.fontsize 237 ) 238 239 def _set_x_locators(self, x_ticks: list[float]) -> None: 240 self.ax.xaxis.set_major_locator(FixedLocator(x_ticks[::2])) 241 self.ax.xaxis.set_minor_locator(FixedLocator(x_ticks[1::2])) 242 243 def _draw_vertical_lines( 244 self, asset_thresholds: list[Models.ThresholdItem] 245 ) -> None: 246 for threshold in asset_thresholds: 247 if self._valid_x_tick(threshold) or threshold.include: 248 self.ax.axvline(threshold.value, linestyle=":", color="k", lw=0.5) 249 250 def _valid_x_tick(self, threshold): 251 return ( 252 self._get_x_min() < threshold.value < self._get_x_max() 253 ) or threshold.include 254 255 @staticmethod 256 def _get_y_ticks( 257 spacing: float, bar_height: float, y_labels: list[str] 258 ) -> list[float]: 259 return [(i + 1) * spacing + bar_height * i for i in range(len(y_labels))] 260 261 def _set_y_ticks(self, bar_height: float, spacing: float, y_labels: list[str]): 262 y_ticks = self._get_y_ticks(spacing, bar_height, y_labels) 263 self.ax.set_yticks(y_ticks) 264 self.ax.set_yticklabels(y_labels, fontsize=IVisualize.fontsize) 265 self.ax.yaxis.set_ticks_position("none") 266 267 def _get_label_color(self, label) -> (str, str, float): 268 """ 269 Returns the color and the final label for a legend entry. 270 271 Through this method, duplications in the legend are avoided. 272 273 Parameters 274 ---------- 275 label: str 276 277 Returns 278 ------- 279 (str, str, float) 280 String representing the final label, a string representing the color and a float representing the opacity. 281 """ 282 if label in self.labels: 283 return ( 284 "_nolegend_", 285 self.colors[label]["color"], 286 self.colors[label]["opacity"], 287 ) 288 self.colors[label] = self._get_label_specific_color(label) 289 self.labels.append(label) 290 return label, self.colors[label]["color"], self.colors[label]["opacity"] 291 292 def _get_label_specific_color(self, label: str) -> dict: 293 if label in self._label_colors.keys(): 294 return self._label_colors[label] 295 return {"color": IVisualize.COLORS[4], "opacity": 0.5} 296 297 def _get_summaries(self) -> list[list[Models.OptimalMergerPolicySummary]]: 298 return [self._get_outcomes_asset_range()] 299 300 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 301 """ 302 Plots the outcome of a model over a range of assets. 303 304 Example 305 ------- 306 ``` 307 import Fumagalli_Motta_Tarantino_2020 as FMT20 308 309 model = FMT20.OptimalMergerPolicy() 310 visualizer = FMT20.MergerPoliciesAssetRange(m) 311 fig, ax = visualizer.plot() 312 # use the figure and axes as you wish, for example: 313 fig.show() 314 ``` 315 316 Parameters 317 ---------- 318 **kwargs 319 Options for further customization of the plots. 320 - title(str): Title for plot<br> 321 - x_label(str): Title for x-axis.<br> 322 - y_label(str): Title for y-axis.<br> 323 - legend(bool): If true, a secondary legend is shown.<br> 324 - thresholds(bool): If true, the essential thresholds are shown.<br> 325 - optimal_policy(bool): If true, the optimal policy is shown. 326 - y_offset(int): Moves the threshold legend vertically. 327 328 Returns 329 ------- 330 Figure 331 Containing the axes with the plots (use Figure.show() to display). 332 Axes 333 Containing the plots (arrange custom summary). 334 """ 335 merger_policies_summaries = self._get_summaries() 336 assert merger_policies_summaries is not None 337 self._clear_legend_list() 338 bar_height, spacing, y_labels = self._draw_all_bars( 339 merger_policies_summaries, **kwargs 340 ) 341 self._set_asset_range_legends(**kwargs) 342 self._draw_vertical_lines(self._thresholds) 343 self._set_x_axis(**kwargs) 344 self._set_y_axis(bar_height, spacing, y_labels, **kwargs) 345 self.ax.set_title(kwargs.get("title", "Outcome dependent on Start-up Assets")) 346 self._set_tight_layout(y_spacing=spacing) 347 return self.fig, self.ax 348 349 def _set_y_axis(self, bar_height, spacing, y_labels, **kwargs): 350 self._set_y_ticks(bar_height, spacing, y_labels) 351 self.ax.set_ylabel(kwargs.get("y_label", "Merger Policy")) 352 353 def _set_asset_range_legends(self, **kwargs): 354 self._set_primary_legend(equal_opacity=False) 355 self._set_secondary_legend( 356 self._thresholds[0].value, kwargs.get("legend", True) 357 ) 358 self._set_threshold_legend( 359 kwargs.get("thresholds", False), 360 kwargs.get("optimal_policy", False), 361 kwargs.get("y_offset", 0), 362 ) 363 364 def _clear_legend_list(self) -> None: 365 self.labels.clear() 366 self.colors.clear() 367 368 def _draw_all_bars( 369 self, merger_policies_summaries, **kwargs 370 ) -> (float, float, list[str]): 371 spacing: float = kwargs.get("spacing", 0.1) 372 bar_height: float = kwargs.get("bar_height", 0.2) 373 y_labels: list[str] = [] 374 for number_merger_policy, summaries in enumerate(merger_policies_summaries): 375 y_labels.append(summaries[0].set_policy.abbreviation()) 376 for summary_index, summary in enumerate(summaries): 377 label: str = self._get_summary_latex(summary) 378 length: float = self._get_bar_length(summary_index) 379 y_coordinate = self._get_bar_y_coordinate( 380 bar_height, number_merger_policy, spacing 381 ) 382 self._draw_bar( 383 y_coordinate, 384 self._thresholds[summary_index].value, 385 bar_height, 386 length, 387 label, 388 ) 389 return bar_height, spacing, y_labels 390 391 def _get_bar_length(self, summary_index: int) -> float: 392 return ( 393 self._thresholds[summary_index + 1].value 394 - self._thresholds[summary_index].value 395 ) 396 397 @staticmethod 398 def _get_bar_y_coordinate( 399 bar_height: float, number_merger_policy: int, spacing: float 400 ) -> float: 401 return spacing * (number_merger_policy + 1) + bar_height * number_merger_policy 402 403 def _draw_bar( 404 self, 405 y_coordinate: float, 406 x_coordinate: float, 407 bar_height: float, 408 length: float, 409 label: str, 410 ) -> None: 411 label, color, opacity = self._get_label_color(label) 412 self.ax.barh( 413 y=y_coordinate, 414 width=length, 415 left=x_coordinate, 416 height=bar_height, 417 color=color, 418 label=label, 419 alpha=opacity, 420 ) 421 422 def _set_threshold_legend( 423 self, show_legend: bool, show_optimal_policy: bool, y_offset: int 424 ) -> None: 425 if show_legend: 426 x_coordinate = self._get_x_max() 427 y_coordinate = self._get_y_max() 428 self.ax.annotate( 429 self._get_model_characteristics( 430 separator="\n", 431 model_parameters=False, 432 thresholds_newline=False, 433 threshold_title="", 434 optimal_policy=show_optimal_policy, 435 ), 436 xy=(x_coordinate, y_coordinate), 437 xytext=(10, y_offset), 438 textcoords="offset points", 439 horizontalalignment="left", 440 verticalalignment="top", 441 fontsize=IVisualize.fontsize, 442 ) 443 444 @staticmethod 445 def _get_y_max() -> float: 446 return 1 447 448 def _get_x_max(self): 449 return self._get_asset_distribution_value(self.model.development_costs) 450 451 def _get_x_min(self): 452 return self._get_asset_distribution_value(0) 453 454 def _set_secondary_legend(self, x_coordinate: float, show_legend: bool) -> None: 455 if show_legend: 456 self.ax.annotate( 457 self._get_symbol_legend(), 458 xy=(x_coordinate, 0), 459 xytext=(0, -50), 460 textcoords="offset points", 461 horizontalalignment="left", 462 verticalalignment="top", 463 fontsize=IVisualize.fontsize, 464 ) 465 466 467class MergerPoliciesAssetRange(AssetRange): 468 def _get_outcomes_different_merger_policies( 469 self, 470 ) -> list[list[Models.OptimalMergerPolicySummary]]: 471 original_policy = self.model.merger_policy 472 outcomes: list[list[Models.OptimalMergerPolicySummary]] = [] 473 for merger_policy in Models.MergerPolicies: 474 try: 475 self.model.merger_policy = merger_policy 476 outcomes.append(self._get_outcomes_asset_range()) 477 except Models.Exceptions.MergerPolicyNotAvailable: 478 pass 479 self.model.merger_policy = original_policy 480 return outcomes 481 482 def _get_summaries(self) -> list[list[Models.OptimalMergerPolicySummary]]: 483 return self._get_outcomes_different_merger_policies() 484 485 486class MergerPoliciesAssetRangePerfectInformation(MergerPoliciesAssetRange): 487 def __init__(self, model: Models.PerfectInformation, **kwargs): 488 """ 489 Uses a Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation for the visualization. See 490 Fumagalli_Motta_Tarantino_2020.Models.Base.CoreModel for other parameters. 491 492 Parameters 493 ---------- 494 model: Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation 495 Model to create the visualization from. 496 """ 497 super(MergerPoliciesAssetRangePerfectInformation, self).__init__( 498 model, **kwargs 499 ) 500 501 def _get_available_thresholds(self) -> list[Models.ThresholdItem]: 502 return [ 503 Models.ThresholdItem("$0$", self._get_x_min(), include=True), 504 Models.ThresholdItem("$K$", self._get_x_max(), include=True), 505 Models.ThresholdItem("$\\bar{A}$", self.model.asset_threshold), 506 Models.ThresholdItem( 507 "$\\bar{A}^T$", self.model.asset_threshold_late_takeover 508 ), 509 ] 510 511 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 512 """ 513 Plots the visual representation for the object. 514 515 Example 516 ------- 517 ``` 518 import Fumagalli_Motta_Tarantino_2020 as FMT20 519 520 model = FMT20.PerfectInformation() 521 visualizer = FMT20.MergerPoliciesAssetRangePerfectInformation(m) 522 fig, ax = visualizer.plot() 523 # use the figure and axes as you wish, for example: 524 fig.show() 525 ``` 526 527 Parameters 528 ---------- 529 **kwargs 530 Options for further customization of the plots (see Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.AssetRange.plot). 531 532 Returns 533 ------- 534 Figure 535 Containing the axes with the plots (use Figure.show() to display). 536 Axes 537 Containing the plots (arrange custom summary). 538 """ 539 kwargs["x_label"] = kwargs.get("x_label", "Start-up Assets $A$") 540 return super(MergerPoliciesAssetRangePerfectInformation, self).plot(**kwargs) 541 542 def _set_model_startup_assets( 543 self, 544 lower_threshold: Models.ThresholdItem, 545 upper_threshold: Models.ThresholdItem, 546 ) -> None: 547 self.model.startup_assets = (lower_threshold.value + upper_threshold.value) / 2 548 549 @staticmethod 550 def _get_y_max() -> float: 551 return 0.55 552 553 def _get_x_max(self) -> float: 554 return self.model.development_costs 555 556 def _get_x_min(self) -> float: 557 return 0 558 559 def _get_model_characteristics_thresholds( 560 self, separator: str, newline: str 561 ) -> str: 562 return ( 563 f"$K = {self._round_floats(self.model.development_costs)}${separator}" 564 f"$\\bar{{A}} = {self._round_floats(self.model.asset_threshold)}${separator}" 565 f"$\\bar{{A}}^T = {self._round_floats(self.model.asset_threshold_late_takeover)}${separator}" 566 ) 567 568 569class Overview(IVisualize): 570 """ 571 Combines Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Timeline, Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Payoffs, 572 Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.MergerPoliciesAssetRange as well as a legend for the 573 model characteristics. 574 """ 575 576 def __init__(self, model: Models.OptimalMergerPolicy, figsize=(14, 10), **kwargs): 577 super().__init__(model, figsize=figsize, constrained_layout=True, **kwargs) 578 self.timeline: Optional[IVisualize] = None 579 self.payoffs: Optional[IVisualize] = None 580 self.range: Optional[IVisualize] = None 581 self.kwargs = kwargs 582 self._clear_main_axes() 583 584 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 585 assert ( 586 self.timeline is not None 587 and self.payoffs is not None 588 and self.range is not None 589 ) 590 super(Overview, self).set_model(model) 591 self.timeline.set_model(model) 592 self.payoffs.set_model(model) 593 self.range.set_model(model) 594 self.fig.clear() 595 596 @staticmethod 597 def _clear_main_axes() -> None: 598 plt.axis("off") 599 600 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 601 """ 602 Plots the visual representation for the object. 603 604 Example 605 ------- 606 ``` 607 import Fumagalli_Motta_Tarantino_2020 as FMT20 608 609 model = FMT20.OptimalMergerPolicy() 610 visualizer = FMT20.Overview(m) 611 fig, ax = visualizer.plot() 612 # use the figure and axes as you wish, for example: 613 fig.show() 614 ``` 615 616 Parameters 617 ---------- 618 **kwargs 619 Options for further customization of the plots (Note: all subplots use the same kwargs). 620 - figure_title(str): Title for plot.<br> 621 - fontsize(int): Fontsize for model characteristics.<br> 622 - model_thresholds(bool): If true, the essential thresholds are shown in model characteristics.<br> 623 $\\Rightarrow$ see the included visualizations for further arguments. 624 625 Returns 626 ------- 627 Figure 628 Containing the axes with the plots (use Figure.show() to display). 629 Axes 630 Containing the plots (arrange custom summary). 631 """ 632 spec = self.fig.add_gridspec(ncols=2, nrows=2) 633 self._set_fig_title(**kwargs) 634 self.timeline = self._generate_visualizer(spec[1, 0], Timeline, **kwargs) 635 self.payoffs = self._generate_visualizer(spec[0, 1], Payoffs, **kwargs) 636 self.range = self._generate_visualizer( 637 spec[1, 1], self._get_merger_policy_asset_range_type(), **kwargs 638 ) 639 self._generate_characteristics_ax(spec[0, 0], **kwargs) 640 return self.fig, self.ax 641 642 def _set_fig_title(self, **kwargs): 643 self.fig.suptitle( 644 kwargs.get("figure_title", "Model Overview"), 645 fontsize=18, 646 ) 647 648 def _get_merger_policy_asset_range_type(self) -> Callable: 649 return ( 650 MergerPoliciesAssetRangePerfectInformation 651 if type(self.model) is Models.PerfectInformation 652 else MergerPoliciesAssetRange 653 ) 654 655 def _generate_characteristics_ax( 656 self, coordinates: matplotlib.gridspec.GridSpec, **kwargs 657 ) -> None: 658 ax = self.fig.add_subplot(coordinates) 659 characteristics_kwargs = deepcopy(kwargs) 660 characteristics_kwargs["model_thresholds"] = characteristics_kwargs.get( 661 "model_thresholds", not characteristics_kwargs.get("thresholds", False) 662 ) 663 characteristics_kwargs["optimal_policy"] = False 664 self._get_model_characteristics_ax(ax, **characteristics_kwargs) 665 666 def _generate_visualizer( 667 self, coordinates: matplotlib.gridspec.GridSpec, visualizer: Callable, **kwargs 668 ) -> IVisualize: 669 ax = self.fig.add_subplot(coordinates) 670 visualization: IVisualize = visualizer(self.model, ax=ax, **self.kwargs) 671 visualization.plot(legend=False, parameters=False, **kwargs) 672 return visualization
14class AssetRange(IVisualize): 15 """ 16 Visualizes the outcomes over an assets range for a specific model. 17 """ 18 19 def __init__(self, model: Models.OptimalMergerPolicy, **kwargs) -> None: 20 super(AssetRange, self).__init__(model, **kwargs) 21 self.labels: list[str] = [] 22 self.colors: dict[str, dict] = {} 23 self._thresholds: list[Models.ThresholdItem] = self._get_essential_thresholds() 24 self._check_thresholds() 25 self._label_colors: dict[str:dict] = self._init_label_colors() 26 27 @staticmethod 28 def _init_label_colors() -> dict[str, dict]: 29 o = PossibleOutcomes 30 d = {} 31 vis_success = 1.0 32 vis_fail = 0.7 33 vis_no_att = 0.4 34 for i in [ 35 (o.NoTakeoversSuccessfulDevelopment, 0, vis_success), 36 (o.NoTakeoversFailedDevelopment, 0, vis_fail), 37 (o.NoTakeoversDevelopmentNotAttempted, 0, vis_no_att), 38 (o.RejectedEarlySeparatingUnsuccessfulDevelopment, 1, vis_success), 39 (o.RejectedEarlySeparatingSuccessfulDevelopment, 1, vis_fail), 40 (o.EarlySeparatingSuccessfulDevelopment, 2, vis_success), 41 (o.EarlySeparatingUnsuccessfulDevelopment, 2, vis_fail), 42 (o.EarlySeparatingDevelopmentNotAttempted, 2, vis_no_att), 43 (o.EarlyPoolingSuccessfulDevelopment, 3, vis_success), 44 (o.EarlyPoolingUnsuccessfulDevelopment, 3, vis_fail), 45 (o.EarlyPoolingDevelopmentNotAttempted, 3, vis_no_att), 46 (o.LatePooling, 4, vis_success), 47 (o.LatePoolingRejectedEarlySeparating, 4, vis_fail), 48 ]: 49 d.update( 50 AssetRange._init_label_color( 51 outcome_type=i[0], color_id=i[1], opacity=i[2] 52 ), 53 ) 54 return d 55 56 @staticmethod 57 def _init_label_color( 58 outcome_type: Models.PossibleOutcomes, color_id: int, opacity: float 59 ) -> dict[dict]: 60 return { 61 IVisualize._get_summary_latex(outcome_type.outcome): { 62 "color": IVisualize.COLORS[color_id], 63 "opacity": opacity, 64 } 65 } 66 67 @staticmethod 68 def plot_label_colors(show_plot=False) -> plt.Axes: 69 """ 70 Plots the colors used in the legend for asset ranges matched to the outcome. 71 72 Returns 73 ------- 74 plt.Axes 75 Axis containing the plot. 76 """ 77 label_colors = AssetRange._init_label_colors() 78 fig, ax = plt.subplots() 79 ax.set_axis_off() 80 height = 0.1 81 width = 0.1 82 ax.set_ylim(bottom=0, top=len(label_colors) * height) 83 ax.set_xlim(left=0, right=width * 1.05 + 0.02) 84 for i, label in enumerate(label_colors): 85 ax.text( 86 width * 1.1, 87 (i + 0.5) * height, 88 label, 89 horizontalalignment="left", 90 verticalalignment="center", 91 ) 92 93 ax.add_patch( 94 Rectangle( 95 xy=(0, i * height), 96 width=width, 97 height=height, 98 facecolor=label_colors[label]["color"], 99 alpha=label_colors[label]["opacity"], 100 ) 101 ) 102 fig.tight_layout() 103 if show_plot: 104 fig.show() 105 return ax 106 107 def _check_thresholds(self) -> None: 108 assert ( 109 self._thresholds is not None and len(self._thresholds) >= 2 110 ), "Essential thresholds are not valid" 111 112 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 113 super(AssetRange, self).set_model(model) 114 self._thresholds = self._get_essential_thresholds() 115 self._check_thresholds() 116 117 def _get_outcomes_asset_range( 118 self, 119 ) -> list[Models.OptimalMergerPolicySummary]: 120 """ 121 Generates a list with all essential threshold concerning the assets of a start-up and an additional list with 122 summaries of the outcomes of the model in between the thresholds. 123 124 Returns 125 ------- 126 (list[Fumagalli_Motta_Tarantino_2020.FMT20.ThresholdItem], list[Fumagalli_Motta_Tarantino_2020.FMT20.OptimalMergerPolicySummary]) 127 List containing the essential asset thresholds in the model and list containing the summaries of the outcomes of the model. 128 """ 129 original_assets = self.model.startup_assets 130 summaries: list[Models.OptimalMergerPolicySummary] = [] 131 for i in range(len(self._thresholds) - 1): 132 self._set_model_startup_assets(self._thresholds[i], self._thresholds[i + 1]) 133 summaries.append(self.model.summary()) 134 self.model.startup_assets = original_assets 135 return summaries 136 137 def _set_model_startup_assets( 138 self, 139 lower_threshold: Models.ThresholdItem, 140 upper_threshold: Models.ThresholdItem, 141 ) -> None: 142 self.model.startup_assets = ( 143 self._get_inverse_asset_distribution_value(lower_threshold.value) 144 + self._get_inverse_asset_distribution_value(upper_threshold.value) 145 ) / 2 146 147 def _get_essential_thresholds(self) -> list[Models.ThresholdItem]: 148 """ 149 Generates a list with all essential threshold concerning the assets of a start-up. 150 151 Returns 152 ------- 153 list[Fumagalli_Motta_Tarantino_2020.FMT20.ThresholdItem] 154 List containing the essential asset thresholds in the model. 155 """ 156 thresholds = self._get_available_thresholds() 157 essential_thresholds: list[Models.ThresholdItem] = [] 158 for threshold in thresholds: 159 if self._valid_x_tick(threshold): 160 essential_thresholds.append(threshold) 161 thresholds = sorted(essential_thresholds, key=lambda x: x.value) 162 return thresholds 163 164 def _get_available_thresholds(self) -> list[Models.ThresholdItem]: 165 return [ 166 Models.ThresholdItem("$F(0)$", self._get_x_min(), include=True), 167 Models.ThresholdItem( 168 "$F(K)$", 169 self._get_x_max(), 170 include=True, 171 ), 172 Models.ThresholdItem( 173 "$\\Gamma$", self.model.asset_distribution_threshold_welfare 174 ), 175 Models.ThresholdItem( 176 "$\\Phi$", 177 self.model.asset_distribution_threshold_profitable_without_late_takeover, 178 ), 179 Models.ThresholdItem( 180 "$\\Phi^T$", self.model.asset_distribution_threshold_with_late_takeover 181 ), 182 Models.ThresholdItem( 183 "$\\Phi^{\\prime}$", 184 self.model.asset_distribution_threshold_unprofitable_without_late_takeover, 185 ), 186 Models.ThresholdItem("$F(\\bar{A})$", self.model.asset_threshold_cdf), 187 Models.ThresholdItem( 188 "$F(\\bar{A}^T)$", self.model.asset_threshold_late_takeover_cdf 189 ), 190 Models.ThresholdItem( 191 "$\\Lambda(\\cdot)$", 192 self.model.asset_distribution_threshold_shelving_approved, 193 ), 194 ] 195 196 def _get_x_labels_ticks(self) -> (list[float], list[str]): 197 """ 198 Generates the locations of the ticks on the x-axis and the corresponding labels on the x-axis. 199 200 Returns 201 ------- 202 (list[float], list[str]) 203 A list containing the ticks on the x-axis and a list containing the labels on the x-axis. 204 """ 205 x_ticks: list[float] = [] 206 x_labels: list[str] = [] 207 for threshold in self._thresholds: 208 x_ticks.append(threshold.value) 209 x_labels.append(threshold.name) 210 return x_ticks, x_labels 211 212 def _set_x_axis(self, **kwargs) -> None: 213 x_ticks, x_labels = self._get_x_labels_ticks() 214 self._set_x_locators(x_ticks) 215 self._set_x_labels(x_labels) 216 self._set_x_ticks() 217 self.ax.set_xlabel( 218 kwargs.get("x_label", "Cumulative Distribution Value of Assets $F(A)$") 219 ) 220 221 def _set_x_ticks(self) -> None: 222 self.ax.tick_params( 223 which="minor", 224 bottom=False, 225 top=True, 226 labelbottom=False, 227 labeltop=True, 228 axis="x", 229 pad=0, 230 ) 231 self.ax.tick_params(which="major", top=False, pad=3, axis="x") 232 self.ax.tick_params(which="both", length=2, axis="x") 233 234 def _set_x_labels(self, x_labels: list[str]) -> None: 235 self.ax.set_xticklabels(x_labels[::2], fontsize=IVisualize.fontsize) 236 self.ax.set_xticklabels( 237 x_labels[1::2], minor=True, fontsize=IVisualize.fontsize 238 ) 239 240 def _set_x_locators(self, x_ticks: list[float]) -> None: 241 self.ax.xaxis.set_major_locator(FixedLocator(x_ticks[::2])) 242 self.ax.xaxis.set_minor_locator(FixedLocator(x_ticks[1::2])) 243 244 def _draw_vertical_lines( 245 self, asset_thresholds: list[Models.ThresholdItem] 246 ) -> None: 247 for threshold in asset_thresholds: 248 if self._valid_x_tick(threshold) or threshold.include: 249 self.ax.axvline(threshold.value, linestyle=":", color="k", lw=0.5) 250 251 def _valid_x_tick(self, threshold): 252 return ( 253 self._get_x_min() < threshold.value < self._get_x_max() 254 ) or threshold.include 255 256 @staticmethod 257 def _get_y_ticks( 258 spacing: float, bar_height: float, y_labels: list[str] 259 ) -> list[float]: 260 return [(i + 1) * spacing + bar_height * i for i in range(len(y_labels))] 261 262 def _set_y_ticks(self, bar_height: float, spacing: float, y_labels: list[str]): 263 y_ticks = self._get_y_ticks(spacing, bar_height, y_labels) 264 self.ax.set_yticks(y_ticks) 265 self.ax.set_yticklabels(y_labels, fontsize=IVisualize.fontsize) 266 self.ax.yaxis.set_ticks_position("none") 267 268 def _get_label_color(self, label) -> (str, str, float): 269 """ 270 Returns the color and the final label for a legend entry. 271 272 Through this method, duplications in the legend are avoided. 273 274 Parameters 275 ---------- 276 label: str 277 278 Returns 279 ------- 280 (str, str, float) 281 String representing the final label, a string representing the color and a float representing the opacity. 282 """ 283 if label in self.labels: 284 return ( 285 "_nolegend_", 286 self.colors[label]["color"], 287 self.colors[label]["opacity"], 288 ) 289 self.colors[label] = self._get_label_specific_color(label) 290 self.labels.append(label) 291 return label, self.colors[label]["color"], self.colors[label]["opacity"] 292 293 def _get_label_specific_color(self, label: str) -> dict: 294 if label in self._label_colors.keys(): 295 return self._label_colors[label] 296 return {"color": IVisualize.COLORS[4], "opacity": 0.5} 297 298 def _get_summaries(self) -> list[list[Models.OptimalMergerPolicySummary]]: 299 return [self._get_outcomes_asset_range()] 300 301 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 302 """ 303 Plots the outcome of a model over a range of assets. 304 305 Example 306 ------- 307 ``` 308 import Fumagalli_Motta_Tarantino_2020 as FMT20 309 310 model = FMT20.OptimalMergerPolicy() 311 visualizer = FMT20.MergerPoliciesAssetRange(m) 312 fig, ax = visualizer.plot() 313 # use the figure and axes as you wish, for example: 314 fig.show() 315 ``` 316 317 Parameters 318 ---------- 319 **kwargs 320 Options for further customization of the plots. 321 - title(str): Title for plot<br> 322 - x_label(str): Title for x-axis.<br> 323 - y_label(str): Title for y-axis.<br> 324 - legend(bool): If true, a secondary legend is shown.<br> 325 - thresholds(bool): If true, the essential thresholds are shown.<br> 326 - optimal_policy(bool): If true, the optimal policy is shown. 327 - y_offset(int): Moves the threshold legend vertically. 328 329 Returns 330 ------- 331 Figure 332 Containing the axes with the plots (use Figure.show() to display). 333 Axes 334 Containing the plots (arrange custom summary). 335 """ 336 merger_policies_summaries = self._get_summaries() 337 assert merger_policies_summaries is not None 338 self._clear_legend_list() 339 bar_height, spacing, y_labels = self._draw_all_bars( 340 merger_policies_summaries, **kwargs 341 ) 342 self._set_asset_range_legends(**kwargs) 343 self._draw_vertical_lines(self._thresholds) 344 self._set_x_axis(**kwargs) 345 self._set_y_axis(bar_height, spacing, y_labels, **kwargs) 346 self.ax.set_title(kwargs.get("title", "Outcome dependent on Start-up Assets")) 347 self._set_tight_layout(y_spacing=spacing) 348 return self.fig, self.ax 349 350 def _set_y_axis(self, bar_height, spacing, y_labels, **kwargs): 351 self._set_y_ticks(bar_height, spacing, y_labels) 352 self.ax.set_ylabel(kwargs.get("y_label", "Merger Policy")) 353 354 def _set_asset_range_legends(self, **kwargs): 355 self._set_primary_legend(equal_opacity=False) 356 self._set_secondary_legend( 357 self._thresholds[0].value, kwargs.get("legend", True) 358 ) 359 self._set_threshold_legend( 360 kwargs.get("thresholds", False), 361 kwargs.get("optimal_policy", False), 362 kwargs.get("y_offset", 0), 363 ) 364 365 def _clear_legend_list(self) -> None: 366 self.labels.clear() 367 self.colors.clear() 368 369 def _draw_all_bars( 370 self, merger_policies_summaries, **kwargs 371 ) -> (float, float, list[str]): 372 spacing: float = kwargs.get("spacing", 0.1) 373 bar_height: float = kwargs.get("bar_height", 0.2) 374 y_labels: list[str] = [] 375 for number_merger_policy, summaries in enumerate(merger_policies_summaries): 376 y_labels.append(summaries[0].set_policy.abbreviation()) 377 for summary_index, summary in enumerate(summaries): 378 label: str = self._get_summary_latex(summary) 379 length: float = self._get_bar_length(summary_index) 380 y_coordinate = self._get_bar_y_coordinate( 381 bar_height, number_merger_policy, spacing 382 ) 383 self._draw_bar( 384 y_coordinate, 385 self._thresholds[summary_index].value, 386 bar_height, 387 length, 388 label, 389 ) 390 return bar_height, spacing, y_labels 391 392 def _get_bar_length(self, summary_index: int) -> float: 393 return ( 394 self._thresholds[summary_index + 1].value 395 - self._thresholds[summary_index].value 396 ) 397 398 @staticmethod 399 def _get_bar_y_coordinate( 400 bar_height: float, number_merger_policy: int, spacing: float 401 ) -> float: 402 return spacing * (number_merger_policy + 1) + bar_height * number_merger_policy 403 404 def _draw_bar( 405 self, 406 y_coordinate: float, 407 x_coordinate: float, 408 bar_height: float, 409 length: float, 410 label: str, 411 ) -> None: 412 label, color, opacity = self._get_label_color(label) 413 self.ax.barh( 414 y=y_coordinate, 415 width=length, 416 left=x_coordinate, 417 height=bar_height, 418 color=color, 419 label=label, 420 alpha=opacity, 421 ) 422 423 def _set_threshold_legend( 424 self, show_legend: bool, show_optimal_policy: bool, y_offset: int 425 ) -> None: 426 if show_legend: 427 x_coordinate = self._get_x_max() 428 y_coordinate = self._get_y_max() 429 self.ax.annotate( 430 self._get_model_characteristics( 431 separator="\n", 432 model_parameters=False, 433 thresholds_newline=False, 434 threshold_title="", 435 optimal_policy=show_optimal_policy, 436 ), 437 xy=(x_coordinate, y_coordinate), 438 xytext=(10, y_offset), 439 textcoords="offset points", 440 horizontalalignment="left", 441 verticalalignment="top", 442 fontsize=IVisualize.fontsize, 443 ) 444 445 @staticmethod 446 def _get_y_max() -> float: 447 return 1 448 449 def _get_x_max(self): 450 return self._get_asset_distribution_value(self.model.development_costs) 451 452 def _get_x_min(self): 453 return self._get_asset_distribution_value(0) 454 455 def _set_secondary_legend(self, x_coordinate: float, show_legend: bool) -> None: 456 if show_legend: 457 self.ax.annotate( 458 self._get_symbol_legend(), 459 xy=(x_coordinate, 0), 460 xytext=(0, -50), 461 textcoords="offset points", 462 horizontalalignment="left", 463 verticalalignment="top", 464 fontsize=IVisualize.fontsize, 465 )
Visualizes the outcomes over an assets range for a specific model.
19 def __init__(self, model: Models.OptimalMergerPolicy, **kwargs) -> None: 20 super(AssetRange, self).__init__(model, **kwargs) 21 self.labels: list[str] = [] 22 self.colors: dict[str, dict] = {} 23 self._thresholds: list[Models.ThresholdItem] = self._get_essential_thresholds() 24 self._check_thresholds() 25 self._label_colors: dict[str:dict] = self._init_label_colors()
Parameters
- model (Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy): Model to create the visualization from.
- ax (Optional[matplotlib.pyplot.Axes]): Axes used for the plot, if not specified, a new set of axes is generated.
- default_style (bool): If true, default matplotlib style is used.
- dark_mode: If true, dark mode is used.
- **kwargs: Arguments for the creation of a new figure.
67 @staticmethod 68 def plot_label_colors(show_plot=False) -> plt.Axes: 69 """ 70 Plots the colors used in the legend for asset ranges matched to the outcome. 71 72 Returns 73 ------- 74 plt.Axes 75 Axis containing the plot. 76 """ 77 label_colors = AssetRange._init_label_colors() 78 fig, ax = plt.subplots() 79 ax.set_axis_off() 80 height = 0.1 81 width = 0.1 82 ax.set_ylim(bottom=0, top=len(label_colors) * height) 83 ax.set_xlim(left=0, right=width * 1.05 + 0.02) 84 for i, label in enumerate(label_colors): 85 ax.text( 86 width * 1.1, 87 (i + 0.5) * height, 88 label, 89 horizontalalignment="left", 90 verticalalignment="center", 91 ) 92 93 ax.add_patch( 94 Rectangle( 95 xy=(0, i * height), 96 width=width, 97 height=height, 98 facecolor=label_colors[label]["color"], 99 alpha=label_colors[label]["opacity"], 100 ) 101 ) 102 fig.tight_layout() 103 if show_plot: 104 fig.show() 105 return ax
Plots the colors used in the legend for asset ranges matched to the outcome.
Returns
- plt.Axes: Axis containing the plot.
112 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 113 super(AssetRange, self).set_model(model) 114 self._thresholds = self._get_essential_thresholds() 115 self._check_thresholds()
Change the model for the visualization.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model_one = FMT20.OptimalMergerPolicy()
model_two = FMT20.OptimalMergerPolicy(development_success=False)
visualizer = FMT20.Overview(model_one)
visualizer.show()
# set the new model
visualizer.set_model(model_two)
# overwrite the previous plot
visualizer.show()
Parameters
- model (Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy): New model to generate the plots from.
301 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 302 """ 303 Plots the outcome of a model over a range of assets. 304 305 Example 306 ------- 307 ``` 308 import Fumagalli_Motta_Tarantino_2020 as FMT20 309 310 model = FMT20.OptimalMergerPolicy() 311 visualizer = FMT20.MergerPoliciesAssetRange(m) 312 fig, ax = visualizer.plot() 313 # use the figure and axes as you wish, for example: 314 fig.show() 315 ``` 316 317 Parameters 318 ---------- 319 **kwargs 320 Options for further customization of the plots. 321 - title(str): Title for plot<br> 322 - x_label(str): Title for x-axis.<br> 323 - y_label(str): Title for y-axis.<br> 324 - legend(bool): If true, a secondary legend is shown.<br> 325 - thresholds(bool): If true, the essential thresholds are shown.<br> 326 - optimal_policy(bool): If true, the optimal policy is shown. 327 - y_offset(int): Moves the threshold legend vertically. 328 329 Returns 330 ------- 331 Figure 332 Containing the axes with the plots (use Figure.show() to display). 333 Axes 334 Containing the plots (arrange custom summary). 335 """ 336 merger_policies_summaries = self._get_summaries() 337 assert merger_policies_summaries is not None 338 self._clear_legend_list() 339 bar_height, spacing, y_labels = self._draw_all_bars( 340 merger_policies_summaries, **kwargs 341 ) 342 self._set_asset_range_legends(**kwargs) 343 self._draw_vertical_lines(self._thresholds) 344 self._set_x_axis(**kwargs) 345 self._set_y_axis(bar_height, spacing, y_labels, **kwargs) 346 self.ax.set_title(kwargs.get("title", "Outcome dependent on Start-up Assets")) 347 self._set_tight_layout(y_spacing=spacing) 348 return self.fig, self.ax
Plots the outcome of a model over a range of assets.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model = FMT20.OptimalMergerPolicy()
visualizer = FMT20.MergerPoliciesAssetRange(m)
fig, ax = visualizer.plot()
# use the figure and axes as you wish, for example:
fig.show()
Parameters
- **kwargs: Options for further customization of the plots.
- title(str): Title for plot
- x_label(str): Title for x-axis.
- y_label(str): Title for y-axis.
- legend(bool): If true, a secondary legend is shown.
- thresholds(bool): If true, the essential thresholds are shown.
- optimal_policy(bool): If true, the optimal policy is shown.
- y_offset(int): Moves the threshold legend vertically.
- title(str): Title for plot
Returns
- Figure: Containing the axes with the plots (use Figure.show() to display).
- Axes: Containing the plots (arrange custom summary).
468class MergerPoliciesAssetRange(AssetRange): 469 def _get_outcomes_different_merger_policies( 470 self, 471 ) -> list[list[Models.OptimalMergerPolicySummary]]: 472 original_policy = self.model.merger_policy 473 outcomes: list[list[Models.OptimalMergerPolicySummary]] = [] 474 for merger_policy in Models.MergerPolicies: 475 try: 476 self.model.merger_policy = merger_policy 477 outcomes.append(self._get_outcomes_asset_range()) 478 except Models.Exceptions.MergerPolicyNotAvailable: 479 pass 480 self.model.merger_policy = original_policy 481 return outcomes 482 483 def _get_summaries(self) -> list[list[Models.OptimalMergerPolicySummary]]: 484 return self._get_outcomes_different_merger_policies()
Visualizes the outcomes over an assets range for a specific model.
487class MergerPoliciesAssetRangePerfectInformation(MergerPoliciesAssetRange): 488 def __init__(self, model: Models.PerfectInformation, **kwargs): 489 """ 490 Uses a Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation for the visualization. See 491 Fumagalli_Motta_Tarantino_2020.Models.Base.CoreModel for other parameters. 492 493 Parameters 494 ---------- 495 model: Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation 496 Model to create the visualization from. 497 """ 498 super(MergerPoliciesAssetRangePerfectInformation, self).__init__( 499 model, **kwargs 500 ) 501 502 def _get_available_thresholds(self) -> list[Models.ThresholdItem]: 503 return [ 504 Models.ThresholdItem("$0$", self._get_x_min(), include=True), 505 Models.ThresholdItem("$K$", self._get_x_max(), include=True), 506 Models.ThresholdItem("$\\bar{A}$", self.model.asset_threshold), 507 Models.ThresholdItem( 508 "$\\bar{A}^T$", self.model.asset_threshold_late_takeover 509 ), 510 ] 511 512 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 513 """ 514 Plots the visual representation for the object. 515 516 Example 517 ------- 518 ``` 519 import Fumagalli_Motta_Tarantino_2020 as FMT20 520 521 model = FMT20.PerfectInformation() 522 visualizer = FMT20.MergerPoliciesAssetRangePerfectInformation(m) 523 fig, ax = visualizer.plot() 524 # use the figure and axes as you wish, for example: 525 fig.show() 526 ``` 527 528 Parameters 529 ---------- 530 **kwargs 531 Options for further customization of the plots (see Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.AssetRange.plot). 532 533 Returns 534 ------- 535 Figure 536 Containing the axes with the plots (use Figure.show() to display). 537 Axes 538 Containing the plots (arrange custom summary). 539 """ 540 kwargs["x_label"] = kwargs.get("x_label", "Start-up Assets $A$") 541 return super(MergerPoliciesAssetRangePerfectInformation, self).plot(**kwargs) 542 543 def _set_model_startup_assets( 544 self, 545 lower_threshold: Models.ThresholdItem, 546 upper_threshold: Models.ThresholdItem, 547 ) -> None: 548 self.model.startup_assets = (lower_threshold.value + upper_threshold.value) / 2 549 550 @staticmethod 551 def _get_y_max() -> float: 552 return 0.55 553 554 def _get_x_max(self) -> float: 555 return self.model.development_costs 556 557 def _get_x_min(self) -> float: 558 return 0 559 560 def _get_model_characteristics_thresholds( 561 self, separator: str, newline: str 562 ) -> str: 563 return ( 564 f"$K = {self._round_floats(self.model.development_costs)}${separator}" 565 f"$\\bar{{A}} = {self._round_floats(self.model.asset_threshold)}${separator}" 566 f"$\\bar{{A}}^T = {self._round_floats(self.model.asset_threshold_late_takeover)}${separator}" 567 )
Visualizes the outcomes over an assets range for a specific model.
488 def __init__(self, model: Models.PerfectInformation, **kwargs): 489 """ 490 Uses a Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation for the visualization. See 491 Fumagalli_Motta_Tarantino_2020.Models.Base.CoreModel for other parameters. 492 493 Parameters 494 ---------- 495 model: Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation 496 Model to create the visualization from. 497 """ 498 super(MergerPoliciesAssetRangePerfectInformation, self).__init__( 499 model, **kwargs 500 )
Uses a Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation for the visualization. See Fumagalli_Motta_Tarantino_2020.Models.Base.CoreModel for other parameters.
Parameters
- model (Fumagalli_Motta_Tarantino_2020.Models.BaseExtended.PerfectInformation): Model to create the visualization from.
512 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 513 """ 514 Plots the visual representation for the object. 515 516 Example 517 ------- 518 ``` 519 import Fumagalli_Motta_Tarantino_2020 as FMT20 520 521 model = FMT20.PerfectInformation() 522 visualizer = FMT20.MergerPoliciesAssetRangePerfectInformation(m) 523 fig, ax = visualizer.plot() 524 # use the figure and axes as you wish, for example: 525 fig.show() 526 ``` 527 528 Parameters 529 ---------- 530 **kwargs 531 Options for further customization of the plots (see Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.AssetRange.plot). 532 533 Returns 534 ------- 535 Figure 536 Containing the axes with the plots (use Figure.show() to display). 537 Axes 538 Containing the plots (arrange custom summary). 539 """ 540 kwargs["x_label"] = kwargs.get("x_label", "Start-up Assets $A$") 541 return super(MergerPoliciesAssetRangePerfectInformation, self).plot(**kwargs)
Plots the visual representation for the object.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model = FMT20.PerfectInformation()
visualizer = FMT20.MergerPoliciesAssetRangePerfectInformation(m)
fig, ax = visualizer.plot()
# use the figure and axes as you wish, for example:
fig.show()
Parameters
- **kwargs: Options for further customization of the plots (see Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.AssetRange.plot).
Returns
- Figure: Containing the axes with the plots (use Figure.show() to display).
- Axes: Containing the plots (arrange custom summary).
570class Overview(IVisualize): 571 """ 572 Combines Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Timeline, Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Payoffs, 573 Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.MergerPoliciesAssetRange as well as a legend for the 574 model characteristics. 575 """ 576 577 def __init__(self, model: Models.OptimalMergerPolicy, figsize=(14, 10), **kwargs): 578 super().__init__(model, figsize=figsize, constrained_layout=True, **kwargs) 579 self.timeline: Optional[IVisualize] = None 580 self.payoffs: Optional[IVisualize] = None 581 self.range: Optional[IVisualize] = None 582 self.kwargs = kwargs 583 self._clear_main_axes() 584 585 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 586 assert ( 587 self.timeline is not None 588 and self.payoffs is not None 589 and self.range is not None 590 ) 591 super(Overview, self).set_model(model) 592 self.timeline.set_model(model) 593 self.payoffs.set_model(model) 594 self.range.set_model(model) 595 self.fig.clear() 596 597 @staticmethod 598 def _clear_main_axes() -> None: 599 plt.axis("off") 600 601 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 602 """ 603 Plots the visual representation for the object. 604 605 Example 606 ------- 607 ``` 608 import Fumagalli_Motta_Tarantino_2020 as FMT20 609 610 model = FMT20.OptimalMergerPolicy() 611 visualizer = FMT20.Overview(m) 612 fig, ax = visualizer.plot() 613 # use the figure and axes as you wish, for example: 614 fig.show() 615 ``` 616 617 Parameters 618 ---------- 619 **kwargs 620 Options for further customization of the plots (Note: all subplots use the same kwargs). 621 - figure_title(str): Title for plot.<br> 622 - fontsize(int): Fontsize for model characteristics.<br> 623 - model_thresholds(bool): If true, the essential thresholds are shown in model characteristics.<br> 624 $\\Rightarrow$ see the included visualizations for further arguments. 625 626 Returns 627 ------- 628 Figure 629 Containing the axes with the plots (use Figure.show() to display). 630 Axes 631 Containing the plots (arrange custom summary). 632 """ 633 spec = self.fig.add_gridspec(ncols=2, nrows=2) 634 self._set_fig_title(**kwargs) 635 self.timeline = self._generate_visualizer(spec[1, 0], Timeline, **kwargs) 636 self.payoffs = self._generate_visualizer(spec[0, 1], Payoffs, **kwargs) 637 self.range = self._generate_visualizer( 638 spec[1, 1], self._get_merger_policy_asset_range_type(), **kwargs 639 ) 640 self._generate_characteristics_ax(spec[0, 0], **kwargs) 641 return self.fig, self.ax 642 643 def _set_fig_title(self, **kwargs): 644 self.fig.suptitle( 645 kwargs.get("figure_title", "Model Overview"), 646 fontsize=18, 647 ) 648 649 def _get_merger_policy_asset_range_type(self) -> Callable: 650 return ( 651 MergerPoliciesAssetRangePerfectInformation 652 if type(self.model) is Models.PerfectInformation 653 else MergerPoliciesAssetRange 654 ) 655 656 def _generate_characteristics_ax( 657 self, coordinates: matplotlib.gridspec.GridSpec, **kwargs 658 ) -> None: 659 ax = self.fig.add_subplot(coordinates) 660 characteristics_kwargs = deepcopy(kwargs) 661 characteristics_kwargs["model_thresholds"] = characteristics_kwargs.get( 662 "model_thresholds", not characteristics_kwargs.get("thresholds", False) 663 ) 664 characteristics_kwargs["optimal_policy"] = False 665 self._get_model_characteristics_ax(ax, **characteristics_kwargs) 666 667 def _generate_visualizer( 668 self, coordinates: matplotlib.gridspec.GridSpec, visualizer: Callable, **kwargs 669 ) -> IVisualize: 670 ax = self.fig.add_subplot(coordinates) 671 visualization: IVisualize = visualizer(self.model, ax=ax, **self.kwargs) 672 visualization.plot(legend=False, parameters=False, **kwargs) 673 return visualization
Combines Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Timeline, Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize.Payoffs, Fumagalli_Motta_Tarantino_2020.Visualizations.VisualizeRanges.MergerPoliciesAssetRange as well as a legend for the model characteristics.
577 def __init__(self, model: Models.OptimalMergerPolicy, figsize=(14, 10), **kwargs): 578 super().__init__(model, figsize=figsize, constrained_layout=True, **kwargs) 579 self.timeline: Optional[IVisualize] = None 580 self.payoffs: Optional[IVisualize] = None 581 self.range: Optional[IVisualize] = None 582 self.kwargs = kwargs 583 self._clear_main_axes()
Parameters
- model (Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy): Model to create the visualization from.
- ax (Optional[matplotlib.pyplot.Axes]): Axes used for the plot, if not specified, a new set of axes is generated.
- default_style (bool): If true, default matplotlib style is used.
- dark_mode: If true, dark mode is used.
- **kwargs: Arguments for the creation of a new figure.
585 def set_model(self, model: Models.OptimalMergerPolicy) -> None: 586 assert ( 587 self.timeline is not None 588 and self.payoffs is not None 589 and self.range is not None 590 ) 591 super(Overview, self).set_model(model) 592 self.timeline.set_model(model) 593 self.payoffs.set_model(model) 594 self.range.set_model(model) 595 self.fig.clear()
Change the model for the visualization.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model_one = FMT20.OptimalMergerPolicy()
model_two = FMT20.OptimalMergerPolicy(development_success=False)
visualizer = FMT20.Overview(model_one)
visualizer.show()
# set the new model
visualizer.set_model(model_two)
# overwrite the previous plot
visualizer.show()
Parameters
- model (Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy): New model to generate the plots from.
601 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 602 """ 603 Plots the visual representation for the object. 604 605 Example 606 ------- 607 ``` 608 import Fumagalli_Motta_Tarantino_2020 as FMT20 609 610 model = FMT20.OptimalMergerPolicy() 611 visualizer = FMT20.Overview(m) 612 fig, ax = visualizer.plot() 613 # use the figure and axes as you wish, for example: 614 fig.show() 615 ``` 616 617 Parameters 618 ---------- 619 **kwargs 620 Options for further customization of the plots (Note: all subplots use the same kwargs). 621 - figure_title(str): Title for plot.<br> 622 - fontsize(int): Fontsize for model characteristics.<br> 623 - model_thresholds(bool): If true, the essential thresholds are shown in model characteristics.<br> 624 $\\Rightarrow$ see the included visualizations for further arguments. 625 626 Returns 627 ------- 628 Figure 629 Containing the axes with the plots (use Figure.show() to display). 630 Axes 631 Containing the plots (arrange custom summary). 632 """ 633 spec = self.fig.add_gridspec(ncols=2, nrows=2) 634 self._set_fig_title(**kwargs) 635 self.timeline = self._generate_visualizer(spec[1, 0], Timeline, **kwargs) 636 self.payoffs = self._generate_visualizer(spec[0, 1], Payoffs, **kwargs) 637 self.range = self._generate_visualizer( 638 spec[1, 1], self._get_merger_policy_asset_range_type(), **kwargs 639 ) 640 self._generate_characteristics_ax(spec[0, 0], **kwargs) 641 return self.fig, self.ax
Plots the visual representation for the object.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model = FMT20.OptimalMergerPolicy()
visualizer = FMT20.Overview(m)
fig, ax = visualizer.plot()
# use the figure and axes as you wish, for example:
fig.show()
Parameters
- **kwargs: Options for further customization of the plots (Note: all subplots use the same kwargs).
- figure_title(str): Title for plot.
- fontsize(int): Fontsize for model characteristics.
- model_thresholds(bool): If true, the essential thresholds are shown in model characteristics.
$\Rightarrow$ see the included visualizations for further arguments.
- figure_title(str): Title for plot.
Returns
- Figure: Containing the axes with the plots (use Figure.show() to display).
- Axes: Containing the plots (arrange custom summary).