Repository: GenericMappingTools/pygmt

Issue:
uint8 datatype issue
**Description of the problem**

 I read an image of uint8 datatype with `rioxarray.open_rasterio` and plot with pygmt raise errors.

If I convert datatype to float, my script runs fluently.


**Full error message**

```
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 3552, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-2-cbda221bbf05>", line 1, in <module>
    runfile('D:/NutSync/code/funcs_lib_dg/plot_func/plot_raster_pygmt.py', wdir='D:/NutSync/code/funcs_lib_dg/plot_func')
  File "C:\Program Files\JetBrains\PyCharm 2020.1\plugins\python\helpers\pydev\_pydev_bundle\pydev_umd.py", line 197, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "C:\Program Files\JetBrains\PyCharm 2020.1\plugins\python\helpers\pydev\_pydev_imps\_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "D:/NutSync/code/funcs_lib_dg/plot_func/plot_raster_pygmt.py", line 307, in <module>
    xrd = main()
  File "D:/NutSync/code/funcs_lib_dg/plot_func/plot_raster_pygmt.py", line 301, in main
    rastr_plot.plot_raster_grid(figname=figname)
  File "D:/NutSync/code/funcs_lib_dg/plot_func/plot_raster_pygmt.py", line 99, in plot_raster_grid
    cmap=cpt
  File "C:\ProgramData\Anaconda3\lib\site-packages\pygmt\helpers\decorators.py", line 586, in new_module
    return module_func(*args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pygmt\helpers\decorators.py", line 726, in new_module
    return module_func(*args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pygmt\src\grdimage.py", line 173, in grdimage
    fname = stack.enter_context(file_context)
  File "C:\ProgramData\Anaconda3\lib\contextlib.py", line 427, in enter_context
    result = _cm_type.__enter__(cm)
  File "C:\ProgramData\Anaconda3\lib\contextlib.py", line 112, in __enter__
    return next(self.gen)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pygmt\clib\session.py", line 1341, in virtualfile_from_grid
    self.put_matrix(gmt_grid, matrix)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pygmt\clib\session.py", line 895, in put_matrix
    raise GMTCLibError(f"Failed to put matrix of type {matrix.dtype}.")
pygmt.exceptions.GMTCLibError: Failed to put matrix of type uint8.
```

**System information**

 I use pygmt 0.5.0 with python 3.7. 



Discussion:
weiji14: Awesome @seisman! Didn't realize GMT even supported these other dtypes!

Just need to update some tests, e.g. these lines:

https://github.com/GenericMappingTools/pygmt/blob/1067fa316b214d470f26f4affba743a4835a53c8/pygmt/tests/test_clib_put_matrix.py#L18

https://github.com/GenericMappingTools/pygmt/blob/1067fa316b214d470f26f4affba743a4835a53c8/pygmt/tests/test_clib_put_matrix.py#L64

https://github.com/GenericMappingTools/pygmt/blob/1067fa316b214d470f26f4affba743a4835a53c8/pygmt/tests/test_clib_put_vector.py#L19

https://github.com/GenericMappingTools/pygmt/blob/1067fa316b214d470f26f4affba743a4835a53c8/pygmt/tests/test_clib_put_vector.py#L59

Also 6 more lines in test_clib.py. Maybe a good idea to make the `dtypes` list into a pytest fixture, use something like:

Use `dtypes = "int8 int16 int32 int64 uint8 uint16 uint32 uint64 float32 float64".split()`
seisman: Looking at the source code of the `GMT_Put_Matrix` function (https://github.com/GenericMappingTools/gmt/blob/b552be3a3f76455cd45f32202d468d14ce93cd28/src/gmt_api.c#L15458) and the `gmtapi_insert_vector ` function (https://github.com/GenericMappingTools/gmt/blob/b552be3a3f76455cd45f32202d468d14ce93cd28/src/gmt_api.c#L15297), I think only numeric data types are supported.
seisman: > Just as an aside, is there any chance of GMT supporting half precision floats? I.e. [numpy.org/doc/stable/reference/arrays.scalars.html#numpy.float16](https://numpy.org/doc/stable/reference/arrays.scalars.html#numpy.float16), or 2-byte floats. Not sure if it's possible in C, but supporting float16 will be useful for some machine learning workloads that use float16.

I have no idea about float16. Better to open a feature request in the GMT repository.

Patch:
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 7b48f0a0..03902233 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -53,14 +53,18 @@ MODES = ["GMT_CONTAINER_ONLY", "GMT_IS_OUTPUT"]
 REGISTRATIONS = ["GMT_GRID_PIXEL_REG", "GMT_GRID_NODE_REG"]
 
 DTYPES = {
-    np.float64: "GMT_DOUBLE",
-    np.float32: "GMT_FLOAT",
-    np.int64: "GMT_LONG",
+    np.int8: "GMT_CHAR",
+    np.int16: "GMT_SHORT",
     np.int32: "GMT_INT",
-    np.uint64: "GMT_ULONG",
+    np.int64: "GMT_LONG",
+    np.uint8: "GMT_UCHAR",
+    np.uint16: "GMT_USHORT",
     np.uint32: "GMT_UINT",
-    np.datetime64: "GMT_DATETIME",
+    np.uint64: "GMT_ULONG",
+    np.float32: "GMT_FLOAT",
+    np.float64: "GMT_DOUBLE",
     np.str_: "GMT_TEXT",
+    np.datetime64: "GMT_DATETIME",
 }
 
 
@@ -732,8 +736,8 @@ class Session:
         The dataset must be created by :meth:`pygmt.clib.Session.create_data`
         first. Use ``family='GMT_IS_DATASET|GMT_VIA_VECTOR'``.
 
-        Not at all numpy dtypes are supported, only: float64, float32, int64,
-        int32, uint64, uint32, datetime64 and str\_.
+        Not all numpy dtypes are supported, only: int8, int16, int32, int64,
+        uint8, uint16, uint32, uint64, float32, float64, str\_ and datetime64.
 
         .. warning::
             The numpy array must be C contiguous in memory. If it comes from a
@@ -856,8 +860,8 @@ class Session:
         The dataset must be created by :meth:`pygmt.clib.Session.create_data`
         first. Use ``|GMT_VIA_MATRIX'`` in the family.
 
-        Not at all numpy dtypes are supported, only: float64, float32, int64,
-        int32, uint64, and uint32.
+        Not all numpy dtypes are supported, only: int8, int16, int32, int64,
+        uint8, uint16, uint32, uint64, float32 and float64.
 
         .. warning::
             The numpy array must be C contiguous in memory. Use


Test patch:
diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py
index 2e3602d8..d52fb0d9 100644
--- a/pygmt/tests/test_clib.py
+++ b/pygmt/tests/test_clib.py
@@ -36,6 +36,14 @@ def data():
     return np.loadtxt(POINTS_DATA)
 
 
+@pytest.fixture(scope="module", name="dtypes")
+def fixture_dtypes():
+    """
+    List of supported numpy dtypes.
+    """
+    return "int8 int16 int32 int64 uint8 uint16 uint32 uint64 float32 float64".split()
+
+
 @contextmanager
 def mock(session, func, returns=None, mock_func=None):
     """
@@ -339,11 +347,10 @@ def test_create_data_fails():
                 )
 
 
-def test_virtual_file():
+def test_virtual_file(dtypes):
     """
     Test passing in data via a virtual file with a Dataset.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     shape = (5, 3)
     for dtype in dtypes:
         with clib.Session() as lib:
@@ -497,11 +504,10 @@ def test_virtualfile_from_data_fail_non_valid_data(data):
             )
 
 
-def test_virtualfile_from_vectors():
+def test_virtualfile_from_vectors(dtypes):
     """
     Test the automation for transforming vectors to virtual file dataset.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     size = 10
     for dtype in dtypes:
         x = np.arange(size, dtype=dtype)
@@ -588,11 +594,10 @@ def test_virtualfile_from_vectors_diff_size():
                 print("This should have failed")
 
 
-def test_virtualfile_from_matrix():
+def test_virtualfile_from_matrix(dtypes):
     """
     Test transforming a matrix to virtual file dataset.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     shape = (7, 5)
     for dtype in dtypes:
         data = np.arange(shape[0] * shape[1], dtype=dtype).reshape(shape)
@@ -606,11 +611,10 @@ def test_virtualfile_from_matrix():
             assert output == expected
 
 
-def test_virtualfile_from_matrix_slice():
+def test_virtualfile_from_matrix_slice(dtypes):
     """
     Test transforming a slice of a larger array to virtual file dataset.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     shape = (10, 6)
     for dtype in dtypes:
         full_data = np.arange(shape[0] * shape[1], dtype=dtype).reshape(shape)
@@ -627,11 +631,10 @@ def test_virtualfile_from_matrix_slice():
             assert output == expected
 
 
-def test_virtualfile_from_vectors_pandas():
+def test_virtualfile_from_vectors_pandas(dtypes):
     """
     Pass vectors to a dataset using pandas Series.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     size = 13
     for dtype in dtypes:
         data = pd.DataFrame(
diff --git a/pygmt/tests/test_clib_put_matrix.py b/pygmt/tests/test_clib_put_matrix.py
index e5c0bfe6..55a3c33b 100644
--- a/pygmt/tests/test_clib_put_matrix.py
+++ b/pygmt/tests/test_clib_put_matrix.py
@@ -11,11 +11,18 @@ from pygmt.helpers import GMTTempFile
 from pygmt.tests.test_clib import mock
 
 
-def test_put_matrix():
+@pytest.fixture(scope="module", name="dtypes")
+def fixture_dtypes():
+    """
+    List of supported numpy dtypes.
+    """
+    return "int8 int16 int32 int64 uint8 uint16 uint32 uint64 float32 float64".split()
+
+
+def test_put_matrix(dtypes):
     """
     Check that assigning a numpy 2d array to a dataset works.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     shape = (3, 4)
     for dtype in dtypes:
         with clib.Session() as lib:
@@ -57,11 +64,10 @@ def test_put_matrix_fails():
                 lib.put_matrix(dataset=None, matrix=np.empty((10, 2)), pad=0)
 
 
-def test_put_matrix_grid():
+def test_put_matrix_grid(dtypes):
     """
     Check that assigning a numpy 2d array to an ASCII and NetCDF grid works.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     wesn = [10, 15, 30, 40, 0, 0]
     inc = [1, 1]
     shape = ((wesn[3] - wesn[2]) // inc[1] + 1, (wesn[1] - wesn[0]) // inc[0] + 1)
diff --git a/pygmt/tests/test_clib_put_vector.py b/pygmt/tests/test_clib_put_vector.py
index 1d085eb9..de137e13 100644
--- a/pygmt/tests/test_clib_put_vector.py
+++ b/pygmt/tests/test_clib_put_vector.py
@@ -12,11 +12,18 @@ from pygmt.exceptions import GMTCLibError, GMTInvalidInput
 from pygmt.helpers import GMTTempFile
 
 
-def test_put_vector():
+@pytest.fixture(scope="module", name="dtypes")
+def fixture_dtypes():
+    """
+    List of supported numpy dtypes.
+    """
+    return "int8 int16 int32 int64 uint8 uint16 uint32 uint64 float32 float64".split()
+
+
+def test_put_vector(dtypes):
     """
     Check that assigning a numpy array to a dataset works.
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     for dtype in dtypes:
         with clib.Session() as lib:
             dataset = lib.create_data(
@@ -50,13 +57,12 @@ def test_put_vector():
                 npt.assert_allclose(newz, z)
 
 
-def test_put_vector_mixed_dtypes():
+def test_put_vector_mixed_dtypes(dtypes):
     """
     Passing a numpy array of mixed dtypes to a dataset.
 
     See https://github.com/GenericMappingTools/pygmt/issues/255
     """
-    dtypes = "float32 float64 int32 int64 uint32 uint64".split()
     for dtypex, dtypey in itertools.permutations(dtypes, r=2):
         with clib.Session() as lib:
             dataset = lib.create_data(