Fumagalli_Motta_Tarantino_2020.Visualizations.Visualize
1from abc import abstractmethod 2from typing import Final, Optional 3import warnings 4 5import math 6import numpy as np 7import matplotlib.pyplot as plt 8 9import Fumagalli_Motta_Tarantino_2020.Models as FMT20 10 11 12class IVisualize: 13 """ 14 Interface for all visualization classes containing useful methods. 15 16 Notes 17 ----- 18 This module is compatible with python versions starting from 3.9, due to introduction of PEP 585. Therefore, the compatibility 19 with mybinder.org is not guaranteed (uses python 3.7 at the moment ). 20 """ 21 22 COLORS: Final[list[str]] = ["salmon", "gold", "lawngreen", "turquoise", "thistle"] 23 """Standard colors used in visualizations.""" 24 fontsize = "x-small" 25 """Default font size for all plots.""" 26 27 def __init__( 28 self, 29 model: FMT20.OptimalMergerPolicy, 30 ax: Optional[plt.Axes] = None, 31 default_style=True, 32 dark_mode=False, 33 **kwargs, 34 ): 35 """ 36 Parameters 37 ---------- 38 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 39 Model to create the visualization from. 40 ax: Optional[matplotlib.pyplot.Axes] 41 Axes used for the plot, if not specified, a new set of axes is generated. 42 default_style: bool 43 If true, default matplotlib style is used. 44 dark_mode 45 If true, dark mode is used. 46 **kwargs 47 Arguments for the creation of a new figure. 48 """ 49 self._set_mode(default_style, dark_mode) 50 self.model: FMT20.OptimalMergerPolicy = model 51 self._set_axes(ax, **kwargs) 52 warnings.filterwarnings("ignore") 53 54 def _set_axes(self, ax, **kwargs) -> None: 55 if ax is None: 56 self.fig, self.ax = plt.subplots(**kwargs) 57 else: 58 self.ax = ax 59 self.fig = self.ax.get_figure() 60 self.ax.patch.set_alpha(0) 61 62 def _set_mode(self, default_style: bool, dark_mode: bool) -> None: 63 if dark_mode: 64 self._set_dark_mode() 65 else: 66 self._set_light_mode(default_style) 67 68 @staticmethod 69 def _set_dark_mode() -> None: 70 plt.style.use("dark_background") 71 72 @staticmethod 73 def _set_light_mode(default_style=False) -> None: 74 if ("science" in plt.style.available) and not default_style: 75 plt.style.use("science") 76 else: 77 plt.style.use("default") 78 79 def set_model(self, model: FMT20.OptimalMergerPolicy) -> None: 80 """ 81 Change the model for the visualization. 82 83 Example 84 ------- 85 ```python 86 import Fumagalli_Motta_Tarantino_2020 as FMT20 87 88 model_one = FMT20.OptimalMergerPolicy() 89 model_two = FMT20.OptimalMergerPolicy(development_success=False) 90 visualizer = FMT20.Overview(model_one) 91 visualizer.show() 92 # set the new model 93 visualizer.set_model(model_two) 94 # overwrite the previous plot 95 visualizer.show() 96 ``` 97 98 Parameters 99 ---------- 100 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 101 New model to generate the plots from. 102 """ 103 self.model = model 104 self.ax.clear() 105 self._reset_legend() 106 self._set_axes(self.ax) 107 108 def _reset_legend(self) -> None: 109 try: 110 self.ax.get_legend().remove() 111 except AttributeError: 112 pass 113 114 def _set_primary_legend(self, equal_opacity=True) -> None: 115 legend: plt.legend = self.ax.legend( 116 bbox_to_anchor=(1.02, 1), loc="upper left", borderaxespad=0, framealpha=0 117 ) 118 if equal_opacity: 119 for entry in legend.legend_handles: 120 entry.set_alpha(1) 121 122 def _set_tight_layout(self, y_spacing: float = None, x_spacing: float = 0) -> None: 123 if y_spacing is not None or x_spacing is not None: 124 self.ax.margins(y=y_spacing, x=x_spacing) 125 self.fig.tight_layout() 126 127 @abstractmethod 128 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 129 """ 130 Plots the visual representation for the object. 131 132 Example 133 ------- 134 ``` 135 import Fumagalli_Motta_Tarantino_2020 as FMT20 136 137 model = FMT20.OptimalMergerPolicy() 138 visualizer = FMT20.MergerPoliciesAssetRange(m) 139 fig, ax = visualizer.plot() 140 # use the figure and axes as you wish, for example: 141 fig.show() 142 ``` 143 144 Parameters 145 ---------- 146 **kwargs 147 Options for further customization of the plots . 148 149 Returns 150 ------- 151 Figure 152 Containing the axes with the plots (use Figure.show() to display). 153 Axes 154 Containing the plots (arrange custom summary). 155 """ 156 raise NotImplementedError 157 158 def show(self, **kwargs) -> None: 159 """ 160 Shows the visual representation for the object. 161 162 Example 163 ------- 164 ``` 165 model = Models.OptimalMergerPolicy() 166 visualizer = MergerPoliciesAssetRange(m) 167 visualizer.show() 168 ``` 169 170 Parameters 171 ---------- 172 **kwargs 173 Same options as Fumagalli_Motta_Tarantino_2020.Visualize.IVisualize.plot. 174 """ 175 self.plot(**kwargs) 176 self.fig.show() 177 178 @staticmethod 179 def get_model_label(m: type(FMT20.OptimalMergerPolicy)) -> str: 180 """ 181 Returns a label for a given model extending Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy. 182 183 Parameters 184 ---------- 185 m: type(FMT20.OptimalMergerPolicy) 186 Type of the model 187 """ 188 189 def _check_type(model_to_check, type_to_check): 190 return ( 191 isinstance(model_to_check, type_to_check) 192 or model_to_check == type_to_check 193 ) 194 195 if _check_type(m, FMT20.OptimalMergerPolicy): 196 return "Optimal Merger Policy" 197 if _check_type(m, FMT20.ProCompetitive): 198 return "Pro-Competitive" 199 if _check_type(m, FMT20.ResourceWaste): 200 return "Resource Waste" 201 if _check_type(m, FMT20.PerfectInformation): 202 return "Perfect Information" 203 if _check_type(m, FMT20.CournotCompetition): 204 return "Cournot Competition" 205 if _check_type(m, FMT20.EquityContract): 206 return "Equity Contract" 207 208 def _get_parameter_legend(self, **kwargs) -> str: 209 """ 210 Generates a legend for the parameter values of a Fumagalli_Motta_Tarantino_2020.Models.BaseModel in latex format. 211 212 Returns 213 ------- 214 str 215 Containing the legend for the parameter values. 216 """ 217 separator_name_value = "=" 218 separator_parameters = kwargs.get("separator", " ; ") 219 output_str = "" 220 counter = 2 221 number_parameters_per_line = kwargs.get("parameter_number", 6) 222 for parameter, value in [ 223 ("A", self.model.startup_assets), 224 ("B", self.model.private_benefit), 225 ("K", self.model.development_costs), 226 ("p", self.model.success_probability), 227 ("CS^m", self.model.cs_without_innovation), 228 ("\\pi^m_I", self.model.incumbent_profit_without_innovation), 229 ("CS^M", self.model.cs_with_innovation), 230 ("\\pi^M_I", self.model.incumbent_profit_with_innovation), 231 ("CS^d", self.model.cs_duopoly), 232 ("\\pi^d_I", self.model.incumbent_profit_duopoly), 233 ("\\pi^d_S", self.model.startup_profit_duopoly), 234 ]: 235 separator = ( 236 "" 237 if counter == 12 238 else ( 239 "\n" 240 if counter % number_parameters_per_line == 0 241 else separator_parameters 242 ) 243 ) 244 output_str += f"${parameter}{separator_name_value}{round(value, ndigits=3)}${separator}" 245 counter += 1 246 return output_str 247 248 @staticmethod 249 def _get_summary_latex(summary: FMT20.Outcome) -> str: 250 """ 251 Generates a chronological entry for the legend based on the input model. 252 253 Returns 254 ------- 255 str 256 Chronological entry for the legend of the input model. 257 """ 258 separator: str = "$\\to$" 259 return ( 260 f"{summary.early_bidding_type.abbreviation()}" 261 f"{IVisualize._get_takeover_legend(summary.early_bidding_type, summary.early_takeover)}{separator}" 262 f"{IVisualize._get_development_attempt_legend(summary.development_attempt)}" 263 f"{IVisualize._get_development_outcome_legend(summary.development_attempt, summary.development_outcome)}{separator}" 264 f"{summary.late_bidding_type.abbreviation()}" 265 f"{IVisualize._get_takeover_legend(summary.late_bidding_type, summary.late_takeover)}" 266 ) 267 268 @staticmethod 269 def _get_takeover_legend(bid_attempt: FMT20.Takeover, is_takeover: bool) -> str: 270 """ 271 Generates a string representation for legend about the takeover (option and approval). 272 273 Parameters 274 ---------- 275 bid_attempt: Fumagalli_Motta_Tarantino_2020.FMT20.Takeover 276 Option for takeover chosen by the incumbent. 277 is_takeover: bool 278 If true, the takeover is approved by AA and the start-up. 279 280 Returns 281 ------- 282 str 283 String representation for legend about takeover (option and approval). 284 """ 285 if bid_attempt is FMT20.Takeover.No: 286 return "" 287 return "$(\\checkmark)$" if is_takeover else "$(\\times)$" 288 289 @staticmethod 290 def _get_development_attempt_legend(is_developing: bool) -> str: 291 """ 292 Generates a string representation for legend about the development attempt. 293 294 Parameters 295 ---------- 296 is_developing: bool 297 True, if the owner is developing the product (otherwise, the product is shelved). 298 299 Returns 300 ------- 301 str 302 String representation for legend about the development attempt. 303 """ 304 return "" if is_developing else "$\\emptyset$" 305 306 @staticmethod 307 def _get_development_outcome_legend( 308 is_developing: bool, is_successful: bool 309 ) -> str: 310 """ 311 Generates a string representation for legend about the development outcome. 312 313 Parameters 314 ---------- 315 is_developing: bool 316 True, if the owner is developing the product (otherwise, the product is shelved). 317 is_successful: bool 318 True, if the development of the product is successful. 319 320 Returns 321 ------- 322 str 323 String representation for legend about the development outcome. 324 """ 325 if is_developing: 326 return "$\\checkmark$" if is_successful else "$\\times$" 327 return "" 328 329 @staticmethod 330 def _get_symbol_legend() -> str: 331 """ 332 Generates a legend for the used abbreviations in the plot legends. 333 334 Returns 335 ------- 336 str 337 Containing the legend for the used abbreviations. 338 """ 339 return ( 340 "${\\bf Merger\\thickspace policies}$:\n" 341 f"{FMT20.MergerPolicies.legend()}\n" 342 "${\\bf Bidding\\thickspace types}$:\n" 343 f"{FMT20.Takeover.legend()}\n" 344 "${\\bf Takeover\\thickspace outcome\\thickspace}$:\n" 345 f"{FMT20.Takeover.Pooling.abbreviation()}|{FMT20.Takeover.Separating.abbreviation()}$(\\checkmark)$: Takeover is approved by the startup and AA\n" 346 f"{FMT20.Takeover.Pooling.abbreviation()}|{FMT20.Takeover.Separating.abbreviation()}$(\\times)$: Takeover is blocked by AA or not accepted by the startup\n" 347 "${\\bf Development\\thickspace outcome}$:\n" 348 f"$\\emptyset$: Product development was shelved\n" 349 f"$\\checkmark$: Product development was attempted and successful\n" 350 f"$\\times$: Product development was attempted and not successful\n" 351 ) 352 353 @staticmethod 354 def _get_payoff_legend(market_situations_only=False) -> str: 355 payoff_str = ( 356 "$\\pi_S$: Profit of the start-up\n" 357 "$\\pi_I$: Profit of the incumbent\n" 358 "$CS$: Consumer surplus\n" 359 "$W$: Total welfare\n" 360 if not market_situations_only 361 else "" 362 ) 363 return ( 364 "${\\bf Market\\thickspace configurations}$\n" 365 f"{payoff_str}" 366 "$m$: Monopoly without the innovation\n" 367 "$M$: Monopoly (innovation in possession of incumbent)\n" 368 "$d$: Duopoly (requires successful development by the start-up)\n" 369 ) 370 371 def _get_model_characteristics( 372 self, 373 separator=" ; ", 374 model_parameters=True, 375 model_thresholds=True, 376 thresholds_newline=True, 377 optimal_policy=False, 378 **kwargs, 379 ) -> str: 380 newline = "\n" if thresholds_newline else separator 381 parameter_text = ( 382 f"${{\\bf Parameters}}$\n{self._get_parameter_legend(separator=separator, **kwargs)}\n" 383 if model_parameters 384 else "" 385 ) 386 threshold_title = kwargs.get( 387 "threshold_title", 388 "Thresholds\\thickspace for\\thickspace the\\thickspace Start-up\\thickspace Assets", 389 ) 390 thresholds = ( 391 f"${{\\bf {threshold_title}}}$\n" 392 f"{self._get_model_characteristics_thresholds(separator, newline)}" 393 if model_thresholds 394 else "" 395 ) 396 optimal = ( 397 f"Optimal policy: {self.model.get_optimal_merger_policy().abbreviation()}\n" 398 if optimal_policy 399 else "" 400 ) 401 return f"{parameter_text}{thresholds}{optimal}" 402 403 def _get_model_characteristics_thresholds( 404 self, separator: str, newline: str 405 ) -> str: 406 return ( 407 f"$F(0) = {self._round_floats(self._get_asset_distribution_value(0))}${separator}" 408 f"$F(K) = {self._round_floats(self._get_asset_distribution_value(self.model.development_costs))}${separator}" 409 f"$F(\\bar{{A}}) = {self._round_floats(self.model.asset_threshold_cdf)}${separator}" 410 f"$F(\\bar{{A}}^T) = {self._round_floats(self.model.asset_threshold_late_takeover_cdf)}${newline}" 411 f"$\\Gamma(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_welfare)}${separator}" 412 f"$\\Phi(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_profitable_without_late_takeover)}${separator}" 413 f"$\\Phi'(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_unprofitable_without_late_takeover)}${separator}" 414 f"$\\Phi^T(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_with_late_takeover)}${separator}" 415 f"$\\Lambda(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_shelving_approved)}$\n" 416 ) 417 418 def _get_asset_distribution_value(self, value: float) -> float: 419 return self.model.asset_distribution.cumulative( 420 value, **self.model.asset_distribution_kwargs 421 ) 422 423 def _get_inverse_asset_distribution_value(self, value: float) -> float: 424 return self.model.asset_distribution.inverse_cumulative( 425 value, **self.model.asset_distribution_kwargs 426 ) 427 428 @staticmethod 429 def _round_floats(value: float, digits=3) -> str: 430 return f"{value:.{digits}f}" 431 432 def _get_model_characteristics_ax(self, ax: plt.Axes, **kwargs) -> None: 433 ax.set_title(kwargs.get("title", "Model Characteristics")) 434 ax.axis("off") 435 model_characteristics = self._get_model_characteristics(**kwargs) 436 text_to_annotate = ( 437 f"{model_characteristics}" 438 f"{self._get_payoff_legend(market_situations_only=True)}" 439 f"{self._get_symbol_legend()}" 440 ) 441 ax.annotate( 442 text_to_annotate, 443 xy=(0.5, 1), 444 xytext=(0, 0), 445 textcoords="offset points", 446 horizontalalignment="center", 447 verticalalignment="top", 448 fontsize=kwargs.get("fontsize", IVisualize.fontsize), 449 ) 450 451 452class Timeline(IVisualize): 453 """ 454 Visualizes the timeline of events for a specific model. 455 """ 456 457 def __init__(self, model: FMT20.OptimalMergerPolicy, **kwargs): 458 super(Timeline, self).__init__(model, **kwargs) 459 self.high_stem = 0.6 460 self.low_stem = 0.3 461 self.stem_levels = [ 462 -self.high_stem, 463 self.high_stem, 464 self.low_stem, 465 -self.high_stem, 466 self.high_stem, 467 -self.high_stem, 468 -self.low_stem, 469 self.high_stem, 470 ] 471 self._x_ticks = list(range(len(self.stem_levels))) 472 473 def _get_stem_labels(self) -> list[str]: 474 """ 475 Generates the label and points in time of the events in the model. 476 477 Returns 478 ------- 479 (list[str], list[str]) 480 List containing label for the events and list containing the points in time of the events. 481 """ 482 ( 483 earl_takeover_attempt, 484 early_takeover, 485 late_takeover_attempt, 486 late_takeover, 487 ) = self._get_takeover_labels() 488 return [ 489 "Competition authority\nestablishes " 490 + self._policy_label() 491 + "\nmerger policy", 492 earl_takeover_attempt, 493 early_takeover, 494 self._development_label(), 495 self._success_str(), 496 late_takeover_attempt, 497 late_takeover, 498 self._get_payoff_label(), 499 ] 500 501 def _get_payoff_label(self): 502 label = "Payoffs\n" 503 if self.model.is_early_takeover or self.model.is_late_takeover: 504 if self.model.is_development_successful: 505 return label + "($CS^M$, $\\pi^M_I$)" 506 return label + "($CS^m$, $\\pi^m_I$)" 507 return label + "($CS^d$, $\\pi^d_I$, $\\pi^d_S$)" 508 509 def _get_takeover_labels(self) -> list[str, str, str, str]: 510 if self.model.is_early_takeover: 511 late_takeover_attempt = "Start-up already\nacquired" 512 late_takeover = "" 513 self.stem_levels[5] = -self.low_stem 514 self.stem_levels[6] = 0 515 elif self.model.merger_policy in [ 516 FMT20.MergerPolicies.Strict, 517 FMT20.MergerPolicies.Intermediate_late_takeover_prohibited, 518 ]: 519 late_takeover_attempt = "Competition authority\nblocks late\ntakeovers" 520 late_takeover = "" 521 self.stem_levels[5] = -self.low_stem 522 self.stem_levels[6] = 0 523 else: 524 late_takeover_attempt = self._takeover_attempt_label( 525 self.model.late_bidding_type 526 ) 527 late_takeover = self._takeover_label( 528 self.model.late_bidding_type, self.model.is_late_takeover 529 ) 530 531 return [ 532 self._takeover_attempt_label(self.model.early_bidding_type), 533 self._takeover_label( 534 self.model.early_bidding_type, self.model.is_early_takeover 535 ), 536 late_takeover_attempt, 537 late_takeover, 538 ] 539 540 @staticmethod 541 def _get_x_labels() -> list[str]: 542 return [ 543 "t=0", 544 "t=1a", 545 "t=1b", 546 "t=1c", 547 "t=1d", 548 "t=2a", 549 "t=2b", 550 "t=3", 551 ] 552 553 @staticmethod 554 def _takeover_attempt_label(takeover: FMT20.Takeover) -> str: 555 """ 556 Generate label for takeover event. 557 558 Parameters 559 ---------- 560 takeover: Fumagalli_Motta_Tarantino_2020.FMT20.Takeover 561 Option for takeover chosen by the incumbent. 562 563 Returns 564 ------- 565 str 566 Label for takeover event. 567 """ 568 return str(takeover) + "\nby incumbent" 569 570 def _policy_label(self) -> str: 571 """ 572 Generate label for establishing of merger policy event. 573 574 Returns 575 ------- 576 str 577 Label for establishing of merger policy event. 578 """ 579 policy_str = str(self.model.merger_policy).lower() 580 if "intermediate" in policy_str: 581 return policy_str.replace("intermediate", "intermediate\n") 582 return policy_str 583 584 @staticmethod 585 def _takeover_label( 586 takeover_attempt: FMT20.Takeover, is_takeover_accepted: bool 587 ) -> str: 588 """ 589 Generates a label about the takeover event (option and approval). 590 591 Parameters 592 ---------- 593 takeover_attempt: FMT20.Takeover 594 Type of the bid by the incumbent. 595 is_takeover_accepted: bool 596 If true, the takeover is approved by AA and the start-up. 597 598 Returns 599 ------- 600 str 601 Label about the takeover event (option and approval). 602 """ 603 is_takeover_attempt = takeover_attempt is not FMT20.Takeover.No 604 if is_takeover_attempt and is_takeover_accepted: 605 return "Takeover\napproved" 606 if is_takeover_attempt and not is_takeover_accepted: 607 return "Takeover rejected\nby start-up" 608 return "No takeover\noccurs" 609 610 def _development_label(self) -> str: 611 """ 612 Generates a label about the development event (attempt and shelving). 613 614 Returns 615 ------- 616 str 617 Label about the development event (attempt and shelving). 618 """ 619 if self.model.is_early_takeover: 620 return ( 621 "Incumbent\n" 622 + ("develops" if self.model.is_owner_investing else "shelves") 623 + " product" 624 + "\n(killer acquisition)" 625 if self.model.is_killer_acquisition() 626 else "" 627 ) 628 return ( 629 "Start-up" 630 + ("" if self.model.is_owner_investing else " does not") 631 + "\nobtain" 632 + ("s" if self.model.is_owner_investing else "") 633 + " enough\nfinancial assets" 634 ) 635 636 def _success_str(self) -> str: 637 """ 638 Generates a label about the development outcome event. 639 640 Returns 641 ------- 642 str 643 Label about the development outcome event. 644 """ 645 if self.model.is_owner_investing: 646 if self.model.is_development_successful: 647 return "Development is\nsuccessful" 648 return "Development is\nnot successful" 649 return "Development was\nnot attempted." 650 651 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 652 """ 653 Plots the visual representation for the object. 654 655 Example 656 ------- 657 ``` 658 import Fumagalli_Motta_Tarantino_2020 as FMT20 659 660 model = FMT20.OptimalMergerPolicy() 661 visualizer = FMT20.Timeline(m) 662 fig, ax = visualizer.plot() 663 # use the figure and axes as you wish, for example: 664 fig.show() 665 ``` 666 667 Parameters 668 ---------- 669 **kwargs 670 Options for further customization of the plots. 671 - title(str): Title for timeline<br> 672 - parameters(bool): If true, a legend containing the parameters is shown. 673 - x_offset(int): Moves the text at the stems horizontally. 674 675 Returns 676 ------- 677 Figure 678 Containing the axes with the plots (use Figure.show() to display). 679 Axes 680 Containing the plots (arrange custom summary). 681 """ 682 self.ax.set(title=kwargs.get("title", "Timeline")) 683 self._set_parameter_legend(kwargs.get("parameters", True)) 684 self._draw_timeline(**kwargs) 685 self._set_x_axis() 686 self._set_y_axis() 687 self._set_tight_layout(y_spacing=0.45, x_spacing=0.02) 688 return self.fig, self.ax 689 690 def _draw_timeline(self, **kwargs): 691 self._annotate_stems(kwargs.get("x_offset", 0)) 692 self._draw_vertical_stems() 693 self._draw_baseline() 694 695 def _annotate_stems( 696 self, 697 x_offset: int, 698 ) -> None: 699 for d, l, r in zip(self._x_ticks, self.stem_levels, self._get_stem_labels()): 700 self.ax.annotate( 701 str(r), 702 xy=(d, l), 703 xytext=(x_offset, np.sign(l) * 8), 704 textcoords="offset points", 705 horizontalalignment="center", 706 verticalalignment="bottom" if l > 0 else "top", 707 fontsize=IVisualize.fontsize, 708 ) 709 710 def _draw_vertical_stems(self) -> None: 711 self.ax.vlines( 712 self._x_ticks, 0, self.stem_levels, color="lightgray", linewidths=1 713 ) 714 715 def _draw_baseline(self) -> None: 716 self.ax.plot( 717 self._x_ticks, 718 np.zeros_like(self._x_ticks), 719 "-o", 720 color="k", 721 markerfacecolor="w", 722 ) 723 724 def _set_x_axis(self) -> None: 725 self.ax.set_xticks(self._x_ticks) 726 self.ax.set_xticklabels(self._get_x_labels()) 727 self.ax.xaxis.set_ticks_position("bottom") 728 729 def _set_y_axis(self) -> None: 730 self.ax.yaxis.set_visible(False) 731 self.ax.spines[["left", "top", "right"]].set_visible(False) 732 733 def _set_parameter_legend(self, show_parameters: bool) -> None: 734 x_coordinate = math.fsum(self._x_ticks) / len(self._x_ticks) 735 if show_parameters: 736 self.ax.annotate( 737 self._get_parameter_legend(), 738 xy=(x_coordinate, self.high_stem * 1.8), 739 horizontalalignment="center", 740 verticalalignment="top", 741 fontsize=IVisualize.fontsize, 742 ) 743 744 745class Payoffs(IVisualize): 746 """ 747 Visualizes the payoffs for a specific model. 748 """ 749 750 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 751 """ 752 Plots the visual representation for the object. 753 754 Example 755 ------- 756 ``` 757 import Fumagalli_Motta_Tarantino_2020 as FMT20 758 759 model = FMT20.OptimalMergerPolicy() 760 visualizer = FMT20.Payoffs(m) 761 fig, ax = visualizer.plot() 762 # use the figure and axes as you wish, for example: 763 fig.show() 764 ``` 765 766 Parameters 767 ---------- 768 **kwargs 769 Options for further customization of the plots. 770 - title(str): Title for plot<br> 771 - legend(bool): If true, a secondary legend is shown.<br> 772 - width(float): Width of the bars.<br> 773 - spacing(float): Spacing between the bars.<br> 774 - max_opacity(float): Opacity of the optimal payoffs.<br> 775 - min_opacity(float): Opacity of the not optimal payoffs.<br> 776 777 Returns 778 ------- 779 Figure 780 Containing the axes with the plots (use Figure.show() to display). 781 Axes 782 Containing the plots (arrange custom summary). 783 """ 784 payoffs: dict[str, float] = self._get_payoffs() 785 bar_width = kwargs.get("width", 0.35) 786 spacing = kwargs.get("spacing", 0.05) 787 self._plot_payoffs_bars(payoffs, bar_width, spacing, **kwargs) 788 self.ax.set_title( 789 kwargs.get("title", "Payoffs for different Market Configurations") 790 ) 791 self._set_primary_legend() 792 self._set_secondary_legend(bar_width, kwargs.get("legend", True)) 793 self._set_tight_layout(x_spacing=spacing) 794 795 def _set_secondary_legend(self, bar_width: float, show_legend: bool) -> None: 796 if show_legend: 797 self.ax.annotate( 798 self._get_payoff_legend(), 799 xy=(-bar_width, 0), 800 xytext=(0, -30), 801 textcoords="offset points", 802 horizontalalignment="left", 803 verticalalignment="top", 804 fontsize=IVisualize.fontsize, 805 ) 806 807 def _plot_payoffs_bars( 808 self, payoffs: dict[str, float], bar_width: float, spacing: float, **kwargs 809 ) -> None: 810 """ 811 Plots the bars representing the payoffs for different market configurations of different stakeholders on the specified axis. 812 813 Parameters 814 ---------- 815 axis matplotlib.axes.Axes 816 To plot the bars on. 817 bar_width: float 818 Width of a bar in the plot. 819 spacing: float 820 Spacing between the bars on the plot. 821 **kwargs 822 Optional key word arguments for the payoff plot.<br> 823 - max_opacity(float): Opacity of the optimal payoffs.<br> 824 - min_opacity(float): Opacity of the not optimal payoffs.<br> 825 """ 826 max_values: list[int] = self._set_max_values(list(payoffs.values())) 827 for number_bar, (label, height) in enumerate(payoffs.items()): 828 x_coordinate: float = self._get_x_coordinate(bar_width, number_bar, spacing) 829 self._set_x_label(label, x_coordinate) 830 if number_bar > 3: 831 label = "__nolegend__" 832 else: 833 label = self._set_payoff_label(label) 834 self.ax.bar( 835 x=x_coordinate, 836 width=bar_width, 837 height=height, 838 label=label, 839 color=self._get_color(number_bar), 840 alpha=( 841 kwargs.get("max_opacity", 1) 842 if number_bar in max_values 843 else kwargs.get("min_opacity", 0.5) 844 ), 845 ) 846 self._set_x_ticks() 847 848 def _set_x_label(self, label: str, x_coordinate: float) -> None: 849 self.ax.annotate( 850 label, 851 xy=(x_coordinate, 0), 852 xytext=(0, -15), 853 textcoords="offset points", 854 horizontalalignment="center", 855 verticalalignment="bottom", 856 fontsize=IVisualize.fontsize, 857 ) 858 859 def _set_x_ticks(self) -> None: 860 self.ax.tick_params( 861 axis="x", 862 which="both", 863 bottom=False, 864 top=False, 865 labelbottom=False, 866 ) 867 868 @staticmethod 869 def _set_payoff_label(label) -> str: 870 payoff_type = label[:-3] 871 if "CS" in payoff_type: 872 return "Consumer Surplus" 873 if "W" in payoff_type: 874 return "Total Welfare" 875 if "I" in payoff_type: 876 return "Profit Incumbent ($\\pi_I$)" 877 return "Profit Start-up ($\\pi_S$)" 878 879 @staticmethod 880 def _set_max_values(payoffs: list[float]) -> list[int]: 881 return [ 882 Payoffs._get_max_index(0, payoffs), 883 Payoffs._get_max_index(1, payoffs), 884 Payoffs._get_max_index(2, payoffs), 885 Payoffs._get_max_index(3, payoffs), 886 ] 887 888 @staticmethod 889 def _get_max_index(offset_index: int, payoffs: list[float]) -> int: 890 values: list[float] = payoffs[offset_index::4] 891 max_value: float = max(values) 892 group_index: int = values.index(max_value) 893 return group_index * 4 + offset_index 894 895 @staticmethod 896 def _get_x_coordinate(bar_width: float, number_bar: int, spacing: float) -> float: 897 group_spacing: int = (math.trunc(number_bar / 4) % 4) * 8 898 return spacing * (number_bar + 1 + group_spacing) + bar_width * number_bar 899 900 @staticmethod 901 def _get_color(number_bar: int, reverse_cycle=True) -> str: 902 color_id = number_bar % 4 903 color_id = len(IVisualize.COLORS) - color_id - 1 if reverse_cycle else color_id 904 return IVisualize.COLORS[color_id] 905 906 def _get_payoffs(self) -> dict[str, float]: 907 return { 908 "$\\pi_S^m$": 0, 909 "$\\pi_I^m$": self.model.incumbent_profit_without_innovation, 910 "$CS^m$": self.model.cs_without_innovation, 911 "$W^m$": self.model.w_without_innovation, 912 "$\\pi^M_S$": 0, 913 "$\\pi^M_I$": self.model.incumbent_profit_with_innovation, 914 "$CS^M$": self.model.cs_with_innovation, 915 "$W^M$": self.model.w_with_innovation, 916 "$\\pi^d_S$": self.model.startup_profit_duopoly, 917 "$\\pi^d_I$": self.model.incumbent_profit_duopoly, 918 "$CS^d$": self.model.cs_duopoly, 919 "$W^d$": self.model.w_duopoly, 920 }
class
IVisualize:
13class IVisualize: 14 """ 15 Interface for all visualization classes containing useful methods. 16 17 Notes 18 ----- 19 This module is compatible with python versions starting from 3.9, due to introduction of PEP 585. Therefore, the compatibility 20 with mybinder.org is not guaranteed (uses python 3.7 at the moment ). 21 """ 22 23 COLORS: Final[list[str]] = ["salmon", "gold", "lawngreen", "turquoise", "thistle"] 24 """Standard colors used in visualizations.""" 25 fontsize = "x-small" 26 """Default font size for all plots.""" 27 28 def __init__( 29 self, 30 model: FMT20.OptimalMergerPolicy, 31 ax: Optional[plt.Axes] = None, 32 default_style=True, 33 dark_mode=False, 34 **kwargs, 35 ): 36 """ 37 Parameters 38 ---------- 39 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 40 Model to create the visualization from. 41 ax: Optional[matplotlib.pyplot.Axes] 42 Axes used for the plot, if not specified, a new set of axes is generated. 43 default_style: bool 44 If true, default matplotlib style is used. 45 dark_mode 46 If true, dark mode is used. 47 **kwargs 48 Arguments for the creation of a new figure. 49 """ 50 self._set_mode(default_style, dark_mode) 51 self.model: FMT20.OptimalMergerPolicy = model 52 self._set_axes(ax, **kwargs) 53 warnings.filterwarnings("ignore") 54 55 def _set_axes(self, ax, **kwargs) -> None: 56 if ax is None: 57 self.fig, self.ax = plt.subplots(**kwargs) 58 else: 59 self.ax = ax 60 self.fig = self.ax.get_figure() 61 self.ax.patch.set_alpha(0) 62 63 def _set_mode(self, default_style: bool, dark_mode: bool) -> None: 64 if dark_mode: 65 self._set_dark_mode() 66 else: 67 self._set_light_mode(default_style) 68 69 @staticmethod 70 def _set_dark_mode() -> None: 71 plt.style.use("dark_background") 72 73 @staticmethod 74 def _set_light_mode(default_style=False) -> None: 75 if ("science" in plt.style.available) and not default_style: 76 plt.style.use("science") 77 else: 78 plt.style.use("default") 79 80 def set_model(self, model: FMT20.OptimalMergerPolicy) -> None: 81 """ 82 Change the model for the visualization. 83 84 Example 85 ------- 86 ```python 87 import Fumagalli_Motta_Tarantino_2020 as FMT20 88 89 model_one = FMT20.OptimalMergerPolicy() 90 model_two = FMT20.OptimalMergerPolicy(development_success=False) 91 visualizer = FMT20.Overview(model_one) 92 visualizer.show() 93 # set the new model 94 visualizer.set_model(model_two) 95 # overwrite the previous plot 96 visualizer.show() 97 ``` 98 99 Parameters 100 ---------- 101 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 102 New model to generate the plots from. 103 """ 104 self.model = model 105 self.ax.clear() 106 self._reset_legend() 107 self._set_axes(self.ax) 108 109 def _reset_legend(self) -> None: 110 try: 111 self.ax.get_legend().remove() 112 except AttributeError: 113 pass 114 115 def _set_primary_legend(self, equal_opacity=True) -> None: 116 legend: plt.legend = self.ax.legend( 117 bbox_to_anchor=(1.02, 1), loc="upper left", borderaxespad=0, framealpha=0 118 ) 119 if equal_opacity: 120 for entry in legend.legend_handles: 121 entry.set_alpha(1) 122 123 def _set_tight_layout(self, y_spacing: float = None, x_spacing: float = 0) -> None: 124 if y_spacing is not None or x_spacing is not None: 125 self.ax.margins(y=y_spacing, x=x_spacing) 126 self.fig.tight_layout() 127 128 @abstractmethod 129 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 130 """ 131 Plots the visual representation for the object. 132 133 Example 134 ------- 135 ``` 136 import Fumagalli_Motta_Tarantino_2020 as FMT20 137 138 model = FMT20.OptimalMergerPolicy() 139 visualizer = FMT20.MergerPoliciesAssetRange(m) 140 fig, ax = visualizer.plot() 141 # use the figure and axes as you wish, for example: 142 fig.show() 143 ``` 144 145 Parameters 146 ---------- 147 **kwargs 148 Options for further customization of the plots . 149 150 Returns 151 ------- 152 Figure 153 Containing the axes with the plots (use Figure.show() to display). 154 Axes 155 Containing the plots (arrange custom summary). 156 """ 157 raise NotImplementedError 158 159 def show(self, **kwargs) -> None: 160 """ 161 Shows the visual representation for the object. 162 163 Example 164 ------- 165 ``` 166 model = Models.OptimalMergerPolicy() 167 visualizer = MergerPoliciesAssetRange(m) 168 visualizer.show() 169 ``` 170 171 Parameters 172 ---------- 173 **kwargs 174 Same options as Fumagalli_Motta_Tarantino_2020.Visualize.IVisualize.plot. 175 """ 176 self.plot(**kwargs) 177 self.fig.show() 178 179 @staticmethod 180 def get_model_label(m: type(FMT20.OptimalMergerPolicy)) -> str: 181 """ 182 Returns a label for a given model extending Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy. 183 184 Parameters 185 ---------- 186 m: type(FMT20.OptimalMergerPolicy) 187 Type of the model 188 """ 189 190 def _check_type(model_to_check, type_to_check): 191 return ( 192 isinstance(model_to_check, type_to_check) 193 or model_to_check == type_to_check 194 ) 195 196 if _check_type(m, FMT20.OptimalMergerPolicy): 197 return "Optimal Merger Policy" 198 if _check_type(m, FMT20.ProCompetitive): 199 return "Pro-Competitive" 200 if _check_type(m, FMT20.ResourceWaste): 201 return "Resource Waste" 202 if _check_type(m, FMT20.PerfectInformation): 203 return "Perfect Information" 204 if _check_type(m, FMT20.CournotCompetition): 205 return "Cournot Competition" 206 if _check_type(m, FMT20.EquityContract): 207 return "Equity Contract" 208 209 def _get_parameter_legend(self, **kwargs) -> str: 210 """ 211 Generates a legend for the parameter values of a Fumagalli_Motta_Tarantino_2020.Models.BaseModel in latex format. 212 213 Returns 214 ------- 215 str 216 Containing the legend for the parameter values. 217 """ 218 separator_name_value = "=" 219 separator_parameters = kwargs.get("separator", " ; ") 220 output_str = "" 221 counter = 2 222 number_parameters_per_line = kwargs.get("parameter_number", 6) 223 for parameter, value in [ 224 ("A", self.model.startup_assets), 225 ("B", self.model.private_benefit), 226 ("K", self.model.development_costs), 227 ("p", self.model.success_probability), 228 ("CS^m", self.model.cs_without_innovation), 229 ("\\pi^m_I", self.model.incumbent_profit_without_innovation), 230 ("CS^M", self.model.cs_with_innovation), 231 ("\\pi^M_I", self.model.incumbent_profit_with_innovation), 232 ("CS^d", self.model.cs_duopoly), 233 ("\\pi^d_I", self.model.incumbent_profit_duopoly), 234 ("\\pi^d_S", self.model.startup_profit_duopoly), 235 ]: 236 separator = ( 237 "" 238 if counter == 12 239 else ( 240 "\n" 241 if counter % number_parameters_per_line == 0 242 else separator_parameters 243 ) 244 ) 245 output_str += f"${parameter}{separator_name_value}{round(value, ndigits=3)}${separator}" 246 counter += 1 247 return output_str 248 249 @staticmethod 250 def _get_summary_latex(summary: FMT20.Outcome) -> str: 251 """ 252 Generates a chronological entry for the legend based on the input model. 253 254 Returns 255 ------- 256 str 257 Chronological entry for the legend of the input model. 258 """ 259 separator: str = "$\\to$" 260 return ( 261 f"{summary.early_bidding_type.abbreviation()}" 262 f"{IVisualize._get_takeover_legend(summary.early_bidding_type, summary.early_takeover)}{separator}" 263 f"{IVisualize._get_development_attempt_legend(summary.development_attempt)}" 264 f"{IVisualize._get_development_outcome_legend(summary.development_attempt, summary.development_outcome)}{separator}" 265 f"{summary.late_bidding_type.abbreviation()}" 266 f"{IVisualize._get_takeover_legend(summary.late_bidding_type, summary.late_takeover)}" 267 ) 268 269 @staticmethod 270 def _get_takeover_legend(bid_attempt: FMT20.Takeover, is_takeover: bool) -> str: 271 """ 272 Generates a string representation for legend about the takeover (option and approval). 273 274 Parameters 275 ---------- 276 bid_attempt: Fumagalli_Motta_Tarantino_2020.FMT20.Takeover 277 Option for takeover chosen by the incumbent. 278 is_takeover: bool 279 If true, the takeover is approved by AA and the start-up. 280 281 Returns 282 ------- 283 str 284 String representation for legend about takeover (option and approval). 285 """ 286 if bid_attempt is FMT20.Takeover.No: 287 return "" 288 return "$(\\checkmark)$" if is_takeover else "$(\\times)$" 289 290 @staticmethod 291 def _get_development_attempt_legend(is_developing: bool) -> str: 292 """ 293 Generates a string representation for legend about the development attempt. 294 295 Parameters 296 ---------- 297 is_developing: bool 298 True, if the owner is developing the product (otherwise, the product is shelved). 299 300 Returns 301 ------- 302 str 303 String representation for legend about the development attempt. 304 """ 305 return "" if is_developing else "$\\emptyset$" 306 307 @staticmethod 308 def _get_development_outcome_legend( 309 is_developing: bool, is_successful: bool 310 ) -> str: 311 """ 312 Generates a string representation for legend about the development outcome. 313 314 Parameters 315 ---------- 316 is_developing: bool 317 True, if the owner is developing the product (otherwise, the product is shelved). 318 is_successful: bool 319 True, if the development of the product is successful. 320 321 Returns 322 ------- 323 str 324 String representation for legend about the development outcome. 325 """ 326 if is_developing: 327 return "$\\checkmark$" if is_successful else "$\\times$" 328 return "" 329 330 @staticmethod 331 def _get_symbol_legend() -> str: 332 """ 333 Generates a legend for the used abbreviations in the plot legends. 334 335 Returns 336 ------- 337 str 338 Containing the legend for the used abbreviations. 339 """ 340 return ( 341 "${\\bf Merger\\thickspace policies}$:\n" 342 f"{FMT20.MergerPolicies.legend()}\n" 343 "${\\bf Bidding\\thickspace types}$:\n" 344 f"{FMT20.Takeover.legend()}\n" 345 "${\\bf Takeover\\thickspace outcome\\thickspace}$:\n" 346 f"{FMT20.Takeover.Pooling.abbreviation()}|{FMT20.Takeover.Separating.abbreviation()}$(\\checkmark)$: Takeover is approved by the startup and AA\n" 347 f"{FMT20.Takeover.Pooling.abbreviation()}|{FMT20.Takeover.Separating.abbreviation()}$(\\times)$: Takeover is blocked by AA or not accepted by the startup\n" 348 "${\\bf Development\\thickspace outcome}$:\n" 349 f"$\\emptyset$: Product development was shelved\n" 350 f"$\\checkmark$: Product development was attempted and successful\n" 351 f"$\\times$: Product development was attempted and not successful\n" 352 ) 353 354 @staticmethod 355 def _get_payoff_legend(market_situations_only=False) -> str: 356 payoff_str = ( 357 "$\\pi_S$: Profit of the start-up\n" 358 "$\\pi_I$: Profit of the incumbent\n" 359 "$CS$: Consumer surplus\n" 360 "$W$: Total welfare\n" 361 if not market_situations_only 362 else "" 363 ) 364 return ( 365 "${\\bf Market\\thickspace configurations}$\n" 366 f"{payoff_str}" 367 "$m$: Monopoly without the innovation\n" 368 "$M$: Monopoly (innovation in possession of incumbent)\n" 369 "$d$: Duopoly (requires successful development by the start-up)\n" 370 ) 371 372 def _get_model_characteristics( 373 self, 374 separator=" ; ", 375 model_parameters=True, 376 model_thresholds=True, 377 thresholds_newline=True, 378 optimal_policy=False, 379 **kwargs, 380 ) -> str: 381 newline = "\n" if thresholds_newline else separator 382 parameter_text = ( 383 f"${{\\bf Parameters}}$\n{self._get_parameter_legend(separator=separator, **kwargs)}\n" 384 if model_parameters 385 else "" 386 ) 387 threshold_title = kwargs.get( 388 "threshold_title", 389 "Thresholds\\thickspace for\\thickspace the\\thickspace Start-up\\thickspace Assets", 390 ) 391 thresholds = ( 392 f"${{\\bf {threshold_title}}}$\n" 393 f"{self._get_model_characteristics_thresholds(separator, newline)}" 394 if model_thresholds 395 else "" 396 ) 397 optimal = ( 398 f"Optimal policy: {self.model.get_optimal_merger_policy().abbreviation()}\n" 399 if optimal_policy 400 else "" 401 ) 402 return f"{parameter_text}{thresholds}{optimal}" 403 404 def _get_model_characteristics_thresholds( 405 self, separator: str, newline: str 406 ) -> str: 407 return ( 408 f"$F(0) = {self._round_floats(self._get_asset_distribution_value(0))}${separator}" 409 f"$F(K) = {self._round_floats(self._get_asset_distribution_value(self.model.development_costs))}${separator}" 410 f"$F(\\bar{{A}}) = {self._round_floats(self.model.asset_threshold_cdf)}${separator}" 411 f"$F(\\bar{{A}}^T) = {self._round_floats(self.model.asset_threshold_late_takeover_cdf)}${newline}" 412 f"$\\Gamma(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_welfare)}${separator}" 413 f"$\\Phi(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_profitable_without_late_takeover)}${separator}" 414 f"$\\Phi'(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_unprofitable_without_late_takeover)}${separator}" 415 f"$\\Phi^T(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_with_late_takeover)}${separator}" 416 f"$\\Lambda(\\cdot) = {self._round_floats(self.model.asset_distribution_threshold_shelving_approved)}$\n" 417 ) 418 419 def _get_asset_distribution_value(self, value: float) -> float: 420 return self.model.asset_distribution.cumulative( 421 value, **self.model.asset_distribution_kwargs 422 ) 423 424 def _get_inverse_asset_distribution_value(self, value: float) -> float: 425 return self.model.asset_distribution.inverse_cumulative( 426 value, **self.model.asset_distribution_kwargs 427 ) 428 429 @staticmethod 430 def _round_floats(value: float, digits=3) -> str: 431 return f"{value:.{digits}f}" 432 433 def _get_model_characteristics_ax(self, ax: plt.Axes, **kwargs) -> None: 434 ax.set_title(kwargs.get("title", "Model Characteristics")) 435 ax.axis("off") 436 model_characteristics = self._get_model_characteristics(**kwargs) 437 text_to_annotate = ( 438 f"{model_characteristics}" 439 f"{self._get_payoff_legend(market_situations_only=True)}" 440 f"{self._get_symbol_legend()}" 441 ) 442 ax.annotate( 443 text_to_annotate, 444 xy=(0.5, 1), 445 xytext=(0, 0), 446 textcoords="offset points", 447 horizontalalignment="center", 448 verticalalignment="top", 449 fontsize=kwargs.get("fontsize", IVisualize.fontsize), 450 )
Interface for all visualization classes containing useful methods.
Notes
This module is compatible with python versions starting from 3.9, due to introduction of PEP 585. Therefore, the compatibility with mybinder.org is not guaranteed (uses python 3.7 at the moment ).
IVisualize( model: Fumagalli_Motta_Tarantino_2020.Models.Base.OptimalMergerPolicy, ax: Optional[matplotlib.axes._axes.Axes] = None, default_style=True, dark_mode=False, **kwargs)
28 def __init__( 29 self, 30 model: FMT20.OptimalMergerPolicy, 31 ax: Optional[plt.Axes] = None, 32 default_style=True, 33 dark_mode=False, 34 **kwargs, 35 ): 36 """ 37 Parameters 38 ---------- 39 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 40 Model to create the visualization from. 41 ax: Optional[matplotlib.pyplot.Axes] 42 Axes used for the plot, if not specified, a new set of axes is generated. 43 default_style: bool 44 If true, default matplotlib style is used. 45 dark_mode 46 If true, dark mode is used. 47 **kwargs 48 Arguments for the creation of a new figure. 49 """ 50 self._set_mode(default_style, dark_mode) 51 self.model: FMT20.OptimalMergerPolicy = model 52 self._set_axes(ax, **kwargs) 53 warnings.filterwarnings("ignore")
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.
COLORS: Final[list[str]] =
['salmon', 'gold', 'lawngreen', 'turquoise', 'thistle']
Standard colors used in visualizations.
def
set_model( self, model: Fumagalli_Motta_Tarantino_2020.Models.Base.OptimalMergerPolicy) -> None:
80 def set_model(self, model: FMT20.OptimalMergerPolicy) -> None: 81 """ 82 Change the model for the visualization. 83 84 Example 85 ------- 86 ```python 87 import Fumagalli_Motta_Tarantino_2020 as FMT20 88 89 model_one = FMT20.OptimalMergerPolicy() 90 model_two = FMT20.OptimalMergerPolicy(development_success=False) 91 visualizer = FMT20.Overview(model_one) 92 visualizer.show() 93 # set the new model 94 visualizer.set_model(model_two) 95 # overwrite the previous plot 96 visualizer.show() 97 ``` 98 99 Parameters 100 ---------- 101 model: Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy 102 New model to generate the plots from. 103 """ 104 self.model = model 105 self.ax.clear() 106 self._reset_legend() 107 self._set_axes(self.ax)
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.
@abstractmethod
def
plot( self, **kwargs) -> (<class 'matplotlib.figure.Figure'>, <class 'matplotlib.axes._axes.Axes'>):
128 @abstractmethod 129 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 130 """ 131 Plots the visual representation for the object. 132 133 Example 134 ------- 135 ``` 136 import Fumagalli_Motta_Tarantino_2020 as FMT20 137 138 model = FMT20.OptimalMergerPolicy() 139 visualizer = FMT20.MergerPoliciesAssetRange(m) 140 fig, ax = visualizer.plot() 141 # use the figure and axes as you wish, for example: 142 fig.show() 143 ``` 144 145 Parameters 146 ---------- 147 **kwargs 148 Options for further customization of the plots . 149 150 Returns 151 ------- 152 Figure 153 Containing the axes with the plots (use Figure.show() to display). 154 Axes 155 Containing the plots (arrange custom summary). 156 """ 157 raise NotImplementedError
Plots the visual representation for the object.
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 .
Returns
- Figure: Containing the axes with the plots (use Figure.show() to display).
- Axes: Containing the plots (arrange custom summary).
def
show(self, **kwargs) -> None:
159 def show(self, **kwargs) -> None: 160 """ 161 Shows the visual representation for the object. 162 163 Example 164 ------- 165 ``` 166 model = Models.OptimalMergerPolicy() 167 visualizer = MergerPoliciesAssetRange(m) 168 visualizer.show() 169 ``` 170 171 Parameters 172 ---------- 173 **kwargs 174 Same options as Fumagalli_Motta_Tarantino_2020.Visualize.IVisualize.plot. 175 """ 176 self.plot(**kwargs) 177 self.fig.show()
Shows the visual representation for the object.
Example
model = Models.OptimalMergerPolicy()
visualizer = MergerPoliciesAssetRange(m)
visualizer.show()
Parameters
- **kwargs: Same options as Fumagalli_Motta_Tarantino_2020.Visualize.IVisualize.plot.
@staticmethod
def
get_model_label(m: type) -> str:
179 @staticmethod 180 def get_model_label(m: type(FMT20.OptimalMergerPolicy)) -> str: 181 """ 182 Returns a label for a given model extending Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy. 183 184 Parameters 185 ---------- 186 m: type(FMT20.OptimalMergerPolicy) 187 Type of the model 188 """ 189 190 def _check_type(model_to_check, type_to_check): 191 return ( 192 isinstance(model_to_check, type_to_check) 193 or model_to_check == type_to_check 194 ) 195 196 if _check_type(m, FMT20.OptimalMergerPolicy): 197 return "Optimal Merger Policy" 198 if _check_type(m, FMT20.ProCompetitive): 199 return "Pro-Competitive" 200 if _check_type(m, FMT20.ResourceWaste): 201 return "Resource Waste" 202 if _check_type(m, FMT20.PerfectInformation): 203 return "Perfect Information" 204 if _check_type(m, FMT20.CournotCompetition): 205 return "Cournot Competition" 206 if _check_type(m, FMT20.EquityContract): 207 return "Equity Contract"
Returns a label for a given model extending Fumagalli_Motta_Tarantino_2020.Models.OptimalMergerPolicy.
Parameters
- m (type(FMT20.OptimalMergerPolicy)): Type of the model
453class Timeline(IVisualize): 454 """ 455 Visualizes the timeline of events for a specific model. 456 """ 457 458 def __init__(self, model: FMT20.OptimalMergerPolicy, **kwargs): 459 super(Timeline, self).__init__(model, **kwargs) 460 self.high_stem = 0.6 461 self.low_stem = 0.3 462 self.stem_levels = [ 463 -self.high_stem, 464 self.high_stem, 465 self.low_stem, 466 -self.high_stem, 467 self.high_stem, 468 -self.high_stem, 469 -self.low_stem, 470 self.high_stem, 471 ] 472 self._x_ticks = list(range(len(self.stem_levels))) 473 474 def _get_stem_labels(self) -> list[str]: 475 """ 476 Generates the label and points in time of the events in the model. 477 478 Returns 479 ------- 480 (list[str], list[str]) 481 List containing label for the events and list containing the points in time of the events. 482 """ 483 ( 484 earl_takeover_attempt, 485 early_takeover, 486 late_takeover_attempt, 487 late_takeover, 488 ) = self._get_takeover_labels() 489 return [ 490 "Competition authority\nestablishes " 491 + self._policy_label() 492 + "\nmerger policy", 493 earl_takeover_attempt, 494 early_takeover, 495 self._development_label(), 496 self._success_str(), 497 late_takeover_attempt, 498 late_takeover, 499 self._get_payoff_label(), 500 ] 501 502 def _get_payoff_label(self): 503 label = "Payoffs\n" 504 if self.model.is_early_takeover or self.model.is_late_takeover: 505 if self.model.is_development_successful: 506 return label + "($CS^M$, $\\pi^M_I$)" 507 return label + "($CS^m$, $\\pi^m_I$)" 508 return label + "($CS^d$, $\\pi^d_I$, $\\pi^d_S$)" 509 510 def _get_takeover_labels(self) -> list[str, str, str, str]: 511 if self.model.is_early_takeover: 512 late_takeover_attempt = "Start-up already\nacquired" 513 late_takeover = "" 514 self.stem_levels[5] = -self.low_stem 515 self.stem_levels[6] = 0 516 elif self.model.merger_policy in [ 517 FMT20.MergerPolicies.Strict, 518 FMT20.MergerPolicies.Intermediate_late_takeover_prohibited, 519 ]: 520 late_takeover_attempt = "Competition authority\nblocks late\ntakeovers" 521 late_takeover = "" 522 self.stem_levels[5] = -self.low_stem 523 self.stem_levels[6] = 0 524 else: 525 late_takeover_attempt = self._takeover_attempt_label( 526 self.model.late_bidding_type 527 ) 528 late_takeover = self._takeover_label( 529 self.model.late_bidding_type, self.model.is_late_takeover 530 ) 531 532 return [ 533 self._takeover_attempt_label(self.model.early_bidding_type), 534 self._takeover_label( 535 self.model.early_bidding_type, self.model.is_early_takeover 536 ), 537 late_takeover_attempt, 538 late_takeover, 539 ] 540 541 @staticmethod 542 def _get_x_labels() -> list[str]: 543 return [ 544 "t=0", 545 "t=1a", 546 "t=1b", 547 "t=1c", 548 "t=1d", 549 "t=2a", 550 "t=2b", 551 "t=3", 552 ] 553 554 @staticmethod 555 def _takeover_attempt_label(takeover: FMT20.Takeover) -> str: 556 """ 557 Generate label for takeover event. 558 559 Parameters 560 ---------- 561 takeover: Fumagalli_Motta_Tarantino_2020.FMT20.Takeover 562 Option for takeover chosen by the incumbent. 563 564 Returns 565 ------- 566 str 567 Label for takeover event. 568 """ 569 return str(takeover) + "\nby incumbent" 570 571 def _policy_label(self) -> str: 572 """ 573 Generate label for establishing of merger policy event. 574 575 Returns 576 ------- 577 str 578 Label for establishing of merger policy event. 579 """ 580 policy_str = str(self.model.merger_policy).lower() 581 if "intermediate" in policy_str: 582 return policy_str.replace("intermediate", "intermediate\n") 583 return policy_str 584 585 @staticmethod 586 def _takeover_label( 587 takeover_attempt: FMT20.Takeover, is_takeover_accepted: bool 588 ) -> str: 589 """ 590 Generates a label about the takeover event (option and approval). 591 592 Parameters 593 ---------- 594 takeover_attempt: FMT20.Takeover 595 Type of the bid by the incumbent. 596 is_takeover_accepted: bool 597 If true, the takeover is approved by AA and the start-up. 598 599 Returns 600 ------- 601 str 602 Label about the takeover event (option and approval). 603 """ 604 is_takeover_attempt = takeover_attempt is not FMT20.Takeover.No 605 if is_takeover_attempt and is_takeover_accepted: 606 return "Takeover\napproved" 607 if is_takeover_attempt and not is_takeover_accepted: 608 return "Takeover rejected\nby start-up" 609 return "No takeover\noccurs" 610 611 def _development_label(self) -> str: 612 """ 613 Generates a label about the development event (attempt and shelving). 614 615 Returns 616 ------- 617 str 618 Label about the development event (attempt and shelving). 619 """ 620 if self.model.is_early_takeover: 621 return ( 622 "Incumbent\n" 623 + ("develops" if self.model.is_owner_investing else "shelves") 624 + " product" 625 + "\n(killer acquisition)" 626 if self.model.is_killer_acquisition() 627 else "" 628 ) 629 return ( 630 "Start-up" 631 + ("" if self.model.is_owner_investing else " does not") 632 + "\nobtain" 633 + ("s" if self.model.is_owner_investing else "") 634 + " enough\nfinancial assets" 635 ) 636 637 def _success_str(self) -> str: 638 """ 639 Generates a label about the development outcome event. 640 641 Returns 642 ------- 643 str 644 Label about the development outcome event. 645 """ 646 if self.model.is_owner_investing: 647 if self.model.is_development_successful: 648 return "Development is\nsuccessful" 649 return "Development is\nnot successful" 650 return "Development was\nnot attempted." 651 652 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 653 """ 654 Plots the visual representation for the object. 655 656 Example 657 ------- 658 ``` 659 import Fumagalli_Motta_Tarantino_2020 as FMT20 660 661 model = FMT20.OptimalMergerPolicy() 662 visualizer = FMT20.Timeline(m) 663 fig, ax = visualizer.plot() 664 # use the figure and axes as you wish, for example: 665 fig.show() 666 ``` 667 668 Parameters 669 ---------- 670 **kwargs 671 Options for further customization of the plots. 672 - title(str): Title for timeline<br> 673 - parameters(bool): If true, a legend containing the parameters is shown. 674 - x_offset(int): Moves the text at the stems horizontally. 675 676 Returns 677 ------- 678 Figure 679 Containing the axes with the plots (use Figure.show() to display). 680 Axes 681 Containing the plots (arrange custom summary). 682 """ 683 self.ax.set(title=kwargs.get("title", "Timeline")) 684 self._set_parameter_legend(kwargs.get("parameters", True)) 685 self._draw_timeline(**kwargs) 686 self._set_x_axis() 687 self._set_y_axis() 688 self._set_tight_layout(y_spacing=0.45, x_spacing=0.02) 689 return self.fig, self.ax 690 691 def _draw_timeline(self, **kwargs): 692 self._annotate_stems(kwargs.get("x_offset", 0)) 693 self._draw_vertical_stems() 694 self._draw_baseline() 695 696 def _annotate_stems( 697 self, 698 x_offset: int, 699 ) -> None: 700 for d, l, r in zip(self._x_ticks, self.stem_levels, self._get_stem_labels()): 701 self.ax.annotate( 702 str(r), 703 xy=(d, l), 704 xytext=(x_offset, np.sign(l) * 8), 705 textcoords="offset points", 706 horizontalalignment="center", 707 verticalalignment="bottom" if l > 0 else "top", 708 fontsize=IVisualize.fontsize, 709 ) 710 711 def _draw_vertical_stems(self) -> None: 712 self.ax.vlines( 713 self._x_ticks, 0, self.stem_levels, color="lightgray", linewidths=1 714 ) 715 716 def _draw_baseline(self) -> None: 717 self.ax.plot( 718 self._x_ticks, 719 np.zeros_like(self._x_ticks), 720 "-o", 721 color="k", 722 markerfacecolor="w", 723 ) 724 725 def _set_x_axis(self) -> None: 726 self.ax.set_xticks(self._x_ticks) 727 self.ax.set_xticklabels(self._get_x_labels()) 728 self.ax.xaxis.set_ticks_position("bottom") 729 730 def _set_y_axis(self) -> None: 731 self.ax.yaxis.set_visible(False) 732 self.ax.spines[["left", "top", "right"]].set_visible(False) 733 734 def _set_parameter_legend(self, show_parameters: bool) -> None: 735 x_coordinate = math.fsum(self._x_ticks) / len(self._x_ticks) 736 if show_parameters: 737 self.ax.annotate( 738 self._get_parameter_legend(), 739 xy=(x_coordinate, self.high_stem * 1.8), 740 horizontalalignment="center", 741 verticalalignment="top", 742 fontsize=IVisualize.fontsize, 743 )
Visualizes the timeline of events for a specific model.
Timeline( model: Fumagalli_Motta_Tarantino_2020.Models.Base.OptimalMergerPolicy, **kwargs)
458 def __init__(self, model: FMT20.OptimalMergerPolicy, **kwargs): 459 super(Timeline, self).__init__(model, **kwargs) 460 self.high_stem = 0.6 461 self.low_stem = 0.3 462 self.stem_levels = [ 463 -self.high_stem, 464 self.high_stem, 465 self.low_stem, 466 -self.high_stem, 467 self.high_stem, 468 -self.high_stem, 469 -self.low_stem, 470 self.high_stem, 471 ] 472 self._x_ticks = list(range(len(self.stem_levels)))
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.
def
plot( self, **kwargs) -> (<class 'matplotlib.figure.Figure'>, <class 'matplotlib.axes._axes.Axes'>):
652 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 653 """ 654 Plots the visual representation for the object. 655 656 Example 657 ------- 658 ``` 659 import Fumagalli_Motta_Tarantino_2020 as FMT20 660 661 model = FMT20.OptimalMergerPolicy() 662 visualizer = FMT20.Timeline(m) 663 fig, ax = visualizer.plot() 664 # use the figure and axes as you wish, for example: 665 fig.show() 666 ``` 667 668 Parameters 669 ---------- 670 **kwargs 671 Options for further customization of the plots. 672 - title(str): Title for timeline<br> 673 - parameters(bool): If true, a legend containing the parameters is shown. 674 - x_offset(int): Moves the text at the stems horizontally. 675 676 Returns 677 ------- 678 Figure 679 Containing the axes with the plots (use Figure.show() to display). 680 Axes 681 Containing the plots (arrange custom summary). 682 """ 683 self.ax.set(title=kwargs.get("title", "Timeline")) 684 self._set_parameter_legend(kwargs.get("parameters", True)) 685 self._draw_timeline(**kwargs) 686 self._set_x_axis() 687 self._set_y_axis() 688 self._set_tight_layout(y_spacing=0.45, x_spacing=0.02) 689 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.Timeline(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 timeline
- parameters(bool): If true, a legend containing the parameters is shown.
- x_offset(int): Moves the text at the stems horizontally.
- title(str): Title for timeline
Returns
- Figure: Containing the axes with the plots (use Figure.show() to display).
- Axes: Containing the plots (arrange custom summary).
Inherited Members
746class Payoffs(IVisualize): 747 """ 748 Visualizes the payoffs for a specific model. 749 """ 750 751 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 752 """ 753 Plots the visual representation for the object. 754 755 Example 756 ------- 757 ``` 758 import Fumagalli_Motta_Tarantino_2020 as FMT20 759 760 model = FMT20.OptimalMergerPolicy() 761 visualizer = FMT20.Payoffs(m) 762 fig, ax = visualizer.plot() 763 # use the figure and axes as you wish, for example: 764 fig.show() 765 ``` 766 767 Parameters 768 ---------- 769 **kwargs 770 Options for further customization of the plots. 771 - title(str): Title for plot<br> 772 - legend(bool): If true, a secondary legend is shown.<br> 773 - width(float): Width of the bars.<br> 774 - spacing(float): Spacing between the bars.<br> 775 - max_opacity(float): Opacity of the optimal payoffs.<br> 776 - min_opacity(float): Opacity of the not optimal payoffs.<br> 777 778 Returns 779 ------- 780 Figure 781 Containing the axes with the plots (use Figure.show() to display). 782 Axes 783 Containing the plots (arrange custom summary). 784 """ 785 payoffs: dict[str, float] = self._get_payoffs() 786 bar_width = kwargs.get("width", 0.35) 787 spacing = kwargs.get("spacing", 0.05) 788 self._plot_payoffs_bars(payoffs, bar_width, spacing, **kwargs) 789 self.ax.set_title( 790 kwargs.get("title", "Payoffs for different Market Configurations") 791 ) 792 self._set_primary_legend() 793 self._set_secondary_legend(bar_width, kwargs.get("legend", True)) 794 self._set_tight_layout(x_spacing=spacing) 795 796 def _set_secondary_legend(self, bar_width: float, show_legend: bool) -> None: 797 if show_legend: 798 self.ax.annotate( 799 self._get_payoff_legend(), 800 xy=(-bar_width, 0), 801 xytext=(0, -30), 802 textcoords="offset points", 803 horizontalalignment="left", 804 verticalalignment="top", 805 fontsize=IVisualize.fontsize, 806 ) 807 808 def _plot_payoffs_bars( 809 self, payoffs: dict[str, float], bar_width: float, spacing: float, **kwargs 810 ) -> None: 811 """ 812 Plots the bars representing the payoffs for different market configurations of different stakeholders on the specified axis. 813 814 Parameters 815 ---------- 816 axis matplotlib.axes.Axes 817 To plot the bars on. 818 bar_width: float 819 Width of a bar in the plot. 820 spacing: float 821 Spacing between the bars on the plot. 822 **kwargs 823 Optional key word arguments for the payoff plot.<br> 824 - max_opacity(float): Opacity of the optimal payoffs.<br> 825 - min_opacity(float): Opacity of the not optimal payoffs.<br> 826 """ 827 max_values: list[int] = self._set_max_values(list(payoffs.values())) 828 for number_bar, (label, height) in enumerate(payoffs.items()): 829 x_coordinate: float = self._get_x_coordinate(bar_width, number_bar, spacing) 830 self._set_x_label(label, x_coordinate) 831 if number_bar > 3: 832 label = "__nolegend__" 833 else: 834 label = self._set_payoff_label(label) 835 self.ax.bar( 836 x=x_coordinate, 837 width=bar_width, 838 height=height, 839 label=label, 840 color=self._get_color(number_bar), 841 alpha=( 842 kwargs.get("max_opacity", 1) 843 if number_bar in max_values 844 else kwargs.get("min_opacity", 0.5) 845 ), 846 ) 847 self._set_x_ticks() 848 849 def _set_x_label(self, label: str, x_coordinate: float) -> None: 850 self.ax.annotate( 851 label, 852 xy=(x_coordinate, 0), 853 xytext=(0, -15), 854 textcoords="offset points", 855 horizontalalignment="center", 856 verticalalignment="bottom", 857 fontsize=IVisualize.fontsize, 858 ) 859 860 def _set_x_ticks(self) -> None: 861 self.ax.tick_params( 862 axis="x", 863 which="both", 864 bottom=False, 865 top=False, 866 labelbottom=False, 867 ) 868 869 @staticmethod 870 def _set_payoff_label(label) -> str: 871 payoff_type = label[:-3] 872 if "CS" in payoff_type: 873 return "Consumer Surplus" 874 if "W" in payoff_type: 875 return "Total Welfare" 876 if "I" in payoff_type: 877 return "Profit Incumbent ($\\pi_I$)" 878 return "Profit Start-up ($\\pi_S$)" 879 880 @staticmethod 881 def _set_max_values(payoffs: list[float]) -> list[int]: 882 return [ 883 Payoffs._get_max_index(0, payoffs), 884 Payoffs._get_max_index(1, payoffs), 885 Payoffs._get_max_index(2, payoffs), 886 Payoffs._get_max_index(3, payoffs), 887 ] 888 889 @staticmethod 890 def _get_max_index(offset_index: int, payoffs: list[float]) -> int: 891 values: list[float] = payoffs[offset_index::4] 892 max_value: float = max(values) 893 group_index: int = values.index(max_value) 894 return group_index * 4 + offset_index 895 896 @staticmethod 897 def _get_x_coordinate(bar_width: float, number_bar: int, spacing: float) -> float: 898 group_spacing: int = (math.trunc(number_bar / 4) % 4) * 8 899 return spacing * (number_bar + 1 + group_spacing) + bar_width * number_bar 900 901 @staticmethod 902 def _get_color(number_bar: int, reverse_cycle=True) -> str: 903 color_id = number_bar % 4 904 color_id = len(IVisualize.COLORS) - color_id - 1 if reverse_cycle else color_id 905 return IVisualize.COLORS[color_id] 906 907 def _get_payoffs(self) -> dict[str, float]: 908 return { 909 "$\\pi_S^m$": 0, 910 "$\\pi_I^m$": self.model.incumbent_profit_without_innovation, 911 "$CS^m$": self.model.cs_without_innovation, 912 "$W^m$": self.model.w_without_innovation, 913 "$\\pi^M_S$": 0, 914 "$\\pi^M_I$": self.model.incumbent_profit_with_innovation, 915 "$CS^M$": self.model.cs_with_innovation, 916 "$W^M$": self.model.w_with_innovation, 917 "$\\pi^d_S$": self.model.startup_profit_duopoly, 918 "$\\pi^d_I$": self.model.incumbent_profit_duopoly, 919 "$CS^d$": self.model.cs_duopoly, 920 "$W^d$": self.model.w_duopoly, 921 }
Visualizes the payoffs for a specific model.
def
plot( self, **kwargs) -> (<class 'matplotlib.figure.Figure'>, <class 'matplotlib.axes._axes.Axes'>):
751 def plot(self, **kwargs) -> (plt.Figure, plt.Axes): 752 """ 753 Plots the visual representation for the object. 754 755 Example 756 ------- 757 ``` 758 import Fumagalli_Motta_Tarantino_2020 as FMT20 759 760 model = FMT20.OptimalMergerPolicy() 761 visualizer = FMT20.Payoffs(m) 762 fig, ax = visualizer.plot() 763 # use the figure and axes as you wish, for example: 764 fig.show() 765 ``` 766 767 Parameters 768 ---------- 769 **kwargs 770 Options for further customization of the plots. 771 - title(str): Title for plot<br> 772 - legend(bool): If true, a secondary legend is shown.<br> 773 - width(float): Width of the bars.<br> 774 - spacing(float): Spacing between the bars.<br> 775 - max_opacity(float): Opacity of the optimal payoffs.<br> 776 - min_opacity(float): Opacity of the not optimal payoffs.<br> 777 778 Returns 779 ------- 780 Figure 781 Containing the axes with the plots (use Figure.show() to display). 782 Axes 783 Containing the plots (arrange custom summary). 784 """ 785 payoffs: dict[str, float] = self._get_payoffs() 786 bar_width = kwargs.get("width", 0.35) 787 spacing = kwargs.get("spacing", 0.05) 788 self._plot_payoffs_bars(payoffs, bar_width, spacing, **kwargs) 789 self.ax.set_title( 790 kwargs.get("title", "Payoffs for different Market Configurations") 791 ) 792 self._set_primary_legend() 793 self._set_secondary_legend(bar_width, kwargs.get("legend", True)) 794 self._set_tight_layout(x_spacing=spacing)
Plots the visual representation for the object.
Example
import Fumagalli_Motta_Tarantino_2020 as FMT20
model = FMT20.OptimalMergerPolicy()
visualizer = FMT20.Payoffs(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
- legend(bool): If true, a secondary legend is shown.
- width(float): Width of the bars.
- spacing(float): Spacing between the bars.
- max_opacity(float): Opacity of the optimal payoffs.
- min_opacity(float): Opacity of the not optimal payoffs.
- 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).