Tile

Source code in geocube/entities/tile.py
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
@dataclass
class Tile:
    crs:       str
    transform: affine.Affine  # Pixel to crs
    shape:     Tuple[int, int]

    @classmethod
    def from_pb(cls, pb: layouts_pb2.Tile):
        return cls(pb.crs, affine.Affine(pb.transform.b, pb.transform.c, pb.transform.a,
                                         pb.transform.e, pb.transform.f, pb.transform.d),
                   shape=(int(pb.size_px.width), int(pb.size_px.height))
                   )

    @classmethod
    def from_geotransform(cls, transform: Union[affine.Affine, Tuple[float, float, float, float, float, float]],
                          crs: Union[str, int], shape: Tuple[int, int]) -> Tile:
        """
        Create a tile from a geotransform, a crs and a shape
        Args:
            transform: geotransform from pixel coordinates to CRS.
            crs: Coordinate Reference System of the tile
            shape: shape of the tile (in pixel) (@warning shape is the transpose of numpy shape)

        Returns:
            A new tile
        """
        return cls(crs_to_str(crs), Tile._parse_geotransform(transform), shape)

    @classmethod
    def from_record(cls, record: entities.Record, crs: Union[str, int], resolution: float) -> Tile:
        """ Create a tile that cover the record in the crs at a given resolution
        Warning: record.aoi must be loaded (with client.load_aoi())
        Warning: Check the `result.shape` as the size might be huge !
        Warning: the aoi is converted to the crs, but it might be imprecise at the borders

        Args:
            record:
            crs: Coordinate Reference System of the tile
            resolution: resolution of the pixel in the CRS

        Returns:
            A new tile
        """
        return Tile.from_aoi(record.aoi, crs, resolution)

    @classmethod
    def from_bbox(cls, bbox: Tuple[float, float, float, float], crs: Union[str, int],
                  resolution: Union[float, Tuple[float, float]]) -> Tile:
        """
        Create a tile from a bbox, a crs and a resolution
        Args:
            bbox : (x1, y1, x2, y2) in crs coordinates
            crs : (Coordinate Reference System) of the tile
            resolution : of the pixel in the CRS

        Returns:
            A new tile
        """
        rx, ry = resolution if isinstance(resolution, tuple) else (resolution, -resolution)
        x1, y1, x2, y2 = bbox
        if math.copysign(1, rx)*(x2-x1) < 0:
            x1, x2 = x2, x1
        if math.copysign(1, ry)*(y2-y1) < 0:
            y1, y2 = y2, y1
        transform = geo_transform(x1, y1, resolution)
        sx, sy = (~transform) * (x2, y2)
        return cls(crs_to_str(crs), transform, (math.ceil(sx), math.ceil(sy)))

    @classmethod
    def from_aoi(cls, aoi: geometry.MultiPolygon, crs: Union[str, int],
                 resolution: Union[float, Tuple[float, float]]) -> Tile:
        """

        Args:
            aoi : multipolygon in 4326 coordinates
            crs : (Coordinate Reference System) of the tile
            resolution : of the pixel in the CRS

        Returns:
            A new tile
        """
        return Tile.from_bbox(gpd.GeoSeries(aoi, crs=4326).to_crs(crs).total_bounds, crs=crs, resolution=resolution)

    def __str__(self):
        return "Tile {}\n" \
               "    transform: ({}, {} {}, {}, {} {})\n" \
               "    bounds:    ({} {}) {}\n" \
               "    shape:     {} \n" \
               "    crs:       {}\n".format(self.shape,
                                            self.transform.c, self.transform.a, self.transform.b,
                                            self.transform.f, self.transform.d, self.transform.e,
                                            self.transform.c, self.transform.f, self.transform*self.shape,
                                            self.shape, self.crs)

    def __repr__(self):
        return self.__str__()

    def geoseries(self) -> gpd.GeoSeries:
        x1, y1 = self.transform*(0, 0)
        x2, y2 = self.transform*self.shape
        p = geometry.Polygon([[x1, y1], [x1, y2], [x2, y2], [x2, y1], [x1, y1]])
        return gpd.GeoSeries(p, crs=self.crs)

    def geometry(self, to_crs: Union[str, int] = None):
        gs = self.geoseries()
        if to_crs is not None:
            gs = gs.to_crs(crs_to_str(to_crs))
        return gs.iloc[0]

    def reshape(self, i1, j1, i2, j2) -> entities.Tile:
        """ Create a new Tile using the coordinate pixels
         @warning inverse of numpy coordinates """
        return Tile.from_bbox(self.transform*(i1, j1) + self.transform*(i2, j2),
                              self.crs, resolution=(self.transform.a, self.transform.e))

    @staticmethod
    def _parse_geotransform(transform: Union[affine.Affine, Tuple[float, float, float, float, float, float]]) \
            -> affine.Affine:
        if isinstance(transform, affine.Affine):
            return transform
        return affine.Affine.from_gdal(*transform)

    @staticmethod
    def plot(tiles: List[Tile], world_path: str = gpd.datasets.get_path('naturalearth_lowres'), ax=None, margin_pc=5):
        ts = gpd.GeoSeries(pd.concat([t.geoseries().to_crs("epsg:4326") for t in tiles]))
        return utils.plot_aoi(ts, world_path, ax, margin_pc)

from_aoi(aoi, crs, resolution) classmethod

Parameters:

Name Type Description Default
aoi

multipolygon in 4326 coordinates

required
crs

(Coordinate Reference System) of the tile

required
resolution

of the pixel in the CRS

required

Returns:

Type Description
Tile

A new tile

Source code in geocube/entities/tile.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
@classmethod
def from_aoi(cls, aoi: geometry.MultiPolygon, crs: Union[str, int],
             resolution: Union[float, Tuple[float, float]]) -> Tile:
    """

    Args:
        aoi : multipolygon in 4326 coordinates
        crs : (Coordinate Reference System) of the tile
        resolution : of the pixel in the CRS

    Returns:
        A new tile
    """
    return Tile.from_bbox(gpd.GeoSeries(aoi, crs=4326).to_crs(crs).total_bounds, crs=crs, resolution=resolution)

from_bbox(bbox, crs, resolution) classmethod

Create a tile from a bbox, a crs and a resolution

Parameters:

Name Type Description Default
bbox

(x1, y1, x2, y2) in crs coordinates

required
crs

(Coordinate Reference System) of the tile

required
resolution

of the pixel in the CRS

required

Returns:

Type Description
Tile

A new tile

Source code in geocube/entities/tile.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
@classmethod
def from_bbox(cls, bbox: Tuple[float, float, float, float], crs: Union[str, int],
              resolution: Union[float, Tuple[float, float]]) -> Tile:
    """
    Create a tile from a bbox, a crs and a resolution
    Args:
        bbox : (x1, y1, x2, y2) in crs coordinates
        crs : (Coordinate Reference System) of the tile
        resolution : of the pixel in the CRS

    Returns:
        A new tile
    """
    rx, ry = resolution if isinstance(resolution, tuple) else (resolution, -resolution)
    x1, y1, x2, y2 = bbox
    if math.copysign(1, rx)*(x2-x1) < 0:
        x1, x2 = x2, x1
    if math.copysign(1, ry)*(y2-y1) < 0:
        y1, y2 = y2, y1
    transform = geo_transform(x1, y1, resolution)
    sx, sy = (~transform) * (x2, y2)
    return cls(crs_to_str(crs), transform, (math.ceil(sx), math.ceil(sy)))

from_geotransform(transform, crs, shape) classmethod

Create a tile from a geotransform, a crs and a shape

Parameters:

Name Type Description Default
transform Union[affine.Affine, Tuple[float, float, float, float, float, float]]

geotransform from pixel coordinates to CRS.

required
crs Union[str, int]

Coordinate Reference System of the tile

required
shape Tuple[int, int]

shape of the tile (in pixel) (@warning shape is the transpose of numpy shape)

required

Returns:

Type Description
Tile

A new tile

Source code in geocube/entities/tile.py
50
51
52
53
54
55
56
57
58
59
60
61
62
63
@classmethod
def from_geotransform(cls, transform: Union[affine.Affine, Tuple[float, float, float, float, float, float]],
                      crs: Union[str, int], shape: Tuple[int, int]) -> Tile:
    """
    Create a tile from a geotransform, a crs and a shape
    Args:
        transform: geotransform from pixel coordinates to CRS.
        crs: Coordinate Reference System of the tile
        shape: shape of the tile (in pixel) (@warning shape is the transpose of numpy shape)

    Returns:
        A new tile
    """
    return cls(crs_to_str(crs), Tile._parse_geotransform(transform), shape)

from_record(record, crs, resolution) classmethod

Create a tile that cover the record in the crs at a given resolution Warning: record.aoi must be loaded (with client.load_aoi()) Warning: Check the result.shape as the size might be huge ! Warning: the aoi is converted to the crs, but it might be imprecise at the borders

Parameters:

Name Type Description Default
record entities.Record required
crs Union[str, int]

Coordinate Reference System of the tile

required
resolution float

resolution of the pixel in the CRS

required

Returns:

Type Description
Tile

A new tile

Source code in geocube/entities/tile.py
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
@classmethod
def from_record(cls, record: entities.Record, crs: Union[str, int], resolution: float) -> Tile:
    """ Create a tile that cover the record in the crs at a given resolution
    Warning: record.aoi must be loaded (with client.load_aoi())
    Warning: Check the `result.shape` as the size might be huge !
    Warning: the aoi is converted to the crs, but it might be imprecise at the borders

    Args:
        record:
        crs: Coordinate Reference System of the tile
        resolution: resolution of the pixel in the CRS

    Returns:
        A new tile
    """
    return Tile.from_aoi(record.aoi, crs, resolution)

reshape(i1, j1, i2, j2)

Create a new Tile using the coordinate pixels @warning inverse of numpy coordinates

Source code in geocube/entities/tile.py
146
147
148
149
150
def reshape(self, i1, j1, i2, j2) -> entities.Tile:
    """ Create a new Tile using the coordinate pixels
     @warning inverse of numpy coordinates """
    return Tile.from_bbox(self.transform*(i1, j1) + self.transform*(i2, j2),
                          self.crs, resolution=(self.transform.a, self.transform.e))