.. _tattributefields: Attribute Fields ________________ A field contains field name, field type and further field characteristics which depend on the field type, like for example the field precision for decimal numbers. Geometry fields are distinguished from other fields and treated separately. Non geometry fields are denominated here attribute fields. Fields are retrieved from layer definitions and are therefore layer dependent. Layer number zero is the retrieved layer whenever the layer number is not explicitly given. Fields are described by ``osgeo.ogr.FieldDefn``. It produces unexpected behaviour if not used correctly. For example, altough the program does not crash in the emphasized lines of the code block below, it shows a wrong output "S". .. code-block:: python :emphasize-lines: 13, 14 from osgeo import ogr dataset = ogr.Open('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp', 0) # open read-only if dataset is None: raise ValueError('Could not open {}'.format('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp')) lyr = dataset.GetLayer(0) print lyr ldf = lyr.GetLayerDefn() print ldf fd = ldf.GetFieldDefn(0) print 'Field name: {}'.format(fd.GetName()) print fd del dataset # This causes the problem print 'Field name: {}'.format(fd.GetName()) print fd # it does not crash but shows a wrong output "S" Output:: > > Field name: ID_0 > Field name: S > Class FieldDefinition ^^^^^^^^^^^^^^^^^^^^^ The ``girs`` class ``girs.feat.layers.FieldDefinition`` stores field properties obtained from ``osgeo.ogr.FieldDefn``, avoiding unexpected behaviours. The class has the following attributes:: class FieldDefinition: - name - oft_type - width - precision - oft_subtype - nullable - default Field properties ^^^^^^^^^^^^^^^^ Number of fields """""""""""""""" .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_count() # layer number 0 print lrs.get_field_count(layer_number=0) # same result Field names """"""""""" .. code-block:: python def ex02_field_names(): from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_names() Output:: ['ID_0', 'ISO', 'NAME_0', 'ID_1', 'NAME_1', 'ID_2', 'NAME_2', 'ID_3', 'NAME_3', 'ID_4', 'NAME_4', 'VARNAME_4', 'CCN_4', 'CCA_4', 'TYPE_4', 'ENGTYPE_4'] Field numbers """"""""""""" Fields are numbered from 0 to n-1, where n is the number of fields in a layer (see `get_field_count()`). In order to get the field number (also called field index): .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_numbers(['NAME_0', 'NAME_1', 'NAME_2', 'NAME_3', 'NAME_4']) # layer 0 Output:: [2, 4, 6, 8, 10] Field definition """""""""""""""" .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_definition('NAME_0') print lrs.get_field_definition('NAME_0', layer_number=0) # same result Field definitions """"""""""""""""" .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_definitions(field_names=['NAME_0', 'NAME_1']) print lrs.get_field_definitions() Output:: [NAME_0 (String), NAME_1 (String)] [ID_0 (Integer64), ISO (String), NAME_0 (String), ID_1 (Integer64), NAME_1 (String), ID_2 (Integer64), NAME_2 (String), ID_3 (Integer64), NAME_3 (String), ID_4 (Integer64), NAME_4 (String), VARNAME_4 (String), CCN_4 (Integer64), CCA_4 (String), TYPE_4 (String), ENGTYPE_4 (String)] Field definitions as data frame """"""""""""""""""""""""""""""" A full description of all fields in a layer is shown with ``get_field_definitions_data_frame()``: .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_definitions_data_frame() Output:: name type type_name width precision subtype subtype_name nullable default 0 ID_0 12 Integer64 10 0 0 None 1 None 1 ISO 4 String 3 0 0 None 1 None 2 NAME_0 4 String 75 0 0 None 1 None 3 ID_1 12 Integer64 10 0 0 None 1 None 4 NAME_1 4 String 75 0 0 None 1 None 5 ID_2 12 Integer64 10 0 0 None 1 None 6 NAME_2 4 String 75 0 0 None 1 None 7 ID_3 12 Integer64 10 0 0 None 1 None 8 NAME_3 4 String 75 0 0 None 1 None 9 ID_4 12 Integer64 10 0 0 None 1 None 10 NAME_4 4 String 100 0 0 None 1 None 11 VARNAME_4 4 String 100 0 0 None 1 None 12 CCN_4 12 Integer64 10 0 0 None 1 None 13 CCA_4 4 String 20 0 0 None 1 None 14 TYPE_4 4 String 35 0 0 None 1 None 15 ENGTYPE_4 4 String 35 0 0 None 1 None field values """""""""""" Field values return a pandas DataFrame indexed by feature ids. It does not include the geometry field. .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') print lrs.get_field_values(field_names=['NAME_1', 'NAME_2', 'NAME_3']) Output:: NAME_1 NAME_2 NAME_3 FID 0 Baden-Württemberg Alb-Donau-Kreis Allmendingen 1 Baden-Württemberg Alb-Donau-Kreis Allmendingen 2 Baden-Württemberg Alb-Donau-Kreis Blaubeuren ... ... ... ... 11299 Thüringen Weimarer Land Nordkreis Weimar 11300 Thüringen Weimarer Land Nordkreis Weimar 11301 Thüringen Weimar Weimar OGR field definitions """"""""""""""""""""" If it is necessary to work with instances of ``osgeo.ogr.FieldDefn``, the less error prone way is to use the method `fields(layer_number)`, which is an iterator through all fields in layer definition: Better not using it: .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') for fd in lrs.fields(layer_number=0): print fd.GetName() # don't use fd outside the loop if lrs is deleted! Use instead: .. code-block:: python from girs.feat.layers import LayersReader lrs = LayersReader('D:/tmp/girs/DEU_adm_shp/DEU_adm4.shp') for field_name in lrs.get_field_names(): print field_name