Aliazimi00 commited on
Commit
bb64899
·
verified ·
1 Parent(s): c198814

Delete core/plot.py

Browse files
Files changed (1) hide show
  1. core/plot.py +0 -330
core/plot.py DELETED
@@ -1,330 +0,0 @@
1
- import matplotlib.pyplot as plt
2
- import seaborn as sns
3
- import pandas as pd
4
- import numpy as np
5
- import networkx as nx
6
-
7
-
8
- def plot_forecast(result):
9
- """Modified to show only last day backtest comparison"""
10
- forecast = result["forecast"]
11
- actual = result["actual"]
12
- next_pred = result.get("latest_prediction", [])
13
-
14
- fig, ax = plt.subplots(figsize=(10, 6))
15
-
16
- # Plot most of the data normally
17
- ax.plot(actual[:-1], label="Historical", color="blue", linewidth=2, alpha=0.7)
18
- ax.plot(forecast[:-1], label="Historical Forecast", color="orange", linestyle="--", linewidth=1, alpha=0.7)
19
-
20
- # Highlight only the last day comparison (backtest)
21
- if len(actual) > 0 and len(forecast) > 0:
22
- last_idx = len(actual) - 1
23
- ax.plot([last_idx-1, last_idx], [actual[last_idx-1], actual[last_idx]],
24
- color="blue", linewidth=3, label="Last Day Actual")
25
- ax.plot([last_idx-1, last_idx], [forecast[last_idx-1], forecast[last_idx]],
26
- color="red", linewidth=3, linestyle="--", label="Last Day Predicted")
27
-
28
- # Add markers for the last day comparison
29
- ax.scatter([last_idx], [actual[last_idx]], color="blue", s=100, zorder=5)
30
- ax.scatter([last_idx], [forecast[last_idx]], color="red", s=100, zorder=5)
31
-
32
- # Add value annotations for last day
33
- actual_val = float(actual[last_idx])
34
- forecast_val = float(forecast[last_idx])
35
- ax.annotate(f'Actual: {actual_val:.2f}',
36
- xy=(last_idx, actual_val),
37
- xytext=(10, 10), textcoords='offset points',
38
- bbox=dict(boxstyle='round,pad=0.3', facecolor='blue', alpha=0.7, edgecolor='none'),
39
- color='white', fontsize=9, fontweight='bold')
40
- ax.annotate(f'Predicted: {forecast_val:.2f}',
41
- xy=(last_idx, forecast_val),
42
- xytext=(10, -20), textcoords='offset points',
43
- bbox=dict(boxstyle='round,pad=0.3', facecolor='red', alpha=0.7, edgecolor='none'),
44
- color='white', fontsize=9, fontweight='bold')
45
-
46
- ax.legend()
47
- ax.set_title("Forecast vs Actual (Last Day Backtest Highlighted)")
48
- ax.set_xlabel("Time Index")
49
- ax.set_ylabel("Value")
50
- ax.grid(True, alpha=0.3)
51
- plt.tight_layout()
52
- return fig
53
-
54
-
55
- def plot_future_forecast(df, result, future_df):
56
- """Enhanced to show trend lines for predictions"""
57
- fig, ax = plt.subplots(figsize=(12, 7))
58
-
59
- # Plot historical data
60
- ax.plot(df['Date'], df['value'], label="Historical Data", color="blue", linewidth=2)
61
-
62
- if "latest_prediction" in result:
63
- last_date = df['Date'].iloc[-1]
64
- horizon = len(result["latest_prediction"])
65
- future_dates = pd.date_range(start=last_date + pd.Timedelta(days=1), periods=horizon, freq='B')
66
-
67
- # Create connection from last historical point to first prediction
68
- connection_dates = [last_date, future_dates[0]]
69
- connection_values = [df['value'].iloc[-1], result["latest_prediction"][0]]
70
- ax.plot(connection_dates, connection_values, color="orange", linestyle=":", linewidth=1, alpha=0.7)
71
-
72
- # Plot forecast with fine connecting lines
73
- ax.plot(future_dates, result["latest_prediction"],
74
- label="Forecast", color="orange", linewidth=2.5,
75
- linestyle="-", marker='o', markersize=6, markerfacecolor='orange',
76
- markeredgecolor='darkorange', markeredgewidth=1)
77
-
78
- # Add value annotations for predictions
79
- for i, val in enumerate(result["latest_prediction"]):
80
- val_float = float(val)
81
- ax.annotate(f"{val_float:.2f}",
82
- xy=(future_dates[i], val_float),
83
- xytext=(0, 15), textcoords='offset points',
84
- ha='center', va='bottom',
85
- bbox=dict(boxstyle='round,pad=0.2', facecolor='orange', alpha=0.8, edgecolor='darkorange'),
86
- color='white', fontsize=8, fontweight='bold')
87
-
88
- # Plot actual future values if available
89
- if not future_df.empty and "future_actuals" in result:
90
- actual_future_dates = future_df['Date']
91
- actual_future_values = future_df['value']
92
-
93
- # Connect to actual future values
94
- ax.plot(actual_future_dates, actual_future_values,
95
- label="Actual Future", color="green", linewidth=2.5,
96
- linestyle="-", marker='s', markersize=6, markerfacecolor='green',
97
- markeredgecolor='darkgreen', markeredgewidth=1)
98
-
99
- # Add value annotations for actuals
100
- for i, val in enumerate(actual_future_values):
101
- val_float = float(val)
102
- ax.annotate(f"{val_float:.2f}",
103
- xy=(actual_future_dates.iloc[i], val_float),
104
- xytext=(0, -20), textcoords='offset points',
105
- ha='center', va='top',
106
- bbox=dict(boxstyle='round,pad=0.2', facecolor='green', alpha=0.8, edgecolor='darkgreen'),
107
- color='white', fontsize=8, fontweight='bold')
108
-
109
- ax.legend(loc='upper left')
110
- ax.set_title("Stock Prediction: Historical Data → Future Forecast", fontsize=14, fontweight='bold')
111
- ax.set_xlabel("Date", fontsize=12)
112
- ax.set_ylabel("Stock Price", fontsize=12)
113
- ax.grid(True, alpha=0.3)
114
-
115
- # Improve date formatting on x-axis
116
- fig.autofmt_xdate(rotation=45)
117
- plt.tight_layout()
118
- return fig
119
-
120
-
121
- def plot_metrics_precision(result):
122
- fig, ax = plt.subplots(figsize=(8, 5))
123
- metrics = {k: v for k, v in result['metrics'].items() if k in ['R² (%)', 'Explained Variance (%)', 'MDA (%)'] and v is not None}
124
- if not metrics:
125
- ax.text(0.5, 0.5, "No valid precision metrics available", ha='center', va='center')
126
- ax.set_title("Precision Metrics (Model Accuracy)")
127
- return fig
128
-
129
- sns.barplot(x=list(metrics.keys()), y=list(metrics.values()), ax=ax, palette="Blues_d")
130
- for i, v in enumerate(metrics.values()):
131
- ax.text(i, v + 0.01 * max(metrics.values(), default=100), f"{v:.2f}%", ha='center', va='bottom', fontsize=10)
132
-
133
- max_val = max(metrics.values(), default=100)
134
- min_val = min(metrics.values(), default=0)
135
- ax.set_ylim(min(min_val - 5, -10), max_val + 10)
136
- ax.set_ylabel("Value (%)")
137
- ax.set_title("Precision Metrics (Model Accuracy)")
138
- ax.grid(True, axis='y')
139
- plt.tight_layout()
140
- return fig
141
-
142
-
143
- def plot_metrics_risk(result):
144
- fig, ax = plt.subplots(figsize=(8, 5))
145
- metrics = {k: v for k, v in result['metrics'].items() if k in ['RMSE', 'MAE', 'MAPE (%)', 'MASE'] and v is not None}
146
- if not metrics:
147
- ax.text(0.5, 0.5, "No valid risk metrics available", ha='center', va='center')
148
- ax.set_title("Risk Metrics (Error Magnitude)")
149
- return fig
150
-
151
- sns.barplot(x=list(metrics.keys()), y=list(metrics.values()), ax=ax, palette="Reds_d")
152
- for i, v in enumerate(metrics.values()):
153
- ax.text(i, v + 0.01 * max(metrics.values(), default=1), f"{v:.2f}", ha='center', va='bottom', fontsize=10)
154
-
155
- max_val = max(metrics.values(), default=1)
156
- ax.set_ylim(0, max_val + 0.2 * max_val)
157
- ax.set_ylabel("Value")
158
- ax.set_title("Risk Metrics (Error Magnitude)")
159
- ax.grid(True, axis='y')
160
- plt.tight_layout()
161
- return fig
162
-
163
-
164
- def plot_loss_curve(result):
165
- train_losses = result.get('train_loss', [])
166
- val_losses = result.get('val_loss', [])
167
- fig, ax = plt.subplots(figsize=(8, 5))
168
- ax.plot(train_losses, label='Train Loss', color='blue', linewidth=2)
169
- if val_losses:
170
- ax.plot(val_losses, label='Validation Loss', color='orange', linewidth=2)
171
- ax.set_title('Training and Validation Loss Curve')
172
- ax.set_xlabel('Epoch')
173
- ax.set_ylabel('Loss (MSE)')
174
- ax.legend()
175
- ax.grid(True)
176
- plt.tight_layout()
177
- return fig
178
-
179
-
180
- def plot_model_architecture(result):
181
- fig, ax = plt.subplots(figsize=(10, 6))
182
- ax.axis('off')
183
- G = nx.DiGraph()
184
-
185
- if "architecture" not in result:
186
- ax.text(0.5, 0.5, "No architecture details available", ha='center', va='center', fontsize=12)
187
- ax.set_title("Model Architecture")
188
- plt.tight_layout()
189
- return fig
190
-
191
- arch = result["architecture"]
192
- model_name = arch["model_name"]
193
- num_layers = arch["num_layers"]
194
- hidden_units = arch["hidden_units"]
195
- dropout = arch["dropout"]
196
- batch_size = arch["batch_size"]
197
- input_size = arch["input_size"]
198
- output_size = arch["output_size"]
199
-
200
- # Handle model-specific hidden units for visualization
201
- if model_name == "MLPModel":
202
- hidden_nodes = min(hidden_units[0], 5) # Use first hidden layer size
203
- units_label = f"{hidden_units[0]},{hidden_units[1]}" # Show both sizes
204
- elif model_name == "CNNModel":
205
- hidden_nodes = 5 # Simplified for visualization
206
- units_label = f"{hidden_units} filters" # num_filters
207
- elif model_name == "TransformerModel":
208
- hidden_nodes = min(hidden_units, 5) # d_model
209
- units_label = f"{hidden_units}"
210
- else:
211
- hidden_nodes = min(hidden_units, 5) # hidden_size
212
- units_label = f"{hidden_units}"
213
-
214
- # Simplified block diagram for complex models
215
- if model_name in ["CNNModel", "HybridModel", "CNN_GRU"]:
216
- G = nx.DiGraph()
217
- pos = {}
218
- nodes = []
219
- y_pos = 0.5
220
- layer_width = 1.0 / 4 # Fixed for 3–4 blocks
221
-
222
- # Define components for each complex model
223
- if model_name == "CNNModel":
224
- components = [
225
- ("Input", f"{input_size} units"),
226
- ("Conv1D", f"{hidden_units} filters"),
227
- ("MaxPool", ""),
228
- ("Output", f"{output_size} units")
229
- ]
230
- elif model_name == "HybridModel":
231
- components = [
232
- ("Input", f"{input_size} units"),
233
- ("Conv1D", "32 filters"),
234
- (f"BiLSTM ({num_layers} layers)", f"{hidden_units*2} units"),
235
- ("Output", f"{output_size} units")
236
- ]
237
- elif model_name == "CNN_GRU":
238
- components = [
239
- ("Input", f"{input_size} units"),
240
- ("Conv1D", "32 filters"),
241
- (f"GRU ({num_layers} layers)", f"{hidden_units} units"),
242
- ("Output", f"{output_size} units")
243
- ]
244
-
245
- # Add nodes and positions
246
- for i, (comp, label) in enumerate(components):
247
- G.add_node(comp, layer=comp)
248
- pos[comp] = (i * layer_width, y_pos)
249
- nodes.append([comp])
250
- if i > 0:
251
- G.add_edge(components[i-1][0], comp)
252
-
253
- # Draw the graph
254
- nx.draw(G, pos, ax=ax, with_labels=False, node_color='lightblue', edge_color='gray',
255
- node_size=2000, node_shape='s', arrowsize=10)
256
-
257
- # Add labels for each block
258
- for node, (x, y) in pos.items():
259
- label = [comp[1] for comp in components if comp[0] == node][0]
260
- ax.text(x, y + 0.05, f"{node}\n{label}", ha='center', va='bottom', fontsize=8,
261
- bbox=dict(facecolor='white', alpha=0.8, edgecolor='black'))
262
-
263
- else:
264
- # Node-based graph for RNN, LSTM, GRU, BiLSTM, MLP, Transformer
265
- max_nodes_display = 5
266
- input_nodes = min(input_size, max_nodes_display)
267
- output_nodes = min(output_size, max_nodes_display)
268
-
269
- nodes = []
270
- pos = {}
271
- layer_width = 1.0 / (num_layers + 2)
272
- y_pos = 0.5
273
-
274
- # Input layer
275
- for i in range(input_nodes):
276
- node = f"input_{i}"
277
- G.add_node(node, layer="input")
278
- pos[node] = (0, y_pos + (i - input_nodes / 2) * 0.1)
279
- nodes.append([f"input_{i}" for i in range(input_nodes)])
280
-
281
- # Hidden layers
282
- for layer in range(num_layers):
283
- layer_nodes = []
284
- for i in range(hidden_nodes):
285
- node = f"hidden_{layer}_{i}"
286
- G.add_node(node, layer=f"hidden_{layer+1}")
287
- pos[node] = ((layer + 1) * layer_width, y_pos + (i - hidden_nodes / 2) * 0.1)
288
- layer_nodes.append(node)
289
- nodes.append(layer_nodes)
290
-
291
- # Output layer
292
- output_layer_nodes = []
293
- for i in range(output_nodes):
294
- node = f"output_{i}"
295
- G.add_node(node, layer="output")
296
- pos[node] = ((num_layers + 1) * layer_width, y_pos + (i - output_nodes / 2) * 0.1)
297
- output_layer_nodes.append(node)
298
- nodes.append(output_layer_nodes)
299
-
300
- # Add edges between layers
301
- for layer in range(len(nodes) - 1):
302
- for src in nodes[layer]:
303
- for dst in nodes[layer + 1]:
304
- G.add_edge(src, dst)
305
-
306
- # Draw the graph
307
- nx.draw(G, pos, ax=ax, with_labels=False, node_color='lightblue', edge_color='gray',
308
- node_size=500, arrowsize=10)
309
-
310
- # Add layer labels
311
- for node in G.nodes(data=True):
312
- layer = node[1]['layer']
313
- x, y = pos[node[0]]
314
- if layer.startswith("hidden"):
315
- label = f"Layer {layer.split('_')[1]}: {units_label} units"
316
- elif layer == "input":
317
- label = f"Input: {input_size} units"
318
- elif layer == "output":
319
- label = f"Output: {output_size} units"
320
- ax.text(x, y + 0.05, label, ha='center', va='bottom', fontsize=8)
321
-
322
- # Add model details as title and annotation
323
- title = f"{model_name} Architecture"
324
- details = f"Dropout: {dropout:.2f}\nBatch Size: {batch_size}"
325
- ax.set_title(title, fontsize=12, pad=20)
326
- ax.text(0.5, 0.05, details, ha='center', va='bottom', fontsize=10, transform=ax.transAxes,
327
- bbox=dict(facecolor='white', alpha=0.8, edgecolor='black'))
328
-
329
- plt.tight_layout()
330
- return fig