Matplotlib logo in Cyberpunk style

showcase
mpl-skia-pathops
mpl-visual-context
Author

Jae-Joon Lee

Published

February 16, 2025

Modified

February 16, 2025

Matplotlib logo in Cyberpunk style

In this post, we will recreate the matplotlib logo in Cyberpunk style.

Code
import matplotlib.pyplot as plt
from matplotlib_logo import make_logo

import mplcyberpunk
from mpl_skia_pathops import PathOpsPathEffect

import mpl_visual_context.patheffects as pe
import mpl_visual_context.image_box as ib
import mpl_visual_context.image_effect as ie

linewidth_scale = 1.5

with plt.rc_context():
    plt.style.use("cyberpunk")
    fig, ax = make_logo(height_px=int(110 * linewidth_scale),
                        lw_bars=0.7*linewidth_scale, lw_grid=0.5*linewidth_scale,
                        lw_border=1*linewidth_scale,
                        rgrid=[1, 3, 5, 7], with_text=True)

    cmap = plt.get_cmap()  # we canche the default cmap of the cyberpunk theme.

fig.patch.set(alpha=1) # The figure patch was set to transparent.
ax.patch.set_alpha(0.3)

tp = fig.axes[0].patches[0]  # The textpath
tp.set_clip_on(False)

# make_logo add a circle (rectangle in polar coordinate) patch, that is larger than
# the axes patch (which is a circle). We will use this circle patch to clip the text.

circle = sorted(ax.patches, key=lambda a: a.get_zorder())[0]
circle.set_visible(False)

union_circle = PathOpsPathEffect.union(circle)
# a path effect that unions the given path with the cricle.

tp.set_path_effects([union_circle])

# glow effect
glow = pe.ImageEffect(ie.Pad(20*linewidth_scale)
                      | ie.GaussianBlur(10, channel_slice=slice(3, 4))
                      | ie.AlphaAxb((2, 0))
                      | ie.Erosion(50*linewidth_scale, channel_slice=slice(0, 3))
                      )

# We will create an imagebox with the colormap of the cyberpunk theme. We need
# to increase the extent so that the image is large enough when we stroke it.
color_gradient_box = ib.ImageBox("right", extent=[-0.1, -0.1, 1.1, 1.1],
                                 coords=tp, axes=ax, cmap=cmap)

stroke_color_gradient = (
    union_circle
    | pe.GCModify(linewidth=3*linewidth_scale, alpha=1)
    | PathOpsPathEffect.stroke2fill()
    | pe.FillImage(color_gradient_box)
)

tp.set_path_effects([
    stroke_color_gradient | glow,
    union_circle | pe.FillImage(color_gradient_box, alpha=0.5),
    stroke_color_gradient
])

Cybepunk Style

We will redraw the logo in cybepunk style (using the cyberpunk package). We will also tweak some aspect of the result.

linewidth_scale = 1.5

with plt.rc_context():
    plt.style.use("cyberpunk")
    fig, ax = make_logo(height_px=int(110 * linewidth_scale),
                        lw_bars=0.7*linewidth_scale, lw_grid=0.5*linewidth_scale,
                        lw_border=1*linewidth_scale,
                        rgrid=[1, 3, 5, 7], with_text=True)

    cmap = plt.get_cmap()  # we canche the default cmap of the cyberpunk theme.

fig.patch.set(alpha=1) # The figure patch was set to transparent.
ax.patch.set_alpha(0.3)

tp = fig.axes[0].patches[0]  # The textpath
tp.set_clip_on(False)

# make_logo add a circle (rectangle in polar coordinate) patch, that is larger than
# the axes patch (which is a circle). We will use this circle patch to clip the text.

circle = sorted(ax.patches, key=lambda a: a.get_zorder())[0]
circle.set_visible(False)

Patheffect to draw the union of two paths

We’d like to merge the text path and the background circular path of the icon. We use mpl_skia_pathops. This example is based on 0.3.0 version. .

from mpl_skia_pathops import PathOpsPathEffect

union_circle = PathOpsPathEffect.union(circle)
# a path effect that unions the given path with the cricle.

tp.set_path_effects([union_circle])

Matplotlib logo in Cyberpunk style

We will make it more cyberpunk. The effect is adopted from cyberpunk example in the mpl-visual-context package.

import mpl_visual_context.patheffects as pe
import mpl_visual_context.image_box as ib
import mpl_visual_context.image_effect as ie

# glow effect
glow = pe.ImageEffect(ie.Pad(20*linewidth_scale)
                      | ie.GaussianBlur(10, channel_slice=slice(3, 4))
                      | ie.AlphaAxb((2, 0))
                      | ie.Erosion(50*linewidth_scale, channel_slice=slice(0, 3))
                      )

# We will create an imagebox with the colormap of the cyberpunk theme. We need
# to increase the extent so that the image is large enough when we stroke it.
color_gradient_box = ib.ImageBox("right", extent=[-0.1, -0.1, 1.1, 1.1],
                                 coords=tp, axes=ax, cmap=cmap)

stroke_color_gradient = (
    union_circle
    | pe.GCModify(linewidth=3*linewidth_scale, alpha=1)
    | PathOpsPathEffect.stroke2fill()
    | pe.FillImage(color_gradient_box)
)

tp.set_path_effects([
    stroke_color_gradient | glow,
    union_circle | pe.FillImage(color_gradient_box, alpha=0.5),
    stroke_color_gradient
])