From f512de6b9493757f3a9c873f7459244185135791 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Fri, 8 Nov 2024 19:35:40 +0800
Subject: [PATCH 01/12] Initial design of Figure.scatter

---
 pygmt/figure.py       |  1 +
 pygmt/src/__init__.py |  1 +
 pygmt/src/scatter.py  | 48 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+)
 create mode 100644 pygmt/src/scatter.py

diff --git a/pygmt/figure.py b/pygmt/figure.py
index 4163ab52eb1..93ec4c5385f 100644
--- a/pygmt/figure.py
+++ b/pygmt/figure.py
@@ -418,6 +418,7 @@ def _repr_html_(self):
         plot3d,
         psconvert,
         rose,
+        scatter,
         set_panel,
         shift_origin,
         solar,
diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py
index e4db7321963..aad5f67cd83 100644
--- a/pygmt/src/__init__.py
+++ b/pygmt/src/__init__.py
@@ -42,6 +42,7 @@
 from pygmt.src.project import project
 from pygmt.src.psconvert import psconvert
 from pygmt.src.rose import rose
+from pygmt.src.scatter import scatter
 from pygmt.src.select import select
 from pygmt.src.shift_origin import shift_origin
 from pygmt.src.solar import solar
diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
new file mode 100644
index 00000000000..9d3fa631e64
--- /dev/null
+++ b/pygmt/src/scatter.py
@@ -0,0 +1,48 @@
+"""
+scatter - Scatter plot.
+"""
+
+from pygmt.helpers import is_nonstr_iter
+
+
+def _parse_symbol_size(symbol, size):
+    """
+    Parse the symbol and size into a style string.
+
+    >>> _parse_symbol_size("c", 0.2)
+    'c0.2'
+    >>> _parse_symbol_size("c", "0.2c")
+    'c0.2c'
+    >>> _parse_symbol_size("c", [0.2, 0.3])
+    'c'
+    >>> _parse_symbol_size(["c", "t"], "0.2c")
+    '0.2c'
+    >>> _parse_symbol_size(["c", "t"], [0.2, 0.3])
+    ''
+    """
+    return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg))
+
+
+def scatter(self, x, y, symbol, size, **kwargs):
+    """
+    Plot scatter points on a map.
+
+    Parameters
+    ----------
+    x, y : array-like
+        The coordinates of the points to plot.
+    symbol : str or sequence
+        The symbol to use for the points.
+    size : float or sequence
+        The size of the points.
+    """
+    kwargs = self._preprocess(**kwargs)
+
+    # style is a combination of symbol and size, but only if they are string-like
+    style = _parse_symbol_size(symbol, size)
+    if not is_nonstr_iter(symbol):
+        symbol = None
+    if not is_nonstr_iter(size):
+        size = None
+
+    self.plot(x=x, y=y, style=style, symbol=symbol, size=size, **kwargs)

From 8bd2777d7343716fa09bc1bb3f9230291bbe36f9 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 13:05:28 +0800
Subject: [PATCH 02/12] Improve docstrings for symbol

---
 pygmt/src/scatter.py | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 9d3fa631e64..ec155041c88 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -2,6 +2,8 @@
 scatter - Scatter plot.
 """
 
+from collections.abc import Sequence
+
 from pygmt.helpers import is_nonstr_iter
 
 
@@ -23,7 +25,14 @@ def _parse_symbol_size(symbol, size):
     return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg))
 
 
-def scatter(self, x, y, symbol, size, **kwargs):
+def scatter(
+    self,
+    x,
+    y,
+    symbol: str | Sequence[str],
+    size: float | str | Sequence[float, str],
+    **kwargs,
+):
     """
     Plot scatter points on a map.
 
@@ -31,9 +40,25 @@ def scatter(self, x, y, symbol, size, **kwargs):
     ----------
     x, y : array-like
         The coordinates of the points to plot.
-    symbol : str or sequence
-        The symbol to use for the points.
-    size : float or sequence
+    symbol
+        Symbol to use for the points. Can be a single symbol or a sequence of symbols.
+        Valid symbols are:
+
+        - ``-``: X-dash (-)
+        - ``+``: Plus
+        - ``a``: Star
+        - ``c``: Circle
+        - ``d``: Diamond
+        - ``g``: Octagon
+        - ``h``: Hexagon
+        - ``i``: Inverted triangle
+        - ``n``: Pentagon
+        - ``p``: Point
+        - ``s``: Square
+        - ``t``: Triangle
+        - ``x``: Cross
+        - ``y``: Y-dash (|)
+    size
         The size of the points.
     """
     kwargs = self._preprocess(**kwargs)

From 96c7ed117e1b309c4b9d8c0c664281397396f9df Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 18:04:59 +0800
Subject: [PATCH 03/12] Fix a typo

---
 pygmt/src/scatter.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index ec155041c88..53bb795b86f 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -30,7 +30,7 @@ def scatter(
     x,
     y,
     symbol: str | Sequence[str],
-    size: float | str | Sequence[float, str],
+    size: float | str | Sequence[float | str],
     **kwargs,
 ):
     """

From 5ca92f7a04a7f4bb77a94a805871acf4779aa6a3 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 18:13:18 +0800
Subject: [PATCH 04/12] Add more parameters

---
 pygmt/src/scatter.py | 38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 53bb795b86f..219d4c0947a 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -25,17 +25,25 @@ def _parse_symbol_size(symbol, size):
     return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg))
 
 
-def scatter(
+def scatter(  # noqa: PLR0913
     self,
     x,
     y,
     symbol: str | Sequence[str],
     size: float | str | Sequence[float | str],
-    **kwargs,
+    fill: str | Sequence[float] | None = None,
+    intensity: float | Sequence[float] | None = None,
+    transparency: float | Sequence[float] | None = None,
+    cmap: str | None = None,
+    no_clip: bool = False,
+    perspective=None,
 ):
     """
     Plot scatter points on a map.
 
+    This function can plot points with different symbols, sizes, and colors.
+
+
     Parameters
     ----------
     x, y : array-like
@@ -60,8 +68,18 @@ def scatter(
         - ``y``: Y-dash (|)
     size
         The size of the points.
+    intensity
+        The intensity of the points.
+    transparency
+        The transparency of the points.
+    cmap
+        The colormap to use for the points.
+    no_clip
+        If True, do not clip the points to the viewport.
+    perspective
+        The perspective of the points.
     """
-    kwargs = self._preprocess(**kwargs)
+    self._preprocess()
 
     # style is a combination of symbol and size, but only if they are string-like
     style = _parse_symbol_size(symbol, size)
@@ -70,4 +88,16 @@ def scatter(
     if not is_nonstr_iter(size):
         size = None
 
-    self.plot(x=x, y=y, style=style, symbol=symbol, size=size, **kwargs)
+    self.plot(
+        x=x,
+        y=y,
+        style=style,
+        symbol=symbol,
+        size=size,
+        fill=fill,
+        intensity=intensity,
+        transparency=transparency,
+        cmap=cmap,
+        no_clip=no_clip,
+        perspective=perspective,
+    )

From 20254f6d47bcc4f70d15c0dcf06d323360aa9011 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 18:15:19 +0800
Subject: [PATCH 05/12] Add to doc API page

---
 doc/api/index.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/api/index.rst b/doc/api/index.rst
index 01fac7d7a89..704938a483e 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -48,6 +48,7 @@ Plotting tabular data
     Figure.plot
     Figure.plot3d
     Figure.rose
+    Figure.scatter
     Figure.ternary
     Figure.velo
     Figure.wiggle

From a83319423a77d85507ebe385eaa2c84cafbf3ed3 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 19:16:28 +0800
Subject: [PATCH 06/12] Improve docstrings

---
 pygmt/src/scatter.py | 44 +++++++++++++++++++++++++++++++-------------
 1 file changed, 31 insertions(+), 13 deletions(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 219d4c0947a..465e02968cf 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -4,7 +4,7 @@
 
 from collections.abc import Sequence
 
-from pygmt.helpers import is_nonstr_iter
+from pygmt.helpers import fmt_docstring, is_nonstr_iter
 
 
 def _parse_symbol_size(symbol, size):
@@ -25,6 +25,7 @@ def _parse_symbol_size(symbol, size):
     return "".join(f"{arg}" for arg in [symbol, size] if not is_nonstr_iter(arg))
 
 
+@fmt_docstring
 def scatter(  # noqa: PLR0913
     self,
     x,
@@ -39,17 +40,26 @@ def scatter(  # noqa: PLR0913
     perspective=None,
 ):
     """
-    Plot scatter points on a map.
+    Plot scatter points.
 
-    This function can plot points with different symbols, sizes, and colors.
+    It can plot data points with constant or varying symbols, sizes, colors, and
+    transparencies, and intensities.
 
+    The parameters ``symbol``, ``size``, ``fill``, ``intensity``, and
+    ``transparency`` can be a single scalar value or a sequence of values with the
+    same length as the number of data points. If a single value is given, it is
+    used for all data points. If a sequence is given, different values are used
+    for different data points.
 
     Parameters
     ----------
-    x, y : array-like
-        The coordinates of the points to plot.
+    x, y
+        The data coordinates.
     symbol
-        Symbol to use for the points. Can be a single symbol or a sequence of symbols.
+        The symbol(s) to use. It can be a single symbol string to use the same
+        symbol for all data points or a sequence of symbol strings to have
+        different symbols for different data points.
+
         Valid symbols are:
 
         - ``-``: X-dash (-)
@@ -67,17 +77,25 @@ def scatter(  # noqa: PLR0913
         - ``x``: Cross
         - ``y``: Y-dash (|)
     size
-        The size of the points.
+        The size(s) of the points.
     intensity
-        The intensity of the points.
+        The intensity(ies) of the points.
     transparency
-        The transparency of the points.
+        The transparency(ies) of the points.
     cmap
-        The colormap to use for the points.
+        The colormap to map scalar values in ``fill`` to colors. In this case,
+        ``fill`` must be a sequence of numbers.
     no_clip
-        If True, do not clip the points to the viewport.
-    perspective
-        The perspective of the points.
+        If True, do not clip the points that fall outside the frame boundaries.
+    {perspective}
+
+    Examples
+    --------
+    >>> import pygmt
+    >>> fig = pygmt.Figure()
+    >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True)
+    >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.5)
+    >>> fig.show()
     """
     self._preprocess()
 

From 8d7f7449a320f970a1badda8c59927bada886f42 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 11 Nov 2024 19:26:25 +0800
Subject: [PATCH 07/12] Add parameter for pen

---
 pygmt/src/scatter.py | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 465e02968cf..e5eb00b71d3 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -36,6 +36,7 @@ def scatter(  # noqa: PLR0913
     intensity: float | Sequence[float] | None = None,
     transparency: float | Sequence[float] | None = None,
     cmap: str | None = None,
+    pen: str | float | None = None,
     no_clip: bool = False,
     perspective=None,
 ):
@@ -85,16 +86,35 @@ def scatter(  # noqa: PLR0913
     cmap
         The colormap to map scalar values in ``fill`` to colors. In this case,
         ``fill`` must be a sequence of numbers.
+    pen
+        The pen property of the symbol outline.
     no_clip
         If True, do not clip the points that fall outside the frame boundaries.
     {perspective}
 
     Examples
     --------
+
+    Plot three points with the same symbol and size.
+
     >>> import pygmt
     >>> fig = pygmt.Figure()
     >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True)
-    >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.5)
+    >>> fig.scatter(x=[0, 1, 2], y=[0, 1, 2], symbol="c", size=0.3, fill="red")
+    >>> fig.show()
+
+    Plot three points with different sizes and transparencies.
+
+    >>> fig = pygmt.Figure()
+    >>> fig.basemap(region=[0, 3, 0, 3], projection="X10c/5c", frame=True)
+    >>> fig.scatter(
+    ...     x=[0, 1, 2],
+    ...     y=[0, 1, 2],
+    ...     symbol="c",
+    ...     size=[0.5, 0.3, 0.2],
+    ...     fill="blue",
+    ...     transparency=[50, 70, 90],
+    ... )
     >>> fig.show()
     """
     self._preprocess()
@@ -116,6 +136,7 @@ def scatter(  # noqa: PLR0913
         intensity=intensity,
         transparency=transparency,
         cmap=cmap,
+        pen=pen,
         no_clip=no_clip,
         perspective=perspective,
     )

From 84c3c6118fdc5c020340c9736cf5a0bc67729e9b Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Wed, 18 Dec 2024 11:27:30 +0800
Subject: [PATCH 08/12] Improve Figure.scatter

---
 pygmt/src/scatter.py | 54 ++++++++++++++++++++++----------------------
 1 file changed, 27 insertions(+), 27 deletions(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index e5eb00b71d3..25294685a6d 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -1,5 +1,5 @@
 """
-scatter - Scatter plot.
+scatter - Plot scatter points.
 """
 
 from collections.abc import Sequence
@@ -7,10 +7,14 @@
 from pygmt.helpers import fmt_docstring, is_nonstr_iter
 
 
-def _parse_symbol_size(symbol, size):
+def _parse_symbol_size(
+    symbol: str | Sequence[str], size: float | str | Sequence[float | str]
+) -> str:
     """
-    Parse the symbol and size into a style string.
+    Parse the 'symbol' and 'size' parameter into GMT's style string.
 
+    Examples
+    --------
     >>> _parse_symbol_size("c", 0.2)
     'c0.2'
     >>> _parse_symbol_size("c", "0.2c")
@@ -43,25 +47,19 @@ def scatter(  # noqa: PLR0913
     """
     Plot scatter points.
 
-    It can plot data points with constant or varying symbols, sizes, colors, and
-    transparencies, and intensities.
-
-    The parameters ``symbol``, ``size``, ``fill``, ``intensity``, and
-    ``transparency`` can be a single scalar value or a sequence of values with the
-    same length as the number of data points. If a single value is given, it is
-    used for all data points. If a sequence is given, different values are used
-    for different data points.
+    It can plot data points with constant or varying symbols, sizes, colors,
+    transparencies, and intensities. The parameters ``symbol``, ``size``, ``fill``,
+    ``intensity``, and ``transparency`` can be a single scalar value or a sequence of
+    values with the same length as the number of data points. If a single value is
+    given, it is used for all data points. If a sequence is given, different values are
+    used for different data points.
 
     Parameters
     ----------
     x, y
         The data coordinates.
     symbol
-        The symbol(s) to use. It can be a single symbol string to use the same
-        symbol for all data points or a sequence of symbol strings to have
-        different symbols for different data points.
-
-        Valid symbols are:
+        The symbol(s) to use. Valid symbols are:
 
         - ``-``: X-dash (-)
         - ``+``: Plus
@@ -79,13 +77,16 @@ def scatter(  # noqa: PLR0913
         - ``y``: Y-dash (|)
     size
         The size(s) of the points.
+    fill
+        Set color or pattern for filling symbols [Default is no fill]. If ``cmap`` is
+        used, ``fill`` must be a sequence of values.
     intensity
         The intensity(ies) of the points.
     transparency
         The transparency(ies) of the points.
     cmap
-        The colormap to map scalar values in ``fill`` to colors. In this case,
-        ``fill`` must be a sequence of numbers.
+        The colormap to map scalar values in ``fill`` to colors. In this case, ``fill``
+        must be a sequence of values.
     pen
         The pen property of the symbol outline.
     no_clip
@@ -119,19 +120,18 @@ def scatter(  # noqa: PLR0913
     """
     self._preprocess()
 
-    # style is a combination of symbol and size, but only if they are string-like
-    style = _parse_symbol_size(symbol, size)
-    if not is_nonstr_iter(symbol):
-        symbol = None
-    if not is_nonstr_iter(size):
-        size = None
+    # Create GMT plot's "style" from "symbol" and "size".
+    _style = _parse_symbol_size(symbol, size)
+    # Set "symbol" and "size" to None if they're not sequences.
+    _symbol = symbol if is_nonstr_iter(symbol) else None
+    _size = size if is_nonstr_iter(size) else None
 
     self.plot(
         x=x,
         y=y,
-        style=style,
-        symbol=symbol,
-        size=size,
+        style=_style,
+        symbol=_symbol,
+        size=_size,
         fill=fill,
         intensity=intensity,
         transparency=transparency,

From ce3f03ec02feaf78a6b70c387af25314dc8d3a93 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 19 Dec 2024 20:40:14 +0800
Subject: [PATCH 09/12] Need to set 'cmap' if 'fill' is a sequence

---
 pygmt/src/scatter.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 25294685a6d..308927e9bfd 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -126,6 +126,10 @@ def scatter(  # noqa: PLR0913
     _symbol = symbol if is_nonstr_iter(symbol) else None
     _size = size if is_nonstr_iter(size) else None
 
+    # Set "cmap" to True if "fill" is a sequence of values.
+    if is_nonstr_iter(fill) and cmap is None:
+        cmap = True
+
     self.plot(
         x=x,
         y=y,

From 66cb558f3e042dd5b5b68581974b250a9b911416 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 19 Dec 2024 20:49:49 +0800
Subject: [PATCH 10/12] Remove point as a valid symbol

---
 pygmt/src/scatter.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 308927e9bfd..8c8d30967a4 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -70,7 +70,6 @@ def scatter(  # noqa: PLR0913
         - ``h``: Hexagon
         - ``i``: Inverted triangle
         - ``n``: Pentagon
-        - ``p``: Point
         - ``s``: Square
         - ``t``: Triangle
         - ``x``: Cross

From 3ec751c53110d454ff98bde3d6a5e93d68a8c69a Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 19 Dec 2024 21:12:24 +0800
Subject: [PATCH 11/12] Improve docstrings for cmap

---
 pygmt/src/scatter.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pygmt/src/scatter.py b/pygmt/src/scatter.py
index 8c8d30967a4..967ebd2a8dd 100644
--- a/pygmt/src/scatter.py
+++ b/pygmt/src/scatter.py
@@ -39,7 +39,7 @@ def scatter(  # noqa: PLR0913
     fill: str | Sequence[float] | None = None,
     intensity: float | Sequence[float] | None = None,
     transparency: float | Sequence[float] | None = None,
-    cmap: str | None = None,
+    cmap: str | bool | None = None,
     pen: str | float | None = None,
     no_clip: bool = False,
     perspective=None,
@@ -77,8 +77,8 @@ def scatter(  # noqa: PLR0913
     size
         The size(s) of the points.
     fill
-        Set color or pattern for filling symbols [Default is no fill]. If ``cmap`` is
-        used, ``fill`` must be a sequence of values.
+        Set color or pattern for filling symbols [Default is no fill]. If a sequence of
+        values is given, ``cmap`` must be specified.
     intensity
         The intensity(ies) of the points.
     transparency

From af90220a0c7aae32944e98859ad1c081077b2686 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 19 Dec 2024 21:12:44 +0800
Subject: [PATCH 12/12] Add tests for Figure.scatter

---
 pygmt/tests/baseline/test_scatter.png.dvc     |   5 +
 .../tests/baseline/test_scatter_fills.png.dvc |   5 +
 .../baseline/test_scatter_intensity.png.dvc   |   5 +
 .../tests/baseline/test_scatter_sizes.png.dvc |   5 +
 .../baseline/test_scatter_sizes_fills.png.dvc |   5 +
 ...scatter_sizes_fills_transparencies.png.dvc |   5 +
 ...zes_fills_transparencies_intensity.png.dvc |   5 +
 .../baseline/test_scatter_symbols.png.dvc     |   5 +
 .../test_scatter_symbols_sizes.png.dvc        |   5 +
 ...zes_fills_transparencies_intensity.png.dvc |   5 +
 .../test_scatter_transparencies.png.dvc       |   5 +
 .../test_scatter_valid_symbols.png.dvc        |   5 +
 pygmt/tests/test_scatter.py                   | 247 ++++++++++++++++++
 13 files changed, 307 insertions(+)
 create mode 100644 pygmt/tests/baseline/test_scatter.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_fills.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_intensity.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_sizes.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_symbols.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_transparencies.png.dvc
 create mode 100644 pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc
 create mode 100644 pygmt/tests/test_scatter.py

diff --git a/pygmt/tests/baseline/test_scatter.png.dvc b/pygmt/tests/baseline/test_scatter.png.dvc
new file mode 100644
index 00000000000..84acf08cf75
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 5705688b5f45ec842980b94bec239b02
+  size: 20703
+  hash: md5
+  path: test_scatter.png
diff --git a/pygmt/tests/baseline/test_scatter_fills.png.dvc b/pygmt/tests/baseline/test_scatter_fills.png.dvc
new file mode 100644
index 00000000000..edc28e369db
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_fills.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: f4bc6e6818d9889f6c729993dbfa8cfe
+  size: 22012
+  hash: md5
+  path: test_scatter_fills.png
diff --git a/pygmt/tests/baseline/test_scatter_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_intensity.png.dvc
new file mode 100644
index 00000000000..e28d11f0119
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_intensity.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: ff2b09d8983b015ea7229c6def8ef7de
+  size: 21670
+  hash: md5
+  path: test_scatter_intensity.png
diff --git a/pygmt/tests/baseline/test_scatter_sizes.png.dvc b/pygmt/tests/baseline/test_scatter_sizes.png.dvc
new file mode 100644
index 00000000000..68b4f0c9a75
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_sizes.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 4b85b972171fa9a5cfcc20fab7e81fb5
+  size: 22315
+  hash: md5
+  path: test_scatter_sizes.png
diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc
new file mode 100644
index 00000000000..d759a6c5aeb
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_sizes_fills.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 457480111a3d08e16aca82e8464809db
+  size: 22049
+  hash: md5
+  path: test_scatter_sizes_fills.png
diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc
new file mode 100644
index 00000000000..1c704cc029a
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 2b85221c5c451cefeb0cd81e033724b2
+  size: 21152
+  hash: md5
+  path: test_scatter_sizes_fills_transparencies.png
diff --git a/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc
new file mode 100644
index 00000000000..086ed902e84
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_sizes_fills_transparencies_intensity.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: f0282431c7ef8d95c870e1c3b6bcdfbd
+  size: 21231
+  hash: md5
+  path: test_scatter_sizes_fills_transparencies_intensity.png
diff --git a/pygmt/tests/baseline/test_scatter_symbols.png.dvc b/pygmt/tests/baseline/test_scatter_symbols.png.dvc
new file mode 100644
index 00000000000..18ad6449807
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_symbols.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 4f5f9fc44bc8f5f32de388bc75a2d474
+  size: 20479
+  hash: md5
+  path: test_scatter_symbols.png
diff --git a/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc b/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc
new file mode 100644
index 00000000000..eafe78a736a
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_symbols_sizes.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 8d23bb9dd39f1b1151412f8a43f6c12c
+  size: 21815
+  hash: md5
+  path: test_scatter_symbols_sizes.png
diff --git a/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc b/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc
new file mode 100644
index 00000000000..3afffde12ac
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_symbols_sizes_fills_transparencies_intensity.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 488eec9d3ef156993a82cc2a66125a67
+  size: 20879
+  hash: md5
+  path: test_scatter_symbols_sizes_fills_transparencies_intensity.png
diff --git a/pygmt/tests/baseline/test_scatter_transparencies.png.dvc b/pygmt/tests/baseline/test_scatter_transparencies.png.dvc
new file mode 100644
index 00000000000..8f1dc493dcf
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_transparencies.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 4943894ddcff5d0f486246e106839158
+  size: 20679
+  hash: md5
+  path: test_scatter_transparencies.png
diff --git a/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc b/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc
new file mode 100644
index 00000000000..e7fb0a73dc0
--- /dev/null
+++ b/pygmt/tests/baseline/test_scatter_valid_symbols.png.dvc
@@ -0,0 +1,5 @@
+outs:
+- md5: 6d4e6acdd44006be6e384f425c302932
+  size: 24570
+  hash: md5
+  path: test_scatter_valid_symbols.png
diff --git a/pygmt/tests/test_scatter.py b/pygmt/tests/test_scatter.py
new file mode 100644
index 00000000000..7305b09d532
--- /dev/null
+++ b/pygmt/tests/test_scatter.py
@@ -0,0 +1,247 @@
+"""
+Test Figure.scatter.
+"""
+
+import numpy as np
+import pytest
+from pygmt import Figure, makecpt
+
+
+#
+#  Fixtures that are used in tests.
+#
+@pytest.fixture(scope="module", name="region")
+def fixture_region():
+    """
+    The region of sample data.
+    """
+    return [0, 5, 5, 10]
+
+
+@pytest.fixture(scope="module", name="x")
+def fixture_x():
+    """
+    The x coordinates of sample data.
+    """
+    return [1, 2, 3, 4]
+
+
+@pytest.fixture(scope="module", name="y")
+def fixture_y():
+    """
+    The y coordinates of sample data.
+    """
+    return [6, 7, 8, 9]
+
+
+@pytest.fixture(scope="module", name="size")
+def fixture_size():
+    """
+    The size of sample data.
+    """
+    return [0.2, 0.4, 0.6, 0.8]
+
+
+@pytest.fixture(scope="module", name="symbol")
+def fixture_symbol():
+    """
+    The symbol of sample data.
+    """
+    return ["a", "c", "i", "t"]
+
+
+@pytest.fixture(scope="module", name="fill")
+def fixture_fill():
+    """
+    The z value of sample data for fill.
+    """
+    return [1, 2, 3, 4]
+
+
+@pytest.fixture(scope="module", name="transparency")
+def fixture_transparency():
+    """
+    The transparency of sample data.
+    """
+    return [20, 40, 60, 80]
+
+
+@pytest.fixture(scope="module", name="intensity")
+def fixture_intensity():
+    """
+    The intensity of sample data.
+    """
+    return [-0.8, -0.3, 0.3, 0.8]
+
+
+#
+# Tests for the simplest scatter plot with constant size and symbol.
+#
+@pytest.mark.mpl_image_compare
+def test_scatter(region, x, y):
+    """
+    Test the simplest scatter plot with constant size and symbol.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    fig.scatter(x=x, y=y, symbol="c", size=0.2)
+    return fig
+
+
+#
+# Tests for scatter plots with one parameter given as a sequence.
+#
+@pytest.mark.mpl_image_compare
+def test_scatter_sizes(region, x, y, size):
+    """
+    Test the scatter plot with different sizes.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    fig.scatter(x=x, y=y, symbol="c", size=size)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_symbols(region, x, y, symbol):
+    """
+    Test the scatter plot with different symbols.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    fig.scatter(x=x, y=y, symbol=symbol, size=0.2)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_fills(region, x, y, fill):
+    """
+    Test the scatter plot with different colors.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[0, 5])
+    fig.scatter(x=x, y=y, symbol="c", size=0.5, fill=fill)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_transparencies(region, x, y, transparency):
+    """
+    Test the scatter plot with different transparency.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[1, 4])
+    fig.scatter(x=x, y=y, symbol="c", size=0.5, fill="red", transparency=transparency)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_intensity(region, x, y, intensity):
+    """
+    Test the scatter plot with different intensity.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    fig.scatter(x=x, y=y, symbol="c", size=0.5, fill="red", intensity=intensity)
+    return fig
+
+
+#
+# Tests for scatter plots with multiple parameters given as sequences.
+#
+@pytest.mark.mpl_image_compare
+def test_scatter_symbols_sizes(region, x, y, symbol, size):
+    """
+    Test the scatter plot with different symbols and sizes.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    fig.scatter(x=x, y=y, symbol=symbol, size=size)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_sizes_fills(region, x, y, size, fill):
+    """
+    Test the scatter plot with different sizes and colors.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[0, 5])
+    fig.scatter(x=x, y=y, symbol="c", size=size, fill=fill)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_sizes_fills_transparencies(region, x, y, size, fill, transparency):
+    """
+    Test the scatter plot with different sizes and colors.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[0, 5])
+    fig.scatter(x=x, y=y, symbol="c", size=size, fill=fill, transparency=transparency)
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_sizes_fills_transparencies_intensity(
+    region, x, y, size, fill, transparency, intensity
+):
+    """
+    Test the scatter plot with different sizes and colors.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[0, 5])
+    fig.scatter(
+        x=x,
+        y=y,
+        symbol="c",
+        size=size,
+        fill=fill,
+        transparency=transparency,
+        intensity=intensity,
+    )
+    return fig
+
+
+@pytest.mark.mpl_image_compare
+def test_scatter_symbols_sizes_fills_transparencies_intensity(
+    region, x, y, symbol, size, fill, transparency, intensity
+):
+    """
+    Test the scatter plot with different sizes and colors.
+    """
+    fig = Figure()
+    fig.basemap(region=region, frame=True)
+    makecpt(cmap="viridis", series=[0, 5])
+    fig.scatter(
+        x=x,
+        y=y,
+        symbol=symbol,
+        size=size,
+        fill=fill,
+        transparency=transparency,
+        intensity=intensity,
+    )
+    return fig
+
+
+#
+# Other tests for scatter plots.
+#
+@pytest.mark.mpl_image_compare
+def test_scatter_valid_symbols():
+    """
+    Test the scatter plot with data.
+    """
+    symbols = ["-", "+", "a", "c", "d", "g", "h", "i", "n", "s", "t", "x", "y"]
+    x = np.arange(len(symbols))
+    y = [1.0] * len(symbols)
+    fig = Figure()
+    fig.basemap(region=[-1, len(symbols), 0, 2], frame=True)
+    fig.scatter(x=x, y=y, symbol=symbols, size=0.5, pen="1p,black")
+    return fig