68
68
69
69
DIRECTIONS = ["GMT_IN" , "GMT_OUT" ]
70
70
71
- MODES = ["GMT_CONTAINER_ONLY" , "GMT_IS_OUTPUT" ]
71
+ MODES = [
72
+ "GMT_CONTAINER_AND_DATA" , # Create/Read/Write both container and the data array
73
+ "GMT_CONTAINER_ONLY" , # Cread/Read/Write the container but no data array
74
+ "GMT_DATA_ONLY" , # Create/Read/Write the container's data array only
75
+ "GMT_IS_OUTPUT" , # For creating a resource as a container for output
76
+ ]
72
77
MODE_MODIFIERS = [
73
- "GMT_GRID_IS_CARTESIAN" ,
74
- "GMT_GRID_IS_GEO" ,
75
- "GMT_WITH_STRINGS" ,
78
+ "GMT_GRID_IS_CARTESIAN" , # Grid is not geographic but Cartesian
79
+ "GMT_GRID_IS_GEO" , # Grid is geographic, not Cartesian
80
+ "GMT_WITH_STRINGS" , # Allocate string array for GMT_DATASET/GMT_VECTOR/GMT_MATRIX
76
81
]
77
82
78
- REGISTRATIONS = ["GMT_GRID_PIXEL_REG " , "GMT_GRID_NODE_REG " ]
83
+ REGISTRATIONS = ["GMT_GRID_NODE_REG " , "GMT_GRID_PIXEL_REG " ]
79
84
80
85
DTYPES = {
81
86
np .int8 : "GMT_CHAR" ,
@@ -643,53 +648,109 @@ def call_module(self, module: str, args: str | list[str]):
643
648
644
649
def create_data (
645
650
self ,
646
- family ,
647
- geometry ,
648
- mode ,
649
- dim = None ,
650
- ranges = None ,
651
- inc = None ,
652
- registration = "GMT_GRID_NODE_REG" ,
653
- pad = None ,
654
- ):
651
+ family : str ,
652
+ geometry : str ,
653
+ mode : str ,
654
+ dim : Sequence [int ] | None = None ,
655
+ ranges : Sequence [float ] | None = None ,
656
+ inc : Sequence [float ] | None = None ,
657
+ registration : Literal [
658
+ "GMT_GRID_NODE_REG" , "GMT_GRID_PIXEL_REG"
659
+ ] = "GMT_GRID_NODE_REG" ,
660
+ pad : int | None = None ,
661
+ ) -> ctp .c_void_p :
655
662
"""
656
- Create an empty GMT data container.
663
+ Create an empty GMT data container and allocate space to hold data.
664
+
665
+ Valid data families and geometries are in ``FAMILIES`` and ``GEOMETRIES``.
666
+
667
+ There are two ways to define the dimensions needed to actually allocate memory:
668
+
669
+ 1. Via ``ranges``, ``inc`` and ``registration``.
670
+ 2. Via ``dim`` and ``registration``.
671
+
672
+ ``dim`` contains up to 4 values and they have different meanings for
673
+ diffenrent GMT data family:
674
+
675
+ For ``GMT_DATASET``:
676
+
677
+ - 0: number of tables
678
+ - 1: number of segments per table
679
+ - 2: number of rows per segment
680
+ - 3: number of columns per row
681
+
682
+ For ``GMT_VECTOR``:
683
+
684
+ - 0: number of columns
685
+ - 1: number of rows [optional, can be 0 if unknown]
686
+ - 2: data type (e.g., ``GMT_DOUBLE``) [Will be override by ``put_vector``]
687
+
688
+ For ``GMT_GRID``/``GMT_IMAGE``/``GMT_CUBE``/``GMT_MATRIX``:
689
+
690
+ - 0: number of columns
691
+ - 1: number of rows
692
+ - 2: number of bands or layers [Ignored for ``GMT_GRID``]
693
+ - 3: data type (e.g., ``GMT_DOUBLE``) [For ``GMT_MATRIX`` only, but will be
694
+ override by ``put_matrix``]
695
+
696
+ In other words, ``inc`` are assumned to be 1.0, and ``ranges`` are
697
+ [0, dim[0], 0, dim[1]] for pixel registration or
698
+ [0, dim[0]-1.0, 0, dim[1]-1.0] for grid registration.
699
+
700
+
701
+ When creating a grid/image/cube, you can do it in one or two steps:
702
+
703
+ 1. Call this function with ``mode="GMT_CONTAINER_AND_DATA"``. This creates
704
+ header and allocates grid|image
705
+ 2. Call this function twice:
706
+
707
+ 1. First with ``mode="GMT_CONTAINER_ONLY"``, to creates header only and
708
+ computes the dimensions based on other parameters
709
+ 2. Second with ``mode="GMT_DATA_ONLY"``, to allocate the grid/image/cube
710
+ array based on the dimensions already set. This time, you pass NULL for
711
+ ``dim``/``ranges``/``inc``/``registration``/``pad`` and let ``data`` be
712
+ the void pointer returned in the first step.
713
+
714
+ **NOTES**: This is not implmented yet, since this function doesn't have the
715
+ ``data`` parameter.
657
716
658
717
Parameters
659
718
----------
660
- family : str
661
- A valid GMT data family name (e.g., ``'GMT_IS_DATASET'``). See the
662
- ``FAMILIES`` attribute for valid names.
663
- geometry : str
664
- A valid GMT data geometry name (e.g., ``'GMT_IS_POINT'``). See the
665
- ``GEOMETRIES`` attribute for valid names.
666
- mode : str
667
- A valid GMT data mode (e.g., ``'GMT_IS_OUTPUT'``). See the
668
- ``MODES`` attribute for valid names.
669
- dim : list of 4 integers
670
- The dimensions of the dataset. See the documentation for the GMT C
671
- API function ``GMT_Create_Data`` (``src/gmt_api.c``) for the full
672
- range of options regarding 'dim'. If ``None``, will pass in the
673
- NULL pointer.
674
- ranges : list of 4 floats
675
- The dataset extent. Also a bit of a complicated argument. See the C
676
- function documentation. It's called ``range`` in the C function but
677
- it would conflict with the Python built-in ``range`` function.
678
- inc : list of 2 floats
679
- The increments between points of the dataset. See the C function
680
- documentation.
681
- registration : str
682
- The node registration (what the coordinates mean). Can be
683
- ``'GMT_GRID_PIXEL_REG'`` or ``'GMT_GRID_NODE_REG'``. Defaults to
684
- ``'GMT_GRID_NODE_REG'``.
685
- pad : int
686
- The grid padding. Defaults to ``GMT_PAD_DEFAULT``.
719
+ family
720
+ A valid GMT data family name (e.g., ``"GMT_IS_DATASET"``). See ``FAMILIES``
721
+ for valid names.
722
+ geometry
723
+ A valid GMT data geometry name (e.g., ``"GMT_IS_POINT"``). See
724
+ ``GEOMETRIES`` for valid names.
725
+ mode
726
+ A valid GMT data mode. See ``MODES`` for valid names. For
727
+ ``GMT_IS_DATASET``/``GMT_IS_MATRIX``/``GMT_IS_VECTOR``, adding
728
+ ``GMT_WITH_STRINGS`` to the ``mode`` will allocate the corresponding arrays
729
+ of string pointers.
730
+ dim
731
+ The dimensions of the dataset, as explained above. If ``None``, will pass in
732
+ the NULL pointer.
733
+ ranges
734
+ The data extent.
735
+ inc
736
+ The increments between points of the dataset.
737
+ registration
738
+ The node registration. Can be ``"GMT_GRID_PIXEL_REG"`` or
739
+ ``"GMT_GRID_NODE_REG"``.
740
+ pad
741
+ The padding for ``GMT_IS_GRID``/``GMT_IS_IMAGE``/``GMT_IS_CUBE``. If
742
+ ``None``, defaults to ``"GMT_PAD_DEFAULT"``.
743
+
744
+ For ``GMT_IS_MATRIX``, it can be:
745
+
746
+ - 0: default row/col orientation [Default]
747
+ - 1: row-major format (C)
748
+ - 2: column-major format (FORTRAN)
687
749
688
750
Returns
689
751
-------
690
- data_ptr : int
691
- A ctypes pointer (an integer) to the allocated ``GMT_Dataset``
692
- object.
752
+ data_ptr
753
+ A ctypes pointer (an integer) to the allocated GMT data container.
693
754
"""
694
755
c_create_data = self .get_libgmt_func (
695
756
"GMT_Create_Data" ,
@@ -703,8 +764,8 @@ def create_data(
703
764
ctp .POINTER (ctp .c_double ), # inc
704
765
ctp .c_uint , # registration
705
766
ctp .c_int , # pad
706
- ctp .c_void_p ,
707
- ], # data
767
+ ctp .c_void_p , # data
768
+ ],
708
769
restype = ctp .c_void_p ,
709
770
)
710
771
@@ -717,15 +778,14 @@ def create_data(
717
778
geometry_int = self ._parse_constant (geometry , valid = GEOMETRIES )
718
779
registration_int = self ._parse_constant (registration , valid = REGISTRATIONS )
719
780
720
- # Convert dim, ranges, and inc to ctypes arrays if given (will be None
721
- # if not given to represent NULL pointers)
781
+ # Convert dim, ranges, and inc to ctypes arrays if given (will be None if not
782
+ # given to represent NULL pointers)
722
783
dim = sequence_to_ctypes_array (dim , ctp .c_uint64 , 4 )
723
784
ranges = sequence_to_ctypes_array (ranges , ctp .c_double , 4 )
724
785
inc = sequence_to_ctypes_array (inc , ctp .c_double , 2 )
725
786
726
- # Use a NULL pointer (None) for existing data to indicate that the
727
- # container should be created empty. Fill it in later using put_vector
728
- # and put_matrix.
787
+ # Use a NULL pointer (None) for existing data to indicate that the container
788
+ # should be created empty. Fill it in later using put_vector and put_matrix.
729
789
data_ptr = c_create_data (
730
790
self .session_pointer ,
731
791
family_int ,
@@ -740,8 +800,8 @@ def create_data(
740
800
)
741
801
742
802
if data_ptr is None :
743
- raise GMTCLibError ( "Failed to create an empty GMT data pointer." )
744
-
803
+ msg = "Failed to create an empty GMT data pointer."
804
+ raise GMTCLibError ( msg )
745
805
return data_ptr
746
806
747
807
def _parse_pad (self , family , pad ):
@@ -1253,7 +1313,7 @@ def open_virtualfile(
1253
1313
... family=family,
1254
1314
... geometry=geometry,
1255
1315
... mode="GMT_CONTAINER_ONLY",
1256
- ... dim=[2, 5, 1 , 0], # columns, lines, segments, type
1316
+ ... dim=[2, 5, self["GMT_INT"] , 0], # ncolumns, nrows, dtype, unused
1257
1317
... )
1258
1318
... lib.put_vector(dataset, column=0, vector=x)
1259
1319
... lib.put_vector(dataset, column=1, vector=y)
@@ -1404,7 +1464,10 @@ def virtualfile_from_vectors(self, *vectors):
1404
1464
geometry = "GMT_IS_POINT"
1405
1465
1406
1466
dataset = self .create_data (
1407
- family , geometry , mode = "GMT_CONTAINER_ONLY" , dim = [columns , rows , 1 , 0 ]
1467
+ family ,
1468
+ geometry ,
1469
+ mode = "GMT_CONTAINER_ONLY" ,
1470
+ dim = [columns , rows , self ["GMT_DOUBLE" ], 0 ],
1408
1471
)
1409
1472
1410
1473
# Use put_vector for columns with numerical type data
@@ -1496,12 +1559,13 @@ def virtualfile_from_matrix(self, matrix):
1496
1559
# closed.
1497
1560
matrix = np .ascontiguousarray (matrix )
1498
1561
rows , columns = matrix .shape
1562
+ layers = 1
1499
1563
1500
1564
family = "GMT_IS_DATASET|GMT_VIA_MATRIX"
1501
1565
geometry = "GMT_IS_POINT"
1502
1566
1503
1567
dataset = self .create_data (
1504
- family , geometry , mode = "GMT_CONTAINER_ONLY" , dim = [columns , rows , 1 , 0 ]
1568
+ family , geometry , mode = "GMT_CONTAINER_ONLY" , dim = [columns , rows , layers , 0 ]
1505
1569
)
1506
1570
1507
1571
self .put_matrix (dataset , matrix )
0 commit comments