diff --git a/doc/api/index.rst b/doc/api/index.rst
index 09e822bc..0598fd10 100644
--- a/doc/api/index.rst
+++ b/doc/api/index.rst
@@ -26,6 +26,7 @@ Plotting data and laying out the map:
     Figure.coast
     Figure.colorbar
     Figure.plot
+    Figure.plot3d
     Figure.contour
     Figure.grdcontour
     Figure.grdimage
diff --git a/examples/gallery/plot/scatter3d.py b/examples/gallery/plot/scatter3d.py
new file mode 100644
index 00000000..047b2225
--- /dev/null
+++ b/examples/gallery/plot/scatter3d.py
@@ -0,0 +1,53 @@
+"""
+3D Scatter plots
+----------------
+
+The :meth:`pygmt.Figure.plot3d` method can be used to plot symbols in 3D.
+In the example below, we show how the
+`Iris flower dataset <https://en.wikipedia.org/wiki/Iris_flower_data_set/>`__
+can be visualized using a perspective 3-dimensional plot. The ``region``
+argument has to include the :math:`x`, :math:`y`, :math:`z` axis limits in the
+form of (xmin, xmax, ymin, ymax, zmin, zmax), which can be done automatically
+using :meth:`pygmt.info`. To include the z-axis stick, set ``frame`` as a
+minimum to something like ``frame=["WsNeZ", "zaf"]``. Use ``perspective`` to
+control the azimuth and elevation angle of the view, and ``zscale`` to adjust
+the vertical exaggeration factor.
+"""
+
+import pandas as pd
+import pygmt
+
+# Load sample iris data, and convert 'species' column to categorical dtype
+df = pd.read_csv("https://github.com/mwaskom/seaborn-data/raw/master/iris.csv")
+df["species"] = df.species.astype(dtype="category")
+
+# Use pygmt.info to get region bounds (xmin, xmax, ymin, ymax, zmin, zmax)
+# The below example will return a numpy array like [0., 3., 4., 8., 1., 7.]
+region = pygmt.info(
+    table=df[["petal_width", "sepal_length", "petal_length"]],  # x, y, z columns
+    per_column=True,  # report output as a numpy array
+    spacing="1/2/0.5",  # rounds x, y and z intervals by 1, 2 and 0.5 respectively
+)
+
+# Make our 3D scatter plot, coloring each of the 3 species differently
+fig = pygmt.Figure()
+pygmt.makecpt(cmap="cubhelix", color_model="+c", series=(0, 3, 1))
+fig.plot3d(
+    x=df.petal_width,
+    y=df.sepal_length,
+    z=df.petal_length,
+    sizes=0.1 * df.sepal_width,  # Vary each symbol size according to a data column
+    color=df.species.cat.codes.astype(int),  # Points colored by categorical number code
+    cmap=True,  # Use colormap created by makecpt
+    region=region,  # (xmin, xmax, ymin, ymax, zmin, zmax)
+    frame=[
+        "WsNeZ3",  # z axis label positioned on 3rd corner
+        'xafg+l"Petal Width"',
+        'yafg+l"Sepal Length"',
+        'zafg+l"Petal Length"',
+    ],
+    style="uc",  # 3D cUbe, with size in centimeter units
+    perspective=[315, 25],  # Azimuth NorthWest (315°), at elevation 25°
+    zscale=1.5,  # Vertical exaggeration factor
+)
+fig.show()
diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py
index 37b938c7..f75f69da 100644
--- a/pygmt/base_plotting.py
+++ b/pygmt/base_plotting.py
@@ -816,6 +816,189 @@ class BasePlotting:
                 arg_str = " ".join([fname, build_arg_string(kwargs)])
                 lib.call_module("plot", arg_str)
 
+    @fmt_docstring
+    @use_alias(
+        A="straight_line",
+        B="frame",
+        C="cmap",
+        D="offset",
+        G="color",
+        I="intensity",
+        J="projection",
+        Jz="zscale",
+        JZ="zsize",
+        L="close",
+        N="no_clip",
+        Q="no_sort",
+        R="region",
+        S="style",
+        V="verbose",
+        W="pen",
+        X="xshift",
+        Y="yshift",
+        Z="zvalue",
+        i="columns",
+        l="label",
+        p="perspective",
+        t="transparency",
+    )
+    @kwargs_to_strings(R="sequence", i="sequence_comma", p="sequence")
+    def plot3d(
+        self, x=None, y=None, z=None, data=None, sizes=None, direction=None, **kwargs
+    ):
+        """
+        Plot lines, polygons, and symbols in 3-D
+
+        Takes a matrix, (x,y,z) triplets, or a file name as input and plots
+        lines, polygons, or symbols at those locations in 3-D.
+
+        Must provide either *data* or *x*, *y* and *z*.
+
+        If providing data through *x*, *y* and *z*, *color* can be a 1d array
+        that will be mapped to a colormap.
+
+        If a symbol is selected and no symbol size given, then plot3d will
+        interpret the fourth column of the input data as symbol size. Symbols
+        whose size is <= 0 are skipped. If no symbols are specified then the
+        symbol code (see *style* below) must be present as last column in the
+        input. If *style* is not used, a line connecting the data points will
+        be drawn instead. To explicitly close polygons, use *close*. Select a
+        fill with *color*. If *color* is set, *pen* will control whether the
+        polygon outline is drawn or not. If a symbol is selected, *color* and
+        *pen* determines the fill and outline/no outline, respectively.
+
+        Full option list at :gmt-docs:`plot3d.html`
+
+        {aliases}
+
+        Parameters
+        ----------
+        x/y/z : float or 1d arrays
+            The x, y, and z coordinates, or arrays of x, y and z coordinates of
+            the data points
+        data : str or 2d array
+            Either a data file name or a 2d numpy array with the tabular data.
+            Use option *columns* (i) to choose which columns are x, y, z,
+            color, and size, respectively.
+        sizes : 1d array
+            The sizes of the data points in units specified in *style* (S).
+            Only valid if using *x*, *y* and *z*.
+        direction : list of two 1d arrays
+            If plotting vectors (using ``style='V'`` or ``style='v'``), then
+            should be a list of two 1d arrays with the vector directions. These
+            can be angle and length, azimuth and length, or x and y components,
+            depending on the style options chosen.
+        {J}
+        zscale/zsize : float or str
+            Set z-axis scaling or z-axis size.
+        {R}
+        straight_line : bool or str
+            ``[m|p|x|y]``.
+            By default, geographic line segments are drawn as great circle
+            arcs. To draw them as straight lines, use *straight_line*.
+            Alternatively, add **m** to draw the line by first following a
+            meridian, then a parallel. Or append **p** to start following a
+            parallel, then a meridian. (This can be practical to draw a line
+            along parallels, for example). For Cartesian data, points are
+            simply connected, unless you append **x** or **y** to draw
+            stair-case curves that whose first move is along *x* or *y*,
+            respectively. **Note**: The **straight_line** option requires
+            constant *z*-coordinates.
+        {B}
+        {CPT}
+        offset : str
+            ``dx/dy[/dz]``.
+            Offset the plot symbol or line locations by the given amounts
+            *dx/dy*[*dz*] [Default is no offset].
+        {G}
+        intensity : float or bool
+            Provide an *intens* value (nominally in the -1 to +1 range) to
+            modulate the fill color by simulating illumination [None]. If
+            using ``intensity=True``, we will instead read *intens* from the
+            first data column after the symbol parameters (if given).
+        close : str
+            ``[+b|d|D][+xl|r|x0][+yl|r|y0][+ppen]``.
+            Force closed polygons. Full documentation is at
+            :gmt-docs:`plot3d.html#l`.
+        no_clip : bool or str
+            ``[c|r]``.
+            Do NOT clip symbols that fall outside map border [Default plots
+            points whose coordinates are strictly inside the map border only].
+            The option does not apply to lines and polygons which are always
+            clipped to the map region. For periodic (360-longitude) maps we
+            must plot all symbols twice in case they are clipped by the
+            repeating boundary. ``no_clip=True`` will turn off clipping and not
+            plot repeating symbols. Use ``no_clip="r"`` to turn off clipping
+            but retain the plotting of such repeating symbols, or use
+            ``no_clip="c"`` to retain clipping but turn off plotting of
+            repeating symbols.
+        no_sort : bool
+            Turn off the automatic sorting of items based on their distance
+            from the viewer. The default is to sort the items so that items in
+            the foreground are plotted after items in the background.
+        style : str
+            Plot symbols. Full documentation is at :gmt-docs:`plot3d.html#s`.
+        {U}
+        {V}
+        {W}
+        {XY}
+        zvalue : str
+            ``value|file``.
+            Instead of specifying a symbol or polygon fill and outline color
+            via **color** and **pen**, give both a *value* via **zvalue** and a
+            color lookup table via **cmap**.  Alternatively, give the name of a
+            *file* with one z-value (read from the last column) for each
+            polygon in the input data. To apply it to the fill color, use
+            ``color='+z'``. To apply it to the pen color, append **+z** to
+            **pen**.
+        label : str
+            Add a legend entry for the symbol or line being plotted.
+        {p}
+        {t}
+            *transparency* can also be a 1d array to set varying transparency
+            for symbols.
+
+        """
+        kwargs = self._preprocess(**kwargs)
+
+        kind = data_kind(data, x, y, z)
+
+        extra_arrays = []
+        if "S" in kwargs and kwargs["S"][0] in "vV" and direction is not None:
+            extra_arrays.extend(direction)
+        if "G" in kwargs and not isinstance(kwargs["G"], str):
+            if kind != "vectors":
+                raise GMTInvalidInput(
+                    "Can't use arrays for color if data is matrix or file."
+                )
+            extra_arrays.append(kwargs["G"])
+            del kwargs["G"]
+        if sizes is not None:
+            if kind != "vectors":
+                raise GMTInvalidInput(
+                    "Can't use arrays for sizes if data is matrix or file."
+                )
+            extra_arrays.append(sizes)
+
+        if "t" in kwargs and is_nonstr_iter(kwargs["t"]):
+            extra_arrays.append(kwargs["t"])
+            kwargs["t"] = ""
+
+        with Session() as lib:
+            # Choose how data will be passed in to the module
+            if kind == "file":
+                file_context = dummy_context(data)
+            elif kind == "matrix":
+                file_context = lib.virtualfile_from_matrix(data)
+            elif kind == "vectors":
+                file_context = lib.virtualfile_from_vectors(
+                    np.atleast_1d(x), np.atleast_1d(y), np.atleast_1d(z), *extra_arrays
+                )
+
+            with file_context as fname:
+                arg_str = " ".join([fname, build_arg_string(kwargs)])
+                lib.call_module("plot3d", arg_str)
+
     @fmt_docstring
     @use_alias(
         R="region",
@@ -921,6 +1104,8 @@ class BasePlotting:
     @use_alias(
         R="region",
         J="projection",
+        Jz="zscale",
+        JZ="zsize",
         B="frame",
         L="map_scale",
         Td="rose",
@@ -935,12 +1120,12 @@ class BasePlotting:
     @kwargs_to_strings(R="sequence", p="sequence")
     def basemap(self, **kwargs):
         """
-        Produce a basemap for the figure.
+        Plot base maps and frames for the figure.
 
-        Several map projections are available, and the user may specify
-        separate tick-mark intervals for boundary annotation, ticking, and
-        [optionally] gridlines. A simple map scale or directional rose may also
-        be plotted.
+        Creates a basic or fancy basemap with axes, fill, and titles. Several
+        map projections are available, and the user may specify separate
+        tick-mark intervals for boundary annotation, ticking, and [optionally]
+        gridlines. A simple map scale or directional rose may also be plotted.
 
         At least one of the options *frame*, *map_scale*, *rose* or *compass*
         must be specified.
@@ -952,6 +1137,8 @@ class BasePlotting:
         Parameters
         ----------
         {J}
+        zscale/zsize : float or str
+            Set z-axis scaling or z-axis size.
         {R}
         {B}
         map_scale : str

Wrapper for plot3d
**Description of the desired feature**

Implement [`plot3d`](https://docs.generic-mapping-tools.org/latest/plot3d.html) which "Plot lines, polygons, and symbols in 3-D". Basically a 3D version of ['plot`](https://docs.generic-mapping-tools.org/latest/plot.html). Below is an example of such a 3D plot from the GMT gallery:

![Example 8 using plot3d from GMT gallery](https://docs.generic-mapping-tools.org/latest/_images/ex08.png)

<!-- Please be as detailed as you can in your description. If possible, include an example of how you would like to use this feature (even better if it's a code example). -->

This would build upon the [`grdview`](https://www.pygmt.org/latest/api/generated/pygmt.Figure.grdview.html) function I last wrapped in #330, extending it to vector symbols. For example, we could plot the change in height of a DEM surface (h) along a transect line (x), over time (t)! Will be keen to get this done for some of my current satellite altimetry work :grin:

**Are you willing to help implement and maintain this feature?** Yes

<!-- Every feature we add is code that we will have to maintain and keep updated. This takes a lot of effort. If you are willing to be involved in the project and help maintain your feature, it will make it easier for us to accept it. -->
diff --git a/pygmt/tests/test_plot.py b/pygmt/tests/test_plot.py
index 196cf460..cef4dae5 100644
--- a/pygmt/tests/test_plot.py
+++ b/pygmt/tests/test_plot.py
@@ -269,7 +269,7 @@ def test_plot_varying_transparency():
 
 @check_figures_equal()
 def test_plot_sizes_colors_transparencies():
-    "Plot the data using z as transparency"
+    "Plot the data with varying sizes and colors using z as transparency"
     x = np.arange(1.0, 10.0)
     y = np.arange(1.0, 10.0)
     color = np.arange(1, 10) * 0.15
diff --git a/pygmt/tests/test_plot3d.py b/pygmt/tests/test_plot3d.py
new file mode 100644
index 00000000..ba0590b1
--- /dev/null
+++ b/pygmt/tests/test_plot3d.py
@@ -0,0 +1,588 @@
+"""
+Tests plot3d.
+"""
+import os
+
+import numpy as np
+import pytest
+
+from .. import Figure
+from ..exceptions import GMTInvalidInput
+from ..helpers import GMTTempFile
+from ..helpers.testing import check_figures_equal
+
+
+TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
+POINTS_DATA = os.path.join(TEST_DATA_DIR, "points.txt")
+
+
+@pytest.fixture(scope="module", name="data")
+def fixture_data():
+    "Load the point data from the test file"
+    return np.loadtxt(POINTS_DATA)
+
+
+@pytest.fixture(scope="module", name="region")
+def fixture_region():
+    "The data region"
+    return [10, 70, -5, 10, 0, 1]
+
+
+@check_figures_equal()
+def test_plot3d_red_circles_zscale(data, region):
+    "Plot the 3D data in red circles passing in vectors and setting zscale = 5"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="X4i",
+        S="c0.2c",
+        G="red",
+        B=["afg", "zafg"],
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="X4i",
+        style="c0.2c",
+        color="red",
+        frame=["afg", "zafg"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_red_circles_zsize(data, region):
+    "Plot the 3D data in red circles passing in vectors and setting zsize = 3i"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        JZ="3i",
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="X4i",
+        S="c0.2c",
+        G="red",
+        B=["afg", "zafg"],
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zsize="3i",
+        perspective=[225, 30],
+        region=region,
+        projection="X4i",
+        style="c0.2c",
+        color="red",
+        frame=["afg", "zafg"],
+    )
+    return fig_ref, fig_test
+
+
+def test_plot3d_fail_no_data(data, region):
+    "Plot should raise an exception if no data is given"
+    fig = Figure()
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            region=region, projection="X4i", style="c0.2c", color="red", frame="afg"
+        )
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            x=data[:, 0],
+            region=region,
+            projection="X4i",
+            style="c0.2c",
+            color="red",
+            frame="afg",
+        )
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            y=data[:, 0],
+            region=region,
+            projection="X4i",
+            style="c0.2c",
+            color="red",
+            frame="afg",
+        )
+    # Should also fail if given too much data
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            x=data[:, 0],
+            y=data[:, 1],
+            z=data[:, 2],
+            data=data,
+            region=region,
+            projection="X4i",
+            style="c0.2c",
+            color="red",
+            frame="afg",
+        )
+
+
+def test_plot3d_fail_size_color(data, region):
+    "Should raise an exception if array sizes and color are used with matrix"
+    fig = Figure()
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            data=data,
+            region=region,
+            projection="X4i",
+            style="c0.2c",
+            color=data[:, 2],
+            frame="afg",
+        )
+    with pytest.raises(GMTInvalidInput):
+        fig.plot3d(
+            data=data,
+            region=region,
+            projection="X4i",
+            style="cc",
+            sizes=data[:, 2],
+            color="red",
+            frame="afg",
+        )
+
+
+@check_figures_equal()
+def test_plot3d_projection(data, region):
+    "Plot the data in green squares with a projection"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="R270/4i",
+        S="s1c",
+        G="green",
+        B=["ag", "zag"],
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="R270/4i",
+        style="s1c",
+        color="green",
+        frame=["ag", "zag"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_colors(data, region):
+    "Plot the data using z as colors"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        G="+z",
+        R="/".join(map(str, region)),
+        J="X3i",
+        S="c0.5c",
+        C="cubhelix",
+        B=["afg", "zafg"],
+        i="0,1,2,2",
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        color=data[:, 2],
+        region=region,
+        projection="X3i",
+        style="c0.5c",
+        cmap="cubhelix",
+        frame=["afg", "zafg"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_sizes(data, region):
+    "Plot the data using z as sizes"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        i="0,1,2,2+s0.5",
+        R="/".join(map(str, region)),
+        J="X4i",
+        S="ui",
+        G="blue",
+        B=["af", "zaf"],
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        sizes=0.5 * data[:, 2],
+        region=region,
+        projection="X4i",
+        # Using inches instead of cm because of upstream bug at
+        # https://github.com/GenericMappingTools/gmt/issues/4386
+        style="ui",
+        color="blue",
+        frame=["af", "zaf"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_colors_sizes(data, region):
+    "Plot the data using z as sizes and colors"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        i="0,1,2,2,2+s0.5",
+        R="/".join(map(str, region)),
+        J="X3i",
+        S="ui",
+        C="copper",
+        B=["af", "zaf"],
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        color=data[:, 2],
+        sizes=0.5 * data[:, 2],
+        region=region,
+        projection="X3i",
+        # Using inches instead of cm because of upstream bug at
+        # https://github.com/GenericMappingTools/gmt/issues/4386
+        style="ui",
+        cmap="copper",
+        frame=["af", "zaf"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_colors_sizes_proj(data, region):
+    "Plot the data using z as sizes and colors with a projection"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="M10i",
+        B=["af", "zaf"],
+        G="+z",
+        i="0,1,2,2,2+s1",
+        S="ui",
+        C="copper",
+    )
+    fig_test.plot3d(
+        x=data[:, 0],
+        y=data[:, 1],
+        z=data[:, 2],
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="M10i",
+        frame=["af", "zaf"],
+        color=data[:, 2],
+        sizes=data[:, 2],
+        # Using inches instead of cm because of upstream bug at
+        # https://github.com/GenericMappingTools/gmt/issues/4386
+        style="ui",
+        cmap="copper",
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_transparency():
+    "Plot the data with a constant transparency"
+    x = np.arange(1, 10)
+    y = np.arange(1, 10)
+    z = np.arange(1, 10) * 10
+
+    fig_ref, fig_test = Figure(), Figure()
+    # Use single-character arguments for the reference image
+    with GMTTempFile() as tmpfile:
+        np.savetxt(tmpfile.name, np.c_[x, y, z], fmt="%d")
+        fig_ref.plot3d(
+            data=tmpfile.name,
+            S="u0.2c",
+            G="blue",
+            R="0/10/0/10/10/90",
+            J="X4i",
+            Jz=0.1,
+            B="",
+            p="135/30",
+            t=80.0,
+        )
+
+    fig_test.plot3d(
+        x=x,
+        y=y,
+        z=z,
+        style="u0.2c",
+        color="blue",
+        region=[0, 10, 0, 10, 10, 90],
+        projection="X4i",
+        zscale=0.1,
+        frame=True,
+        perspective=[135, 30],
+        transparency=80.0,
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_varying_transparency():
+    "Plot the data using z as transparency using 3-D column symbols"
+    x = np.arange(1, 10)
+    y = np.arange(1, 10)
+    z = np.arange(1, 10) * 10
+
+    fig_ref, fig_test = Figure(), Figure()
+    # Use single-character arguments for the reference image
+    with GMTTempFile() as tmpfile:
+        np.savetxt(tmpfile.name, np.c_[x, y, z, z, z], fmt="%d")
+        fig_ref.plot3d(
+            data=tmpfile.name,
+            S="o0.2c+B5",
+            G="blue",
+            R="0/10/0/10/10/90",
+            J="X4i",
+            Jz=0.1,
+            B="",
+            p="135/30",
+            t="",
+        )
+    fig_test.plot3d(
+        x=x,
+        y=y,
+        z=z,
+        style="o0.2c+B5",
+        color="blue",
+        region=[0, 10, 0, 10, 10, 90],
+        projection="X4i",
+        zscale=0.1,
+        frame=True,
+        perspective=[135, 30],
+        transparency=z,
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_sizes_colors_transparencies():
+    "Plot the data with varying sizes and colors using z as transparency"
+    x = np.arange(1.0, 10.0)
+    y = np.arange(1.0, 10.0)
+    z = np.arange(1, 10) * 10
+    color = np.arange(1, 10) * 0.15
+    size = np.arange(1, 10) * 0.2
+    transparency = np.arange(1, 10) * 10
+
+    fig_ref, fig_test = Figure(), Figure()
+    # Use single-character arguments for the reference image
+    with GMTTempFile() as tmpfile:
+        np.savetxt(tmpfile.name, np.c_[x, y, z, color, size, transparency])
+        fig_ref.plot3d(
+            data=tmpfile.name,
+            R="0/10/0/10/10/90",
+            J="X4i",
+            Jz=0.1,
+            p="135/30",
+            B="",
+            S="uc",
+            C="gray",
+            t="",
+        )
+    fig_test.plot3d(
+        x=x,
+        y=y,
+        z=z,
+        region=[0, 10, 0, 10, 10, 90],
+        projection="X4i",
+        zscale=0.1,
+        perspective=[135, 30],
+        frame=True,
+        style="uc",
+        color=color,
+        sizes=size,
+        cmap="gray",
+        transparency=transparency,
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_matrix(data, region):
+    "Plot the data passing in a matrix and specifying columns"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="M10i",
+        S="c1c",
+        G="#aaaaaa",
+        B=["a", "za"],
+        i="0,1,2",
+    )
+    fig_test.plot3d(
+        data=data,
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="M10i",
+        style="c1c",
+        color="#aaaaaa",
+        frame=["a", "za"],
+        columns="0,1,2",
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_matrix_color(data, region):
+    "Plot the data passing in a matrix and using a colormap"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="X5i",
+        S="c0.5cc",
+        C="rainbow",
+        i="0,1,2,2",
+        B=["a", "za"],
+    )
+    fig_test.plot3d(
+        data=data,
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="X5i",
+        style="c0.5c",
+        cmap="rainbow",
+        columns=[0, 1, 2, 2],
+        frame=["a", "za"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_from_file(region):
+    "Plot using the data file name instead of loaded data"
+    fig_ref, fig_test = Figure(), Figure()
+    fig_ref.plot3d(
+        data=POINTS_DATA,
+        Jz=5,
+        p="225/30",
+        R="/".join(map(str, region)),
+        J="X10i",
+        S="d1c",
+        G="yellow",
+        B=["af", "zaf"],
+        i="0,1,2",
+    )
+    fig_test.plot3d(
+        data=POINTS_DATA,
+        zscale=5,
+        perspective=[225, 30],
+        region=region,
+        projection="X10i",
+        style="d1c",
+        color="yellow",
+        frame=["af", "zaf"],
+        columns=[0, 1, 2],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_vectors():
+    "Plot vectors"
+    azimuth = np.array([0, 45, 90, 135, 180, 225, 270, 310])
+    lengths = np.linspace(0.1, 1, len(azimuth))
+    lon = np.sin(np.deg2rad(azimuth))
+    lat = np.cos(np.deg2rad(azimuth))
+    elev = np.tan(np.deg2rad(azimuth))
+    fig_ref, fig_test = Figure(), Figure()
+    with GMTTempFile() as tmpfile:
+        np.savetxt(tmpfile.name, np.c_[lon, lat, elev, azimuth, lengths])
+        fig_ref.plot3d(
+            data=tmpfile.name,
+            Jz=2,
+            p="225/30",
+            R="-2/2/-2/2/-2/2",
+            J="X4i",
+            S="V1c+e",
+            G="black",
+            B=["af", "zaf"],
+        )
+    fig_test.plot3d(
+        x=lon,
+        y=lat,
+        z=elev,
+        zscale=2,
+        perspective=[225, 30],
+        direction=(azimuth, lengths),
+        region=[-2, 2, -2, 2, -2, 2],
+        projection="X4i",
+        style="V1c+e",
+        color="black",
+        frame=["af", "zaf"],
+    )
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_plot3d_scalar_xyz():
+    "Plot symbols given scalar x, y, z coordinates"
+    fig_ref, fig_test = Figure(), Figure()
+    with GMTTempFile() as tmpfile:
+        np.savetxt(tmpfile.name, np.c_[[-1.5, 0, 1.5], [1.5, 0, -1.5], [-1.5, 0, 1.5]])
+        fig_ref.basemap(
+            R="-2/2/-2/2/-2/2", B=["xaf+lx", "yaf+ly", "zaf+lz"], Jz=2, p="225/30"
+        )
+        fig_ref.plot3d(data=tmpfile.name, S="c1c", G="red", Jz="", p="", qi=0)
+        fig_ref.plot3d(data=tmpfile.name, S="t1c", G="green", Jz="", p="", qi=1)
+        fig_ref.plot3d(data=tmpfile.name, S="s1c", G="blue", Jz="", p="", qi=2)
+
+    fig_test.basemap(
+        region=[-2, 2, -2, 2, -2, 2],
+        frame=["xaf+lx", "yaf+ly", "zaf+lz"],
+        zscale=2,
+        perspective=[225, 30],
+    )
+    fig_test.plot3d(
+        x=-1.5, y=1.5, z=-1.5, style="c1c", color="red", zscale=True, perspective=True
+    )
+    fig_test.plot3d(
+        x=0, y=0, z=0, style="t1c", color="green", zscale=True, perspective=True
+    )
+    fig_test.plot3d(
+        x=1.5, y=-1.5, z=1.5, style="s1c", color="blue", zscale=True, perspective=True
+    )
+    return fig_ref, fig_test

environment.yml
pip install -e .[dev]
parse_log_pytest
environment.yml
pytest
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster @ file:///home/conda/feedstock_root/build_artifacts/alabaster_1673645646525/work
anyio @ file:///home/conda/feedstock_root/build_artifacts/anyio_1688651106312/work/dist
argon2-cffi @ file:///home/conda/feedstock_root/build_artifacts/argon2-cffi_1692818318753/work
argon2-cffi-bindings @ file:///home/conda/feedstock_root/build_artifacts/argon2-cffi-bindings_1649500320262/work
astroid @ file:///croot/astroid_1676904296642/work
attrs @ file:///home/conda/feedstock_root/build_artifacts/attrs_1722977137225/work
Babel @ file:///home/conda/feedstock_root/build_artifacts/babel_1702422572539/work
backcall @ file:///home/conda/feedstock_root/build_artifacts/backcall_1592338393461/work
backports.functools-lru-cache @ file:///home/conda/feedstock_root/build_artifacts/backports.functools_lru_cache_1702571698061/work
beautifulsoup4 @ file:///home/conda/feedstock_root/build_artifacts/beautifulsoup4_1705564648255/work
black @ file:///home/conda/feedstock_root/build_artifacts/black-recipe_1666773063432/work
blackdoc @ file:///home/conda/feedstock_root/build_artifacts/blackdoc_1667564908653/work
bleach @ file:///home/conda/feedstock_root/build_artifacts/bleach_1696630167146/work
Bottleneck @ file:///home/conda/feedstock_root/build_artifacts/bottleneck_1649629660965/work
Brotli @ file:///home/conda/feedstock_root/build_artifacts/brotli-split_1648883617327/work
certifi @ file:///home/conda/feedstock_root/build_artifacts/certifi_1725278078093/work/certifi
cffi @ file:///home/conda/feedstock_root/build_artifacts/cffi_1636046052501/work
cftime @ file:///home/conda/feedstock_root/build_artifacts/cftime_1649636858592/work
charset-normalizer @ file:///home/conda/feedstock_root/build_artifacts/charset-normalizer_1728479282467/work
click @ file:///home/conda/feedstock_root/build_artifacts/click_1651215140632/work
colorama @ file:///home/conda/feedstock_root/build_artifacts/colorama_1666700638685/work
comm @ file:///home/conda/feedstock_root/build_artifacts/comm_1710320294760/work
coverage @ file:///home/conda/feedstock_root/build_artifacts/coverage_1652409068862/work
cycler @ file:///home/conda/feedstock_root/build_artifacts/cycler_1635519461629/work
debugpy @ file:///home/conda/feedstock_root/build_artifacts/debugpy_1649586340600/work
decorator @ file:///home/conda/feedstock_root/build_artifacts/decorator_1641555617451/work
defusedxml @ file:///home/conda/feedstock_root/build_artifacts/defusedxml_1615232257335/work
dill @ file:///home/conda/feedstock_root/build_artifacts/dill_1706434688412/work
docutils @ file:///home/conda/feedstock_root/build_artifacts/docutils_1610127754852/work
entrypoints @ file:///home/conda/feedstock_root/build_artifacts/entrypoints_1643888246732/work
exceptiongroup @ file:///home/conda/feedstock_root/build_artifacts/exceptiongroup_1720869315914/work
fastjsonschema @ file:///home/conda/feedstock_root/build_artifacts/python-fastjsonschema_1718477020893/work/dist
flake8 @ file:///home/conda/feedstock_root/build_artifacts/flake8_1659645013175/work
fonttools @ file:///home/conda/feedstock_root/build_artifacts/fonttools_1651017735934/work
GDAL==3.3.1
idna @ file:///home/conda/feedstock_root/build_artifacts/idna_1726459485162/work
imagesize @ file:///home/conda/feedstock_root/build_artifacts/imagesize_1656939531508/work
importlib-metadata @ file:///home/conda/feedstock_root/build_artifacts/importlib-metadata_1653252814274/work
importlib-resources @ file:///home/conda/feedstock_root/build_artifacts/importlib_resources_1688813467203/work
iniconfig @ file:///home/conda/feedstock_root/build_artifacts/iniconfig_1673103042956/work
ipykernel @ file:///home/conda/feedstock_root/build_artifacts/ipykernel_1666723258080/work
ipython @ file:///home/conda/feedstock_root/build_artifacts/ipython_1651240553635/work
ipython_genutils @ file:///home/conda/feedstock_root/build_artifacts/ipython_genutils_1716278396992/work
ipywidgets @ file:///home/conda/feedstock_root/build_artifacts/ipywidgets_1724334859652/work
isort @ file:///home/conda/feedstock_root/build_artifacts/isort_1675293796116/work
jedi @ file:///home/conda/feedstock_root/build_artifacts/jedi_1696326070614/work
Jinja2 @ file:///home/conda/feedstock_root/build_artifacts/jinja2_1715127149914/work
json5 @ file:///home/conda/feedstock_root/build_artifacts/json5_1712986206667/work
jsonschema @ file:///home/conda/feedstock_root/build_artifacts/jsonschema-meta_1669810440410/work
jupyter @ file:///home/conda/feedstock_root/build_artifacts/jupyter_1725037521377/work
jupyter-client @ file:///home/conda/feedstock_root/build_artifacts/jupyter_client_1654730843242/work
jupyter-console @ file:///home/conda/feedstock_root/build_artifacts/jupyter_console_1676328545892/work
jupyter-server @ file:///home/conda/feedstock_root/build_artifacts/jupyter_server_1671591499479/work
jupyter_core @ file:///home/conda/feedstock_root/build_artifacts/jupyter_core_1658332345782/work
jupyterlab @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_1674494302491/work
jupyterlab_pygments @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_pygments_1700744013163/work
jupyterlab_server @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_server_1690205927615/work
jupyterlab_widgets @ file:///home/conda/feedstock_root/build_artifacts/jupyterlab_widgets_1724331334887/work
kiwisolver @ file:///home/conda/feedstock_root/build_artifacts/kiwisolver_1648854392523/work
lazy-object-proxy @ file:///home/conda/feedstock_root/build_artifacts/lazy-object-proxy_1649033171084/work
markdown-it-py @ file:///home/conda/feedstock_root/build_artifacts/markdown-it-py_1677100944732/work
MarkupSafe @ file:///home/conda/feedstock_root/build_artifacts/markupsafe_1648737551960/work
matplotlib @ file:///croot/matplotlib-suite_1667356714455/work
matplotlib-inline @ file:///home/conda/feedstock_root/build_artifacts/matplotlib-inline_1713250518406/work
mccabe @ file:///home/conda/feedstock_root/build_artifacts/mccabe_1643049622439/work
mdurl @ file:///home/conda/feedstock_root/build_artifacts/mdurl_1704317613764/work
mistune @ file:///home/conda/feedstock_root/build_artifacts/mistune_1698947099619/work
more-itertools @ file:///home/conda/feedstock_root/build_artifacts/more-itertools_1690211628840/work
munkres==1.1.4
mypy-extensions @ file:///home/conda/feedstock_root/build_artifacts/mypy_extensions_1675543315189/work
nbclassic @ file:///home/conda/feedstock_root/build_artifacts/nbclassic_1716838762700/work
nbclient @ file:///home/conda/feedstock_root/build_artifacts/nbclient_1665125402713/work
nbconvert @ file:///home/conda/feedstock_root/build_artifacts/nbconvert-meta_1687202153002/work
nbformat @ file:///home/conda/feedstock_root/build_artifacts/nbformat_1679336765223/work
nbsphinx @ file:///home/conda/feedstock_root/build_artifacts/nbsphinx_1741075436613/work
nest_asyncio @ file:///home/conda/feedstock_root/build_artifacts/nest-asyncio_1705850609492/work
netCDF4 @ file:///home/conda/feedstock_root/build_artifacts/netcdf4_1624308195839/work
notebook @ file:///home/conda/feedstock_root/build_artifacts/notebook_1715848908871/work
notebook_shim @ file:///home/conda/feedstock_root/build_artifacts/notebook-shim_1707957777232/work
numexpr @ file:///home/conda/feedstock_root/build_artifacts/numexpr_1649636747170/work
numpy @ file:///home/conda/feedstock_root/build_artifacts/numpy_1649806299270/work
olefile @ file:///home/conda/feedstock_root/build_artifacts/olefile_1701735466804/work
packaging @ file:///home/conda/feedstock_root/build_artifacts/packaging_1696202382185/work
pandas==1.3.5
pandocfilters @ file:///home/conda/feedstock_root/build_artifacts/pandocfilters_1631603243851/work
parso @ file:///home/conda/feedstock_root/build_artifacts/parso_1712320355065/work
pathspec @ file:///home/conda/feedstock_root/build_artifacts/pathspec_1702249949303/work
pexpect @ file:///home/conda/feedstock_root/build_artifacts/pexpect_1706113125309/work
pickleshare @ file:///home/conda/feedstock_root/build_artifacts/pickleshare_1602536217715/work
Pillow @ file:///home/conda/feedstock_root/build_artifacts/pillow_1630696604087/work
pkgutil_resolve_name @ file:///home/conda/feedstock_root/build_artifacts/pkgutil-resolve-name_1694617248815/work
platformdirs @ file:///home/conda/feedstock_root/build_artifacts/platformdirs_1699715570510/work
pluggy @ file:///home/conda/feedstock_root/build_artifacts/pluggy_1648772594554/work
prometheus-client @ file:///home/conda/feedstock_root/build_artifacts/prometheus_client_1689032443210/work
prompt_toolkit @ file:///home/conda/feedstock_root/build_artifacts/prompt-toolkit_1727341649933/work
psutil @ file:///home/conda/feedstock_root/build_artifacts/psutil_1653089169272/work
ptyprocess @ file:///home/conda/feedstock_root/build_artifacts/ptyprocess_1609419310487/work/dist/ptyprocess-0.7.0-py2.py3-none-any.whl
pycodestyle @ file:///home/conda/feedstock_root/build_artifacts/pycodestyle_1659638152915/work
pycparser @ file:///home/conda/feedstock_root/build_artifacts/pycparser_1636257122734/work
pyflakes @ file:///home/conda/feedstock_root/build_artifacts/pyflakes_1659210156976/work
Pygments @ file:///home/conda/feedstock_root/build_artifacts/pygments_1700607939962/work
-e git+https://github.com/GenericMappingTools/pygmt.git@0ea9886ca209dd947afc5bb8364f930a2b0ab49f#egg=pygmt
pylint @ file:///home/conda/feedstock_root/build_artifacts/pylint_1678161361281/work
pyparsing @ file:///home/conda/feedstock_root/build_artifacts/pyparsing_1724616129934/work
PyQt5==5.12.3
PyQt5_sip==4.19.18
PyQtChart==5.12
PyQtWebEngine==5.12.1
pyrsistent @ file:///home/conda/feedstock_root/build_artifacts/pyrsistent_1649013358450/work
PySocks @ file:///home/conda/feedstock_root/build_artifacts/pysocks_1648857264451/work
pytest @ file:///home/conda/feedstock_root/build_artifacts/pytest_1704035161844/work
pytest-cov @ file:///home/conda/feedstock_root/build_artifacts/pytest-cov_1684964868191/work
pytest-mpl @ file:///home/conda/feedstock_root/build_artifacts/pytest-mpl_1708026142435/work
python-dateutil @ file:///home/conda/feedstock_root/build_artifacts/python-dateutil_1709299778482/work
pytz @ file:///home/conda/feedstock_root/build_artifacts/pytz_1726055524169/work
pyzmq @ file:///home/conda/feedstock_root/build_artifacts/pyzmq_1652965483789/work
requests @ file:///home/conda/feedstock_root/build_artifacts/requests_1716354486713/work
rich @ file:///home/conda/feedstock_root/build_artifacts/rich_1726066019428/work/dist
Send2Trash @ file:///home/conda/feedstock_root/build_artifacts/send2trash_1712584999685/work
six @ file:///home/conda/feedstock_root/build_artifacts/six_1620240208055/work
sniffio @ file:///home/conda/feedstock_root/build_artifacts/sniffio_1708952932303/work
snowballstemmer @ file:///home/conda/feedstock_root/build_artifacts/snowballstemmer_1637143057757/work
soupsieve @ file:///home/conda/feedstock_root/build_artifacts/soupsieve_1658207591808/work
Sphinx==2.2.1
sphinx-gallery @ file:///home/conda/feedstock_root/build_artifacts/sphinx-gallery_1700542355088/work
sphinx-rtd-theme==0.4.3
sphinxcontrib-applehelp @ file:///home/conda/feedstock_root/build_artifacts/sphinxcontrib-applehelp_1674487779667/work
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp @ file:///home/conda/feedstock_root/build_artifacts/sphinxcontrib-htmlhelp_1675256494457/work
sphinxcontrib-jsmath @ file:///home/conda/feedstock_root/build_artifacts/sphinxcontrib-jsmath_1691604704163/work
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml @ file:///home/conda/feedstock_root/build_artifacts/sphinxcontrib-serializinghtml_1649380998999/work
terminado @ file:///home/conda/feedstock_root/build_artifacts/terminado_1670253674810/work
tinycss2 @ file:///home/conda/feedstock_root/build_artifacts/tinycss2_1729802851396/work
toml @ file:///home/conda/feedstock_root/build_artifacts/toml_1604308577558/work
tomli @ file:///home/conda/feedstock_root/build_artifacts/tomli_1727974628237/work
tomlkit @ file:///home/conda/feedstock_root/build_artifacts/tomlkit_1715185399719/work
tornado @ file:///home/conda/feedstock_root/build_artifacts/tornado_1648827244717/work
traitlets @ file:///home/conda/feedstock_root/build_artifacts/traitlets_1675110562325/work
typed-ast @ file:///home/conda/feedstock_root/build_artifacts/typed-ast_1650218777101/work
typing_extensions @ file:///home/conda/feedstock_root/build_artifacts/typing_extensions_1688315532570/work
unicodedata2 @ file:///home/conda/feedstock_root/build_artifacts/unicodedata2_1649111917568/work
urllib3 @ file:///home/conda/feedstock_root/build_artifacts/urllib3_1708239446578/work
wcwidth @ file:///home/conda/feedstock_root/build_artifacts/wcwidth_1699959196938/work
webencodings @ file:///home/conda/feedstock_root/build_artifacts/webencodings_1694681268211/work
websocket-client @ file:///home/conda/feedstock_root/build_artifacts/websocket-client_1687789148259/work
widgetsnbextension @ file:///home/conda/feedstock_root/build_artifacts/widgetsnbextension_1724331337528/work
wrapt @ file:///home/conda/feedstock_root/build_artifacts/wrapt_1651495229974/work
xarray @ file:///home/conda/feedstock_root/build_artifacts/xarray_1639125986756/work
zipp @ file:///home/conda/feedstock_root/build_artifacts/zipp_1677313463193/work

name: pygmt
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - alabaster=0.7.13=pyhd8ed1ab_0
  - alsa-lib=1.2.3.2=h166bdaf_0
  - anyio=3.7.1=pyhd8ed1ab_0
  - argon2-cffi=23.1.0=pyhd8ed1ab_0
  - argon2-cffi-bindings=21.2.0=py37h540881e_2
  - astroid=2.14.2=py37h06a4308_0
  - atk-1.0=2.36.0=h3371d22_4
  - attrs=24.2.0=pyh71513ae_0
  - babel=2.14.0=pyhd8ed1ab_0
  - backcall=0.2.0=pyh9f0ad1d_0
  - backports=1.0=pyhd8ed1ab_4
  - backports.functools_lru_cache=2.0.0=pyhd8ed1ab_0
  - beautifulsoup4=4.12.3=pyha770c72_0
  - black=22.10.0=py37h89c1867_1
  - blackdoc=0.3.8=pyhd8ed1ab_0
  - bleach=6.1.0=pyhd8ed1ab_0
  - boost-cpp=1.74.0=h312852a_4
  - bottleneck=1.3.4=py37hda87dfa_1
  - brotli=1.0.9=h166bdaf_7
  - brotli-bin=1.0.9=h166bdaf_7
  - brotli-python=1.0.9=py37hd23a5d3_7
  - bzip2=1.0.8=h7f98852_4
  - c-ares=1.18.1=h7f98852_0
  - ca-certificates=2025.2.25=h06a4308_0
  - cairo=1.16.0=h6cf1ce9_1008
  - certifi=2024.8.30=pyhd8ed1ab_0
  - cffi=1.15.0=py37h036bc23_0
  - cfitsio=3.470=hb418390_7
  - cftime=1.6.0=py37hda87dfa_1
  - charset-normalizer=3.4.0=pyhd8ed1ab_0
  - chrpath=0.16=h7f98852_1002
  - click=8.1.3=py37h89c1867_0
  - colorama=0.4.6=pyhd8ed1ab_0
  - comm=0.2.2=pyhd8ed1ab_0
  - coverage=6.3.3=py37h540881e_0
  - curl=7.79.1=h2574ce0_1
  - cycler=0.11.0=pyhd8ed1ab_0
  - dbus=1.13.6=h48d8840_2
  - dcw-gmt=2.2.0=ha770c72_0
  - debugpy=1.6.0=py37hd23a5d3_0
  - decorator=5.1.1=pyhd8ed1ab_0
  - defusedxml=0.7.1=pyhd8ed1ab_0
  - dill=0.3.8=pyhd8ed1ab_0
  - docutils=0.16=py37h89c1867_3
  - entrypoints=0.4=pyhd8ed1ab_0
  - exceptiongroup=1.2.2=pyhd8ed1ab_0
  - expat=2.4.8=h27087fc_0
  - ffmpeg=4.3.2=hca11adc_0
  - fftw=3.3.10=nompi_h77c792f_102
  - flake8=5.0.4=pyhd8ed1ab_0
  - font-ttf-dejavu-sans-mono=2.37=hab24e00_0
  - font-ttf-inconsolata=3.000=h77eed37_0
  - font-ttf-source-code-pro=2.038=h77eed37_0
  - font-ttf-ubuntu=0.83=h77eed37_3
  - fontconfig=2.14.0=h8e229c2_0
  - fonts-conda-ecosystem=1=0
  - fonts-conda-forge=1=0
  - fonttools=4.33.3=py37h540881e_0
  - freetype=2.12.1=h4a9f257_0
  - freexl=1.0.6=h7f98852_0
  - fribidi=1.0.10=h36c2ea0_0
  - gdal=3.3.1=py37hb0e9ad2_1
  - gdk-pixbuf=2.42.6=h04a7f16_0
  - geos=3.9.1=h9c3ff4c_2
  - geotiff=1.6.0=h4f31c25_6
  - gettext=0.19.8.1=h73d1719_1008
  - ghostscript=9.54.0=h27087fc_2
  - giflib=5.2.1=h36c2ea0_2
  - glib=2.68.4=h9c3ff4c_1
  - glib-tools=2.68.4=h9c3ff4c_1
  - gmp=6.2.1=h58526e2_0
  - gmt=6.1.1=h88440e8_7
  - gnuplot=5.4.1=hec6539f_2
  - gnutls=3.6.13=h85f3911_1
  - graphicsmagick=1.3.36=hdc87540_0
  - graphite2=1.3.13=h58526e2_1001
  - gshhg-gmt=2.3.7=ha770c72_1003
  - gst-plugins-base=1.18.5=hf529b03_0
  - gstreamer=1.18.5=h76c114f_0
  - gtk2=2.24.33=h539f30e_1
  - harfbuzz=3.0.0=h83ec7ef_1
  - hdf4=4.2.15=h10796ff_3
  - hdf5=1.10.6=nompi_h6a2412b_1114
  - icu=68.2=h9c3ff4c_0
  - idna=3.10=pyhd8ed1ab_0
  - imagesize=1.4.1=pyhd8ed1ab_0
  - importlib-metadata=4.11.4=py37h89c1867_0
  - importlib_metadata=4.11.4=hd8ed1ab_0
  - importlib_resources=6.0.0=pyhd8ed1ab_0
  - iniconfig=2.0.0=pyhd8ed1ab_0
  - ipykernel=6.16.2=pyh210e3f2_0
  - ipython=7.33.0=py37h89c1867_0
  - ipython_genutils=0.2.0=pyhd8ed1ab_1
  - ipywidgets=8.1.5=pyhd8ed1ab_0
  - isort=5.11.5=pyhd8ed1ab_0
  - jbig=2.1=h7f98852_2003
  - jedi=0.19.1=pyhd8ed1ab_0
  - jinja2=3.1.4=pyhd8ed1ab_0
  - jpeg=9e=h166bdaf_1
  - json-c=0.15=h98cffda_0
  - json5=0.9.25=pyhd8ed1ab_0
  - jsonschema=4.17.3=pyhd8ed1ab_0
  - jupyter=1.1.1=pyhd8ed1ab_0
  - jupyter_client=7.3.4=pyhd8ed1ab_0
  - jupyter_console=6.5.1=pyhd8ed1ab_0
  - jupyter_core=4.11.1=py37h89c1867_0
  - jupyter_server=1.23.4=pyhd8ed1ab_0
  - jupyterlab=3.5.3=pyhd8ed1ab_0
  - jupyterlab_pygments=0.3.0=pyhd8ed1ab_0
  - jupyterlab_server=2.24.0=pyhd8ed1ab_0
  - jupyterlab_widgets=3.0.13=pyhd8ed1ab_0
  - kealib=1.4.14=hcc255d8_2
  - keyutils=1.6.1=h166bdaf_0
  - kiwisolver=1.4.2=py37h7cecad7_1
  - krb5=1.19.3=h3790be6_0
  - lame=3.100=h7f98852_1001
  - lazy-object-proxy=1.7.1=py37h540881e_1
  - lcms2=2.12=hddcbb42_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - lerc=2.2.1=h9c3ff4c_0
  - libblas=3.9.0=16_linux64_openblas
  - libbrotlicommon=1.0.9=h166bdaf_7
  - libbrotlidec=1.0.9=h166bdaf_7
  - libbrotlienc=1.0.9=h166bdaf_7
  - libcblas=3.9.0=16_linux64_openblas
  - libclang=11.1.0=default_ha53f305_1
  - libcurl=7.79.1=h2574ce0_1
  - libdap4=3.20.6=hd7c4107_2
  - libdeflate=1.7=h7f98852_5
  - libedit=3.1.20191231=he28a2e2_2
  - libev=4.33=h516909a_1
  - libevent=2.1.10=h9b69904_4
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgd=2.3.3=h6ad9fb6_0
  - libgdal=3.3.1=h8f005ca_1
  - libgfortran-ng=13.2.0=h69a702a_0
  - libgfortran5=13.2.0=ha4646dd_0
  - libglib=2.68.4=h174f98d_1
  - libgomp=11.2.0=h1234567_1
  - libiconv=1.17=h166bdaf_0
  - libkml=1.3.0=h238a007_1014
  - liblapack=3.9.0=16_linux64_openblas
  - libllvm11=11.1.0=hf817b99_2
  - libnetcdf=4.8.0=nompi_hcd642e3_103
  - libnghttp2=1.43.0=h812cca2_1
  - libnsl=2.0.0=h7f98852_0
  - libogg=1.3.4=h7f98852_1
  - libopenblas=0.3.21=h043d6bf_0
  - libopus=1.3.1=h7f98852_1
  - libpng=1.6.37=h21135ba_2
  - libpq=13.3=hd57d9b9_0
  - librttopo=1.1.0=h1185371_6
  - libsodium=1.0.18=h36c2ea0_1
  - libspatialite=5.0.1=h8694cbe_6
  - libssh2=1.10.0=ha56f1ee_2
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.3.0=hf544144_1
  - libuuid=2.32.1=h7f98852_1000
  - libvorbis=1.3.7=h9c3ff4c_0
  - libwebp=1.2.2=h3452ae3_0
  - libwebp-base=1.2.2=h7f98852_1
  - libxcb=1.13=h7f98852_1004
  - libxkbcommon=1.0.3=he3ba5ed_0
  - libxml2=2.9.12=h72842e0_0
  - libzip=1.8.0=h4de3113_1
  - lz4-c=1.9.3=h9c3ff4c_1
  - markdown-it-py=2.2.0=pyhd8ed1ab_0
  - markupsafe=2.1.1=py37h540881e_1
  - matplotlib=3.5.3=py37h89c1867_2
  - matplotlib-base=3.5.3=py37hf590b9c_0
  - matplotlib-inline=0.1.7=pyhd8ed1ab_0
  - mccabe=0.7.0=pyhd8ed1ab_0
  - mdurl=0.1.2=pyhd8ed1ab_0
  - mistune=3.0.2=pyhd8ed1ab_0
  - more-itertools=10.0.0=pyhd8ed1ab_0
  - munkres=1.1.4=pyh9f0ad1d_0
  - mypy_extensions=1.0.0=pyha770c72_0
  - mysql-common=8.0.25=ha770c72_2
  - mysql-libs=8.0.25=hfa10184_2
  - nbclassic=1.1.0=pyhd8ed1ab_0
  - nbclient=0.7.0=pyhd8ed1ab_0
  - nbconvert=7.6.0=pyhd8ed1ab_0
  - nbconvert-core=7.6.0=pyhd8ed1ab_0
  - nbconvert-pandoc=7.6.0=pyhd8ed1ab_0
  - nbformat=5.8.0=pyhd8ed1ab_0
  - nbsphinx=0.9.7=pyhd8ed1ab_0
  - ncurses=6.4=h6a678d5_0
  - nest-asyncio=1.6.0=pyhd8ed1ab_0
  - netcdf4=1.5.7=nompi_py37h946d57d_100
  - nettle=3.6=he412f7d_0
  - nomkl=1.0=h5ca1d4c_0
  - notebook=6.5.7=pyha770c72_0
  - notebook-shim=0.2.4=pyhd8ed1ab_0
  - nspr=4.32=h9c3ff4c_1
  - nss=3.69=hb5efdd6_1
  - numexpr=2.8.0=py37h85a3170_102
  - numpy=1.21.6=py37h976b520_0
  - olefile=0.47=pyhd8ed1ab_0
  - openh264=2.1.1=h780b84a_0
  - openjpeg=2.4.0=hb52868f_1
  - openssl=1.1.1w=h7f8727e_0
  - packaging=23.2=pyhd8ed1ab_0
  - pandas=1.3.5=py37h8c16a72_0
  - pandoc=3.6.4=ha770c72_0
  - pandocfilters=1.5.0=pyhd8ed1ab_0
  - pango=1.48.10=h54213e6_2
  - parso=0.8.4=pyhd8ed1ab_0
  - pathspec=0.12.1=pyhd8ed1ab_0
  - pcre=8.45=h9c3ff4c_0
  - pexpect=4.9.0=pyhd8ed1ab_0
  - pickleshare=0.7.5=py_1003
  - pillow=8.3.2=py37h0f21c89_0
  - pip=24.0=pyhd8ed1ab_0
  - pixman=0.40.0=h36c2ea0_0
  - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1
  - platformdirs=4.0.0=pyhd8ed1ab_0
  - pluggy=1.0.0=py37h89c1867_3
  - poppler=21.03.0=h93df280_0
  - poppler-data=0.4.12=hd8ed1ab_0
  - postgresql=13.3=h2510834_0
  - proj=8.0.1=h277dcde_0
  - prometheus_client=0.17.1=pyhd8ed1ab_0
  - prompt-toolkit=3.0.48=pyha770c72_0
  - prompt_toolkit=3.0.48=hd8ed1ab_1
  - psutil=5.9.1=py37h540881e_0
  - pthread-stubs=0.4=h36c2ea0_1001
  - ptyprocess=0.7.0=pyhd3deb0d_0
  - pycodestyle=2.9.1=pyhd8ed1ab_0
  - pycparser=2.21=pyhd8ed1ab_0
  - pyflakes=2.5.0=pyhd8ed1ab_0
  - pygments=2.17.2=pyhd8ed1ab_0
  - pylint=2.16.4=pyhd8ed1ab_0
  - pyparsing=3.1.4=pyhd8ed1ab_0
  - pyqt=5.12.3=py37h89c1867_8
  - pyqt-impl=5.12.3=py37hac37412_8
  - pyqt5-sip=4.19.18=py37hcd2ae1e_8
  - pyqtchart=5.12=py37he336c9b_8
  - pyqtwebengine=5.12.1=py37he336c9b_8
  - pyrsistent=0.18.1=py37h540881e_1
  - pysocks=1.7.1=py37h89c1867_5
  - pytest=7.4.4=pyhd8ed1ab_0
  - pytest-cov=4.1.0=pyhd8ed1ab_0
  - pytest-mpl=0.17.0=pyhd8ed1ab_0
  - python=3.7.16=h7a1cb2a_0
  - python-dateutil=2.9.0=pyhd8ed1ab_0
  - python-fastjsonschema=2.20.0=pyhd8ed1ab_0
  - python_abi=3.7=2_cp37m
  - pytz=2024.2=pyhd8ed1ab_0
  - pyzmq=23.0.0=py37h0c0c2a8_0
  - qt=5.12.9=hda022c4_4
  - readline=8.2=h5eee18b_0
  - requests=2.32.2=pyhd8ed1ab_0
  - rich=13.8.1=pyhd8ed1ab_0
  - send2trash=1.8.3=pyh0d859eb_0
  - setuptools=65.6.3=py37h06a4308_0
  - six=1.16.0=pyh6c4a22f_0
  - sniffio=1.3.1=pyhd8ed1ab_0
  - snowballstemmer=2.2.0=pyhd8ed1ab_0
  - soupsieve=2.3.2.post1=pyhd8ed1ab_0
  - sphinx=2.2.1=py_0
  - sphinx-gallery=0.15.0=pyhd8ed1ab_0
  - sphinx_rtd_theme=0.4.3=py_0
  - sphinxcontrib-applehelp=1.0.4=pyhd8ed1ab_0
  - sphinxcontrib-devhelp=1.0.2=py_0
  - sphinxcontrib-htmlhelp=2.0.1=pyhd8ed1ab_0
  - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0
  - sphinxcontrib-qthelp=1.0.3=py_0
  - sphinxcontrib-serializinghtml=1.1.5=pyhd8ed1ab_2
  - sqlite=3.45.3=h5eee18b_0
  - terminado=0.17.1=pyh41d4057_0
  - tiledb=2.3.4=he87e0bf_0
  - tinycss2=1.4.0=pyhd8ed1ab_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd8ed1ab_0
  - tomli=2.0.2=pyhd8ed1ab_0
  - tomlkit=0.12.5=pyha770c72_0
  - tornado=6.1=py37h540881e_3
  - traitlets=5.9.0=pyhd8ed1ab_0
  - typed-ast=1.5.3=py37h540881e_0
  - typing-extensions=4.7.1=hd8ed1ab_0
  - typing_extensions=4.7.1=pyha770c72_0
  - tzcode=2022a=h166bdaf_0
  - tzdata=2025b=h78e105d_0
  - unicodedata2=14.0.0=py37h540881e_1
  - urllib3=2.2.1=pyhd8ed1ab_0
  - wcwidth=0.2.10=pyhd8ed1ab_0
  - webencodings=0.5.1=pyhd8ed1ab_2
  - websocket-client=1.6.1=pyhd8ed1ab_0
  - wheel=0.38.4=py37h06a4308_0
  - widgetsnbextension=4.0.13=pyhd8ed1ab_0
  - wrapt=1.14.1=py37h540881e_0
  - x264=1!161.3030=h7f98852_1
  - xarray=0.20.2=pyhd8ed1ab_0
  - xerces-c=3.2.3=h9d8b166_3
  - xorg-kbproto=1.0.7=h7f98852_1002
  - xorg-libice=1.0.10=h7f98852_0
  - xorg-libsm=1.2.3=hd9c2040_1000
  - xorg-libx11=1.7.2=h7f98852_0
  - xorg-libxau=1.0.9=h7f98852_0
  - xorg-libxdmcp=1.1.3=h7f98852_0
  - xorg-libxext=1.3.4=h7f98852_1
  - xorg-libxrender=0.9.10=h7f98852_1003
  - xorg-libxt=1.2.1=h7f98852_2
  - xorg-renderproto=0.11.1=h7f98852_1002
  - xorg-xextproto=7.3.0=h7f98852_1002
  - xorg-xproto=7.0.31=h7f98852_1007
  - xz=5.6.4=h5eee18b_1
  - zeromq=4.3.4=h9c3ff4c_1
  - zipp=3.15.0=pyhd8ed1ab_0
  - zlib=1.2.13=h5eee18b_1
  - zstd=1.5.0=ha95c52a_0
prefix: /opt/conda/envs/pygmt

pygmt/tests/test_plot3d.py::test_plot3d_red_circles_zscale[png] pygmt/tests/test_plot3d.py::test_plot3d_red_circles_zsize[png] pygmt/tests/test_plot3d.py::test_plot3d_fail_no_data pygmt/tests/test_plot3d.py::test_plot3d_fail_size_color pygmt/tests/test_plot3d.py::test_plot3d_projection[png] pygmt/tests/test_plot3d.py::test_plot3d_colors[png] pygmt/tests/test_plot3d.py::test_plot3d_sizes[png] pygmt/tests/test_plot3d.py::test_plot3d_colors_sizes[png] pygmt/tests/test_plot3d.py::test_plot3d_colors_sizes_proj[png] pygmt/tests/test_plot3d.py::test_plot3d_transparency[png] pygmt/tests/test_plot3d.py::test_plot3d_varying_transparency[png] pygmt/tests/test_plot3d.py::test_plot3d_sizes_colors_transparencies[png] pygmt/tests/test_plot3d.py::test_plot3d_matrix[png] pygmt/tests/test_plot3d.py::test_plot3d_matrix_color[png] pygmt/tests/test_plot3d.py::test_plot3d_from_file[png] pygmt/tests/test_plot3d.py::test_plot3d_vectors[png] pygmt/tests/test_plot3d.py::test_plot3d_scalar_xyz[png]
pygmt/tests/test_plot.py::test_plot_red_circles pygmt/tests/test_plot.py::test_plot_fail_no_data pygmt/tests/test_plot.py::test_plot_fail_size_color pygmt/tests/test_plot.py::test_plot_projection pygmt/tests/test_plot.py::test_plot_colors[png] pygmt/tests/test_plot.py::test_plot_sizes pygmt/tests/test_plot.py::test_plot_colors_sizes pygmt/tests/test_plot.py::test_plot_colors_sizes_proj pygmt/tests/test_plot.py::test_plot_transparency[png] pygmt/tests/test_plot.py::test_plot_varying_transparency[png] pygmt/tests/test_plot.py::test_plot_sizes_colors_transparencies[png] pygmt/tests/test_plot.py::test_plot_matrix pygmt/tests/test_plot.py::test_plot_matrix_color pygmt/tests/test_plot.py::test_plot_from_file pygmt/tests/test_plot.py::test_plot_vectors pygmt/tests/test_plot.py::test_plot_lines_with_arrows pygmt/tests/test_plot.py::test_plot_scalar_xy pygmt/tests/test_plot.py::test_plot_datetime
examples/gallery/plot/scatter3d.py doc/api/index.rst pygmt/base_plotting.py
examples/gallery/plot/scatter3d.py doc/api/index.rst pygmt/base_plotting.py