Exemple #1
0
 def test_write_to_rootgrp(self):
     crs = CoordinateReferenceSystem(epsg=4326, name='hello_world')
     path = os.path.join(self.current_dir_output, 'foo.nc')
     with nc_scope(path, 'w') as ds:
         variable = crs.write_to_rootgrp(ds)
         self.assertIsInstance(variable, nc.Variable)
Exemple #2
0
    def test_add_shapefile_unique_identifier(self):
        in_path = os.path.join(self.current_dir_output, 'foo_in.shp')

        # create a shapefile without a ugid and another integer attribute
        data = [{
            'geom': Point(1, 2),
            'fid': 6
        }, {
            'geom': Point(2, 3),
            'fid': 60
        }]
        crs = Spherical()
        driver = 'ESRI Shapefile'
        schema = {'properties': {'fid': 'int'}, 'geometry': 'Point'}
        with fiona.open(in_path,
                        'w',
                        driver=driver,
                        crs=crs.value,
                        schema=schema) as source:
            for xx in data:
                record = {
                    'properties': {
                        'fid': xx['fid']
                    },
                    'geometry': mapping(xx['geom'])
                }
                source.write(record)

        out_path = os.path.join(self.current_dir_output, 'foo_out.shp')
        add_shapefile_unique_identifier(in_path, out_path)

        sci = GeomCabinetIterator(path=out_path)
        records = list(sci)
        self.assertAsSetEqual([1, 2], [
            xx['properties'][OCGIS_UNIQUE_GEOMETRY_IDENTIFIER]
            for xx in records
        ])
        self.assertAsSetEqual([6, 60],
                              [xx['properties']['fid'] for xx in records])
        self.assertEqual(CoordinateReferenceSystem(records[0]['meta']['crs']),
                         crs)

        # test it works for the current working directory
        cwd = os.getcwd()
        os.chdir(self.current_dir_output)
        try:
            add_shapefile_unique_identifier(in_path, 'foo3.shp')
            self.assertTrue(
                os.path.exists(
                    os.path.join(self.current_dir_output, 'foo3.shp')))
        finally:
            os.chdir(cwd)

        # test using a template attribute
        out_path = os.path.join(self.current_dir_output, 'template.shp')
        add_shapefile_unique_identifier(in_path, out_path, template='fid')
        sci = GeomCabinetIterator(path=out_path)
        records = list(sci)
        self.assertAsSetEqual([6, 60], [
            xx['properties'][OCGIS_UNIQUE_GEOMETRY_IDENTIFIER]
            for xx in records
        ])

        # test with a different name attribute
        out_path = os.path.join(self.current_dir_output, 'name.shp')
        add_shapefile_unique_identifier(in_path,
                                        out_path,
                                        template='fid',
                                        name='new_id')
        with fiona.open(out_path) as sci:
            records = list(sci)
        self.assertAsSetEqual([6, 60],
                              [xx['properties']['new_id'] for xx in records])
Exemple #3
0
    def from_records(cls, records, schema=None, crs=UNINITIALIZED, uid=None, union=False, data_model=None):
        """
        Create a :class:`~ocgis.Field` from Fiona-like records.

        :param records: A sequence of records returned from an Fiona file object.
        :type records: `sequence` of :class:`dict`
        :param schema: A Fiona-like schema dictionary. If ``None`` and any records properties are ``None``, then this
         must be provided.
        :type schema: dict

        >>> schema = {'geometry': 'Point', 'properties': {'UGID': 'int', 'NAME', 'str:4'}}

        :param crs: If :attr:`ocgis.constants.UNINITIALIZED`, default to :attr:`ocgis.env.DEFAULT_COORDSYS`.
        :type crs: :class:`dict` | :class:`~ocgis.variable.crs.AbstractCoordinateReferenceSystem`
        :param str uid: If provided, use this attribute name as the unique identifier. Otherwise search for
         :attr:`env.DEFAULT_GEOM_UID` and, if not present, construct a 1-based identifier with this name.
        :param bool union: If ``True``, union the geometries from records yielding a single geometry with a unique
         identifier value of ``1``.
        :param str data_model: See :meth:`~ocgis.driver.nc.create_typed_variable_from_data_model`.
        :returns: Field object constructed from records.
        :rtype: :class:`~ocgis.Field`
        """

        if uid is None:
            uid = env.DEFAULT_GEOM_UID

        if isinstance(crs, dict):
            crs = CoordinateReferenceSystem(value=crs)
        elif crs == UNINITIALIZED:
            crs = env.DEFAULT_COORDSYS

        if union:
            deque_geoms = None
            deque_uid = [1]
        else:
            # Holds geometry objects.
            deque_geoms = deque()
            # Holds unique identifiers.
            deque_uid = deque()

        build = True
        for ctr, record in enumerate(records, start=1):

            # Get the geometry from a keyword present on the input dictionary or construct from the coordinates
            # sequence.
            try:
                current_geom = record['geom']
            except KeyError:
                current_geom = shape(record['geometry'])

            if union:
                if build:
                    deque_geoms = current_geom
                else:
                    deque_geoms = deque_geoms.union(current_geom)
            else:
                deque_geoms.append(current_geom)

            # Set up the properties array
            if build:
                build = False

                if uid in record['properties']:
                    has_uid = True
                else:
                    has_uid = False

            # The geometry unique identifier may be present as a property. Otherwise the enumeration counter is used for
            # the identifier.
            if not union:
                if has_uid:
                    to_append = int(record['properties'][uid])
                else:
                    to_append = ctr
                deque_uid.append(to_append)

        # If we are unioning, the target geometry is not yet a sequence.
        if union:
            deque_geoms = [deque_geoms]

        # Dimension for the outgoing field.
        if union:
            size = 1
        else:
            size = ctr
        dim = Dimension(name=DimensionName.GEOMETRY_DIMENSION, size=size)

        # Set default geometry type if no schema is provided.
        if schema is None:
            geom_type = 'auto'
        else:
            geom_type = schema['geometry']

        geom = GeometryVariable(value=deque_geoms, geom_type=geom_type, dimensions=dim)
        uid = create_typed_variable_from_data_model('int', data_model=data_model, name=uid, value=deque_uid,
                                                    dimensions=dim)
        geom.set_ugid(uid)

        field = Field(geom=geom, crs=crs)

        # All records from a unioned geometry are not relevant.
        if not union:
            from ocgis.driver.vector import get_dtype_from_fiona_type, get_fiona_type_from_pydata

            if schema is None:
                has_schema = False
            else:
                has_schema = True

            for idx, record in enumerate(records):
                if idx == 0 and not has_schema:
                    schema = {'properties': OrderedDict()}
                    for k, v in list(record['properties'].items()):
                        schema['properties'][k] = get_fiona_type_from_pydata(v)
                if idx == 0:
                    for k, v in list(schema['properties'].items()):
                        if k == uid.name:
                            continue
                        dtype = get_dtype_from_fiona_type(v, data_model=data_model)
                        var = Variable(name=k, dtype=dtype, dimensions=dim)
                        field.add_variable(var)
                for k, v in list(record['properties'].items()):
                    if k == uid.name:
                        continue

                    field[k].get_value()[idx] = v

        data_variables = [uid.name]
        if not union:
            data_variables += [k for k in list(schema['properties'].keys()) if k != uid.name]
        field.append_to_tags(TagName.DATA_VARIABLES, data_variables, create=True)

        return field
Exemple #4
0
 def _parse_string_(self, value):
     return CoordinateReferenceSystem(epsg=int(value))