Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:30:10 +08:00
commit f0bd18fb4e
824 changed files with 331919 additions and 0 deletions

View File

@@ -0,0 +1,401 @@
#!/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()

View File

@@ -0,0 +1,409 @@
#!/usr/bin/env python3
"""
Matplotlib Style Configurator
Interactive utility to configure matplotlib style preferences and generate
custom style sheets. Creates a preview of the style and optionally saves
it as a .mplstyle file.
Usage:
python style_configurator.py [--preset PRESET] [--output FILE] [--preview]
Presets:
publication, presentation, web, dark, minimal
"""
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import argparse
import os
# Predefined style presets
STYLE_PRESETS = {
'publication': {
'figure.figsize': (8, 6),
'figure.dpi': 100,
'savefig.dpi': 300,
'savefig.bbox': 'tight',
'font.family': 'sans-serif',
'font.sans-serif': ['Arial', 'Helvetica'],
'font.size': 11,
'axes.labelsize': 12,
'axes.titlesize': 14,
'axes.linewidth': 1.5,
'axes.grid': False,
'axes.spines.top': False,
'axes.spines.right': False,
'lines.linewidth': 2,
'lines.markersize': 8,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'xtick.direction': 'in',
'ytick.direction': 'in',
'xtick.major.size': 6,
'ytick.major.size': 6,
'xtick.major.width': 1.5,
'ytick.major.width': 1.5,
'legend.fontsize': 10,
'legend.frameon': True,
'legend.framealpha': 1.0,
'legend.edgecolor': 'black',
},
'presentation': {
'figure.figsize': (12, 8),
'figure.dpi': 100,
'savefig.dpi': 150,
'font.size': 16,
'axes.labelsize': 20,
'axes.titlesize': 24,
'axes.linewidth': 2,
'lines.linewidth': 3,
'lines.markersize': 12,
'xtick.labelsize': 16,
'ytick.labelsize': 16,
'legend.fontsize': 16,
'axes.grid': True,
'grid.alpha': 0.3,
},
'web': {
'figure.figsize': (10, 6),
'figure.dpi': 96,
'savefig.dpi': 150,
'font.size': 11,
'axes.labelsize': 12,
'axes.titlesize': 14,
'lines.linewidth': 2,
'axes.grid': True,
'grid.alpha': 0.2,
'grid.linestyle': '--',
},
'dark': {
'figure.facecolor': '#1e1e1e',
'figure.edgecolor': '#1e1e1e',
'axes.facecolor': '#1e1e1e',
'axes.edgecolor': 'white',
'axes.labelcolor': 'white',
'text.color': 'white',
'xtick.color': 'white',
'ytick.color': 'white',
'grid.color': 'gray',
'grid.alpha': 0.3,
'axes.grid': True,
'legend.facecolor': '#1e1e1e',
'legend.edgecolor': 'white',
'savefig.facecolor': '#1e1e1e',
},
'minimal': {
'figure.figsize': (10, 6),
'axes.spines.top': False,
'axes.spines.right': False,
'axes.spines.left': False,
'axes.spines.bottom': False,
'axes.grid': False,
'xtick.bottom': True,
'ytick.left': True,
'axes.axisbelow': True,
'lines.linewidth': 2.5,
'font.size': 12,
}
}
def generate_preview_data():
"""Generate sample data for style preview."""
np.random.seed(42)
x = np.linspace(0, 10, 100)
y1 = np.sin(x) + 0.1 * np.random.randn(100)
y2 = np.cos(x) + 0.1 * np.random.randn(100)
scatter_x = np.random.randn(100)
scatter_y = 2 * scatter_x + np.random.randn(100)
categories = ['A', 'B', 'C', 'D', 'E']
bar_values = [25, 40, 30, 55, 45]
return {
'x': x, 'y1': y1, 'y2': y2,
'scatter_x': scatter_x, 'scatter_y': scatter_y,
'categories': categories, 'bar_values': bar_values
}
def create_style_preview(style_dict=None):
"""Create a preview figure demonstrating the style."""
if style_dict:
plt.rcParams.update(style_dict)
data = generate_preview_data()
fig = plt.figure(figsize=(14, 10))
gs = GridSpec(2, 2, figure=fig, hspace=0.3, wspace=0.3)
# Line plot
ax1 = fig.add_subplot(gs[0, 0])
ax1.plot(data['x'], data['y1'], label='sin(x)', marker='o', markevery=10)
ax1.plot(data['x'], data['y2'], label='cos(x)', linestyle='--')
ax1.set_xlabel('X axis')
ax1.set_ylabel('Y axis')
ax1.set_title('Line Plot')
ax1.legend()
ax1.grid(True, alpha=0.3)
# Scatter plot
ax2 = fig.add_subplot(gs[0, 1])
colors = np.sqrt(data['scatter_x']**2 + data['scatter_y']**2)
scatter = ax2.scatter(data['scatter_x'], data['scatter_y'],
c=colors, cmap='viridis', alpha=0.6, s=50)
ax2.set_xlabel('X axis')
ax2.set_ylabel('Y axis')
ax2.set_title('Scatter Plot')
cbar = plt.colorbar(scatter, ax=ax2)
cbar.set_label('Distance')
ax2.grid(True, alpha=0.3)
# Bar chart
ax3 = fig.add_subplot(gs[1, 0])
bars = ax3.bar(data['categories'], data['bar_values'],
edgecolor='black', linewidth=1)
# Color bars with gradient
colors = plt.cm.viridis(np.linspace(0.2, 0.8, len(bars)))
for bar, color in zip(bars, colors):
bar.set_facecolor(color)
ax3.set_xlabel('Categories')
ax3.set_ylabel('Values')
ax3.set_title('Bar Chart')
ax3.grid(True, axis='y', alpha=0.3)
# Multiple line plot with fills
ax4 = fig.add_subplot(gs[1, 1])
ax4.plot(data['x'], data['y1'], label='Signal 1', linewidth=2)
ax4.fill_between(data['x'], data['y1'] - 0.2, data['y1'] + 0.2,
alpha=0.3, label='±1 std')
ax4.plot(data['x'], data['y2'], label='Signal 2', linewidth=2)
ax4.fill_between(data['x'], data['y2'] - 0.2, data['y2'] + 0.2,
alpha=0.3)
ax4.set_xlabel('X axis')
ax4.set_ylabel('Y axis')
ax4.set_title('Time Series with Uncertainty')
ax4.legend()
ax4.grid(True, alpha=0.3)
fig.suptitle('Style Preview', fontsize=16, fontweight='bold')
return fig
def save_style_file(style_dict, filename):
"""Save style dictionary as .mplstyle file."""
with open(filename, 'w') as f:
f.write("# Custom matplotlib style\n")
f.write("# Generated by style_configurator.py\n\n")
# Group settings by category
categories = {
'Figure': ['figure.'],
'Font': ['font.'],
'Axes': ['axes.'],
'Lines': ['lines.'],
'Markers': ['markers.'],
'Ticks': ['tick.', 'xtick.', 'ytick.'],
'Grid': ['grid.'],
'Legend': ['legend.'],
'Savefig': ['savefig.'],
'Text': ['text.'],
}
for category, prefixes in categories.items():
category_items = {k: v for k, v in style_dict.items()
if any(k.startswith(p) for p in prefixes)}
if category_items:
f.write(f"# {category}\n")
for key, value in sorted(category_items.items()):
# Format value appropriately
if isinstance(value, (list, tuple)):
value_str = ', '.join(str(v) for v in value)
elif isinstance(value, bool):
value_str = str(value)
else:
value_str = str(value)
f.write(f"{key}: {value_str}\n")
f.write("\n")
print(f"Style saved to {filename}")
def print_style_info(style_dict):
"""Print information about the style."""
print("\n" + "="*60)
print("STYLE CONFIGURATION")
print("="*60)
categories = {
'Figure Settings': ['figure.'],
'Font Settings': ['font.'],
'Axes Settings': ['axes.'],
'Line Settings': ['lines.'],
'Grid Settings': ['grid.'],
'Legend Settings': ['legend.'],
}
for category, prefixes in categories.items():
category_items = {k: v for k, v in style_dict.items()
if any(k.startswith(p) for p in prefixes)}
if category_items:
print(f"\n{category}:")
for key, value in sorted(category_items.items()):
print(f" {key}: {value}")
print("\n" + "="*60 + "\n")
def list_available_presets():
"""Print available style presets."""
print("\nAvailable style presets:")
print("-" * 40)
descriptions = {
'publication': 'Optimized for academic publications',
'presentation': 'Large fonts for presentations',
'web': 'Optimized for web display',
'dark': 'Dark background theme',
'minimal': 'Minimal, clean style',
}
for preset, desc in descriptions.items():
print(f" {preset:15s} - {desc}")
print("-" * 40 + "\n")
def interactive_mode():
"""Run interactive mode to customize style settings."""
print("\n" + "="*60)
print("MATPLOTLIB STYLE CONFIGURATOR - Interactive Mode")
print("="*60)
list_available_presets()
preset = input("Choose a preset to start from (or 'custom' for default): ").strip().lower()
if preset in STYLE_PRESETS:
style_dict = STYLE_PRESETS[preset].copy()
print(f"\nStarting from '{preset}' preset")
else:
style_dict = {}
print("\nStarting from default matplotlib style")
print("\nCommon settings you might want to customize:")
print(" 1. Figure size")
print(" 2. Font sizes")
print(" 3. Line widths")
print(" 4. Grid settings")
print(" 5. Color scheme")
print(" 6. Done, show preview")
while True:
choice = input("\nSelect option (1-6): ").strip()
if choice == '1':
width = input(" Figure width (inches, default 10): ").strip() or '10'
height = input(" Figure height (inches, default 6): ").strip() or '6'
style_dict['figure.figsize'] = (float(width), float(height))
elif choice == '2':
base = input(" Base font size (default 12): ").strip() or '12'
style_dict['font.size'] = float(base)
style_dict['axes.labelsize'] = float(base) + 2
style_dict['axes.titlesize'] = float(base) + 4
elif choice == '3':
lw = input(" Line width (default 2): ").strip() or '2'
style_dict['lines.linewidth'] = float(lw)
elif choice == '4':
grid = input(" Enable grid? (y/n): ").strip().lower()
style_dict['axes.grid'] = grid == 'y'
if style_dict['axes.grid']:
alpha = input(" Grid transparency (0-1, default 0.3): ").strip() or '0.3'
style_dict['grid.alpha'] = float(alpha)
elif choice == '5':
print(" Theme options: 1=Light, 2=Dark")
theme = input(" Select theme (1-2): ").strip()
if theme == '2':
style_dict.update(STYLE_PRESETS['dark'])
elif choice == '6':
break
return style_dict
def main():
"""Main function."""
parser = argparse.ArgumentParser(
description='Matplotlib style configurator',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Show available presets
python style_configurator.py --list
# Preview a preset
python style_configurator.py --preset publication --preview
# Save a preset as .mplstyle file
python style_configurator.py --preset publication --output my_style.mplstyle
# Interactive mode
python style_configurator.py --interactive
"""
)
parser.add_argument('--preset', type=str, choices=list(STYLE_PRESETS.keys()),
help='Use a predefined style preset')
parser.add_argument('--output', type=str,
help='Save style to .mplstyle file')
parser.add_argument('--preview', action='store_true',
help='Show style preview')
parser.add_argument('--list', action='store_true',
help='List available presets')
parser.add_argument('--interactive', action='store_true',
help='Run in interactive mode')
args = parser.parse_args()
if args.list:
list_available_presets()
# Also show currently available matplotlib styles
print("\nBuilt-in matplotlib styles:")
print("-" * 40)
for style in sorted(plt.style.available):
print(f" {style}")
return
if args.interactive:
style_dict = interactive_mode()
elif args.preset:
style_dict = STYLE_PRESETS[args.preset].copy()
print(f"Using '{args.preset}' preset")
else:
print("No preset or interactive mode specified. Showing default preview.")
style_dict = {}
if style_dict:
print_style_info(style_dict)
if args.output:
save_style_file(style_dict, args.output)
if args.preview or args.interactive:
print("Creating style preview...")
fig = create_style_preview(style_dict if style_dict else None)
if args.output:
preview_filename = args.output.replace('.mplstyle', '_preview.png')
plt.savefig(preview_filename, dpi=150, bbox_inches='tight')
print(f"Preview saved to {preview_filename}")
plt.show()
if __name__ == "__main__":
main()