Repository: GenericMappingTools/pygmt

Issue:
Varying transparency levels for plot, plot3d and text
**Description of the desired feature**

#614 added the `transparency` argument to all plotting functions. In most functions, `transparency` can be an int/float value in 0-100. For a few functions (plot, plot3d and text), transparency can be a list to have varying transparency for symbols and texts.

We should extend these functions to support the varying transparency feature.

**Are you willing to help implement and maintain this feature?** Yes


Discussion:
seisman: /format
seisman: > Style checks are failing, and we really need to refactor this `text` function (along with #483).
> 
> ```
> pygmt/base_plotting.py:1377:4: R0914: Too many local variables (16/15) (too-many-locals)
> pygmt/base_plotting.py:1377:4: R0912: Too many branches (13/12) (too-many-branches)
> ```

Yes, let's leave it to future PRs.

Patch:
diff --git a/pygmt/base_plotting.py b/pygmt/base_plotting.py
index 2a908b18..a203def4 100644
--- a/pygmt/base_plotting.py
+++ b/pygmt/base_plotting.py
@@ -1481,6 +1481,10 @@ class BasePlotting:
         {p}
         {t}
         """
+
+        # pylint: disable=too-many-locals
+        # pylint: disable=too-many-branches
+
         kwargs = self._preprocess(**kwargs)
 
         # Ensure inputs are either textfiles, x/y/text, or position/text
@@ -1515,6 +1519,13 @@ class BasePlotting:
         if position is not None and isinstance(position, str):
             kwargs["F"] += f'+c{position}+t"{text}"'
 
+        extra_arrays = []
+        # If an array of transparency is given, GMT will read it from
+        # the last numerical column per data record.
+        if "t" in kwargs and is_nonstr_iter(kwargs["t"]):
+            extra_arrays.append(kwargs["t"])
+            kwargs["t"] = ""
+
         with Session() as lib:
             file_context = dummy_context(textfiles) if kind == "file" else ""
             if kind == "vectors":
@@ -1522,7 +1533,10 @@ class BasePlotting:
                     file_context = dummy_context("")
                 else:
                     file_context = lib.virtualfile_from_vectors(
-                        np.atleast_1d(x), np.atleast_1d(y), np.atleast_1d(text)
+                        np.atleast_1d(x),
+                        np.atleast_1d(y),
+                        *extra_arrays,
+                        np.atleast_1d(text),
                     )
             with file_context as fname:
                 arg_str = " ".join([fname, build_arg_string(kwargs)])


Test patch:
diff --git a/pygmt/tests/test_text.py b/pygmt/tests/test_text.py
index 26e45f8f..e267a8bf 100644
--- a/pygmt/tests/test_text.py
+++ b/pygmt/tests/test_text.py
@@ -5,10 +5,12 @@ Tests text
 import os
 
 import pytest
+import numpy as np
 
 from .. import Figure
 from ..exceptions import GMTCLibError, 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")
@@ -295,3 +297,44 @@ def test_text_angle_font_justify_from_textfile():
             justify=True,
         )
     return fig
+
+
+@check_figures_equal()
+def test_text_transparency():
+    "Add texts with a constant transparency"
+    x = np.arange(1, 10)
+    y = np.arange(11, 20)
+    text = [f"TEXT-{i}-{j}" for i, j in zip(x, y)]
+
+    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, text], fmt="%s")
+        fig_ref.basemap(R="0/10/10/20", J="X10c", B="")
+        fig_ref.text(textfiles=tmpfile.name, t=50)
+
+    fig_test.basemap(region=[0, 10, 10, 20], projection="X10c", frame=True)
+    fig_test.text(x=x, y=y, text=text, transparency=50)
+
+    return fig_ref, fig_test
+
+
+@check_figures_equal()
+def test_text_varying_transparency():
+    "Add texts with varying transparency"
+    x = np.arange(1, 10)
+    y = np.arange(11, 20)
+    text = [f"TEXT-{i}-{j}" for i, j in zip(x, y)]
+    transparency = np.arange(10, 100, 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, transparency, text], fmt="%s")
+        fig_ref.basemap(R="0/10/10/20", J="X10c", B="")
+        fig_ref.text(textfiles=tmpfile.name, t="")
+
+    fig_test.basemap(region=[0, 10, 10, 20], projection="X10c", frame=True)
+    fig_test.text(x=x, y=y, text=text, transparency=transparency)
+
+    return fig_ref, fig_test