I like to make my matplotlib plots aesthetically pleasing. For each new project, I end up creating a fresh “aesthetic setup” for my plots; this causes inconsistencies across my visualizations and unnecessary overhead.

So, I decided to swallow the bitter pill, and learn about customizing matplotlib the proper way. Thankfully, there is a neat blog explaining this. The recommendation appears to be overriding a dict-like variable matplotlib.rcParams.

I will use this space to log my most current rcParams overrides and some rationale behind the design where needed. I expect this to evolve over time, and I will try my best to log details when making changes.

custom_rcParams = {
    # Figure
    'figure.dpi': 150,

    # Font
    'font.family': 'serif',
    'font.serif': ['cmr10', 'serif'], # NOTE: pass fontfamily='cmb10' for bold
    'font.sans-serif': ['cmss10', 'sans-serif'],
    'font.size': 13,
    'mathtext.fontset': 'cm',
    
    # Axes aesthetics
    'axes.titlesize': 18,
    'axes.titlepad': 10,
    'axes.titleweight': 'bold',
    'axes.labelpad': 7.5,
    'axes.labelsize': 14,
    'axes.grid': True,
    'axes.facecolor': '#f5f5f5',
    'axes.formatter.use_mathtext': True,
    
    # Tick formatting
    'xtick.labelsize': 13,
    'ytick.labelsize': 13,
    'xtick.major.pad': 7,
    'ytick.major.pad': 7,
    
    # Line styling
    'lines.linewidth': 2.,
    'lines.markersize': 6.5,

    # Grid styling
    'grid.linestyle': ':',      # Dotted line style
    'grid.linewidth': 1.0,      # Slightly thinner for dotted lines
    'grid.color': 'gray',
    'grid.alpha': 0.5,
    
    # Color cycles - using a pleasing palette
    'axes.prop_cycle': plt.cycler('color', ['#4878d0', '#6acc64', '#d65f5f', 
                                            '#956cb4', '#d8882b', '#e27e8d', 
                                            '#7f7f7f', '#f1c27d', '#bcbd22', 
                                            '#17becf']),
    
    # Legend
    'legend.fontsize': 12,
    'legend.frameon': True,
    'legend.framealpha': 0.8,
    'legend.edgecolor': 'lightgray',
    'legend.facecolor': '#ffffff',
    
    # Saving figures
    'savefig.bbox': 'tight',
    'savefig.dpi': 300,
}

Use the above in code before plotting as:

matplotlib.rcParams.update(custom_rcParams)

The comparison will be tracked using this data:

import numpy as np
np.random.seed(15213)

plt.figure()
num_series = 4
x = np.arange(10)
for i in range(num_series):
    # Generate random data with some structure
    y = np.random.rand(10)
    # Add some pattern to make it look more realistic
    y = y * 0.5 + 0.5 * np.sin(x/3.0 + i)
    # Ensure values stay in 0-1 range
    y = np.clip(y, 0, 1)
    plt.plot(y, marker="o", label=f"series {i+1}")


plt.title("Random Data")
plt.xlabel("x-axis")
plt.ylabel("y-axis")
plt.legend()

Results

Default Customized