1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.collections import LineCollection
import numpy as np
from typing import List, Tuple, Optional
# Advanced matplotlib usage patterns
class MatplotlibOptimizer:
"""Advanced matplotlib techniques for performance and aesthetics"""
def __init__(self):
self.setup_style()
def setup_style(self):
"""Configure matplotlib for publication-quality plots"""
plt.style.use('seaborn-v0_8-whitegrid') # Clean, professional style
# Custom styling parameters
custom_params = {
'figure.figsize': (12, 8),
'figure.dpi': 100,
'savefig.dpi': 300,
'font.size': 11,
'axes.labelsize': 12,
'axes.titlesize': 14,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'lines.linewidth': 2,
'lines.markersize': 6,
'axes.grid': True,
'grid.alpha': 0.3
}
plt.rcParams.update(custom_params)
def efficient_line_plotting(self, x_data: List[np.ndarray],
y_data: List[np.ndarray],
colors: List[str] = None) -> plt.Figure:
"""Efficient plotting of multiple lines using LineCollection"""
fig, ax = plt.subplots(figsize=(12, 8))
if colors is None:
colors = plt.cm.viridis(np.linspace(0, 1, len(x_data)))
# Create line segments for efficient rendering
lines = []
for x, y in zip(x_data, y_data):
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
lines.extend(segments)
# Use LineCollection for better performance with many lines
lc = LineCollection(lines, colors=colors, linewidths=2)
ax.add_collection(lc)
# Set appropriate limits
all_x = np.concatenate(x_data)
all_y = np.concatenate(y_data)
ax.set_xlim(all_x.min(), all_x.max())
ax.set_ylim(all_y.min(), all_y.max())
return fig
def create_subplot_grid(self, data_dict: dict,
ncols: int = 2) -> plt.Figure:
"""Create optimized subplot layouts"""
nplots = len(data_dict)
nrows = (nplots + ncols - 1) // ncols
fig, axes = plt.subplots(nrows, ncols, figsize=(6*ncols, 4*nrows))
axes = axes.flatten() if nplots > 1 else [axes]
for idx, (title, (x, y)) in enumerate(data_dict.items()):
ax = axes[idx]
ax.plot(x, y, linewidth=2)
ax.set_title(title, fontweight='bold')
ax.grid(True, alpha=0.3)
# Add statistical information
ax.text(0.02, 0.98, f'μ={np.mean(y):.2f}\nσ={np.std(y):.2f}',
transform=ax.transAxes, verticalalignment='top',
bbox=dict(boxstyle='round', facecolor='white', alpha=0.8))
# Hide unused subplots
for idx in range(nplots, len(axes)):
axes[idx].set_visible(False)
plt.tight_layout()
return fig
def advanced_annotations(self, x: np.ndarray, y: np.ndarray,
peaks: List[int] = None) -> plt.Figure:
"""Create plots with sophisticated annotations"""
fig, ax = plt.subplots(figsize=(12, 8))
# Main plot
line = ax.plot(x, y, linewidth=2, label='Data')[0]
if peaks:
# Highlight peaks
ax.scatter(x[peaks], y[peaks], color='red', s=100,
zorder=5, label='Peaks')
# Add annotations for significant peaks
for peak in peaks:
if y[peak] > np.percentile(y, 90): # Only annotate top 10%
ax.annotate(f'Peak: {y[peak]:.2f}',
xy=(x[peak], y[peak]),
xytext=(10, 10), textcoords='offset points',
bbox=dict(boxstyle='round,pad=0.5',
facecolor='yellow', alpha=0.7),
arrowprops=dict(arrowstyle='->',
connectionstyle='arc3,rad=0'))
# Statistical overlay
mean_y = np.mean(y)
std_y = np.std(y)
ax.axhline(mean_y, color='green', linestyle='--', alpha=0.7,
label=f'Mean: {mean_y:.2f}')
ax.axhline(mean_y + std_y, color='orange', linestyle=':', alpha=0.7,
label=f'+1σ: {mean_y + std_y:.2f}')
ax.axhline(mean_y - std_y, color='orange', linestyle=':', alpha=0.7,
label=f'-1σ: {mean_y - std_y:.2f}')
# Shaded confidence interval
ax.fill_between(x, mean_y - std_y, mean_y + std_y,
alpha=0.2, color='orange', label='±1σ region')
ax.set_xlabel('X Values', fontweight='bold')
ax.set_ylabel('Y Values', fontweight='bold')
ax.set_title('Advanced Data Visualization with Annotations',
fontsize=16, fontweight='bold')
ax.legend(loc='best')
ax.grid(True, alpha=0.3)
return fig
# Effective matplotlib usage patterns
def effective_matplotlib_practices():
"""Demonstrate best practices for matplotlib usage"""
# Generate sample data
np.random.seed(42)
x = np.linspace(0, 10, 1000)
y1 = np.sin(x) + 0.1 * np.random.randn(1000)
y2 = np.cos(x) + 0.1 * np.random.randn(1000)
y3 = np.sin(2*x) * np.exp(-x/10) + 0.05 * np.random.randn(1000)
optimizer = MatplotlibOptimizer()
# 1. Efficient multiple line plotting
print("Creating efficient line plot...")
line_fig = optimizer.efficient_line_plotting(
[x, x, x], [y1, y2, y3],
colors=['blue', 'red', 'green']
)
# 2. Subplot grid with data analysis
data_dict = {
'Sine Wave': (x, y1),
'Cosine Wave': (x, y2),
'Damped Oscillation': (x, y3),
'Combined Signal': (x, y1 + y2 + y3)
}
print("Creating subplot grid...")
subplot_fig = optimizer.create_subplot_grid(data_dict, ncols=2)
# 3. Advanced annotations
from scipy.signal import find_peaks
peaks, _ = find_peaks(y3, height=0.1, distance=50)
print("Creating annotated plot...")
annotated_fig = optimizer.advanced_annotations(x, y3, peaks)
# Memory cleanup
plt.close('all')
return line_fig, subplot_fig, annotated_fig
# Performance optimization for large datasets
class LargeDataVisualizer:
"""Handle visualization of large datasets efficiently"""
@staticmethod
def downsample_data(x: np.ndarray, y: np.ndarray,
max_points: int = 10000) -> Tuple[np.ndarray, np.ndarray]:
"""Intelligently downsample data for plotting"""
if len(x) <= max_points:
return x, y
# Use decimation for uniform downsampling
step = len(x) // max_points
indices = np.arange(0, len(x), step)
# Always include first and last points
if indices[-1] != len(x) - 1:
indices = np.append(indices, len(x) - 1)
return x[indices], y[indices]
@staticmethod
def plot_large_dataset(x: np.ndarray, y: np.ndarray,
title: str = "Large Dataset") -> plt.Figure:
"""Efficiently plot large datasets"""
# Downsample if necessary
x_plot, y_plot = LargeDataVisualizer.downsample_data(x, y)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
# Main plot
ax1.plot(x_plot, y_plot, linewidth=1, alpha=0.8)
ax1.set_title(f'{title} (Showing {len(x_plot):,} of {len(x):,} points)')
ax1.grid(True, alpha=0.3)
# Distribution histogram
ax2.hist(y, bins=50, alpha=0.7, density=True, edgecolor='black')
ax2.set_title('Data Distribution')
ax2.set_xlabel('Value')
ax2.set_ylabel('Density')
ax2.grid(True, alpha=0.3)
# Add summary statistics
stats_text = f'''
Count: {len(y):,}
Mean: {np.mean(y):.3f}
Std: {np.std(y):.3f}
Min: {np.min(y):.3f}
Max: {np.max(y):.3f}
'''
ax2.text(0.02, 0.98, stats_text, transform=ax2.transAxes,
verticalalignment='top', fontfamily='monospace',
bbox=dict(boxstyle='round', facecolor='white', alpha=0.9))
plt.tight_layout()
return fig
|