| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- #!/usr/bin/env python3
- """
- Matplotlib Plot Template
- Comprehensive template demonstrating various plot types and best practices.
- Use this as a starting point for creating publication-quality visualizations.
- Usage:
- python plot_template.py [--plot-type TYPE] [--style STYLE] [--output FILE]
- Plot types:
- line, scatter, bar, histogram, heatmap, contour, box, violin, 3d, all
- """
- import numpy as np
- import matplotlib.pyplot as plt
- from matplotlib.gridspec import GridSpec
- import argparse
- def set_publication_style():
- """Configure matplotlib for publication-quality figures."""
- plt.rcParams.update({
- 'figure.figsize': (10, 6),
- 'figure.dpi': 100,
- 'savefig.dpi': 300,
- 'savefig.bbox': 'tight',
- 'font.size': 11,
- 'axes.labelsize': 12,
- 'axes.titlesize': 14,
- 'xtick.labelsize': 10,
- 'ytick.labelsize': 10,
- 'legend.fontsize': 10,
- 'lines.linewidth': 2,
- 'axes.linewidth': 1.5,
- })
- def generate_sample_data():
- """Generate sample data for demonstrations."""
- np.random.seed(42)
- x = np.linspace(0, 10, 100)
- y1 = np.sin(x)
- y2 = np.cos(x)
- scatter_x = np.random.randn(200)
- scatter_y = np.random.randn(200)
- categories = ['A', 'B', 'C', 'D', 'E']
- bar_values = np.random.randint(10, 100, len(categories))
- hist_data = np.random.normal(0, 1, 1000)
- matrix = np.random.rand(10, 10)
- X, Y = np.meshgrid(np.linspace(-3, 3, 100), np.linspace(-3, 3, 100))
- Z = np.sin(np.sqrt(X**2 + Y**2))
- return {
- 'x': x, 'y1': y1, 'y2': y2,
- 'scatter_x': scatter_x, 'scatter_y': scatter_y,
- 'categories': categories, 'bar_values': bar_values,
- 'hist_data': hist_data, 'matrix': matrix,
- 'X': X, 'Y': Y, 'Z': Z
- }
- def create_line_plot(data, ax=None):
- """Create line plot with best practices."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- ax.plot(data['x'], data['y1'], label='sin(x)', linewidth=2, marker='o',
- markevery=10, markersize=6)
- ax.plot(data['x'], data['y2'], label='cos(x)', linewidth=2, linestyle='--')
- ax.set_xlabel('x')
- ax.set_ylabel('y')
- ax.set_title('Line Plot Example')
- ax.legend(loc='best', framealpha=0.9)
- ax.grid(True, alpha=0.3, linestyle='--')
- # Remove top and right spines for cleaner look
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- if ax is None:
- return fig
- return ax
- def create_scatter_plot(data, ax=None):
- """Create scatter plot with color and size variations."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- # Color based on distance from origin
- colors = np.sqrt(data['scatter_x']**2 + data['scatter_y']**2)
- sizes = 50 * (1 + np.abs(data['scatter_x']))
- scatter = ax.scatter(data['scatter_x'], data['scatter_y'],
- c=colors, s=sizes, alpha=0.6,
- cmap='viridis', edgecolors='black', linewidth=0.5)
- ax.set_xlabel('X')
- ax.set_ylabel('Y')
- ax.set_title('Scatter Plot Example')
- ax.grid(True, alpha=0.3, linestyle='--')
- # Add colorbar
- cbar = plt.colorbar(scatter, ax=ax)
- cbar.set_label('Distance from origin')
- if ax is None:
- return fig
- return ax
- def create_bar_chart(data, ax=None):
- """Create bar chart with error bars and styling."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- x_pos = np.arange(len(data['categories']))
- errors = np.random.randint(5, 15, len(data['categories']))
- bars = ax.bar(x_pos, data['bar_values'], yerr=errors,
- color='steelblue', edgecolor='black', linewidth=1.5,
- capsize=5, alpha=0.8)
- # Color bars by value
- colors = plt.cm.viridis(data['bar_values'] / data['bar_values'].max())
- for bar, color in zip(bars, colors):
- bar.set_facecolor(color)
- ax.set_xlabel('Category')
- ax.set_ylabel('Values')
- ax.set_title('Bar Chart Example')
- ax.set_xticks(x_pos)
- ax.set_xticklabels(data['categories'])
- ax.grid(True, axis='y', alpha=0.3, linestyle='--')
- # Remove top and right spines
- ax.spines['top'].set_visible(False)
- ax.spines['right'].set_visible(False)
- if ax is None:
- return fig
- return ax
- def create_histogram(data, ax=None):
- """Create histogram with density overlay."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- n, bins, patches = ax.hist(data['hist_data'], bins=30, density=True,
- alpha=0.7, edgecolor='black', color='steelblue')
- # Overlay theoretical normal distribution
- from scipy.stats import norm
- mu, std = norm.fit(data['hist_data'])
- x_theory = np.linspace(data['hist_data'].min(), data['hist_data'].max(), 100)
- ax.plot(x_theory, norm.pdf(x_theory, mu, std), 'r-', linewidth=2,
- label=f'Normal fit (μ={mu:.2f}, σ={std:.2f})')
- ax.set_xlabel('Value')
- ax.set_ylabel('Density')
- ax.set_title('Histogram with Normal Fit')
- ax.legend()
- ax.grid(True, axis='y', alpha=0.3, linestyle='--')
- if ax is None:
- return fig
- return ax
- def create_heatmap(data, ax=None):
- """Create heatmap with colorbar and annotations."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 8), constrained_layout=True)
- im = ax.imshow(data['matrix'], cmap='coolwarm', aspect='auto',
- vmin=0, vmax=1)
- # Add colorbar
- cbar = plt.colorbar(im, ax=ax)
- cbar.set_label('Value')
- # Optional: Add text annotations
- # for i in range(data['matrix'].shape[0]):
- # for j in range(data['matrix'].shape[1]):
- # text = ax.text(j, i, f'{data["matrix"][i, j]:.2f}',
- # ha='center', va='center', color='black', fontsize=8)
- ax.set_xlabel('X Index')
- ax.set_ylabel('Y Index')
- ax.set_title('Heatmap Example')
- if ax is None:
- return fig
- return ax
- def create_contour_plot(data, ax=None):
- """Create contour plot with filled contours and labels."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 8), constrained_layout=True)
- # Filled contours
- contourf = ax.contourf(data['X'], data['Y'], data['Z'],
- levels=20, cmap='viridis', alpha=0.8)
- # Contour lines
- contour = ax.contour(data['X'], data['Y'], data['Z'],
- levels=10, colors='black', linewidths=0.5, alpha=0.4)
- # Add labels to contour lines
- ax.clabel(contour, inline=True, fontsize=8)
- # Add colorbar
- cbar = plt.colorbar(contourf, ax=ax)
- cbar.set_label('Z value')
- ax.set_xlabel('X')
- ax.set_ylabel('Y')
- ax.set_title('Contour Plot Example')
- ax.set_aspect('equal')
- if ax is None:
- return fig
- return ax
- def create_box_plot(data, ax=None):
- """Create box plot comparing distributions."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- # Generate multiple distributions
- box_data = [np.random.normal(0, std, 100) for std in range(1, 5)]
- bp = ax.boxplot(box_data, labels=['Group 1', 'Group 2', 'Group 3', 'Group 4'],
- patch_artist=True, showmeans=True,
- boxprops=dict(facecolor='lightblue', edgecolor='black'),
- medianprops=dict(color='red', linewidth=2),
- meanprops=dict(marker='D', markerfacecolor='green', markersize=8))
- ax.set_xlabel('Groups')
- ax.set_ylabel('Values')
- ax.set_title('Box Plot Example')
- ax.grid(True, axis='y', alpha=0.3, linestyle='--')
- if ax is None:
- return fig
- return ax
- def create_violin_plot(data, ax=None):
- """Create violin plot showing distribution shapes."""
- if ax is None:
- fig, ax = plt.subplots(figsize=(10, 6), constrained_layout=True)
- # Generate multiple distributions
- violin_data = [np.random.normal(0, std, 100) for std in range(1, 5)]
- parts = ax.violinplot(violin_data, positions=range(1, 5),
- showmeans=True, showmedians=True)
- # Customize colors
- for pc in parts['bodies']:
- pc.set_facecolor('lightblue')
- pc.set_alpha(0.7)
- pc.set_edgecolor('black')
- ax.set_xlabel('Groups')
- ax.set_ylabel('Values')
- ax.set_title('Violin Plot Example')
- ax.set_xticks(range(1, 5))
- ax.set_xticklabels(['Group 1', 'Group 2', 'Group 3', 'Group 4'])
- ax.grid(True, axis='y', alpha=0.3, linestyle='--')
- if ax is None:
- return fig
- return ax
- def create_3d_plot():
- """Create 3D surface plot."""
- from mpl_toolkits.mplot3d import Axes3D
- fig = plt.figure(figsize=(12, 9))
- ax = fig.add_subplot(111, projection='3d')
- # Generate data
- X = np.linspace(-5, 5, 50)
- Y = np.linspace(-5, 5, 50)
- X, Y = np.meshgrid(X, Y)
- Z = np.sin(np.sqrt(X**2 + Y**2))
- # Create surface plot
- surf = ax.plot_surface(X, Y, Z, cmap='viridis',
- edgecolor='none', alpha=0.9)
- # Add colorbar
- fig.colorbar(surf, ax=ax, shrink=0.5)
- ax.set_xlabel('X')
- ax.set_ylabel('Y')
- ax.set_zlabel('Z')
- ax.set_title('3D Surface Plot Example')
- # Set viewing angle
- ax.view_init(elev=30, azim=45)
- plt.tight_layout()
- return fig
- def create_comprehensive_figure():
- """Create a comprehensive figure with multiple subplots."""
- data = generate_sample_data()
- fig = plt.figure(figsize=(16, 12), constrained_layout=True)
- gs = GridSpec(3, 3, figure=fig)
- # Create subplots
- ax1 = fig.add_subplot(gs[0, :2]) # Line plot - top left, spans 2 columns
- create_line_plot(data, ax1)
- ax2 = fig.add_subplot(gs[0, 2]) # Bar chart - top right
- create_bar_chart(data, ax2)
- ax3 = fig.add_subplot(gs[1, 0]) # Scatter plot - middle left
- create_scatter_plot(data, ax3)
- ax4 = fig.add_subplot(gs[1, 1]) # Histogram - middle center
- create_histogram(data, ax4)
- ax5 = fig.add_subplot(gs[1, 2]) # Box plot - middle right
- create_box_plot(data, ax5)
- ax6 = fig.add_subplot(gs[2, :2]) # Contour plot - bottom left, spans 2 columns
- create_contour_plot(data, ax6)
- ax7 = fig.add_subplot(gs[2, 2]) # Heatmap - bottom right
- create_heatmap(data, ax7)
- fig.suptitle('Comprehensive Matplotlib Template', fontsize=18, fontweight='bold')
- return fig
- def main():
- """Main function to run the template."""
- parser = argparse.ArgumentParser(description='Matplotlib plot template')
- parser.add_argument('--plot-type', type=str, default='all',
- choices=['line', 'scatter', 'bar', 'histogram', 'heatmap',
- 'contour', 'box', 'violin', '3d', 'all'],
- help='Type of plot to create')
- parser.add_argument('--style', type=str, default='default',
- help='Matplotlib style to use')
- parser.add_argument('--output', type=str, default='plot.png',
- help='Output filename')
- args = parser.parse_args()
- # Set style
- if args.style != 'default':
- plt.style.use(args.style)
- else:
- set_publication_style()
- # Generate data
- data = generate_sample_data()
- # Create plot based on type
- plot_functions = {
- 'line': create_line_plot,
- 'scatter': create_scatter_plot,
- 'bar': create_bar_chart,
- 'histogram': create_histogram,
- 'heatmap': create_heatmap,
- 'contour': create_contour_plot,
- 'box': create_box_plot,
- 'violin': create_violin_plot,
- }
- if args.plot_type == '3d':
- fig = create_3d_plot()
- elif args.plot_type == 'all':
- fig = create_comprehensive_figure()
- else:
- fig = plot_functions[args.plot_type](data)
- # Save figure
- plt.savefig(args.output, dpi=300, bbox_inches='tight')
- print(f"Plot saved to {args.output}")
- # Display
- plt.show()
- if __name__ == "__main__":
- main()
|