Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

/portfolio/po : allow getting plotly figure with the SDK #4449

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions openbb_terminal/helper_classes.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
"""Helper classes."""
__docformat__ = "numpy"
import argparse
import io
import json
import os
from importlib import machinery, util
from pathlib import Path
from typing import Dict, List, Optional, Union

import matplotlib.pyplot as plt
import plotly.express as px
from matplotlib import font_manager, ticker
from PIL import Image

from openbb_terminal.core.config.paths import MISCELLANEOUS_DIRECTORY
from openbb_terminal.core.session.current_user import get_current_user
Expand Down Expand Up @@ -346,7 +349,9 @@ def add_cmd_source(
)

# pylint: disable=import-outside-toplevel
def visualize_output(self, force_tight_layout: bool = True):
def visualize_output(
self, force_tight_layout: bool = True, external_axes: bool = False
):
"""Show chart in an interactive widget."""
current_user = get_current_user()

Expand All @@ -356,9 +361,20 @@ def visualize_output(self, force_tight_layout: bool = True):
self.add_label(plt.gcf())
if force_tight_layout:
plt.tight_layout(pad=self.tight_layout_padding)
if current_user.preferences.USE_ION:
plt.ion()
plt.show()

if external_axes:
img_buf = io.BytesIO()
plt.savefig(img_buf, format="jpg")
im = Image.open(img_buf)
fig = px.imshow(im)
else:
if current_user.preferences.USE_ION:
plt.ion()

fig = None
plt.show()

return fig


class AllowArgsWithWhiteSpace(argparse.Action):
Expand Down
83 changes: 35 additions & 48 deletions openbb_terminal/portfolio/portfolio_optimization/optimizer_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -2175,12 +2175,9 @@ def display_ef(
try:
risk_free_rate = risk_free_rate / time_factor[freq.upper()]

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_frontier(
w_frontier=frontier,
Expand Down Expand Up @@ -2277,8 +2274,10 @@ def display_ef(
ax1 = ax.get_figure().axes
ll, bb, ww, hh = ax1[-1].get_position().bounds
ax1[-1].set_position([ll * 1.02, bb, ww, hh])
if external_axes is None:
theme.visualize_output(force_tight_layout=False)

return theme.visualize_output(
force_tight_layout=False, external_axes=external_axes
)
except Exception as _:
console.print("[red]Error plotting efficient frontier.[/red]")

Expand Down Expand Up @@ -3644,12 +3643,9 @@ def pie_chart_weights(
total_size = np.sum(sizes)
colors = theme.get_colors()

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

if math.isclose(sum(sizes), 1, rel_tol=0.1):
_, _, autotexts = ax.pie(
Expand Down Expand Up @@ -3714,8 +3710,7 @@ def pie_chart_weights(
title += "Portfolio Composition"
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand Down Expand Up @@ -3868,12 +3863,9 @@ def additional_plots(
pie_chart_weights(weights, title_opt, external_axes)

if hist:
if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_hist(data, w=pd.Series(weights).to_frame(), alpha=alpha, ax=ax)
ax.legend(fontsize="x-small", loc="best")
Expand All @@ -3894,16 +3886,14 @@ def additional_plots(
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(
force_tight_layout=False, external_axes=external_axes
)

if dd:
if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

nav = data.cumsum()
ax = rp.plot_drawdown(
Expand Down Expand Up @@ -3932,16 +3922,14 @@ def additional_plots(
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(
force_tight_layout=False, external_axes=external_axes
)

if rc_chart:
if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_risk_con(
w=pd.Series(weights).to_frame(),
Expand All @@ -3968,8 +3956,9 @@ def additional_plots(
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(
force_tight_layout=False, external_axes=external_axes
)

if heat:
if len(weights) == 1:
Expand All @@ -3979,12 +3968,9 @@ def additional_plots(
)
return

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

if len(weights) <= 3:
number_of_clusters = len(weights)
Expand Down Expand Up @@ -4047,8 +4033,9 @@ def additional_plots(
title += ax[3].get_title(loc="left")
ax[3].set_title(title)

if external_axes is None:
theme.visualize_output(force_tight_layout=True)
return theme.visualize_output(
force_tight_layout=False, external_axes=external_axes
)


def display_show(weights: Dict, tables: List[str], categories_dict: Dict[Any, Any]):
Expand Down
73 changes: 25 additions & 48 deletions openbb_terminal/portfolio/portfolio_optimization/po_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,9 @@ def display_ef(portfolio_engine: Optional[PoEngine] = None, **kwargs):

risk_free_rate = risk_free_rate / TIME_FACTOR[freq.upper()]

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_frontier(
w_frontier=frontier,
Expand Down Expand Up @@ -246,8 +243,8 @@ def display_ef(portfolio_engine: Optional[PoEngine] = None, **kwargs):
ax1 = ax.get_figure().axes
ll, bb, ww, hh = ax1[-1].get_position().bounds
ax1[-1].set_position([ll * 1.02, bb, ww, hh])
if external_axes is None:
theme.visualize_output(force_tight_layout=False)

return theme.visualize_output(force_tight_layout=False, external_axes=external_axes)


@log_start_end(log=logger)
Expand Down Expand Up @@ -417,12 +414,9 @@ def display_heat(**kwargs):
)
return

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

if len(weights) <= 3:
number_of_clusters = len(weights)
Expand Down Expand Up @@ -485,8 +479,7 @@ def display_heat(**kwargs):
title += ax[3].get_title(loc="left")
ax[3].set_title(title)

if external_axes is None:
theme.visualize_output(force_tight_layout=True)
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand All @@ -505,12 +498,9 @@ def display_rc(**kwargs):
b_sim = get_kwarg("b_sim", kwargs)
freq = get_kwarg("freq", kwargs)

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_risk_con(
w=pd.Series(weights).to_frame(),
Expand All @@ -537,8 +527,7 @@ def display_rc(**kwargs):
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand All @@ -551,12 +540,9 @@ def display_hist(**kwargs):

alpha = kwargs.get("alpha", 0.05)

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

ax = rp.plot_hist(data, w=pd.Series(weights).to_frame(), alpha=alpha, ax=ax)
ax.legend(fontsize="x-small", loc="best")
Expand All @@ -577,8 +563,7 @@ def display_hist(**kwargs):
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand All @@ -591,12 +576,9 @@ def display_dd(**kwargs):

alpha = get_kwarg("alpha", kwargs)

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

nav = data.cumsum()
ax = rp.plot_drawdown(nav=nav, w=pd.Series(weights).to_frame(), alpha=alpha, ax=ax)
Expand All @@ -623,8 +605,7 @@ def display_dd(**kwargs):
title += ax.get_title(loc="left")
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand Down Expand Up @@ -661,12 +642,9 @@ def display_pie(**kwargs):
total_size = np.sum(sizes)
colors = theme.get_colors()

if external_axes is None:
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)
else:
ax = external_axes[0]
_, ax = plt.subplots(
figsize=plot_autoscale(), dpi=get_current_user().preferences.PLOT_DPI
)

if math.isclose(sum(sizes), 1, rel_tol=0.1):
_, _, autotexts = ax.pie(
Expand Down Expand Up @@ -731,8 +709,7 @@ def display_pie(**kwargs):
title += "Portfolio Composition"
ax.set_title(title)

if external_axes is None:
theme.visualize_output()
return theme.visualize_output(force_tight_layout=True, external_axes=external_axes)


@log_start_end(log=logger)
Expand Down