# Source code for pygrass.utils

    import itertools
    import fnmatch
    import os
    from sqlite3 import OperationalError

    import grass.lib.gis as libgis

    libgis.G_gisinit("")
    import grass.lib.raster as libraster
    from grass.lib.ctypes_preamble import String
    from grass.script import core as grasscore
    from grass.script import utils as grassutils

    from grass.pygrass.errors import GrassError

    test_vector_name = "Utils_test_vector"
    test_raster_name = "Utils_test_raster"

    def looking(obj, filter_string):
        """
        >>> import grass.lib.vector as libvect
        >>> sorted(looking(libvect, '*by_box*'))  # doctest: +NORMALIZE_WHITESPACE
        ['Vect_select_areas_by_box', 'Vect_select_isles_by_box',
         'Vect_select_lines_by_box', 'Vect_select_nodes_by_box']

        """
        word_list = dir(obj)
        word_list.sort()
        return fnmatch.filter(word_list, filter_string)

    def findfiles(dirpath, match=None):
        """Return a list of the files"""
        res = []
        for f in sorted(os.listdir(dirpath)):
            abspath = os.path.join(dirpath, f)
            if os.path.isdir(abspath):
                res.extend(findfiles(abspath, match))

            if match:
                if fnmatch.fnmatch(abspath, match):
                    res.append(abspath)
            else:
                res.append(abspath)
        return res

    def findmaps(type, pattern=None, mapset="", location="", gisdbase=""):
        """Return a list of tuple contining the names of the:

        * map
        * mapset,
        * location,
        * gisdbase

        """
        from grass.pygrass.gis import Gisdbase, Location, Mapset

        def find_in_location(type, pattern, location):
            res = []
            for msetname in location.mapsets():
                mset = Mapset(msetname, location.name, location.gisdbase)
                res.extend(
                    [
                        (m, mset.name, mset.location, mset.gisdbase)
                        for m in mset.glist(type, pattern)
                    ]
                )
            return res

        def find_in_gisdbase(type, pattern, gisdbase):
            res = []
            for loc in gisdbase.locations():
                res.extend(find_in_location(type, pattern, Location(loc, gisdbase.name)))
            return res

        if gisdbase and location and mapset:
            mset = Mapset(mapset, location, gisdbase)
            return [
                (m, mset.name, mset.location, mset.gisdbase)
                for m in mset.glist(type, pattern)
            ]
        elif gisdbase and location:
            loc = Location(location, gisdbase)
            return find_in_location(type, pattern, loc)
        elif gisdbase:
            gis = Gisdbase(gisdbase)
            return find_in_gisdbase(type, pattern, gis)
        elif location:
            loc = Location(location)
            return find_in_location(type, pattern, loc)
        elif mapset:
            mset = Mapset(mapset)
            return [
                (m, mset.name, mset.location, mset.gisdbase)
                for m in mset.glist(type, pattern)
            ]
        else:
            gis = Gisdbase()
            return find_in_gisdbase(type, pattern, gis)

    def remove(oldname, maptype):
        """Remove a map"""
        grasscore.run_command("g.remove", quiet=True, flags="f", type=maptype, name=oldname)

    def rename(oldname, newname, maptype, **kwargs):
        """Rename a map"""
        kwargs.update(
            {
                maptype: "{old},{new}".format(old=oldname, new=newname),
            }
        )
        grasscore.run_command("g.rename", quiet=True, **kwargs)

    def copy(existingmap, newmap, maptype, **kwargs):
        """Copy a map

        >>> copy(test_vector_name, 'mycensus', 'vector')
        >>> rename('mycensus', 'mynewcensus', 'vector')
        >>> remove('mynewcensus', 'vector')

        """
        kwargs.update({maptype: "{old},{new}".format(old=existingmap, new=newmap)})
        grasscore.run_command("g.copy", quiet=True, **kwargs)

    def decode(obj, encoding=None):
        """Decode string coming from c functions,
        can be ctypes class String, bytes, or None
        """
        if isinstance(obj, String):
            return grassutils.decode(obj.data, encoding=encoding)
        elif isinstance(obj, bytes):
            return grassutils.decode(obj)
        else:
            # eg None
            return obj

    def getenv(env):
        """Return the current grass environment variables

        >>> from grass.script.core import gisenv
        >>> getenv("MAPSET") == gisenv()["MAPSET"]
        True

        """
        return decode(libgis.G_getenv_nofatal(env))

    def get_mapset_raster(mapname, mapset=""):
        """Return the mapset of the raster map

        >>> get_mapset_raster(test_raster_name) == getenv("MAPSET")
        True

        """
        return decode(libgis.G_find_raster2(mapname, mapset))

    def get_mapset_vector(mapname, mapset=""):
        """Return the mapset of the vector map

        >>> get_mapset_vector(test_vector_name) == getenv("MAPSET")
        True

        """
        return decode(libgis.G_find_vector2(mapname, mapset))

    def is_clean_name(name):
        """Return if the name is valid

        >>> is_clean_name('census')
        True
        >>> is_clean_name('0census')
        True
        >>> is_clean_name('census?')
        True
        >>> is_clean_name('cénsus')
        False

        """
        if libgis.G_legal_filename(name) < 0:
            return False
        return True

    def coor2pixel(coord, region):
        """Convert coordinates into a pixel row and col

        >>> from grass.pygrass.gis.region import Region
        >>> reg = Region()
        >>> coor2pixel((reg.west, reg.north), reg)
        (0.0, 0.0)
        >>> coor2pixel((reg.east, reg.south), reg) == (reg.rows, reg.cols)
        True

        """
        (east, north) = coord
        return (
            libraster.Rast_northing_to_row(north, region.byref()),
            libraster.Rast_easting_to_col(east, region.byref()),
        )

    def pixel2coor(pixel, region):
        """Convert row and col of a pixel into a coordinates

        >>> from grass.pygrass.gis.region import Region
        >>> reg = Region()
        >>> pixel2coor((0, 0), reg) == (reg.north, reg.west)
        True
        >>> pixel2coor((reg.cols, reg.rows), reg) == (reg.south, reg.east)
        True

        """
        (col, row) = pixel
        return (
            libraster.Rast_row_to_northing(row, region.byref()),
            libraster.Rast_col_to_easting(col, region.byref()),
        )

    def get_raster_for_points(poi_vector, raster, column=None, region=None):
        """Query a raster map for each point feature of a vector

        Example

        >>> from grass.pygrass.raster import RasterRow
        >>> from grass.pygrass.gis.region import Region
        >>> from grass.pygrass.vector import VectorTopo
        >>> from grass.pygrass.vector.geometry import Point

        Create a vector map

        >>> cols = [(u'cat', 'INTEGER PRIMARY KEY'),
        ...         (u'value', 'double precision')]
        >>> vect = VectorTopo("test_vect_2")
        >>> vect.open("w",tab_name="test_vect_2",
        ...           tab_cols=cols)
        >>> vect.write(Point(10, 6), cat=1, attrs=[10, ])
        >>> vect.write(Point(12, 6), cat=2, attrs=[12, ])
        >>> vect.write(Point(14, 6), cat=3, attrs=[14, ])
        >>> vect.table.conn.commit()
        >>> vect.close()

        Setup the raster sampling

        >>> region = Region()
        >>> region.from_rast(test_raster_name)
        >>> region.set_raster_region()
        >>> ele = RasterRow(test_raster_name)

        Sample the raster layer at the given points, return a list of values

        >>> l = get_raster_for_points(vect, ele, region=region)
        >>> l[0]                                        # doctest: +ELLIPSIS
        (1, 10.0, 6.0, 1)
        >>> l[1]                                        # doctest: +ELLIPSIS
        (2, 12.0, 6.0, 1)

        Add a new column and sample again

        >>> vect.open("r")
        >>> vect.table.columns.add(test_raster_name,'double precision')
        >>> vect.table.conn.commit()
        >>> test_raster_name in vect.table.columns
        True
        >>> get_raster_for_points(vect, ele, column=test_raster_name, region=region)
        True
        >>> vect.table.filters.select('value', test_raster_name)
        Filters('SELECT value, Utils_test_raster FROM test_vect_2;')
        >>> cur = vect.table.execute()
        >>> r = cur.fetchall()
        >>> r[0]                                        # doctest: +ELLIPSIS
        (10.0, 1.0)
        >>> r[1]                                        # doctest: +ELLIPSIS
        (12.0, 1.0)
        >>> remove('test_vect_2','vect')

        :param poi_vector: A VectorTopo object that contains points
        :param raster: raster object
        :param str column: column name to update in the attrinute table,
                           if set to None a list of sampled values will be returned
        :param region: The region to work with, if not set the current computational region will be used

        :return: True in case of success and a specified column for update,
                 if column name for update was not set a list of (id, x, y, value) is returned
        """
        from math import isnan

        if not column:
            result = []
        if region is None:
            from grass.pygrass.gis.region import Region

            region = Region()
        if not poi_vector.is_open():
            poi_vector.open("r")
        if not raster.is_open():
            raster.open("r")
        if poi_vector.num_primitive_of("point") == 0:
            raise GrassError(_("Vector doesn't contain points"))

        for poi in poi_vector.viter("points"):
            val = raster.get_value(poi, region)
            if column:
                if val is not None and not isnan(val):
                    poi.attrs[column] = val
            else:
                if val is not None and not isnan(val):
                    result.append((poi.id, poi.x, poi.y, val))
                else:
                    result.append((poi.id, poi.x, poi.y, None))
        if not column:
            return result
        else:
            poi.attrs.commit()
            return True

    def r_export(rast, output="", fmt="png", **kargs):
        from grass.pygrass.modules import Module

        if rast.exist():
            output = output if output else "%s_%s.%s" % (rast.name, rast.mapset, fmt)
            Module(
                "r.out.%s" % fmt,
                input=rast.fullname(),
                output=output,
                overwrite=True,
                **kargs,
            )
            return output
        else:
            raise ValueError("Raster map does not exist.")

    def get_lib_path(modname, libname=None):
        """Return the path of the libname contained in the module.

        .. deprecated:: 7.1
            Use :func:`grass.script.utils.get_lib_path` instead.
        """
        from grass.script.utils import get_lib_path

        return get_lib_path(modname=modname, libname=libname)

    def set_path(modulename, dirname=None, path="."):
        """Set sys.path looking in the the local directory GRASS directories.

        :param modulename: string with the name of the GRASS module
        :param dirname: string with the directory name containing the python
                        libraries, default None
        :param path: string with the path to reach the dirname locally.

        .. deprecated:: 7.1
            Use :func:`grass.script.utils.set_path` instead.
        """
        from grass.script.utils import set_path

        return set_path(modulename=modulename, dirname=dirname, path=path)

    def split_in_chunk(iterable, length=10):
        """Split a list in chunk.

        >>> for chunk in split_in_chunk(range(25)): print (chunk)
        (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
        (10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
        (20, 21, 22, 23, 24)
        >>> for chunk in split_in_chunk(range(25), 3): print (chunk)
        (0, 1, 2)
        (3, 4, 5)
        (6, 7, 8)
        (9, 10, 11)
        (12, 13, 14)
        (15, 16, 17)
        (18, 19, 20)
        (21, 22, 23)
        (24,)
        """
        it = iter(iterable)
        while True:
            chunk = tuple(itertools.islice(it, length))
            if not chunk:
                return
            yield chunk

    def table_exist(cursor, table_name):
        """Return True if the table exist False otherwise"""
        try:
            # sqlite
            cursor.execute(
                "SELECT name FROM sqlite_master"
                " WHERE type='table' AND name='%s';" % table_name
            )
        except OperationalError:
            try:
                # pg
                cursor.execute(
                    "SELECT EXISTS(SELECT * FROM "
                    "information_schema.tables "
                    "WHERE table_name=%s)" % table_name
                )
            except OperationalError:
                return False
        one = cursor.fetchone() if cursor else None
        return True if one and one[0] else False

    def create_test_vector_map(map_name="test_vector"):
        """This functions creates a vector map layer with points, lines, boundaries,
        centroids, areas, isles and attributes for testing purposes

        This should be used in doc and unit tests to create location/mapset
        independent vector map layer. This map includes 3 points, 3 lines,
        11 boundaries and 4 centroids. The attribute table contains cat, name
        and value columns.

         param map_name: The vector map name that should be used

                                   P1 P2 P3
            6                       *  *  *
            5
            4    _______ ___ ___   L1 L2 L3
         Y  3   |A1___ *|  *|  *|   |  |  |
            2   | |A2*| |   |   |   |  |  |
            1   | |___| |A3 |A4 |   |  |  |
            0   |_______|___|___|   |  |  |
           -1
             -1 0 1 2 3 4 5 6 7 8 9 10 12 14
                            X
        """

        from grass.pygrass.vector import VectorTopo
        from grass.pygrass.vector.geometry import Point, Line, Centroid, Boundary

        cols = [
            ("cat", "INTEGER PRIMARY KEY"),
            ("name", "varchar(50)"),
            ("value", "double precision"),
        ]
        with VectorTopo(map_name, mode="w", tab_name=map_name, tab_cols=cols) as vect:

            # Write 3 points
            vect.write(Point(10, 6), cat=1, attrs=("point", 1))
            vect.write(Point(12, 6), cat=1)
            vect.write(Point(14, 6), cat=1)
            # Write 3 lines
            vect.write(Line([(10, 4), (10, 2), (10, 0)]), cat=2, attrs=("line", 2))
            vect.write(Line([(12, 4), (12, 2), (12, 0)]), cat=2)
            vect.write(Line([(14, 4), (14, 2), (14, 0)]), cat=2)
            # boundaries 1 - 4
            vect.write(Boundary(points=[(0, 0), (0, 4)]))
            vect.write(Boundary(points=[(0, 4), (4, 4)]))
            vect.write(Boundary(points=[(4, 4), (4, 0)]))
            vect.write(Boundary(points=[(4, 0), (0, 0)]))
            # 5. boundary (Isle)
            vect.write(Boundary(points=[(1, 1), (1, 3), (3, 3), (3, 1), (1, 1)]))
            # boundaries 6 - 8
            vect.write(Boundary(points=[(4, 4), (6, 4)]))
            vect.write(Boundary(points=[(6, 4), (6, 0)]))
            vect.write(Boundary(points=[(6, 0), (4, 0)]))
            # boundaries 9 - 11
            vect.write(Boundary(points=[(6, 4), (8, 4)]))
            vect.write(Boundary(points=[(8, 4), (8, 0)]))
            vect.write(Boundary(points=[(8, 0), (6, 0)]))
            # Centroids, all have the same cat and attribute
            vect.write(Centroid(x=3.5, y=3.5), cat=3, attrs=("centroid", 3))
            vect.write(Centroid(x=2.5, y=2.5), cat=3)
            vect.write(Centroid(x=5.5, y=3.5), cat=3)
            vect.write(Centroid(x=7.5, y=3.5), cat=3)

            vect.organization = "Thuenen Institut"
            vect.person = "Soeren Gebbert"
            vect.title = "Test dataset"
            vect.comment = "This is a comment"

            vect.table.conn.commit()

            vect.organization = "Thuenen Institut"
            vect.person = "Soeren Gebbert"
            vect.title = "Test dataset"
            vect.comment = "This is a comment"
            vect.close()

    def create_test_stream_network_map(map_name="streams"):
        R"""Create test data

           This functions creates a vector map layer with lines that represent
           a stream network with two different graphs. The first graph
           contains a loop, the second can be used as directed graph.

           This should be used in doc and unit tests to create location/mapset
           independent vector map layer.

            param map_name: The vector map name that should be used

           1(0,2)  3(2,2)
            \     /
           1 \   / 2
              \ /
               2(1,1)
        6(0,1) ||  5(2,1)
           5 \ || / 4
              \||/
               4(1,0)
               |
               | 6
               |7(1,-1)

           7(0,-1) 8(2,-1)
            \     /
           8 \   / 9
              \ /
               9(1, -2)
               |
               | 10
               |
              10(1,-3)
        """

        from grass.pygrass.vector import VectorTopo
        from grass.pygrass.vector.geometry import Line

        cols = [("cat", "INTEGER PRIMARY KEY"), ("id", "INTEGER")]
        with VectorTopo(map_name, mode="w", tab_name=map_name, tab_cols=cols) as streams:

            # First flow graph
            line = Line([(0, 2), (0.22, 1.75), (0.55, 1.5), (1, 1)])
            streams.write(line, cat=1, attrs=(1,))
            line = Line([(2, 2), (1, 1)])
            streams.write(line, cat=2, attrs=(2,))
            line = Line([(1, 1), (0.85, 0.5), (1, 0)])
            streams.write(line, cat=3, attrs=(3,))
            line = Line([(2, 1), (1, 0)])
            streams.write(line, cat=4, attrs=(4,))
            line = Line([(0, 1), (1, 0)])
            streams.write(line, cat=5, attrs=(5,))
            line = Line([(1, 0), (1, -1)])
            streams.write(line, cat=6, attrs=(6,))
            # Reverse line 3
            line = Line([(1, 0), (1.15, 0.5), (1, 1)])
            streams.write(line, cat=7, attrs=(7,))

            # second flow graph
            line = Line([(0, -1), (1, -2)])
            streams.write(line, cat=8, attrs=(8,))
            line = Line([(2, -1), (1, -2)])
            streams.write(line, cat=9, attrs=(9,))
            line = Line([(1, -2), (1, -3)])
            streams.write(line, cat=10, attrs=(10,))

            streams.organization = "Thuenen Institut"
            streams.person = "Soeren Gebbert"
            streams.title = "Test dataset for stream networks"
            streams.comment = "This is a comment"

            streams.table.conn.commit()
            streams.close()

    if __name__ == "__main__":

        import doctest
        from grass.pygrass import utils
        from grass.script.core import run_command

        utils.create_test_vector_map(test_vector_name)
        run_command("g.region", n=50, s=0, e=60, w=0, res=1)
        run_command("r.mapcalc", expression="%s = 1" % (test_raster_name), overwrite=True)

        doctest.testmod()

        """Remove the generated vector map, if exist"""
        mset = utils.get_mapset_vector(test_vector_name, mapset="")
        if mset:
            run_command("g.remove", flags="f", type="vector", name=test_vector_name)
        mset = utils.get_mapset_raster(test_raster_name, mapset="")
        if mset:
            run_command("g.remove", flags="f", type="raster", name=test_raster_name)

Help Index | Topics Index | Keywords Index | Full Index

© 2003-2024 GRASS Development Team, GRASS GIS 8.2.2dev Reference Manual