OpenAI-Inspired Matplotlib Styling: Modern Data Visualization in Python
Back to Writing

OpenAI-Inspired Matplotlib Styling: Modern Data Visualization in Python

Michael Brenndoerfer•September 27, 2025•3 min read•581 words•Jupyter Notebook

Learn how to create OpenAI-inspired, modern plots in Python using Matplotlib. This guide covers custom color palettes, typography, layout tips, and practical code examples to help you elevate your data visualizations for presentations, reports, and publications.

In[1]:
1import pandas as pd
2import numpy as np
3import matplotlib.pyplot as plt
4import seaborn as sns
In[2]:
1# Matplotlib rcParams for OpenAI-inspired style
2from pathlib import Path
3from textwrap import dedent
4import numpy as np
5import matplotlib.pyplot as plt
6from matplotlib.ticker import PercentFormatter
7
8
9import matplotlib as mpl
10
11mpl.rcParams.update(
12    {
13        "figure.facecolor": "white",
14        "figure.autolayout": False,
15        "figure.dpi": 160,
16        "savefig.transparent": True,
17        "savefig.bbox": "tight",
18        "savefig.pad_inches": 0.05,
19        "font.family": "DejaVu Sans",
20        "font.size": 12,
21        "text.color": "black",
22        "axes.titlesize": 18,
23        "axes.titleweight": 700,
24        "axes.titlepad": 14,
25        "axes.labelsize": 13,
26        "axes.linewidth": 0.8,
27        "axes.edgecolor": "gainsboro",
28        "axes.facecolor": "white",
29        "axes.spines.top": False,
30        "axes.spines.right": False,
31        "xtick.color": "dimgray",
32        "ytick.color": "dimgray",
33        "xtick.labelsize": 12,
34        "ytick.labelsize": 12,
35        "xtick.major.size": 0,
36        "ytick.major.size": 0,
37        "xtick.major.pad": 6,
38        "ytick.major.pad": 6,
39        "axes.grid": True,
40        "axes.grid.axis": "y",
41        "grid.linestyle": "-",
42        "grid.linewidth": 1.0,
43        "grid.color": "lightgray",
44        "legend.frameon": False,
45        "legend.fontsize": 12,
46        "legend.loc": "upper left",
47        "lines.linewidth": 2,
48        "patch.edgecolor": "none",
49    }
50)
In[12]:
1def label_bars(ax, rects, fmt="{:.1f}%", dy=3, fontsize=12, weight="600"):
2    for r in rects:
3        h = r.get_height()
4        ax.annotate(
5            fmt.format(h),
6            (r.get_x() + r.get_width() / 2, h),
7            xytext=(0, dy),
8            textcoords="offset points",
9            ha="center",
10            va="bottom",
11            fontsize=fontsize,
12            fontweight=weight,
13        )
14
15
16def tweak_axes(ax, top_margin=0.15):
17    ax.set_axisbelow(True)
18    ax.margins(y=top_margin)
19    for s in ("top", "right"):
20        ax.spines[s].set_visible(False)
21
22
23def circular_legend(ax, labels, colors):
24    from matplotlib.lines import Line2D
25
26    handles = [
27        Line2D(
28            [0],
29            [0],
30            marker="o",
31            color="w",
32            markerfacecolor=c,
33            markersize=10,
34            linewidth=0,
35        )
36        for c in colors
37    ]
38    ax.legend(
39        handles,
40        labels,
41        ncol=len(labels),
42        frameon=False,
43        bbox_to_anchor=(0, 1.06),
44        loc="lower left",
45    )
46
47
48# Light/bold paired palette (you can swap these)
49COLORS = ["#C8D7FF", "#4D61D6"]  # light indigo, bold indigo
50
51# ---------------------------------------------------------
52# 3) Demo 1 — Incorrect comments (percent bars + error bars)
In[4]:
1# ---------------------------------------------------------
2labels = ["GPT-5 (high)", "GPT-5-Codex (high)"]
3vals = np.array([13.7, 4.4])
4errs = np.array([1.6, 1.2])
5x = np.arange(len(labels))
6w = 0.55
7
8fig, ax = plt.subplots(figsize=(6.8, 4.2))
9bars = ax.bar(
10    x,
11    vals,
12    yerr=errs,
13    width=w,
14    capsize=3,
15    color=COLORS,
16    zorder=3,
17    edgecolor="dimgray",  # solid border color
18    linewidth=1.5,  # border thickness
19)
20
21# Round the edges of the bars (simulate rounded corners by overlaying a rectangle with rounded edges)
22for bar in bars:
23    bar.set_linewidth(1.5)
24    bar.set_edgecolor("dimgray")
25    bar.set_zorder(3)
26    # set_capstyle and set_joinstyle are for lines, not patches, so we use path effects for a stylized look
27    import matplotlib.patheffects as pe
28
29    bar.set_path_effects([pe.Stroke(linewidth=1.5, foreground="dimgray"), pe.Normal()])
30    bar.set_antialiased(True)
31    # Simulate rounded corners by overlaying a FancyBboxPatch
32    from matplotlib.patches import FancyBboxPatch
33
34    bbox = bar.get_bbox()
35    fancy = FancyBboxPatch(
36        (bbox.x0, bbox.y0),
37        bbox.width,
38        bbox.height,
39        boxstyle="round,pad=0.02,rounding_size=0.3",
40        linewidth=1.5,
41        edgecolor="dimgray",
42        facecolor=bar.get_facecolor(),
43        zorder=bar.get_zorder() + 1,
44        mutation_aspect=1,
45    )
46    ax.add_patch(fancy)
47    bar.set_visible(False)  # Hide the original bar
48
49ax.set_title("Incorrect comments", fontsize=14)
50ax.set_ylabel("% of comments")
51ax.set_xticks(x, labels, rotation=20, ha="right")
52ax.yaxis.set_major_formatter(PercentFormatter())
53label_bars(ax, bars, fmt="{:.1f}%")
54circular_legend(ax, labels, COLORS)
55tweak_axes(ax)
56fig.tight_layout()
57fig.savefig("demo_incorrect_comments.png")
Out[4]:
Visualization
Notebook output
In[11]:
1# ---------------------------------------------------------
2# 4) Demo 2 — High-impact comments
3# ---------------------------------------------------------
4vals2 = np.array([39.4, 52.4])
5errs2 = np.array([1.7, 2.2])
6fig, ax = plt.subplots(figsize=(6.8, 4.2))
7bars = ax.bar(x, vals2, yerr=errs2, width=w, capsize=3, color=COLORS, zorder=3)
8ax.set_title("High-impact comments")
9ax.set_ylabel("% of comments")
10ax.set_xticks(x, labels, rotation=20, ha="right")
11ax.yaxis.set_major_formatter(PercentFormatter())
12label_bars(ax, bars, fmt="{:.1f}%")
13circular_legend(ax, labels, COLORS)
14tweak_axes(ax)
15fig.tight_layout()
16
17# ---------------------------------------------------------
18# 5) Demo 3 — Comments per PR (avg)
19# ---------------------------------------------------------
20vals3 = np.array([1.32, 0.93])
21fig, ax = plt.subplots(figsize=(6.8, 4.2))
22bars = ax.bar(x, vals3, width=w, color=COLORS, zorder=3)
23ax.set_title("Comments per PR (avg)")
24ax.set_ylabel("# of comments")
25ax.set_xticks(x, labels, rotation=20, ha="right")
26label_bars(ax, bars, fmt="{:.2f}", dy=4)
27circular_legend(ax, labels, COLORS)
28tweak_axes(ax, top_margin=0.22)
29fig.tight_layout()
30
31# ---------------------------------------------------------
32# 6) Demo 4 — Stacked bar, “Economically important tasks”
33# ---------------------------------------------------------
34models = ["GPT-5", "ChatGPT agent", "OpenAI o3"]
35wins = np.array([41.0, 36.5, 27.5])
36ties = np.array([6.1, 7.0, 6.0])
37
38fig, ax = plt.subplots(figsize=(7.0, 4.6))
39x = np.arange(len(models))
40w = 0.55
41p1 = ax.bar(x, wins, width=w, color="#B07CFF", label="Wins", zorder=3)
42p2 = ax.bar(x, ties, width=w, bottom=wins, color="#E7D2FF", label="Ties", zorder=3)
43
44ax.set_title("Economically important tasks")
45ax.set_ylabel("%")
46ax.set_xticks(x, models, rotation=20, ha="right")
47ax.set_ylim(0, 60)
48ax.axhline(50, color="gray", linestyle="--", linewidth=1)
49ax.text(ax.get_xlim()[0], 50.5, "Industry expert baseline", fontsize=11)
50
51for a, b in zip(p1, p2):
52    total = a.get_height() + b.get_height()
53    ax.annotate(
54        f"{total:.1f}",
55        (a.get_x() + a.get_width() / 2, total),
56        ha="center",
57        va="bottom",
58        fontsize=11,
59        fontweight="600",
60        xytext=(0, 3),
61        textcoords="offset points",
62    )
63
64ax.legend(ncol=2, bbox_to_anchor=(0, 1.06), loc="lower left")
65tweak_axes(ax)
66fig.tight_layout()
Out[11]:
Visualization
Notebook output
Notebook output
Notebook output
In[6]:
Michael Brenndoerfer

About the author: Michael Brenndoerfer

All opinions expressed here are my own and do not reflect the views of my employer.

Michael currently works as an Associate Director of Data Science at EQT Partners in Singapore, where he drives AI and data initiatives across private capital investments.

With over a decade of experience spanning private equity, management consulting, and software engineering, he specializes in building and scaling analytics capabilities from the ground up. He has published research in leading AI conferences and holds expertise in machine learning, natural language processing, and value creation through data.

Stay updated

Get notified when I publish new articles on data and AI, private equity, technology, and more.