Fix projection plot bugs.
This commit is contained in:
@@ -646,14 +646,20 @@ def create_plots(df, start=None, end=None, project_days=365):
|
|||||||
# Set up the style
|
# Set up the style
|
||||||
plt.style.use("seaborn-v0_8")
|
plt.style.use("seaborn-v0_8")
|
||||||
|
|
||||||
# Create figure with adjusted size for additional subplot
|
# Create figure with adjusted size and spacing
|
||||||
_ = plt.figure(figsize=(15, 15)) # Increased height to accommodate new subplot
|
fig = plt.figure(figsize=(15, 15))
|
||||||
|
|
||||||
|
# Use GridSpec for better control over subplot spacing
|
||||||
|
gs = plt.GridSpec(5, 1, height_ratios=[3, 1.5, 1.5, 1.5, 2], hspace=0.4)
|
||||||
|
|
||||||
# Date range for titles
|
# Date range for titles
|
||||||
hist_date_range = f" ({plot_df['Date'].min().strftime('%Y-%m-%d')} to {plot_df['Date'].max().strftime('%Y-%m-%d')})"
|
hist_date_range = f" ({plot_df['Date'].min().strftime('%Y-%m-%d')} to {plot_df['Date'].max().strftime('%Y-%m-%d')})"
|
||||||
|
|
||||||
|
# Calculate full date range including projections
|
||||||
|
full_date_range = pd.date_range(plot_df["Date"].min(), projections.index.max())
|
||||||
|
|
||||||
# 1. Price history and projections (log scale)
|
# 1. Price history and projections (log scale)
|
||||||
ax1 = plt.subplot(4, 1, 1)
|
ax1 = fig.add_subplot(gs[0])
|
||||||
|
|
||||||
# Plot historical prices
|
# Plot historical prices
|
||||||
ax1.semilogy(plot_df["Date"], plot_df["Close"], "b-", label="Historical Price")
|
ax1.semilogy(plot_df["Date"], plot_df["Close"], "b-", label="Historical Price")
|
||||||
@@ -703,22 +709,43 @@ def create_plots(df, start=None, end=None, project_days=365):
|
|||||||
ax1.set_title("Bitcoin Price History and Projections (Log Scale)" + hist_date_range)
|
ax1.set_title("Bitcoin Price History and Projections (Log Scale)" + hist_date_range)
|
||||||
ax1.legend(fontsize=8)
|
ax1.legend(fontsize=8)
|
||||||
|
|
||||||
|
# Set x-axis limits to full range
|
||||||
|
ax1.set_xlim(full_date_range[0], full_date_range[-1])
|
||||||
|
ax1.tick_params(axis="x", rotation=45)
|
||||||
|
|
||||||
# 3. Rolling volatility
|
# 3. Rolling volatility
|
||||||
ax3 = plt.subplot(5, 1, 2)
|
ax3 = fig.add_subplot(gs[1])
|
||||||
ax3.plot(
|
ax3.plot(
|
||||||
plot_df["Date"],
|
plot_df["Date"],
|
||||||
plot_df["Rolling_Volatility_30d"],
|
plot_df["Rolling_Volatility_30d"],
|
||||||
"r-",
|
"r-",
|
||||||
label="30-Day Rolling Volatility",
|
label="30-Day Rolling Volatility",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add empty space to match price plot x-axis
|
||||||
|
ax3.set_xlim(full_date_range[0], full_date_range[-1])
|
||||||
|
|
||||||
|
# Add vertical line to mark start of projections
|
||||||
|
ax3.axvline(plot_df["Date"].max(), color="gray", linestyle="--", alpha=0.5)
|
||||||
|
ax3.text(
|
||||||
|
plot_df["Date"].max(),
|
||||||
|
ax3.get_ylim()[1],
|
||||||
|
"Projection Start",
|
||||||
|
rotation=90,
|
||||||
|
va="top",
|
||||||
|
ha="right",
|
||||||
|
alpha=0.7,
|
||||||
|
)
|
||||||
|
|
||||||
ax3.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
|
ax3.set_title("30-Day Rolling Volatility (Annualized)" + hist_date_range)
|
||||||
ax3.set_ylabel("Volatility")
|
ax3.set_ylabel("Volatility")
|
||||||
ax3.grid(True)
|
ax3.grid(True)
|
||||||
ax3.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
|
ax3.yaxis.set_major_formatter(plt.FuncFormatter(lambda y, _: "{:.0%}".format(y)))
|
||||||
ax3.legend()
|
ax3.legend()
|
||||||
|
ax3.tick_params(axis="x", rotation=45)
|
||||||
|
|
||||||
# 4. Returns distribution
|
# 4. Returns distribution
|
||||||
ax4 = plt.subplot(5, 1, 3)
|
ax4 = fig.add_subplot(gs[2])
|
||||||
returns_mean = plot_df["Daily_Return"].mean()
|
returns_mean = plot_df["Daily_Return"].mean()
|
||||||
returns_std = plot_df["Daily_Return"].std()
|
returns_std = plot_df["Daily_Return"].std()
|
||||||
filtered_returns = plot_df["Daily_Return"][
|
filtered_returns = plot_df["Daily_Return"][
|
||||||
@@ -746,7 +773,7 @@ def create_plots(df, start=None, end=None, project_days=365):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 5. Projection ranges
|
# 5. Projection ranges
|
||||||
ax5 = plt.subplot(5, 1, 4)
|
ax5 = fig.add_subplot(gs[3:]) # Use last two grid spaces for larger plot
|
||||||
timepoints = np.array(range(30, project_days, 30))
|
timepoints = np.array(range(30, project_days, 30))
|
||||||
timepoints = timepoints[timepoints <= project_days]
|
timepoints = timepoints[timepoints <= project_days]
|
||||||
|
|
||||||
@@ -786,13 +813,13 @@ def create_plots(df, start=None, end=None, project_days=365):
|
|||||||
ax5.grid(True, alpha=0.3)
|
ax5.grid(True, alpha=0.3)
|
||||||
ax5.set_xticks(timepoints)
|
ax5.set_xticks(timepoints)
|
||||||
|
|
||||||
# Adjust layout
|
|
||||||
plt.tight_layout(h_pad=1.0) # Increased spacing between subplots
|
|
||||||
|
|
||||||
# Save the plot
|
# Save the plot
|
||||||
start_str = start if start else plot_df["Date"].min().strftime("%Y-%m-%d")
|
start_str = start if start else plot_df["Date"].min().strftime("%Y-%m-%d")
|
||||||
end_str = end if end else plot_df["Date"].max().strftime("%Y-%m-%d")
|
end_str = end if end else plot_df["Date"].max().strftime("%Y-%m-%d")
|
||||||
filename = f"bitcoin_analysis_{start_str}_to_{end_str}_with_projections.png"
|
filename = f"bitcoin_analysis_{start_str}_to_{end_str}_with_projections.png"
|
||||||
|
|
||||||
|
# Use tight_layout with adjusted parameters
|
||||||
|
plt.tight_layout(pad=2.0)
|
||||||
plt.savefig(filename, dpi=300, bbox_inches="tight")
|
plt.savefig(filename, dpi=300, bbox_inches="tight")
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user