plot_template.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #!/usr/bin/env python3
  2. """
  3. Matplotlib Plot Template
  4. Comprehensive template demonstrating various plot types and best practices.
  5. Use this as a starting point for creating publication-quality visualizations.
  6. Usage:
  7. python plot_template.py [--plot-type TYPE] [--style STYLE] [--output FILE]
  8. Plot types:
  9. line, scatter, bar, histogram, heatmap, contour, box, violin, 3d, all
  10. """
  11. import numpy as np
  12. import matplotlib.pyplot as plt
  13. from matplotlib.gridspec import GridSpec
  14. import argparse
  15. def set_publication_style():
  16. """Configure matplotlib for publication-quality figures."""
  17. plt.rcParams.update({
  18. 'figure.figsize': (10, 6),
  19. 'figure.dpi': 100,
  20. 'savefig.dpi': 300,
  21. 'savefig.bbox': 'tight',
  22. 'font.size': 11,
  23. 'axes.labelsize': 12,
  24. 'axes.titlesize': 14,
  25. 'xtick.labelsize': 10,
  26. 'ytick.labelsize': 10,
  27. 'legend.fontsize': 10,
  28. 'lines.linewidth': 2,
  29. 'axes.linewidth': 1.5,
  30. })
  31. def generate_sample_data():
  32. """Generate sample data for demonstrations."""
  33. np.random.seed(42)
  34. x = np.linspace(0, 10, 100)
  35. y1 = np.sin(x)
  36. y2 = np.cos(x)
  37. scatter_x = np.random.randn(200)
  38. scatter_y = np.random.randn(200)
  39. categories = ['A', 'B', 'C', 'D', 'E']
  40. bar_values = np.random.randint(10, 100, len(categories))
  41. hist_data = np.random.normal(0, 1, 1000)
  42. matrix = np.random.rand(10, 10)
  43. X, Y = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))
  44. Z = np.sin(np.sqrt(X**2 + Y**2))
  45. return {
  46. 'x': x, 'y1': y1, 'y2': y2,
  47. 'scatter_x': scatter_x, 'scatter_y': scatter_y,
  48. 'categories': categories, 'bar_values': bar_values,
  49. 'hist_data': hist_data, 'matrix': matrix,
  50. 'X': X, 'Y': Y, 'Z': Z
  51. }
  52. def create_line_plot(data, ax=None):
  53. """Create line plot with best practices."""
  54. if ax is None:
  55. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  56. ax.plot(data['x'], data['y1'], label='sin(x)', linewidth=2, marker='o',
  57. markevery=10, markersize=6)
  58. ax.plot(data['x'], data['y2'], label='cos(x)', linewidth=2, linestyle='--')
  59. ax.set_xlabel('x')
  60. ax.set_ylabel('y')
  61. ax.set_title('Line Plot Example')
  62. ax.legend(loc='best', framealpha=0.9)
  63. ax.grid(True, alpha=0.3, linestyle='--')
  64. # Remove top and right spines for cleaner look
  65. ax.spines['top'].set_visible(False)
  66. ax.spines['right'].set_visible(False)
  67. if ax is None:
  68. return fig
  69. return ax
  70. def create_scatter_plot(data, ax=None):
  71. """Create scatter plot with color and size variations."""
  72. if ax is None:
  73. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  74. # Color based on distance from origin
  75. colors = np.sqrt(data['scatter_x']**2 + data['scatter_y']**2)
  76. sizes = 50 * (1 + np.abs(data['scatter_x']))
  77. scatter = ax.scatter(data['scatter_x'], data['scatter_y'],
  78. c=colors, s=sizes, alpha=0.6,
  79. cmap='viridis', edgecolors='black', linewidth=0.5)
  80. ax.set_xlabel('X')
  81. ax.set_ylabel('Y')
  82. ax.set_title('Scatter Plot Example')
  83. ax.grid(True, alpha=0.3, linestyle='--')
  84. # Add colorbar
  85. cbar = plt.colorbar(scatter, ax=ax)
  86. cbar.set_label('Distance from origin')
  87. if ax is None:
  88. return fig
  89. return ax
  90. def create_bar_chart(data, ax=None):
  91. """Create bar chart with error bars and styling."""
  92. if ax is None:
  93. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  94. x_pos = np.arange(len(data['categories']))
  95. errors = np.random.randint(5, 15, len(data['categories']))
  96. bars = ax.bar(x_pos, data['bar_values'], yerr=errors,
  97. color='steelblue', edgecolor='black', linewidth=1.5,
  98. capsize=5, alpha=0.8)
  99. # Color bars by value
  100. colors = plt.cm.viridis(data['bar_values'] / data['bar_values'].max())
  101. for bar, color in zip(bars, colors):
  102. bar.set_facecolor(color)
  103. ax.set_xlabel('Category')
  104. ax.set_ylabel('Values')
  105. ax.set_title('Bar Chart Example')
  106. ax.set_xticks(x_pos)
  107. ax.set_xticklabels(data['categories'])
  108. ax.grid(True, axis='y', alpha=0.3, linestyle='--')
  109. # Remove top and right spines
  110. ax.spines['top'].set_visible(False)
  111. ax.spines['right'].set_visible(False)
  112. if ax is None:
  113. return fig
  114. return ax
  115. def create_histogram(data, ax=None):
  116. """Create histogram with density overlay."""
  117. if ax is None:
  118. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  119. n, bins, patches = ax.hist(data['hist_data'], bins=30, density=True,
  120. alpha=0.7, edgecolor='black', color='steelblue')
  121. # Overlay theoretical normal distribution
  122. from scipy.stats import norm
  123. mu, std = norm.fit(data['hist_data'])
  124. x_theory = np.linspace(data['hist_data'].min(), data['hist_data'].max(), 100)
  125. ax.plot(x_theory, norm.pdf(x_theory, mu, std), 'r-', linewidth=2,
  126. label=f'Normal fit (μ={mu:.2f}, σ={std:.2f})')
  127. ax.set_xlabel('Value')
  128. ax.set_ylabel('Density')
  129. ax.set_title('Histogram with Normal Fit')
  130. ax.legend()
  131. ax.grid(True, axis='y', alpha=0.3, linestyle='--')
  132. if ax is None:
  133. return fig
  134. return ax
  135. def create_heatmap(data, ax=None):
  136. """Create heatmap with colorbar and annotations."""
  137. if ax is None:
  138. fig, ax = plt.subplots(figsize=(10, 8), constrained_layout=True)
  139. im = ax.imshow(data['matrix'], cmap='coolwarm', aspect='auto',
  140. vmin=0, vmax=1)
  141. # Add colorbar
  142. cbar = plt.colorbar(im, ax=ax)
  143. cbar.set_label('Value')
  144. # Optional: Add text annotations
  145. # for i in range(data['matrix'].shape[0]):
  146. # for j in range(data['matrix'].shape[1]):
  147. # text = ax.text(j, i, f'{data["matrix"][i, j]:.2f}',
  148. # ha='center', va='center', color='black', fontsize=8)
  149. ax.set_xlabel('X Index')
  150. ax.set_ylabel('Y Index')
  151. ax.set_title('Heatmap Example')
  152. if ax is None:
  153. return fig
  154. return ax
  155. def create_contour_plot(data, ax=None):
  156. """Create contour plot with filled contours and labels."""
  157. if ax is None:
  158. fig, ax = plt.subplots(figsize=(10, 8), constrained_layout=True)
  159. # Filled contours
  160. contourf = ax.contourf(data['X'], data['Y'], data['Z'],
  161. levels=20, cmap='viridis', alpha=0.8)
  162. # Contour lines
  163. contour = ax.contour(data['X'], data['Y'], data['Z'],
  164. levels=10, colors='black', linewidths=0.5, alpha=0.4)
  165. # Add labels to contour lines
  166. ax.clabel(contour, inline=True, fontsize=8)
  167. # Add colorbar
  168. cbar = plt.colorbar(contourf, ax=ax)
  169. cbar.set_label('Z value')
  170. ax.set_xlabel('X')
  171. ax.set_ylabel('Y')
  172. ax.set_title('Contour Plot Example')
  173. ax.set_aspect('equal')
  174. if ax is None:
  175. return fig
  176. return ax
  177. def create_box_plot(data, ax=None):
  178. """Create box plot comparing distributions."""
  179. if ax is None:
  180. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  181. # Generate multiple distributions
  182. box_data = [np.random.normal(0, std, 100) for std in range(1, 5)]
  183. bp = ax.boxplot(box_data, labels=['Group 1', 'Group 2', 'Group 3', 'Group 4'],
  184. patch_artist=True, showmeans=True,
  185. boxprops=dict(facecolor='lightblue', edgecolor='black'),
  186. medianprops=dict(color='red', linewidth=2),
  187. meanprops=dict(marker='D', markerfacecolor='green', markersize=8))
  188. ax.set_xlabel('Groups')
  189. ax.set_ylabel('Values')
  190. ax.set_title('Box Plot Example')
  191. ax.grid(True, axis='y', alpha=0.3, linestyle='--')
  192. if ax is None:
  193. return fig
  194. return ax
  195. def create_violin_plot(data, ax=None):
  196. """Create violin plot showing distribution shapes."""
  197. if ax is None:
  198. fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
  199. # Generate multiple distributions
  200. violin_data = [np.random.normal(0, std, 100) for std in range(1, 5)]
  201. parts = ax.violinplot(violin_data, positions=range(1, 5),
  202. showmeans=True, showmedians=True)
  203. # Customize colors
  204. for pc in parts['bodies']:
  205. pc.set_facecolor('lightblue')
  206. pc.set_alpha(0.7)
  207. pc.set_edgecolor('black')
  208. ax.set_xlabel('Groups')
  209. ax.set_ylabel('Values')
  210. ax.set_title('Violin Plot Example')
  211. ax.set_xticks(range(1, 5))
  212. ax.set_xticklabels(['Group 1', 'Group 2', 'Group 3', 'Group 4'])
  213. ax.grid(True, axis='y', alpha=0.3, linestyle='--')
  214. if ax is None:
  215. return fig
  216. return ax
  217. def create_3d_plot():
  218. """Create 3D surface plot."""
  219. from mpl_toolkits.mplot3d import Axes3D
  220. fig = plt.figure(figsize=(12, 9))
  221. ax = fig.add_subplot(111, projection='3d')
  222. # Generate data
  223. X = np.linspace(-5, 5, 50)
  224. Y = np.linspace(-5, 5, 50)
  225. X, Y = np.meshgrid(X, Y)
  226. Z = np.sin(np.sqrt(X**2 + Y**2))
  227. # Create surface plot
  228. surf = ax.plot_surface(X, Y, Z, cmap='viridis',
  229. edgecolor='none', alpha=0.9)
  230. # Add colorbar
  231. fig.colorbar(surf, ax=ax, shrink=0.5)
  232. ax.set_xlabel('X')
  233. ax.set_ylabel('Y')
  234. ax.set_zlabel('Z')
  235. ax.set_title('3D Surface Plot Example')
  236. # Set viewing angle
  237. ax.view_init(elev=30, azim=45)
  238. plt.tight_layout()
  239. return fig
  240. def create_comprehensive_figure():
  241. """Create a comprehensive figure with multiple subplots."""
  242. data = generate_sample_data()
  243. fig = plt.figure(figsize=(16, 12), constrained_layout=True)
  244. gs = GridSpec(3, 3, figure=fig)
  245. # Create subplots
  246. ax1 = fig.add_subplot(gs[0, :2]) # Line plot - top left, spans 2 columns
  247. create_line_plot(data, ax1)
  248. ax2 = fig.add_subplot(gs[0, 2]) # Bar chart - top right
  249. create_bar_chart(data, ax2)
  250. ax3 = fig.add_subplot(gs[1, 0]) # Scatter plot - middle left
  251. create_scatter_plot(data, ax3)
  252. ax4 = fig.add_subplot(gs[1, 1]) # Histogram - middle center
  253. create_histogram(data, ax4)
  254. ax5 = fig.add_subplot(gs[1, 2]) # Box plot - middle right
  255. create_box_plot(data, ax5)
  256. ax6 = fig.add_subplot(gs[2, :2]) # Contour plot - bottom left, spans 2 columns
  257. create_contour_plot(data, ax6)
  258. ax7 = fig.add_subplot(gs[2, 2]) # Heatmap - bottom right
  259. create_heatmap(data, ax7)
  260. fig.suptitle('Comprehensive Matplotlib Template', fontsize=18, fontweight='bold')
  261. return fig
  262. def main():
  263. """Main function to run the template."""
  264. parser = argparse.ArgumentParser(description='Matplotlib plot template')
  265. parser.add_argument('--plot-type', type=str, default='all',
  266. choices=['line', 'scatter', 'bar', 'histogram', 'heatmap',
  267. 'contour', 'box', 'violin', '3d', 'all'],
  268. help='Type of plot to create')
  269. parser.add_argument('--style', type=str, default='default',
  270. help='Matplotlib style to use')
  271. parser.add_argument('--output', type=str, default='plot.png',
  272. help='Output filename')
  273. args = parser.parse_args()
  274. # Set style
  275. if args.style != 'default':
  276. plt.style.use(args.style)
  277. else:
  278. set_publication_style()
  279. # Generate data
  280. data = generate_sample_data()
  281. # Create plot based on type
  282. plot_functions = {
  283. 'line': create_line_plot,
  284. 'scatter': create_scatter_plot,
  285. 'bar': create_bar_chart,
  286. 'histogram': create_histogram,
  287. 'heatmap': create_heatmap,
  288. 'contour': create_contour_plot,
  289. 'box': create_box_plot,
  290. 'violin': create_violin_plot,
  291. }
  292. if args.plot_type == '3d':
  293. fig = create_3d_plot()
  294. elif args.plot_type == 'all':
  295. fig = create_comprehensive_figure()
  296. else:
  297. fig = plot_functions[args.plot_type](data)
  298. # Save figure
  299. plt.savefig(args.output, dpi=300, bbox_inches='tight')
  300. print(f"Plot saved to {args.output}")
  301. # Display
  302. plt.show()
  303. if __name__ == "__main__":
  304. main()