diff --git a/doc/api/index.rst b/doc/api/index.rst
index 7828a225652..525095891a1 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -31,6 +31,7 @@ Plotting map elements
     Figure.inset
     Figure.legend
     Figure.logo
+    Figure.pygmtlogo
     Figure.solar
     Figure.text
     Figure.timestamp
diff --git a/examples/gallery/embellishments/pygmt_logo.py b/examples/gallery/embellishments/pygmt_logo.py
new file mode 100644
index 00000000000..b9655035656
--- /dev/null
+++ b/examples/gallery/embellishments/pygmt_logo.py
@@ -0,0 +1,160 @@
+"""
+PyGMT logo
+==========
+Beside the GMT logo, there is a separate PyGMT logo which can be plotted and added
+to a figure using :meth:`pygmt.Figure.pygmtlogo`. The design of the logo itself is
+kindly provided by `@sfrooti <https://github.com/sfrooti>`_ and consists of a visual
+and the wordmark "PyGMT".
+The logo is available in circle and hexagon shape. It can be plotted using colors of
+Python (blue and yellow) and GMT (red) or in black and white as well as in light or
+dark mode. The wordmark can be added at the right side or bottom of the visual.
+"""
+
+import pygmt
+
+fig = pygmt.Figure()
+fig.pygmtlogo()
+fig.show()
+
+# %%
+
+fig = pygmt.Figure()
+fig.pygmtlogo(theme="dark", box="+ggray20")
+fig.show()
+
+# %%
+
+fig = pygmt.Figure()
+fig.basemap(region=[-5, 5, -5, 5], projection="X10c", frame=[1, "+gtan"])
+
+fig.pygmtlogo(position="jTL+o0.2c+w4c", box="+gwhite+p1p,gray")
+fig.pygmtlogo(shape="hexagon", position="jTR+o0.2c+w4c")
+
+fig.pygmtlogo(color=False, wordmark=False, position="jTL+o0.5c/2c+w1.5c", box=False)
+fig.pygmtlogo(
+    color=False,
+    theme="dark",
+    shape="hexagon",
+    wordmark=False,
+    position="jTR+o0.5c/2c+w1.5c",
+    box=False,
+)
+fig.pygmtlogo(wordmark="vertical", position="jMC+w2c", box="+gwhite")
+
+fig.show()
+
+# %%
+# All combinations
+
+i_plot = 0
+
+fig = pygmt.Figure()
+
+for color in [True, False]:
+    for theme in ["light", "dark"]:
+        for shape in ["circle", "hexagon"]:
+            for wordmark in [False, True, "horizontal", "vertical"]:
+                for box in [False, True]:
+                    if not box:
+                        box_used = False
+                    elif box:
+                        if theme == "light":
+                            box_used = "+gwhite"
+                        elif theme == "dark":
+                            box_used = "+ggray20"
+                    # fig = pygmt.Figure()
+                    fig.basemap(
+                        region=[-1, 1, -1, 1], projection="X2.5c/3.5c", frame="+gtan"
+                    )
+                    # fig.image("@needle.png", position="jMC+w2c", box=box_used)
+                    fig.pygmtlogo(
+                        color=color,
+                        theme=theme,
+                        shape=shape,
+                        wordmark=wordmark,
+                        position="jMC+w2c",
+                        box=box_used,
+                    )
+
+                    fig.shift_origin(xshift="+w+0.5c")
+                    n_hor = 8
+                    if i_plot in range(n_hor - 1, 100, n_hor):
+                        fig.shift_origin(
+                            xshift=f"-{(n_hor * 2.5 + n_hor * 0.5)}c",
+                            yshift="-h-0.5c",
+                        )  # n_hor*width + n_hor*xshift
+
+                    i_plot = i_plot + 1
+fig.show()
+
+
+# %%
+# All versions
+# modified from
+# https://github.com/GenericMappingTools/pygmt/pull/3849#issuecomment-2753372170
+# by @seisman
+
+fig = pygmt.Figure()
+
+# Logo without workmark.
+fig.basemap(region=[0, 7, 0, 13], projection="x1c", frame="a1f1g1")
+for x, y, theme in [(1, 3, "light"), (4, 3, "dark")]:
+    for color, shape in [
+        (True, "circle"),
+        (True, "hexagon"),
+        (False, "circle"),
+        (False, "hexagon"),
+    ]:
+        fig.pygmtlogo(
+            color=color,
+            theme=theme,
+            shape=shape,
+            wordmark=False,
+            position=f"g{x}/{y}+jTL+w2c",
+        )
+        y += 3  # noqa: PLW2901
+
+fig.shift_origin(xshift=8)
+
+# Logo with vertical wordmark.
+fig.basemap(region=[0, 7, 0, 13], projection="x1c", frame="a1f1g1")
+for x, y, theme in [(1, 3, "light"), (4, 3, "dark")]:
+    for color, shape in [
+        (True, "circle"),
+        (True, "hexagon"),
+        (False, "circle"),
+        (False, "hexagon"),
+    ]:
+        fig.pygmtlogo(
+            color=color,
+            theme=theme,
+            shape=shape,
+            wordmark="vertical",
+            position=f"g{x}/{y}+jTL+w2c",
+        )
+        y += 3  # noqa: PLW2901
+
+fig.shift_origin(xshift=8)
+
+# Logo with horizontal wordmark.
+fig.basemap(region=[0, 20, 0, 13], projection="x1c", frame="a1f1g1")
+for x, y, theme in [(1, 3, "light"), (11, 3, "dark")]:
+    for color, shape in [
+        (True, "circle"),
+        (True, "hexagon"),
+        (False, "circle"),
+        (False, "hexagon"),
+    ]:
+        fig.pygmtlogo(
+            color=color,
+            theme=theme,
+            shape=shape,
+            wordmark="horizontal",
+            position=f"g{x}/{y}+jTL+w0/2c",
+        )
+        y += 3  # noqa: PLW2901
+
+fig.show(width=1000)
+
+
+# sphinx_gallery_thumbnail_number = 3
diff --git a/pygmt/figure.py b/pygmt/figure.py
index 474cd91179b..9a86ae964bf 100644
--- a/pygmt/figure.py
+++ b/pygmt/figure.py
@@ -448,6 +448,7 @@ def _repr_html_(self) -> str:
         plot,
         plot3d,
         psconvert,
+        pygmtlogo,
         rose,
         set_panel,
         shift_origin,
diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py
index 8905124f917..93be835fffb 100644
--- a/pygmt/src/__init__.py
+++ b/pygmt/src/__init__.py
@@ -42,6 +42,7 @@
 from pygmt.src.plot3d import plot3d
 from pygmt.src.project import project
 from pygmt.src.psconvert import psconvert
+from pygmt.src.pygmtlogo import pygmtlogo
 from pygmt.src.rose import rose
 from pygmt.src.select import select
 from pygmt.src.shift_origin import shift_origin
diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py
new file mode 100644
index 00000000000..88d427790e9
--- /dev/null
+++ b/pygmt/src/pygmtlogo.py
@@ -0,0 +1,258 @@
+"""
+pygmtlogo - Create and plot the PyGMT logo.
+The design of the logo is kindly provided by `@sfrooti <https://github.com/sfrooti>`_
+and consists of a visual and the wordmark "PyGMT".
+"""
+
+from pathlib import Path
+
+import pygmt
+
+
+def create_logo(color=True, theme="light", shape="circle", wordmark=True):  # noqa: PLR0915
+    """
+    Create the PyGMT logo using PyGMT.
+    The design of the logo is kindly provided by `@sfrooti <https://github.com/sfrooti>`_
+    and consists of a visual and the wordmark "PyGMT".
+
+    Parameters
+    ----------
+
+    color : bool
+        Set to ``True`` to use colors referring to Python (blue and yellow) and GMT
+        (red) [Default]. For ``False``, the logo is drawn in black and white.
+    theme : str
+        Use ``"light"`` for light mode (i.e., white background) [Default] and ``"dark"``
+        for dark mode (i.e., darkgray [gray20] background).
+    shape : str
+        Shape of the visual. Use ``"circle"`` for a circle shape [Default] or
+        ``"hexagon"`` for a hexagon shape.
+    wordmark : bool, str
+        Add the wordmark "PyGMT" and adjust its orientation relative to the visual.
+        Set to ``True`` or ``"horizontal"``, to add the wordmark at the right side of
+        the visual [Default]. Use ``"vertical"`` to place the wordmark below the
+        visual and ``False`` to add no wordmark.
+    """
+
+    # Helpful definitions
+    size = 4
+    region = [-size, size] * 2
+    projection = "x1c"
+
+    # Outer and inner radii of compass lines
+    r1, r2 = size * 0.625, size * 0.325
+
+    # Rotation around z (vertical) axis placed in the center
+    # Has to be applied to each plotting command, up on second call set to True
+    perspective = "30+w0/0"  # Rotation by 30 degrees
+
+    # Define colors
+    color_light = "white"
+    color_dark = "gray20"
+
+    # visual
+    color_blue = "48/105/152"  # Python blue
+    color_yellow = "255/212/59"  # Python yellow
+    color_red = "238/86/52"  # GMT red
+    if not color:
+        color_blue = color_yellow = color_red = color_dark
+        if theme == "dark":
+            color_blue = color_yellow = color_red = color_light
+
+    # background and wordmark
+    match theme:
+        case "light":
+            color_bg = color_light
+            color_py = color_blue
+            color_gmt = color_dark
+        case "dark":
+            color_bg = color_dark
+            color_py = color_yellow
+            color_gmt = color_light
+
+    # Define shape
+    match shape:
+        case "circle":
+            symbol = "c"  # circle
+            diameter = 7.5
+            diameter_add = 0.5
+        case "hexagon":
+            symbol = "h"  # hexagon
+            diameter = 8.6
+            diameter_add = 0.6
+
+    # Define wordmark
+    font = "AvantGarde-Book"
+    match wordmark:
+        case "vertical":
+            args_text_wm = {"x": 0, "y": -5, "justify": "CT", "font": f"2.5c,{font}"}
+        case True | "horizontal":
+            args_text_wm = {"x": 6, "y": 0, "justify": "LM", "font": f"8c,{font}"}
+
+    fig = pygmt.Figure()
+
+    # blue circle / hexagon for Earth
+    fig.plot(
+        x=0,
+        y=0,
+        region=region,
+        projection=projection,
+        style=f"{symbol}{diameter}c",
+        pen=f"0.5c,{color_blue}",
+        fill=color_bg,
+        perspective=perspective,
+        no_clip=True,  # needed for corners of hexagon shape
+    )
+
+    # yellow lines for compass
+    lines_yellow = [
+        ([-size, size], [0, 0]),  # horizontal line
+        ([-r1, -r2], [r1, r2]),  # upper left
+        ([-r1, -r2], [-r1, -r2]),  # lower left
+        ([r1, r2], [r1, r2]),  # upper right
+        ([r1, r2], [-r1, -r2]),  # lower right
+    ]
+    for x, y in lines_yellow:
+        fig.plot(x=x, y=y, pen=f"5p,{color_yellow}", perspective=True)
+
+    # letter G
+    # horizontal red line
+    fig.plot(x=[0.1, 1.65], y=[0, 0], pen=f"12p,{color_red}", perspective=True)
+    # red ring sector
+    fig.plot(x=0, y=0, style="w3.3c/90/0+i2.35c", fill=color_red, perspective=True)
+    # space between yellow lines and ring sector
+    fig.plot(x=0, y=0, style="w3.7c/0/360+i3.3c", fill=color_bg, perspective=True)
+    # vertical yellow line
+    fig.plot(x=[0, 0], y=[-4, 4], pen=f"6p,{color_yellow}", perspective=True)
+    # cover yellow line in lower part of the ring sector
+    fig.plot(x=0, y=0, style="w3.3c/260/-80+i2.35c", fill=color_red, perspective=True)
+
+    # upper vertical red line
+    # space between red line and blue circle / hexagon
+    fig.plot(x=[0, 0], y=[4, 3.0], pen=f"18p,{color_bg}", perspective=True)
+    # red line
+    fig.plot(x=[0, 0], y=[4, 1.9], pen=f"12p,{color_red}", perspective=True)
+
+    # letter M
+    # space between letter M and yellow line at the right side
+    # fig.plot(x=[1.6, 1.6], y=[1.5, 1.775], pen=f"10p,{color_bg}")
+    fig.plot(x=[1.6, 1.6], y=[1.5, 2.0], pen=f"10p,{color_bg}", perspective=True)
+
+    # polygon with small distance to horizontal line of letter G
+    # starting point: lower right corner of the left vertical line of letter M
+    # direction: clockwise
+    m_x1 = 0.33 - 0.33 / 2 - 0.06
+    m_x2 = 1.54 + 0.33 / 2 - 0.06  # outer radius of letter G
+    m_x = [
+        m_x1 + m_x2 / 5,  # vertical left upwarts
+        m_x1,
+        m_x1,
+        m_x1 + m_x2 / 5,
+        m_x1 + (m_x2 - m_x1) / 2,  # mid pick above
+        m_x2 - m_x2 / 5,  # vertical right downwarts
+        m_x2,
+        m_x2,
+        m_x2 - m_x2 / 5,
+        m_x2 - m_x2 / 5,  # right pick below
+        m_x1 + (m_x2 - m_x1) / 2,  # mid pick below
+        m_x1 + m_x2 / 5,  # left pick below
+    ]
+    m_y1 = 0.3
+    m_y2 = 1.65  # outer radius of letter G
+    m_y = [
+        m_y1,  # vertical left upwarts
+        m_y1,
+        m_y2,
+        m_y2,
+        m_y2 - m_y2 / 4,  # mid pick above
+        m_y2,  # vertical right downwarts
+        m_y2,
+        m_y1,
+        m_y1,
+        m_y2 - m_y2 / 3,  # right pick below
+        m_y2 - m_y2 / 2 - m_y2 / 18,  # mid pick below
+        m_y2 - m_y2 / 3,  # left pick below
+    ]
+    fig.plot(x=m_x, y=m_y, close=True, fill=color_red)
+
+    # letter T
+    # red curved horizontal line
+    fig.plot(x=0, y=0, style="w4.6c/240/-60+i3.7c", fill=color_red, perspective=True)
+    # vertical endings of curved horizontal line
+    args_vert = {"y": [-1.5, -2.5], "pen": f"9p,{color_bg}", "perspective": True}
+    fig.plot(x=[-1.05, -1.05], **args_vert)
+    fig.plot(x=[1.05, 1.05], **args_vert)
+    # arrow head as inverse triangle with pen for space to blue circle / hexagon
+    fig.plot(
+        x=0,
+        y=-3.55,
+        style="i1.1c",
+        fill=color_red,
+        pen=f"3p,{color_bg}",
+        perspective=True,
+    )
+    # arrow tail
+    fig.plot(x=[0, 0], y=[-2, -3.57], pen=f"12p,{color_red}", perspective=True)
+
+    # outline around the shape for black and white color with dark theme
+    if not color and theme == "dark":
+        fig.plot(
+            x=0,
+            y=0,
+            style=f"{symbol}{diameter + diameter_add}c",
+            pen=f"1p,{color_dark}",
+            perspective=True,
+            no_clip=True,
+        )
+
+    # Add wordmark "PyGMT"
+    if wordmark:
+        text_wm = f"@;{color_py};Py@;;@;{color_gmt};GMT@;;"
+        fig.text(text=text_wm, no_clip=True, **args_text_wm)
+
+    fig_name_logo = "pygmt_logo"
+    fig.savefig(fname=f"{fig_name_logo}.eps")
+
+    return fig_name_logo, color_bg
+
+
+def pygmtlogo(  # noqa: PLR0913
+    self,
+    color=True,
+    theme="light",
+    shape="circle",
+    wordmark=True,
+    position=None,  # -> use position parameter of Figure.image
+    box=None,  # -> use box parameter of Figure.image
+    projection=None,
+    region=None,
+    verbose=None,
+    panel=None,
+    transparency=None,
+):
+    """
+    Plot the PyGMT logo.
+    """
+
+    # -----------------------------------------------------------------------------
+    # Create logo file
+    # -----------------------------------------------------------------------------
+    fig_name_logo, color_bg = create_logo(
+        color=color, theme=theme, shape=shape, wordmark=wordmark
+    )
+
+    # -----------------------------------------------------------------------------
+    # Add to existing Figure instance
+    # -----------------------------------------------------------------------------
+    self.image(
+        imagefile=f"{fig_name_logo}.eps",
+        position=position,
+        box=box,
+        projection=projection,
+        region=region,
+        verbose=verbose,
+        panel=panel,
+        transparency=transparency,
+    )
+
+    Path.unlink(f"{fig_name_logo}.eps")
diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py
new file mode 100644
index 00000000000..a632ac13427
--- /dev/null
+++ b/pygmt/tests/test_pygmtlogo.py
@@ -0,0 +1,61 @@
+"""
+Test Figure.pygmtlogo.
+"""
+
+import pytest
+from pygmt import Figure
+
+
+@pytest.mark.benchmark
+@pytest.mark.mpl_image_compare
+def test_pylogo():
+    """
+    Plot the PyGMT logo using the default settings.
+    """
+    fig = Figure()
+    fig.pygmtlogo()
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_pylogo_on_a_map():
+    """
+    Plot the PyGMT logo and adjust the position, offset, and size.
+    """
+    fig = Figure()
+    fig.basemap(region=[-5, 5, -5, 5], projection="X10c", frame=1)
+    fig.pygmtlogo(position="jMC+o0.25c/0.25c+w7.5c", box=True)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_pylogo_no_wordmark():
+    """
+    Plot the PyGMT logo without wordmark.
+    """
+    fig = Figure()
+    fig.basemap(region=[-5, 5, -5, 5], projection="X10c", frame=1)
+    fig.pygmtlogo(wordmark=False)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_pylogo_lightmode():
+    """
+    Plot the PyGMT logo in light mode.
+    """
+    fig = Figure()
+    fig.basemap(region=[-5, 5, -5, 5], projection="X10c", frame=1)
+    fig.pygmtlogo(darkmode=False)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_pylogo_vertical():
+    """
+    Plot the PyGMT logo with vertical orientation of the wordmark.
+    """
+    fig = Figure()
+    fig.basemap(region=[-5, 5, -5, 5], projection="X10c", frame=1)
+    fig.pygmtlogo(orientation="vertical")
+    return fig