From 4868c8ae2f50e609c91ac5e99b75e418e226579f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= <94163266+yvonnefroehlich@users.noreply.github.com> Date: Sat, 2 May 2026 10:17:19 +0200 Subject: [PATCH 01/10] Figure.pygmtlogo: Initial implementation for the circular, colored PyGMT logo (#3849) Co-authored-by: Dongdong Tian Co-authored-by: Michael Grund <23025878+michaelgrund@users.noreply.github.com> Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- doc/api/index.rst | 1 + pygmt/figure.py | 2 + pygmt/src/pygmtlogo.py | 357 ++++++++++++++++++++ pygmt/tests/baseline/test_pygmtlogo.png.dvc | 5 + pygmt/tests/test_pygmtlogo.py | 19 ++ 5 files changed, 384 insertions(+) create mode 100644 pygmt/src/pygmtlogo.py create mode 100644 pygmt/tests/baseline/test_pygmtlogo.png.dvc create mode 100644 pygmt/tests/test_pygmtlogo.py diff --git a/doc/api/index.rst b/doc/api/index.rst index a760615228b..60285216d73 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -35,6 +35,7 @@ Plotting figure elements Figure.logo Figure.magnetic_rose Figure.paragraph + Figure.pygmtlogo Figure.scalebar Figure.solar Figure.text diff --git a/pygmt/figure.py b/pygmt/figure.py index a1494c29fd8..ccf3a21d292 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -30,6 +30,7 @@ from pygmt.src.plot import plot as _plot from pygmt.src.plot3d import plot3d as _plot3d from pygmt.src.psconvert import psconvert as _psconvert +from pygmt.src.pygmtlogo import pygmtlogo as _pygmtlogo from pygmt.src.rose import rose as _rose from pygmt.src.scalebar import scalebar as _scalebar from pygmt.src.shift_origin import shift_origin as _shift_origin @@ -464,6 +465,7 @@ def _repr_html_(self) -> str: plot = _plot plot3d = _plot3d psconvert = _psconvert + pygmtlogo = _pygmtlogo rose = _rose scalebar = _scalebar set_panel = _set_panel diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py new file mode 100644 index 00000000000..8da5e008f16 --- /dev/null +++ b/pygmt/src/pygmtlogo.py @@ -0,0 +1,357 @@ +""" +pygmtlogo - Plot the PyGMT logo. + +The initial design of the logo is kindly provided by `@sfrooti `_ +and consists of a visual and the wordmark "PyGMT". +""" + +from collections.abc import Sequence +from typing import Literal + +import numpy as np +from pygmt._typing import AnchorCode, PathLike +from pygmt.helpers import GMTTempFile, fmt_docstring +from pygmt.params import Box, Position + +__doctest_skip__ = ["pygmtlogo"] + + +def _create_logo( # noqa: PLR0915 + shape: Literal["circle", "hexagon"] = "circle", + theme: Literal["light", "dark"] = "light", + wordmark: Literal["none", "horizontal", "vertical"] = "none", + color: bool = True, + figname: PathLike = "pygmt_logo.eps", + debug: bool = False, +): + """ + Create the PyGMT logo using PyGMT. + """ + from pygmt.figure import Figure # noqa: PLC0415 + + # Helpful definitions + size = 4 + region = [-size, size] * 2 + proj = "x1c" + # Rotation around z-axis by 30 degrees counter-clockwise placed in the center. + perspective = "30+w0/0" + + # Radii (make sure that r4-r5 == r2-r3) + r0, r1, r2, r3, r4, r5 = size * np.array([128, 112, 75, 61, 53, 39]) / 128 + # Pen thicknesses + thick_shape = r0 - r1 # for shape + thick_gt = r4 - r5 # for letters G and T + thick_m = r4 / 5 # for letter M + thick_comp = thick_shape / 3 # for compass lines + thick_gap = thick_shape / 4 + + # Define colors + color_light = "white" + color_dark = "gray20" + + blue = "48/105/152" # Python blue + yellow = "255/212/59" # Python yellow + red = "238/86/52" # GMT red + if not color: + blue = yellow = red = color_dark + if theme == "dark": + blue = yellow = red = color_light + + # Background and wordmark + match theme: + case "light": + color_bg = color_light + color_py = blue + color_gmt = color_dark + case "dark": + color_bg = color_dark + color_py = yellow + color_gmt = color_light + + # Define shape + match shape: + case "circle": + symbol = "c" + size_shape = r0 + r1 + hex_factor = 1.0 + case "hexagon": + symbol = "h" + size_shape = (r0 + 0.34) * 2 + hex_factor = 1.1 + + # Define wordmark + font = "AvantGarde-Book" + match wordmark: + case "vertical": + args_text_wm = {"x": 0, "y": -4.5, "justify": "CT", "font": f"2.5c,{font}"} + case "horizontal": + args_text_wm = {"x": 4.5, "y": 0.8, "justify": "LM", "font": f"8c,{font}"} + + def _letter_g_coords(): + """Coordinates for letter G.""" + outer_angles = np.deg2rad(np.arange(90, 361)) + inner_angles = outer_angles[::-1] + offset = thick_gt / 2 + # Outer arc (r4) + arc_outer_x, arc_outer_y = np.cos(outer_angles) * r4, np.sin(outer_angles) * r4 + # Connecting lines + connector_x, connector_y = [r4, 0, 0, r5], [offset, offset, -offset, -offset] + # Inner arc (r5) + arc_inner_x, arc_inner_y = np.cos(inner_angles) * r5, np.sin(inner_angles) * r5 + # Combine all coordinates (outer arc, connectors, inner arc) + g_x = np.concatenate([arc_outer_x, connector_x, arc_inner_x]) + g_y = np.concatenate([arc_outer_y, connector_y, arc_inner_y]) + return {"x": g_x, "y": g_y} + + def _letter_m_coords(): + """Coordinates for letter M.""" + # X-coordinates from left to right. + x1 = thick_gap # Left edge of left vertical line of M. + x5 = r4 # Right edge of right vertical line of M. + x2 = x1 + thick_m # Right edge of left vertical line of M. + x3 = (x1 + x5) / 2 # The middle of M. + x4 = x5 - thick_m # Left edge of right vertical line of M. + # Y-coordinates from bottom to top. + y1 = thick_gt / 2 + thick_gap # Bottom of the letter M. + y2 = r5 - thick_gt # Bottom of the middle peak of M. + y3 = r5 # Top of the middle peak of M. + y4 = r4 # Top of letter M. + # X- and Y-coordinates of the letter M, starting from the left edge of the left + # vertical line and going clockwise. + m_x = [x1, x1, x2, x3, x4, x5, x5, x4, x4, x3, x2, x2] + m_y = [y1, y4, y4, y3, y4, y4, y1, y1, y3, y2, y3, y1] + return {"x": m_x, "y": m_y} + + def _letter_t_coords(): + """Coordinates for letter T.""" + outer_angles = np.deg2rad(np.arange(240, 300, 0.5)) + inner_angles = outer_angles[::-1] + arc_outer_x, arc_outer_y = np.cos(outer_angles) * r2, np.sin(outer_angles) * r2 + arc_inner_x, arc_inner_y = np.cos(inner_angles) * r3, np.sin(inner_angles) * r3 + # The arrowhead is an equilateral triangle + x0 = thick_gt / 2 # Extra half-width for arrow head + y0 = 1.8 * x0 * np.sqrt(3) # Height for arrow head + arrow_x = [-x0, -x0, -x0 * 2.0, 0, x0 * 2.0, x0, x0] + arrow_y = [-r2, -r0 + y0, -r0 + y0, -r0, -r0 + y0, -r0 + y0, -r2] + mask_left = arc_outer_x < -x0 + mask_right = arc_outer_x > x0 + t_x = np.concatenate( + [arc_inner_x, arc_outer_x[mask_left], arrow_x, arc_outer_x[mask_right]] + ) + t_y = np.concatenate( + [arc_inner_y, arc_outer_y[mask_left], arrow_y, arc_outer_y[mask_right]] + ) + # Ensure the same X-coordinate for the right edge of T and the middle of M. + mask = np.abs(t_x) <= (thick_gap + r4) / 2 + return {"x": t_x[mask], "y": t_y[mask]} + + def _bg_arrow_coords(): + """Coordinates for the background arrow.""" + # x0, y0 is the same as in _letter_t_coords(). + x0 = thick_gt / 2 + y0 = 1.8 * x0 * np.sqrt(3) + # The background arrow is thick_comp wider than the letter T. + x1 = x0 + thick_comp / 2.0 # Half-width of the arrow tail + x2 = 2 * x0 + thick_comp / np.sqrt(3) # Half-width of the arrow head + + arrow_x = [-x1, -x1, -x2, -(x2 - 2 * x0), (x2 - 2 * x0), x2, x1, x1] + arrow_y = [r0, -r0 + y0, -r0 + y0, -r0, -r0, -r0 + y0, -r0 + y0, r0] + return {"x": arrow_x, "y": arrow_y} + + def _compass_lines(): + """Coordinates of compass lines.""" + sqrt2 = np.sqrt(2) / 2 + x1, x2, x3 = r0 * sqrt2, r3 * sqrt2, (r2 + (r3 - r4)) * sqrt2 + # Coordinates of vectors in the format of (x_start, y_start, x_end, y_end). + return [ + (-r0 * hex_factor, 0, -r3, 0), # left horizontal + (r3, 0, r0 * hex_factor, 0), # right horizontal + (-x1, x1, -x2, x2), # upper left + (-x1, -x1, -x2, -x2), # lower left + (x1, x1, x3, x3), # upper right + (x1, -x1, x2, -x2), # lower right + ] + + def _vline_coords(): + """ + Coordinates for the vertical line at the top. + """ + x0 = thick_gt / 2 + return {"x": [-x0, -x0, x0, x0], "y": [r0, r3, r3, r0]} + + fig = Figure() + fig.basemap(region=region, projection=proj, perspective=perspective, frame="none") + + # Earth - circle / hexagon + args_shape = { + "style": f"{symbol}{size_shape}c", + "perspective": True, + "no_clip": True, # Needed for corners of hexagon shape + } + # Shape fill + fig.plot(x=0, y=0, fill=color_bg, **args_shape) + + # Compass lines + fig.plot( + data=_compass_lines(), + pen=f"{thick_comp}c,{yellow}", + style="v0c+s", + perspective=True, + no_clip=True, + ) + + # Shape outline (over ends of compass lines for hexagon shape) + fig.plot(x=0, y=0, pen=f"{thick_shape}c,{blue}", **args_shape) + + # Arrow in background color (over shape outline but under letters) + fig.plot(data=_bg_arrow_coords(), fill=color_bg, perspective=True) + + # Letters G, M, and T + fig.plot(data=_letter_g_coords(), fill=red, perspective=True) + fig.plot(data=_letter_m_coords(), fill=red, perspective=True) + fig.plot(data=_letter_t_coords(), fill=red, perspective=True) + + # Upper vertical line + fig.plot(data=_vline_coords(), fill=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}{size_shape + thick_shape}c", + pen=f"1p,{color_dark}", + perspective=True, + no_clip=True, + ) + + # Add wordmark "PyGMT" + if wordmark != "none": + text_wm = f"@;{color_py};Py@;;@;{color_gmt};GMT@;;" + fig.text(text=text_wm, no_clip=True, **args_text_wm) + + # Helpful for implementing the logo; not included in the logo + if debug: + from pygmt import config # noqa: PLC0415 + + # Gridlines + with config(MAP_FRAME_TYPE="inside", MAP_GRID_PEN="0.1p,gray30"): + fig.basemap(frame="g1") + # Circles for the different radii + for r in [r0, r1, r2, r3, r4, r5]: + fig.plot(x=0, y=0, style=f"c{2 * r}c", pen="0.3p,gray30") + pen = "0.3p,gray30,2_2" + fig.plot(x=0, y=0, style=f"c{2 * (r2 + (r3 - r4))}c", pen=pen) + # Lines for letter M + fig.hlines(y=[r4, r5], xmin=-3, pen=pen, perspective=True) + fig.vlines(x=[r4, (thick_gap + r4) / 2], ymax=3, pen=pen, perspective=True) + + fig.savefig(fname=figname) + + +@fmt_docstring +def pygmtlogo( # noqa: PLR0913 + self, + shape: Literal["circle", "hexagon"] = "circle", + theme: Literal["light", "dark"] = "light", + wordmark: Literal["none", "horizontal", "vertical"] = "none", + color: bool = True, + width: float | str | None = None, + height: float | str | None = None, + position: Position | Sequence[float | str] | AnchorCode | None = None, + box: Box | bool = False, + verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] + | bool = False, + panel: int | Sequence[int] | bool = False, + perspective: float | Sequence[float] | str | bool = False, + transparency: float | None = None, +): + """ + Plot the PyGMT logo. + + The design of the logo is kindly provided by `@sfrooti `_ + and consists of a visual and the wordmark "PyGMT". + + Parameters + ---------- + shape + Shape of the visual logo. Use ``"circle"`` for a circle shape [Default] or + ``"hexagon"`` for a hexagon shape. + theme + Use ``"light"`` for light mode (i.e., a white background) [Default] and + ``"dark"`` for dark mode (i.e., a darkgray background). + wordmark + Add the wordmark "PyGMT" and adjust its orientation relative to the visual. + Valid values are: + + - ``"none"``: no wordmark [Default]. + - ``"horizontal"``: wordmark at the right side of the visual. + - ``"vertical"``: wordmark below the visual. + color + ``True`` for a color logo, and ``False`` for a black and white logo. + position + Position of the GMT logo on the plot. It can be specified in multiple ways: + + - A :class:`pygmt.params.Position` object to fully control the reference point, + anchor point, and offset. + - A sequence of two values representing the x- and y-coordinates in plot + coordinates, e.g., ``(1, 2)`` or ``("1c", "2c")``. + - A :doc:`2-character justification code ` for a + position inside the plot, e.g., ``"TL"`` for Top Left corner inside the plot. + + If not specified, defaults to the Bottom Left corner of the plot (position + ``(0, 0)`` with anchor ``"BL"``). + width + height + Width or height of the PyGMT logo. Since the aspect ratio is fixed, only one of + the two can be specified. + box + Draw a background box behind the logo. If set to ``True``, a simple rectangular + box is drawn using :gmt-term:`MAP_FRAME_PEN`. To customize the box appearance, + pass a :class:`pygmt.params.Box` object to control style, fill, pen, and other + box properties. + $verbose + $panel + $perspective + $transparency + + Examples + -------- + >>> import pygmt + + The simplest way to plot the PyGMT logo is to call the method without any arguments. + + >>> fig = pygmt.Figure() + >>> fig.pygmtlogo() + >>> fig.show() + + Plot the PyGMT logo with the wordmark "PyGMT" with a height of 1 centimeter at the + right side in the Bottom Right corner on an existing basemap: + + >>> fig = pygmt.Figure() + >>> fig.basemap(region=[-90, -70, 0, 20], projection="M10c", frame=True) + >>> fig.pygmtlogo(wordmark="horizontal", position="BR", height="1c") + >>> fig.show() + """ + with GMTTempFile(suffix=".eps") as logofile: + # Create logo file + _create_logo( + color=color, + theme=theme, + shape=shape, + wordmark=wordmark, + figname=logofile.name, + ) + + # Add to existing Figure instance + self.image( + imagefile=logofile.name, + position=position, + width=width, + height=height, + box=box, + verbose=verbose, + panel=panel, + perspective=perspective, + transparency=transparency, + ) diff --git a/pygmt/tests/baseline/test_pygmtlogo.png.dvc b/pygmt/tests/baseline/test_pygmtlogo.png.dvc new file mode 100644 index 00000000000..010f8e4c4db --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 35c59c31c92f13c705a24933465ff551 + size: 14374 + hash: md5 + path: test_pygmtlogo.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py new file mode 100644 index 00000000000..fb117b9b097 --- /dev/null +++ b/pygmt/tests/test_pygmtlogo.py @@ -0,0 +1,19 @@ +""" +Test Figure.pygmtlogo. +""" + +import pytest +from pygmt import Figure + + +@pytest.mark.benchmark +@pytest.mark.mpl_image_compare +def test_pygmtlogo(): + """ + Plot the default PyGMT logo, colored, light and dark themes, without wordmark. + """ + fig = Figure() + fig.pygmtlogo() + fig.shift_origin(xshift="+w") + fig.pygmtlogo(theme="dark") + return fig From bd24b5a12aa58662c9596557ff07aa8879f30b60 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 6 May 2026 19:16:27 +0800 Subject: [PATCH 02/10] Force the default logo size to 2-cm and rename test_pygmtlogo to test_pygmtlogo_circle_no_wordmark (#4617) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/src/pygmtlogo.py | 18 +++++++++++++++++- pygmt/tests/baseline/test_pygmtlogo.png.dvc | 5 ----- .../test_pygmtlogo_circle_no_wordmark.png.dvc | 5 +++++ pygmt/tests/test_pygmtlogo.py | 19 +++++++++++++------ 4 files changed, 35 insertions(+), 12 deletions(-) delete mode 100644 pygmt/tests/baseline/test_pygmtlogo.png.dvc create mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index 8da5e008f16..93286689cd7 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -10,6 +10,7 @@ import numpy as np from pygmt._typing import AnchorCode, PathLike +from pygmt.exceptions import GMTValueError from pygmt.helpers import GMTTempFile, fmt_docstring from pygmt.params import Box, Position @@ -304,7 +305,8 @@ def pygmtlogo( # noqa: PLR0913 width height Width or height of the PyGMT logo. Since the aspect ratio is fixed, only one of - the two can be specified. + the two can be specified. If not specified, the default size of the visual logo + is set to 2 cm. box Draw a background box behind the logo. If set to ``True``, a simple rectangular box is drawn using :gmt-term:`MAP_FRAME_PEN`. To customize the box appearance, @@ -333,6 +335,20 @@ def pygmtlogo( # noqa: PLR0913 >>> fig.pygmtlogo(wordmark="horizontal", position="BR", height="1c") >>> fig.show() """ + # Set the default size of the visual logo to 2 cm. + if width is None and height is None: + match wordmark: + case "none" | "vertical": + width = width or "2c" + case "horizontal": + height = height or "2c" + case _: + raise GMTValueError( + wordmark, + description="value for wordmark", + choices={"none", "horizontal", "vertical"}, + ) + with GMTTempFile(suffix=".eps") as logofile: # Create logo file _create_logo( diff --git a/pygmt/tests/baseline/test_pygmtlogo.png.dvc b/pygmt/tests/baseline/test_pygmtlogo.png.dvc deleted file mode 100644 index 010f8e4c4db..00000000000 --- a/pygmt/tests/baseline/test_pygmtlogo.png.dvc +++ /dev/null @@ -1,5 +0,0 @@ -outs: -- md5: 35c59c31c92f13c705a24933465ff551 - size: 14374 - hash: md5 - path: test_pygmtlogo.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc new file mode 100644 index 00000000000..d33a5c5bd35 --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: b1dee02932b292335cf5f8b95676a258 + size: 19161 + hash: md5 + path: test_pygmtlogo_circle_no_wordmark.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index fb117b9b097..2495a9a3a1a 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -4,16 +4,23 @@ import pytest from pygmt import Figure +from pygmt.params import Axis, Position -@pytest.mark.benchmark @pytest.mark.mpl_image_compare -def test_pygmtlogo(): +def test_pygmtlogo_circle_no_wordmark(): """ - Plot the default PyGMT logo, colored, light and dark themes, without wordmark. + Test the PyGMT circular logo without the wordmark, including both light/dark themes, + and colored/black-and-white versions. """ fig = Figure() - fig.pygmtlogo() - fig.shift_origin(xshift="+w") - fig.pygmtlogo(theme="dark") + fig.basemap(region=[-0.5, 5.0, -0.5, 5.0], projection="x1c", frame=Axis(grid=0.5)) + fig.pygmtlogo( + position=Position((1, 3.5), anchor="CM", cstype="mapcoords"), + theme="light", + ) + fig.pygmtlogo( + position=Position((3.5, 3.5), anchor="CM", cstype="mapcoords"), + theme="dark", + ) return fig From 091d62c60efc207bb4f537a93a61b5def0960f29 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 7 May 2026 15:53:57 +0800 Subject: [PATCH 03/10] Add a test to check the design details of the circular logo (#4623) --- pygmt/src/pygmtlogo.py | 13 ++++++++----- .../baseline/test_pygmtlogo_circle_design.png.dvc | 5 +++++ pygmt/tests/test_pygmtlogo.py | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index 93286689cd7..e9351b0edad 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -17,12 +17,12 @@ __doctest_skip__ = ["pygmtlogo"] -def _create_logo( # noqa: PLR0915 +def _create_logo( # noqa: PLR0915, PLR0912 shape: Literal["circle", "hexagon"] = "circle", theme: Literal["light", "dark"] = "light", wordmark: Literal["none", "horizontal", "vertical"] = "none", color: bool = True, - figname: PathLike = "pygmt_logo.eps", + figname: PathLike | None = None, debug: bool = False, ): """ @@ -236,8 +236,8 @@ def _vline_coords(): from pygmt import config # noqa: PLC0415 # Gridlines - with config(MAP_FRAME_TYPE="inside", MAP_GRID_PEN="0.1p,gray30"): - fig.basemap(frame="g1") + with config(MAP_GRID_PEN="0.1p,gray30"): + fig.basemap(frame="00g1") # Circles for the different radii for r in [r0, r1, r2, r3, r4, r5]: fig.plot(x=0, y=0, style=f"c{2 * r}c", pen="0.3p,gray30") @@ -247,7 +247,10 @@ def _vline_coords(): fig.hlines(y=[r4, r5], xmin=-3, pen=pen, perspective=True) fig.vlines(x=[r4, (thick_gap + r4) / 2], ymax=3, pen=pen, perspective=True) - fig.savefig(fname=figname) + if figname: + fig.savefig(fname=figname) + return None + return fig @fmt_docstring diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc new file mode 100644 index 00000000000..7a81601eafe --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 2d9fd4fdb1189514d374500d5f4add73 + size: 149683 + hash: md5 + path: test_pygmtlogo_circle_design.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index 2495a9a3a1a..924ff965a18 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -5,6 +5,20 @@ import pytest from pygmt import Figure from pygmt.params import Axis, Position +from pygmt.src.pygmtlogo import _create_logo + + +@pytest.mark.mpl_image_compare(savefig_kwargs={"dpi": 600}) +def test_pygmtlogo_circle_design(): + """ + Test the design details of the PyGMT circular logo. + + This is a regression test to ensure that the design of the logo does not change + unintentionally. The debugging lines (gridlines and circles) are helpful for + implementing the logo, but they are not included in the final logo design. + """ + fig = _create_logo(debug=True) + return fig @pytest.mark.mpl_image_compare From c63767fbc085616741fef1265ad30bd9522ea63a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 8 May 2026 06:39:35 +0800 Subject: [PATCH 04/10] Figure.pygmtlogo: Add tests for the circular, black/white PyGMT logo (#4625) --- pygmt/src/pygmtlogo.py | 2 +- .../baseline/test_pygmtlogo_circle_no_wordmark.png.dvc | 4 ++-- pygmt/tests/test_pygmtlogo.py | 10 ++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index e9351b0edad..6691ebd8bd8 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -221,7 +221,7 @@ def _vline_coords(): x=0, y=0, style=f"{symbol}{size_shape + thick_shape}c", - pen=f"1p,{color_dark}", + pen=f"{thick_comp / 2.0}c,{color_bg}", perspective=True, no_clip=True, ) diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc index d33a5c5bd35..3530063c1f5 100644 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc @@ -1,5 +1,5 @@ outs: -- md5: b1dee02932b292335cf5f8b95676a258 - size: 19161 +- md5: dcb54b2c28e02c4fc83d38278b2700c6 + size: 31454 hash: md5 path: test_pygmtlogo_circle_no_wordmark.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index 924ff965a18..e4d6f4aff5e 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -37,4 +37,14 @@ def test_pygmtlogo_circle_no_wordmark(): position=Position((3.5, 3.5), anchor="CM", cstype="mapcoords"), theme="dark", ) + fig.pygmtlogo( + position=Position((1, 1), anchor="CM", cstype="mapcoords"), + theme="light", + color=False, + ) + fig.pygmtlogo( + position=Position((3.5, 1), anchor="CM", cstype="mapcoords"), + theme="dark", + color=False, + ) return fig From 21cb57a9196bcfedbf1e656ab4fd814b6265f206 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 9 May 2026 18:02:18 +0800 Subject: [PATCH 05/10] Figure.pygmtlogo: Simplify the code logic for defining colors (#4629) --- pygmt/src/pygmtlogo.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index 6691ebd8bd8..c15f309381b 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -17,7 +17,7 @@ __doctest_skip__ = ["pygmtlogo"] -def _create_logo( # noqa: PLR0915, PLR0912 +def _create_logo( # noqa: PLR0915 shape: Literal["circle", "hexagon"] = "circle", theme: Literal["light", "dark"] = "light", wordmark: Literal["none", "horizontal", "vertical"] = "none", @@ -49,25 +49,18 @@ def _create_logo( # noqa: PLR0915, PLR0912 # Define colors color_light = "white" color_dark = "gray20" - + # Blue, yellow, and red colors blue = "48/105/152" # Python blue yellow = "255/212/59" # Python yellow red = "238/86/52" # GMT red if not color: - blue = yellow = red = color_dark - if theme == "dark": - blue = yellow = red = color_light - + mono = color_dark if theme == "light" else color_light + blue = yellow = red = mono # Background and wordmark - match theme: - case "light": - color_bg = color_light - color_py = blue - color_gmt = color_dark - case "dark": - color_bg = color_dark - color_py = yellow - color_gmt = color_light + color_bg, color_py, color_gmt = { + "light": (color_light, blue, color_dark), + "dark": (color_dark, yellow, color_light), + }[theme] # Define shape match shape: From 7581ebf777796d8a0d727dadf7c862d72e10319a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 9 May 2026 21:27:51 +0800 Subject: [PATCH 06/10] Figure.pygmtlogo: Explicitly set the angle of diagonal compass lines for readability (#4630) --- pygmt/src/pygmtlogo.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index c15f309381b..15a706501b8 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -154,16 +154,19 @@ def _bg_arrow_coords(): def _compass_lines(): """Coordinates of compass lines.""" - sqrt2 = np.sqrt(2) / 2 - x1, x2, x3 = r0 * sqrt2, r3 * sqrt2, (r2 + (r3 - r4)) * sqrt2 + angle = np.deg2rad(45.0) # Angle of diagonal compass lines + sinx, cosx = np.sin(angle), np.cos(angle) + + x1, x2, x3 = r0 * sinx, r3 * sinx, (r2 + (r3 - r4)) * sinx + y1, y2, y3 = r0 * cosx, r3 * cosx, (r2 + (r3 - r4)) * cosx # Coordinates of vectors in the format of (x_start, y_start, x_end, y_end). return [ (-r0 * hex_factor, 0, -r3, 0), # left horizontal (r3, 0, r0 * hex_factor, 0), # right horizontal - (-x1, x1, -x2, x2), # upper left - (-x1, -x1, -x2, -x2), # lower left - (x1, x1, x3, x3), # upper right - (x1, -x1, x2, -x2), # lower right + (-x1, y1, -x2, y2), # upper left + (-x1, -y1, -x2, -y2), # lower left + (x1, y1, x3, y3), # upper right + (x1, -y1, x2, -y2), # lower right ] def _vline_coords(): From 5c7d48248a74d90dd88e61db241a47b7296d748d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 May 2026 18:24:50 +0800 Subject: [PATCH 07/10] Figure.pygmtlogo: Increase the gap around the vertical red line and arrow (#4635) --- pygmt/src/pygmtlogo.py | 20 +++++++++---------- .../test_pygmtlogo_circle_design.png.dvc | 4 ++-- .../test_pygmtlogo_circle_no_wordmark.png.dvc | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index 15a706501b8..bf94b2c4c78 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -139,14 +139,21 @@ def _letter_t_coords(): mask = np.abs(t_x) <= (thick_gap + r4) / 2 return {"x": t_x[mask], "y": t_y[mask]} + def _vline_coords(): + """ + Coordinates for the vertical line at the top. + """ + x0 = thick_gt / 2 + return {"x": [-x0, -x0, x0, x0], "y": [r0, r3, r3, r0]} + def _bg_arrow_coords(): """Coordinates for the background arrow.""" # x0, y0 is the same as in _letter_t_coords(). x0 = thick_gt / 2 y0 = 1.8 * x0 * np.sqrt(3) - # The background arrow is thick_comp wider than the letter T. - x1 = x0 + thick_comp / 2.0 # Half-width of the arrow tail - x2 = 2 * x0 + thick_comp / np.sqrt(3) # Half-width of the arrow head + # The background arrow 2*thick_gap wider than the letter T. + x1 = x0 + thick_gap # Half-width of the arrow tail + x2 = 2 * (x0 + thick_gap / np.sqrt(3)) # Half-width of the arrow head arrow_x = [-x1, -x1, -x2, -(x2 - 2 * x0), (x2 - 2 * x0), x2, x1, x1] arrow_y = [r0, -r0 + y0, -r0 + y0, -r0, -r0, -r0 + y0, -r0 + y0, r0] @@ -169,13 +176,6 @@ def _compass_lines(): (x1, -y1, x2, -y2), # lower right ] - def _vline_coords(): - """ - Coordinates for the vertical line at the top. - """ - x0 = thick_gt / 2 - return {"x": [-x0, -x0, x0, x0], "y": [r0, r3, r3, r0]} - fig = Figure() fig.basemap(region=region, projection=proj, perspective=perspective, frame="none") diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc index 7a81601eafe..8f3e5ef22e7 100644 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc @@ -1,5 +1,5 @@ outs: -- md5: 2d9fd4fdb1189514d374500d5f4add73 - size: 149683 +- md5: 459b74dee35adcb7f3519269ad49668d + size: 149831 hash: md5 path: test_pygmtlogo_circle_design.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc index 3530063c1f5..bf96a88e900 100644 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc @@ -1,5 +1,5 @@ outs: -- md5: dcb54b2c28e02c4fc83d38278b2700c6 - size: 31454 +- md5: 781ac55a32194d2818a1d96ab2d32727 + size: 31485 hash: md5 path: test_pygmtlogo_circle_no_wordmark.png From 71f66ddfb259b8d15cea5006b9ca47b9660038ac Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 12 May 2026 21:36:15 +0800 Subject: [PATCH 08/10] Figure.pygmtlogo: Set the region based on wordmark for easier design (#4634) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/src/pygmtlogo.py | 18 ++++++++++++------ .../test_pygmtlogo_circle_design.png.dvc | 5 ----- ..._pygmtlogo_circle_design_horizontal.png.dvc | 5 +++++ ...st_pygmtlogo_circle_design_vertical.png.dvc | 5 +++++ pygmt/tests/test_pygmtlogo.py | 7 ++++--- 5 files changed, 26 insertions(+), 14 deletions(-) delete mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc create mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc create mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index bf94b2c4c78..ec1bb7d9250 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -32,8 +32,13 @@ def _create_logo( # noqa: PLR0915 # Helpful definitions size = 4 - region = [-size, size] * 2 proj = "x1c" + region = { + "horizontal": [-size, size * 8.0, -size, size], + "vertical": [-size, size, -size * 1.75, size], + "none": [-size, size, -size, size], + }[wordmark] + # Rotation around z-axis by 30 degrees counter-clockwise placed in the center. perspective = "30+w0/0" @@ -77,7 +82,7 @@ def _create_logo( # noqa: PLR0915 font = "AvantGarde-Book" match wordmark: case "vertical": - args_text_wm = {"x": 0, "y": -4.5, "justify": "CT", "font": f"2.5c,{font}"} + args_text_wm = {"x": 0, "y": -4.5, "justify": "CT", "font": f"2.4c,{font}"} case "horizontal": args_text_wm = {"x": 4.5, "y": 0.8, "justify": "LM", "font": f"8c,{font}"} @@ -224,8 +229,7 @@ def _compass_lines(): # Add wordmark "PyGMT" if wordmark != "none": - text_wm = f"@;{color_py};Py@;;@;{color_gmt};GMT@;;" - fig.text(text=text_wm, no_clip=True, **args_text_wm) + fig.text(text=f"@;{color_py};Py@;;@;{color_gmt};GMT@;;", **args_text_wm) # Helpful for implementing the logo; not included in the logo if debug: @@ -240,8 +244,10 @@ def _compass_lines(): pen = "0.3p,gray30,2_2" fig.plot(x=0, y=0, style=f"c{2 * (r2 + (r3 - r4))}c", pen=pen) # Lines for letter M - fig.hlines(y=[r4, r5], xmin=-3, pen=pen, perspective=True) - fig.vlines(x=[r4, (thick_gap + r4) / 2], ymax=3, pen=pen, perspective=True) + size_s = 0.9 * size + fig.hlines(y=[r4, r5], xmin=-size_s, xmax=size_s, pen=pen, perspective=True) + m_mid = (thick_gap + r4) / 2 + fig.vlines(x=[r4, m_mid], ymin=-size_s, ymax=size_s, pen=pen, perspective=True) if figname: fig.savefig(fname=figname) diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc deleted file mode 100644 index 8f3e5ef22e7..00000000000 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_design.png.dvc +++ /dev/null @@ -1,5 +0,0 @@ -outs: -- md5: 459b74dee35adcb7f3519269ad49668d - size: 149831 - hash: md5 - path: test_pygmtlogo_circle_design.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc new file mode 100644 index 00000000000..3648ff8045d --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: de3f281a09815faff7fed339c1635bc5 + size: 336254 + hash: md5 + path: test_pygmtlogo_circle_design_horizontal.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc new file mode 100644 index 00000000000..dc0b53a0cd7 --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: dd09fa24c575eabac7659dc49f313f5f + size: 173671 + hash: md5 + path: test_pygmtlogo_circle_design_vertical.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index e4d6f4aff5e..71078f95548 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -9,15 +9,16 @@ @pytest.mark.mpl_image_compare(savefig_kwargs={"dpi": 600}) -def test_pygmtlogo_circle_design(): +@pytest.mark.parametrize("wordmark", ["horizontal", "vertical"]) +def test_pygmtlogo_circle_design(wordmark): """ - Test the design details of the PyGMT circular logo. + Test the design details of the PyGMT circular logo, with a wordmark. This is a regression test to ensure that the design of the logo does not change unintentionally. The debugging lines (gridlines and circles) are helpful for implementing the logo, but they are not included in the final logo design. """ - fig = _create_logo(debug=True) + fig = _create_logo(debug=True, wordmark=wordmark) return fig From 1ea6e8e8d6929b974b8971ce9832d732eb8badb2 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 14 May 2026 07:14:43 +0800 Subject: [PATCH 09/10] Figure.pygmtlogo: Remove the additional black outline for the black-and-white dark-theme logo (#4638) --- pygmt/src/pygmtlogo.py | 11 ------ .../test_pygmtlogo_circle_no_wordmark.png.dvc | 4 +-- pygmt/tests/test_pygmtlogo.py | 35 +++++++++---------- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/pygmt/src/pygmtlogo.py b/pygmt/src/pygmtlogo.py index ec1bb7d9250..93ad9cbcc3b 100644 --- a/pygmt/src/pygmtlogo.py +++ b/pygmt/src/pygmtlogo.py @@ -216,17 +216,6 @@ def _compass_lines(): # Upper vertical line fig.plot(data=_vline_coords(), fill=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}{size_shape + thick_shape}c", - pen=f"{thick_comp / 2.0}c,{color_bg}", - perspective=True, - no_clip=True, - ) - # Add wordmark "PyGMT" if wordmark != "none": fig.text(text=f"@;{color_py};Py@;;@;{color_gmt};GMT@;;", **args_text_wm) diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc index bf96a88e900..ad21905884e 100644 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc +++ b/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc @@ -1,5 +1,5 @@ outs: -- md5: 781ac55a32194d2818a1d96ab2d32727 - size: 31485 +- md5: fdc90d2867bcbc096bcf5a9303d15ddf + size: 31962 hash: md5 path: test_pygmtlogo_circle_no_wordmark.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index 71078f95548..4db0dc05b84 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -4,7 +4,7 @@ import pytest from pygmt import Figure -from pygmt.params import Axis, Position +from pygmt.params import Axis, Frame, Position from pygmt.src.pygmtlogo import _create_logo @@ -29,23 +29,20 @@ def test_pygmtlogo_circle_no_wordmark(): and colored/black-and-white versions. """ fig = Figure() - fig.basemap(region=[-0.5, 5.0, -0.5, 5.0], projection="x1c", frame=Axis(grid=0.5)) - fig.pygmtlogo( - position=Position((1, 3.5), anchor="CM", cstype="mapcoords"), - theme="light", - ) - fig.pygmtlogo( - position=Position((3.5, 3.5), anchor="CM", cstype="mapcoords"), - theme="dark", - ) - fig.pygmtlogo( - position=Position((1, 1), anchor="CM", cstype="mapcoords"), - theme="light", - color=False, - ) - fig.pygmtlogo( - position=Position((3.5, 1), anchor="CM", cstype="mapcoords"), - theme="dark", - color=False, + fig.basemap( + region=[-0.5, 5.0, -0.5, 5.0], + projection="x1c", + frame=Frame(fill="gray", axis=Axis(grid=0.5)), ) + for (x, y), theme, color in [ + ((1.0, 3.5), "light", True), + ((3.5, 3.5), "dark", True), + ((1.0, 1.0), "light", False), + ((3.5, 1.0), "dark", False), + ]: + fig.pygmtlogo( + position=Position((x, y), anchor="CM", cstype="mapcoords"), + theme=theme, + color=color, + ) return fig From 4f09ba61d1fd89b390485e9f429529373af34850 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 14 May 2026 18:26:34 +0800 Subject: [PATCH 10/10] Figure.pygmtlogo: Parameterize existing tests (#4639) --- ...t_pygmtlogo_circle_design_horizontal.png.dvc | 5 ----- ...est_pygmtlogo_circle_design_vertical.png.dvc | 5 ----- ...t_pygmtlogo_design_circle-horizontal.png.dvc | 5 +++++ ...est_pygmtlogo_design_circle-vertical.png.dvc | 5 +++++ ...test_pygmtlogo_wordmark_none_circle.png.dvc} | 2 +- pygmt/tests/test_pygmtlogo.py | 17 ++++++++++------- 6 files changed, 21 insertions(+), 18 deletions(-) delete mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc delete mode 100644 pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc create mode 100644 pygmt/tests/baseline/test_pygmtlogo_design_circle-horizontal.png.dvc create mode 100644 pygmt/tests/baseline/test_pygmtlogo_design_circle-vertical.png.dvc rename pygmt/tests/baseline/{test_pygmtlogo_circle_no_wordmark.png.dvc => test_pygmtlogo_wordmark_none_circle.png.dvc} (60%) diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc deleted file mode 100644 index 3648ff8045d..00000000000 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_design_horizontal.png.dvc +++ /dev/null @@ -1,5 +0,0 @@ -outs: -- md5: de3f281a09815faff7fed339c1635bc5 - size: 336254 - hash: md5 - path: test_pygmtlogo_circle_design_horizontal.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc deleted file mode 100644 index dc0b53a0cd7..00000000000 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_design_vertical.png.dvc +++ /dev/null @@ -1,5 +0,0 @@ -outs: -- md5: dd09fa24c575eabac7659dc49f313f5f - size: 173671 - hash: md5 - path: test_pygmtlogo_circle_design_vertical.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_design_circle-horizontal.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_design_circle-horizontal.png.dvc new file mode 100644 index 00000000000..55cb442316c --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_design_circle-horizontal.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 8924c7d80afcc92df4e77e6856b553a4 + size: 336254 + hash: md5 + path: test_pygmtlogo_design_circle-horizontal.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_design_circle-vertical.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_design_circle-vertical.png.dvc new file mode 100644 index 00000000000..ec88138185f --- /dev/null +++ b/pygmt/tests/baseline/test_pygmtlogo_design_circle-vertical.png.dvc @@ -0,0 +1,5 @@ +outs: +- md5: 5ee82660f20bc8424f3051af4f9fb9ac + size: 173671 + hash: md5 + path: test_pygmtlogo_design_circle-vertical.png diff --git a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc b/pygmt/tests/baseline/test_pygmtlogo_wordmark_none_circle.png.dvc similarity index 60% rename from pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc rename to pygmt/tests/baseline/test_pygmtlogo_wordmark_none_circle.png.dvc index ad21905884e..eb9140b19c1 100644 --- a/pygmt/tests/baseline/test_pygmtlogo_circle_no_wordmark.png.dvc +++ b/pygmt/tests/baseline/test_pygmtlogo_wordmark_none_circle.png.dvc @@ -2,4 +2,4 @@ outs: - md5: fdc90d2867bcbc096bcf5a9303d15ddf size: 31962 hash: md5 - path: test_pygmtlogo_circle_no_wordmark.png + path: test_pygmtlogo_wordmark_none_circle.png diff --git a/pygmt/tests/test_pygmtlogo.py b/pygmt/tests/test_pygmtlogo.py index 4db0dc05b84..6280a6573b1 100644 --- a/pygmt/tests/test_pygmtlogo.py +++ b/pygmt/tests/test_pygmtlogo.py @@ -10,23 +10,25 @@ @pytest.mark.mpl_image_compare(savefig_kwargs={"dpi": 600}) @pytest.mark.parametrize("wordmark", ["horizontal", "vertical"]) -def test_pygmtlogo_circle_design(wordmark): +@pytest.mark.parametrize("shape", ["circle"]) +def test_pygmtlogo_design(shape, wordmark): """ - Test the design details of the PyGMT circular logo, with a wordmark. + Test the design details of the PyGMT logo with a wordmark. This is a regression test to ensure that the design of the logo does not change unintentionally. The debugging lines (gridlines and circles) are helpful for implementing the logo, but they are not included in the final logo design. """ - fig = _create_logo(debug=True, wordmark=wordmark) + fig = _create_logo(debug=True, shape=shape, wordmark=wordmark) return fig @pytest.mark.mpl_image_compare -def test_pygmtlogo_circle_no_wordmark(): +@pytest.mark.parametrize("shape", ["circle"]) +def test_pygmtlogo_wordmark_none(shape): """ - Test the PyGMT circular logo without the wordmark, including both light/dark themes, - and colored/black-and-white versions. + Test the PyGMT logo without the wordmark, including both light/dark themes, and + colored/black-and-white versions. """ fig = Figure() fig.basemap( @@ -41,8 +43,9 @@ def test_pygmtlogo_circle_no_wordmark(): ((3.5, 1.0), "dark", False), ]: fig.pygmtlogo( - position=Position((x, y), anchor="CM", cstype="mapcoords"), + position=Position((x, y), anchor="MC", cstype="mapcoords"), theme=theme, color=color, + shape=shape, ) return fig