diff --git a/gamestonk_terminal/parent_classes.py b/gamestonk_terminal/parent_classes.py index 9ed6df0283c..50a68a8dc70 100644 --- a/gamestonk_terminal/parent_classes.py +++ b/gamestonk_terminal/parent_classes.py @@ -27,6 +27,7 @@ from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, valid_date_in_past, ) +from gamestonk_terminal.config_terminal import theme from gamestonk_terminal.rich_config import console from gamestonk_terminal.stocks import stocks_helper from gamestonk_terminal.cryptocurrency import cryptocurrency_helpers @@ -94,6 +95,8 @@ class BaseController(metaclass=ABCMeta): ) self.parser.add_argument("cmd", choices=self.controller_choices) + theme.applyMPLstyle() + def check_path(self) -> None: path = self.PATH if path[0] != "/": diff --git a/gamestonk_terminal/stocks/comparison_analysis/finbrain_view.py b/gamestonk_terminal/stocks/comparison_analysis/finbrain_view.py index 70d50d0352d..b3270e0c521 100644 --- a/gamestonk_terminal/stocks/comparison_analysis/finbrain_view.py +++ b/gamestonk_terminal/stocks/comparison_analysis/finbrain_view.py @@ -64,8 +64,8 @@ def display_sentiment_compare( for idx, tick in enumerate(similar): offset = 2 * idx - ax.axhline(y=offset, color="grey", linestyle="--", lw=2) - ax.axhline(y=offset + 1, color="grey", linestyle="--", lw=1) + ax.axhline(y=offset, color="white", linestyle="--", lw=1) + ax.axhline(y=offset + 1, color="white", linestyle="--", lw=1) senValues = np.array(pd.to_numeric(df_sentiment[tick].values)) senNone = np.array(0 * len(df_sentiment)) @@ -74,7 +74,6 @@ def display_sentiment_compare( pd.to_numeric(df_sentiment[tick].values) + offset, offset, where=(senValues < senNone), - alpha=0.60, color=theme.down_color, interpolate=True, ) @@ -84,15 +83,13 @@ def display_sentiment_compare( pd.to_numeric(df_sentiment[tick].values) + offset, offset, where=(senValues >= senNone), - alpha=0.60, color=theme.up_color, interpolate=True, ) ax.set_ylabel("Sentiment") - ax.axhline(y=-1, color="grey", linestyle="--", lw=1) - ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) - ax.minorticks_on() + + ax.axhline(y=-1, color="white", linestyle="--", lw=1) ax.set_yticks(np.arange(len(similar)) * 2) ax.set_yticklabels(similar) ax.set_xlim(df_sentiment.index[0], df_sentiment.index[-1]) @@ -172,7 +169,9 @@ def display_sentiment_correlation( ax=ax, ) similar_string = ",".join(similar) - ax.set_title(f"Correlation heatmap across {similar_string}") + ax.set_title( + f"Sentiment correlation heatmap across \n{similar_string}", fontsize=11 + ) if not external_axes: theme.visualize_output() diff --git a/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_model.py b/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_model.py index 0bdde6b91e8..5e27b2711bb 100644 --- a/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_model.py +++ b/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_model.py @@ -3,7 +3,7 @@ __docformat__ = "numpy" import logging from datetime import datetime, timedelta -from typing import List +from typing import List, Optional import matplotlib.pyplot as plt import pandas as pd @@ -11,10 +11,11 @@ import yfinance as yf from sklearn.manifold import TSNE from sklearn.preprocessing import normalize -from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.config_terminal import theme from gamestonk_terminal.config_plot import PLOT_DPI from gamestonk_terminal.decorators import log_start_end from gamestonk_terminal.helper_funcs import plot_autoscale +from gamestonk_terminal.rich_config import console logger = logging.getLogger(__name__) @@ -84,7 +85,11 @@ def get_1y_sp500() -> pd.DataFrame: @log_start_end(log=logger) def get_sp500_comps_tsne( - ticker: str, lr: int = 200, no_plot: bool = False, num_tickers: int = 10 + ticker: str, + lr: int = 200, + no_plot: bool = False, + num_tickers: int = 10, + external_axes: Optional[List[plt.Axes]] = None, ) -> List[str]: """ Runs TSNE on SP500 tickers (along with ticker if not in SP500). @@ -125,20 +130,61 @@ def get_sp500_comps_tsne( xs = tsne_features[:, 0] ys = tsne_features[:, 1] if not no_plot: - fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) - ax.scatter(xs, ys, alpha=0.5) - for x, y, company in zip(xs, ys, rets.index): - if company != ticker: - ax.annotate(company, (x, y), fontsize=9, alpha=0.75) - else: - ax.scatter(x, y, s=50, c="r") - ax.annotate(company, (x, y), fontsize=9, alpha=1) - fig.tight_layout() - if gtff.USE_ION: - plt.ion() - plt.show() - data = pd.DataFrame({"X": xs, "Y": ys}, index=rets.index) - x0, y0 = data.loc[ticker] - data["dist"] = (data.X - x0) ** 2 + (data.Y - y0) ** 2 - data = data.sort_values(by="dist") - return data.iloc[1 : num_tickers + 1].index.to_list() + # This plot has 1 axis + if not external_axes: + _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) + else: + if len(external_axes) != 1: + console.print("[red]Expected list of one axis item./n[/red]") + return [] + (ax,) = external_axes + + data = pd.DataFrame({"X": xs, "Y": ys}, index=rets.index) + x0, y0 = data.loc[ticker] + data["dist"] = (data.X - x0) ** 2 + (data.Y - y0) ** 2 + data = data.sort_values(by="dist") + ticker_df = data[data.index == ticker] + + top_n = data.iloc[1 : (num_tickers + 1)] + top_n_name = top_n.index.to_list() + + top_100 = data[(num_tickers + 1) : 101] + + ax.scatter( + top_n.X, + top_n.Y, + alpha=0.8, + c=theme.up_color, + label=f"Top {num_tickers} closest tickers", + ) + ax.scatter( + top_100.X, top_100.Y, alpha=0.5, c="grey", label="Top 100 closest tickers" + ) + + for x, y, company in zip(top_n.X, top_n.Y, top_n.index): + ax.annotate(company, (x, y), fontsize=9, alpha=0.9) + + for x, y, company in zip(top_100.X, top_100.Y, top_100.index): + ax.annotate(company, (x, y), fontsize=9, alpha=0.75) + + ax.scatter( + ticker_df.X, + ticker_df.Y, + s=50, + c=theme.down_color, + ) + ax.annotate(ticker, (ticker_df.X, ticker_df.Y), fontsize=9, alpha=1) + ax.legend() + + ax.set_title( + f"Top 100 closest stocks on S&P500 to {ticker} using TSNE algorithm", + fontsize=11, + ) + ax.set_xlabel("Dimension 1") + ax.set_ylabel("Dimension 2") + theme.style_primary_axis(ax) + + if not external_axes: + theme.visualize_output() + + return top_n_name diff --git a/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_view.py b/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_view.py index 26667d4563b..47413d11dc0 100644 --- a/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_view.py +++ b/gamestonk_terminal/stocks/comparison_analysis/yahoo_finance_view.py @@ -89,12 +89,14 @@ def display_historical( return (ax,) = external_axes - ax.plot(df_similar) + # breakpoint() + companies_names = df_similar.columns.to_list() + ax.plot(df_similar, label=companies_names) ax.set_title("Historical price of similar companies") ax.set_ylabel(f"{['','Normalized'][normalize]} Share Price {['($)',''][normalize]}") # ensures that the historical data starts from same datapoint ax.set_xlim([df_similar.index[0], df_similar.index[-1]]) - + ax.legend(loc="best") theme.style_primary_axis(ax) if not external_axes: @@ -139,13 +141,15 @@ def display_volume( (ax,) = external_axes df_similar = df_similar.div(1_000_000) + companies_names = df_similar.columns.to_list() - ax.plot(df_similar) + ax.plot(df_similar, label=companies_names) ax.set_title("Historical volume of similar companies") ax.set_ylabel("Volume [M]") # ensures that the historical data starts from same datapoint ax.set_xlim([df_similar.index[0], df_similar.index[-1]]) + ax.legend() theme.style_primary_axis(ax) if not external_axes: diff --git a/gamestonk_terminal/stocks/dark_pool_shorts/finra_view.py b/gamestonk_terminal/stocks/dark_pool_shorts/finra_view.py index 264556efbfb..48fe81de482 100644 --- a/gamestonk_terminal/stocks/dark_pool_shorts/finra_view.py +++ b/gamestonk_terminal/stocks/dark_pool_shorts/finra_view.py @@ -108,6 +108,7 @@ def plot_dark_pools( ax2.set_ylabel("Shares per Trade") ax2.xaxis.set_major_formatter(mdates.DateFormatter("%m/%d")) ax2.xaxis.set_major_locator(mdates.DayLocator(interval=4)) + ax2.set_xlim(otc.index[0], otc.index[-1]) ax2.set_xlabel("Weeks") theme.style_primary_axis(ax1) @@ -191,6 +192,8 @@ def plot_dark_pools_ats( ax.set_ylabel("Total Weekly Shares [Million]") ax.set_title("Dark Pool (ATS) growing tickers") ax.set_xlabel("Weeks") + ats["weekStartDate"] = pd.to_datetime(ats["weekStartDate"]) + ax.set_xlim(ats["weekStartDate"].iloc[0], ats["weekStartDate"].iloc[-1]) theme.style_primary_axis(ax) if not external_axes: diff --git a/gamestonk_terminal/stocks/dark_pool_shorts/nyse_view.py b/gamestonk_terminal/stocks/dark_pool_shorts/nyse_view.py index c744f5bce1b..ec65f7bdb9c 100644 --- a/gamestonk_terminal/stocks/dark_pool_shorts/nyse_view.py +++ b/gamestonk_terminal/stocks/dark_pool_shorts/nyse_view.py @@ -86,6 +86,11 @@ def display_short_by_exchange( # remove the scientific notion on the left hand side ax.ticklabel_format(style="plain", axis="y") + ax.set_xlim( + volume_by_exchange.Date.iloc[0], + volume_by_exchange.Date.iloc[-1], + ) + ax.set_title(f"Net Short Volume for {ticker}") theme.style_primary_axis(ax) diff --git a/gamestonk_terminal/stocks/dark_pool_shorts/sec_view.py b/gamestonk_terminal/stocks/dark_pool_shorts/sec_view.py index 13a62cef37e..f77757bacaf 100644 --- a/gamestonk_terminal/stocks/dark_pool_shorts/sec_view.py +++ b/gamestonk_terminal/stocks/dark_pool_shorts/sec_view.py @@ -71,9 +71,11 @@ def fails_to_deliver( ax1.bar( ftds_data["SETTLEMENT DATE"], ftds_data["QUANTITY (FAILS)"] / 1000, + label="Fail Quantity", ) ax1.set_ylabel("Shares [K]") ax1.set_title(f"Fails-to-deliver Data for {ticker}") + ax1.legend(loc="lower right") if num > 0: stock_ftd = stock[stock.index > (datetime.now() - timedelta(days=num + 31))] @@ -81,8 +83,11 @@ def fails_to_deliver( stock_ftd = stock[stock.index > start] stock_ftd = stock_ftd[stock_ftd.index < end] - ax2.plot(stock_ftd.index, stock_ftd["Adj Close"], color="tab:orange") + ax2.plot( + stock_ftd.index, stock_ftd["Adj Close"], color="orange", label="Share Price" + ) ax2.set_ylabel("Share Price [$]") + ax2.legend(loc="upper right") theme.style_twin_axes(ax1, ax2) diff --git a/gamestonk_terminal/stocks/dark_pool_shorts/stockgrid_view.py b/gamestonk_terminal/stocks/dark_pool_shorts/stockgrid_view.py index 965c4dc4883..fa613b99046 100644 --- a/gamestonk_terminal/stocks/dark_pool_shorts/stockgrid_view.py +++ b/gamestonk_terminal/stocks/dark_pool_shorts/stockgrid_view.py @@ -197,7 +197,6 @@ def short_interest_volume( df["total_volume"] / 1_000_000, width=timedelta(days=1), color=theme.up_color, - alpha=0.4, label="Total Volume", ) ax.bar( @@ -205,7 +204,6 @@ def short_interest_volume( df["short_volume"] / 1_000_000, width=timedelta(days=1), color=theme.down_color, - alpha=0.4, label="Short Volume", ) @@ -327,7 +325,6 @@ def net_short_position( df["dates"], df["dollar_net_volume"] / 1_000, color=theme.down_color, - alpha=0.4, label="Net Short Vol. (1k $)", ) ax1.set_ylabel("Net Short Vol. (1k $)") diff --git a/gamestonk_terminal/stocks/due_diligence/business_insider_view.py b/gamestonk_terminal/stocks/due_diligence/business_insider_view.py index 303187d0f21..04165d47530 100644 --- a/gamestonk_terminal/stocks/due_diligence/business_insider_view.py +++ b/gamestonk_terminal/stocks/due_diligence/business_insider_view.py @@ -85,10 +85,12 @@ def price_target_from_analysts( df_analyst_data = df_analyst_data[start:] # type: ignore if interval == "1440min": - ax.plot(stock.index, stock["Adj Close"].values, lw=3) + ax.plot(stock.index, stock["Adj Close"].values) + legend_price_label = "Adjusted closing price" # Intraday else: - ax.plot(stock.index, stock["Close"].values, lw=3) + ax.plot(stock.index, stock["Close"].values) + legend_price_label = "Closing price" if start: ax.plot(df_analyst_data.groupby(by=["Date"]).mean()[start:]) # type: ignore @@ -96,10 +98,14 @@ def price_target_from_analysts( ax.plot(df_analyst_data.groupby(by=["Date"]).mean()) ax.scatter( - df_analyst_data.index, df_analyst_data["Price Target"], c="red", s=40 + df_analyst_data.index, + df_analyst_data["Price Target"], + color=theme.down_color, + edgecolors=theme.up_color, + zorder=2, ) - ax.legend(["Closing Price", "Average Price Target", "Price Target"]) + ax.legend([legend_price_label, "Average Price Target", "Price Target"]) ax.set_title(f"{ticker} (Time Series) and Price Target") ax.set_xlim(stock.index[0], stock.index[-1]) diff --git a/gamestonk_terminal/stocks/fundamental_analysis/yahoo_finance_view.py b/gamestonk_terminal/stocks/fundamental_analysis/yahoo_finance_view.py index 43b3db2fd8d..b76a3024465 100644 --- a/gamestonk_terminal/stocks/fundamental_analysis/yahoo_finance_view.py +++ b/gamestonk_terminal/stocks/fundamental_analysis/yahoo_finance_view.py @@ -191,11 +191,12 @@ def display_dividends( mfc=theme.down_color, mec=theme.down_color, alpha=1, + label="Dividends Payout", ) ax.set_ylabel("Amount ($)") ax.set_title(f"Dividend History for {ticker}") ax.set_xlim(div_history.index[-1], div_history.index[0]) - + ax.legend() theme.style_primary_axis(ax) if not external_axes: diff --git a/gamestonk_terminal/stocks/government/quiverquant_view.py b/gamestonk_terminal/stocks/government/quiverquant_view.py index b79882f215c..1ea158e0b1a 100644 --- a/gamestonk_terminal/stocks/government/quiverquant_view.py +++ b/gamestonk_terminal/stocks/government/quiverquant_view.py @@ -11,6 +11,7 @@ from datetime import datetime, timedelta import numpy as np import pandas as pd from matplotlib import pyplot as plt +import matplotlib from gamestonk_terminal.config_terminal import theme from gamestonk_terminal.config_plot import PLOT_DPI @@ -203,9 +204,10 @@ def display_government_buys( return (ax,) = external_axes + colors = theme.get_colors() df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values(ascending=False).head( n=num - ).plot(kind="bar", rot=0, ax=ax) + ).plot(kind="bar", rot=0, ax=ax, color=colors) ax.set_ylabel("Amount [1k $]") ax.set_title( @@ -321,15 +323,15 @@ def display_government_sells( return (ax,) = external_axes + colors = theme.get_colors() df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values().abs().head( n=num - ).plot(kind="bar", rot=0, ax=ax) + ).plot(kind="bar", rot=0, ax=ax, color=colors) ax.set_ylabel("Amount ($1k)") ax.set_title( f"{num} most sold stocks over last {past_transactions_months} months" f" (upper bound) for {gov_type}" ) - # plt.gcf().axes[0].yaxis.get_major_formatter().set_scientific(False) theme.style_primary_axis(ax) @@ -608,6 +610,8 @@ def display_contracts( ax.set_ylabel("Amount ($1k)") ax.set_title(f"Sum of latest government contracts to {ticker}") + ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(4)) + theme.style_primary_axis(ax) if not external_axes: @@ -775,7 +779,14 @@ def display_hist_contracts( return (ax,) = external_axes - ax.plot(np.arange(0, len(amounts)), amounts / 1000, "-*", lw=2, ms=15) + ax.plot( + np.arange(0, len(amounts)), + amounts / 1000, + marker=".", + markerfacecolor=theme.down_color, + lw=2, + ms=15, + ) ax.set_xlim([-0.5, len(amounts) - 0.5]) ax.set_xticks(np.arange(0, len(amounts))) @@ -844,7 +855,8 @@ def display_top_lobbying( return (ax,) = external_axes - lobbying_by_ticker.head(num).plot(kind="bar", ax=ax) + colors = theme.get_colors() + lobbying_by_ticker.head(num).plot(kind="bar", ax=ax, color=colors) ax.set_xlabel("Ticker") ax.set_ylabel("Total Amount ($100k)") ax.set_title(f"Corporate Lobbying Spent since {df_lobbying['Date'].min()}") diff --git a/gamestonk_terminal/stocks/insider/businessinsider_view.py b/gamestonk_terminal/stocks/insider/businessinsider_view.py index b3bc748940c..9c42f5cc1f7 100644 --- a/gamestonk_terminal/stocks/insider/businessinsider_view.py +++ b/gamestonk_terminal/stocks/insider/businessinsider_view.py @@ -103,7 +103,7 @@ def insider_activity( * float(row["Shares Traded"].replace(",", "")), axis=1, ) - ax.set_xlim(df_insider.index[0], stock.index[-1]) + ax.set_xlim(right=stock.index[-1]) min_price, max_price = ax.get_ylim() price_range = max_price - min_price diff --git a/gamestonk_terminal/stocks/sector_industry_analysis/financedatabase_view.py b/gamestonk_terminal/stocks/sector_industry_analysis/financedatabase_view.py index 548522988f7..23defa83ed9 100644 --- a/gamestonk_terminal/stocks/sector_industry_analysis/financedatabase_view.py +++ b/gamestonk_terminal/stocks/sector_industry_analysis/financedatabase_view.py @@ -296,8 +296,8 @@ def display_companies_per_sector_in_country( df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " cap companies " if mktcap else "Companies " - title += f"in {country}" - title += " excl. exchanges" if exclude_exchanges else " incl. exchanges" + title += f"in {country}\n" + title += "excl. exchanges" if exclude_exchanges else " incl. exchanges" if raw: print_rich_table(df, headers=list(df.columns), show_index=True, title=title) @@ -357,7 +357,7 @@ def display_companies_per_sector_in_country( colors=colors, wedgeprops={"linewidth": 0.5, "edgecolor": "white"}, labeldistance=1.05, - startangle=90, + startangle=45, ) ax.set_title(title, fontsize=14) @@ -439,8 +439,8 @@ def display_companies_per_industry_in_country( df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " cap companies " if mktcap else "Companies " - title += f"in {country}" - title += " excl. exchanges" if exclude_exchanges else " incl. exchanges" + title += f"in {country}\n" + title += "excl. exchanges" if exclude_exchanges else " incl. exchanges" if raw: print_rich_table(df, headers=list(df.columns), show_index=True, title=title) @@ -507,7 +507,7 @@ def display_companies_per_industry_in_country( colors=colors, wedgeprops={"linewidth": 0.5, "edgecolor": "white"}, labeldistance=1.05, - startangle=90, + startangle=45, ) ax.set_title(title, fontsize=14) @@ -587,8 +587,8 @@ def display_companies_per_industry_in_sector( df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " cap companies " if mktcap else "Companies " - title += f"in {sector} sector" - title += " excl. exchanges" if exclude_exchanges else " incl. exchanges" + title += f"in {sector} sector\n" + title += "excl. exchanges" if exclude_exchanges else " incl. exchanges" if raw: print_rich_table( @@ -660,7 +660,7 @@ def display_companies_per_industry_in_sector( colors=colors, wedgeprops={"linewidth": 0.5, "edgecolor": "white"}, labeldistance=1.05, - startangle=90, + startangle=45, ) ax.set_title(title, fontsize=14) @@ -739,8 +739,8 @@ def display_companies_per_country_in_sector( df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " cap companies " if mktcap else "Companies " - title += f"in {sector} sector" - title += " excl. exchanges" if exclude_exchanges else " incl. exchanges" + title += f"in {sector} sector\n" + title += "excl. exchanges" if exclude_exchanges else " incl. exchanges" if raw: print_rich_table(df, headers=list(df.columns), show_index=True, title=title) @@ -805,7 +805,7 @@ def display_companies_per_country_in_sector( colors=colors, wedgeprops={"linewidth": 0.5, "edgecolor": "white"}, labeldistance=1.05, - startangle=90, + startangle=45, ) ax.set_title(title, fontsize=14) @@ -884,8 +884,8 @@ def display_companies_per_country_in_industry( df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " cap companies " if mktcap else "Companies " - title += f"per country in {industry} industry" - title += " excl. exchanges" if exclude_exchanges else " incl. exchanges" + title += f"per country in {industry} industry\n" + title += "excl. exchanges" if exclude_exchanges else " incl. exchanges" if raw: print_rich_table(df, headers=list(df.columns), show_index=True, title=title) @@ -950,7 +950,7 @@ def display_companies_per_country_in_industry( colors=colors, wedgeprops={"linewidth": 0.5, "edgecolor": "white"}, labeldistance=1.05, - startangle=90, + startangle=45, ) ax.set_title(title, fontsize=14) diff --git a/gamestonk_terminal/stocks/stocks_helper.py b/gamestonk_terminal/stocks/stocks_helper.py index 3d385530b9f..1a67fa0b194 100644 --- a/gamestonk_terminal/stocks/stocks_helper.py +++ b/gamestonk_terminal/stocks/stocks_helper.py @@ -21,8 +21,8 @@ from numpy.core.fromnumeric import transpose from plotly.subplots import make_subplots from scipy import stats +from gamestonk_terminal.config_terminal import theme from gamestonk_terminal import config_terminal as cfg -from gamestonk_terminal import feature_flags as gtff from gamestonk_terminal.helper_funcs import ( parse_known_args_and_warn, plot_autoscale, @@ -269,6 +269,7 @@ def display_candle( add_trend: bool = False, ma: Optional[Tuple[int, ...]] = None, asset_type: str = "Stock", + external_axes: Optional[List[plt.Axes]] = None, ): """Shows candle plot of loaded ticker. [Source: Yahoo Finance, IEX Cloud or Alpha Vantage] @@ -288,6 +289,10 @@ def display_candle( Moving averages to add to the candle asset_type_: str String to include in title + external_axes : Optional[List[plt.Axes]], optional + External axes (2 axes are expected in the list), by default None + asset_type_: str + String to include in title """ if add_trend: if (df_stock.index[1] - df_stock.index[0]).total_seconds() >= 86400: @@ -299,45 +304,54 @@ def display_candle( if add_trend: if "OC_High_trend" in df_stock.columns: ap0.append( - mpf.make_addplot(df_stock["OC_High_trend"], color="g"), + mpf.make_addplot(df_stock["OC_High_trend"], color=theme.up_color), ) if "OC_Low_trend" in df_stock.columns: ap0.append( - mpf.make_addplot(df_stock["OC_Low_trend"], color="b"), + mpf.make_addplot(df_stock["OC_Low_trend"], color=theme.down_color), ) - if gtff.USE_ION: - plt.ion() + candle_chart_kwargs = { + "type": "candle", + "style": theme.mpf_style, + "volume": True, + "addplot": ap0, + "xrotation": theme.xticks_rotation, + "scale_padding": {"left": 0.3, "right": 1, "top": 0.8, "bottom": 0.8}, + "update_width_config": { + "candle_linewidth": 0.6, + "candle_width": 0.8, + "volume_linewidth": 0.8, + "volume_width": 0.8, + }, + "warn_too_much_data": 10000, + } + kwargs = {"mav": ma} if ma else {} - fig, _ = mpf.plot( - df_stock, - type="candle", - style=cfg.theme.mpf_style, - volume=True, - addplot=ap0, - xrotation=10, - figratio=(10, 7), - figscale=1.10, - scale_padding={"left": 0.3, "right": 1.1, "top": 0.8, "bottom": 0.8}, - figsize=(plot_autoscale()), - update_width_config=dict( - candle_linewidth=0.6, - candle_width=0.8, - volume_linewidth=0.8, - volume_width=0.8, - ), - warn_too_much_data=10000, - returnfig=True, - **kwargs, - ) - fig.suptitle( - f"{asset_type} {s_ticker}", - x=0.055, - y=0.965, - horizontalalignment="left", - ) + if external_axes is None: + candle_chart_kwargs["returnfig"] = True + candle_chart_kwargs["figratio"] = (10, 7) + candle_chart_kwargs["figscale"] = 1.10 + candle_chart_kwargs["figsize"] = plot_autoscale() + fig, _ = mpf.plot(df_stock, **candle_chart_kwargs, **kwargs) + fig.suptitle( + f"{asset_type} {s_ticker}", + x=0.055, + y=0.965, + horizontalalignment="left", + ) + + theme.visualize_output(force_tight_layout=False) + else: + if len(external_axes) != 1: + console.print("[red]Expected list of 1 axis items./n[/red]") + return + (ax1,) = external_axes + candle_chart_kwargs["ax"] = ax1 + mpf.plot(df_stock, **candle_chart_kwargs) + else: fig = make_subplots( rows=2, diff --git a/styles/default/dark.mplstyle b/styles/default/dark.mplstyle index 5d81706e86d..52ac57cf4dd 100644 --- a/styles/default/dark.mplstyle +++ b/styles/default/dark.mplstyle @@ -54,6 +54,7 @@ xtick.major.size: 2 xtick.minor.size: 1 xtick.labelsize: small xtick.alignment: center +xtick.major.width: 0.2 ytick.major.size: 2 ytick.minor.size: 1 @@ -63,6 +64,7 @@ ytick.left: False ytick.labelleft: False ytick.right: True ytick.labelright: True +ytick.major.width: 0.2 grid.color: F5EFF3 grid.linewidth: 0.4 diff --git a/tests/gamestonk_terminal/stocks/test_stocks_helper.py b/tests/gamestonk_terminal/stocks/test_stocks_helper.py index 80de1820353..384d8bf34b8 100644 --- a/tests/gamestonk_terminal/stocks/test_stocks_helper.py +++ b/tests/gamestonk_terminal/stocks/test_stocks_helper.py @@ -6,6 +6,7 @@ import pytest # IMPORTATION INTERNAL from gamestonk_terminal.stocks import stocks_helper +from gamestonk_terminal import helper_funcs @pytest.fixture(scope="module") @@ -35,7 +36,7 @@ def test_quote(): ) def test_search(mocker, use_tab): mocker.patch.object( - target=stocks_helper.gtff, attribute="USE_TABULATE_DF", new=use_tab + target=helper_funcs.gtff, attribute="USE_TABULATE_DF", new=use_tab ) stocks_helper.search(query="pharma", amount=5) @@ -73,8 +74,11 @@ def test_load(interval, recorder, source): [True, False], ) def test_display_candle(mocker, use_matplotlib): - mocker.patch.object(target=stocks_helper.gtff, attribute="USE_ION", new=False) - mocker.patch("matplotlib.pyplot.show") + # MOCK VISUALIZE_OUTPUT + mocker.patch( + target="gamestonk_terminal.helper_classes.TerminalStyle.visualize_output" + ) + mocker.patch("plotly.basedatatypes.BaseFigure.show") # LOAD DATA