ssb-sgis 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sgis/__init__.py +107 -121
- sgis/exceptions.py +5 -3
- sgis/geopandas_tools/__init__.py +1 -0
- sgis/geopandas_tools/bounds.py +86 -47
- sgis/geopandas_tools/buffer_dissolve_explode.py +62 -39
- sgis/geopandas_tools/centerlines.py +53 -44
- sgis/geopandas_tools/cleaning.py +87 -104
- sgis/geopandas_tools/conversion.py +164 -107
- sgis/geopandas_tools/duplicates.py +33 -19
- sgis/geopandas_tools/general.py +84 -52
- sgis/geopandas_tools/geometry_types.py +24 -10
- sgis/geopandas_tools/neighbors.py +23 -11
- sgis/geopandas_tools/overlay.py +136 -53
- sgis/geopandas_tools/point_operations.py +11 -10
- sgis/geopandas_tools/polygon_operations.py +53 -61
- sgis/geopandas_tools/polygons_as_rings.py +121 -78
- sgis/geopandas_tools/sfilter.py +17 -17
- sgis/helpers.py +116 -58
- sgis/io/dapla_functions.py +32 -23
- sgis/io/opener.py +13 -6
- sgis/io/read_parquet.py +2 -2
- sgis/maps/examine.py +55 -28
- sgis/maps/explore.py +471 -112
- sgis/maps/httpserver.py +12 -12
- sgis/maps/legend.py +285 -134
- sgis/maps/map.py +248 -129
- sgis/maps/maps.py +123 -119
- sgis/maps/thematicmap.py +260 -94
- sgis/maps/tilesources.py +3 -8
- sgis/networkanalysis/_get_route.py +5 -4
- sgis/networkanalysis/_od_cost_matrix.py +44 -1
- sgis/networkanalysis/_points.py +10 -4
- sgis/networkanalysis/_service_area.py +5 -2
- sgis/networkanalysis/closing_network_holes.py +22 -64
- sgis/networkanalysis/cutting_lines.py +58 -46
- sgis/networkanalysis/directednetwork.py +16 -8
- sgis/networkanalysis/finding_isolated_networks.py +6 -5
- sgis/networkanalysis/network.py +15 -13
- sgis/networkanalysis/networkanalysis.py +79 -61
- sgis/networkanalysis/networkanalysisrules.py +21 -17
- sgis/networkanalysis/nodes.py +2 -3
- sgis/networkanalysis/traveling_salesman.py +6 -3
- sgis/parallel/parallel.py +372 -142
- sgis/raster/base.py +9 -3
- sgis/raster/cube.py +331 -213
- sgis/raster/cubebase.py +15 -29
- sgis/raster/image_collection.py +2560 -0
- sgis/raster/indices.py +17 -12
- sgis/raster/raster.py +356 -275
- sgis/raster/sentinel_config.py +104 -0
- sgis/raster/zonal.py +38 -14
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.3.dist-info}/LICENSE +1 -1
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.3.dist-info}/METADATA +87 -16
- ssb_sgis-1.0.3.dist-info/RECORD +61 -0
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.3.dist-info}/WHEEL +1 -1
- sgis/raster/bands.py +0 -48
- sgis/raster/gradient.py +0 -78
- sgis/raster/methods_as_functions.py +0 -124
- sgis/raster/torchgeo.py +0 -150
- ssb_sgis-1.0.1.dist-info/RECORD +0 -63
sgis/maps/maps.py
CHANGED
|
@@ -8,37 +8,45 @@ The 'qtm' function shows a simple static map of one or more GeoDataFrames.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import inspect
|
|
11
|
+
import random
|
|
11
12
|
from numbers import Number
|
|
12
13
|
from typing import Any
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
from
|
|
15
|
+
import pyproj
|
|
16
|
+
from geopandas import GeoDataFrame
|
|
17
|
+
from geopandas import GeoSeries
|
|
16
18
|
from shapely import Geometry
|
|
17
|
-
|
|
18
|
-
from
|
|
19
|
-
|
|
19
|
+
from shapely import box
|
|
20
|
+
from shapely.geometry import Polygon
|
|
21
|
+
|
|
22
|
+
from ..geopandas_tools.bounds import get_total_bounds
|
|
23
|
+
from ..geopandas_tools.conversion import to_bbox
|
|
24
|
+
from ..geopandas_tools.conversion import to_gdf
|
|
25
|
+
from ..geopandas_tools.conversion import to_shapely
|
|
26
|
+
from ..geopandas_tools.general import clean_geoms
|
|
27
|
+
from ..geopandas_tools.general import get_common_crs
|
|
28
|
+
from ..geopandas_tools.general import is_wkt
|
|
20
29
|
from ..geopandas_tools.geocoding import address_to_gdf
|
|
21
30
|
from ..geopandas_tools.geometry_types import get_geom_type
|
|
22
31
|
from .explore import Explore
|
|
23
32
|
from .map import Map
|
|
24
33
|
from .thematicmap import ThematicMap
|
|
25
34
|
|
|
26
|
-
|
|
27
35
|
try:
|
|
28
36
|
from torchgeo.datasets.geo import RasterDataset
|
|
29
37
|
except ImportError:
|
|
30
38
|
|
|
31
39
|
class RasterDataset:
|
|
32
|
-
"""Placeholder"""
|
|
40
|
+
"""Placeholder."""
|
|
33
41
|
|
|
34
42
|
|
|
35
43
|
def _get_location_mask(kwargs: dict, gdfs) -> tuple[GeoDataFrame | None, dict]:
|
|
36
44
|
try:
|
|
37
45
|
crs = get_common_crs(gdfs)
|
|
38
|
-
except IndexError:
|
|
46
|
+
except (IndexError, pyproj.exceptions.CRSError):
|
|
39
47
|
for x in kwargs.values():
|
|
40
48
|
try:
|
|
41
|
-
crs = CRS(x.crs) if hasattr(x, "crs") else CRS(x["crs"])
|
|
49
|
+
crs = pyproj.CRS(x.crs) if hasattr(x, "crs") else pyproj.CRS(x["crs"])
|
|
42
50
|
break
|
|
43
51
|
except Exception:
|
|
44
52
|
crs = None
|
|
@@ -62,7 +70,7 @@ def _get_location_mask(kwargs: dict, gdfs) -> tuple[GeoDataFrame | None, dict]:
|
|
|
62
70
|
kwargs.pop(key)
|
|
63
71
|
if isinstance(value, Number) and value > 1:
|
|
64
72
|
size = value
|
|
65
|
-
the_mask =
|
|
73
|
+
the_mask = to_gdf([mask], crs=4326).to_crs(crs).buffer(size)
|
|
66
74
|
return the_mask, kwargs
|
|
67
75
|
|
|
68
76
|
return None, kwargs
|
|
@@ -72,14 +80,13 @@ def explore(
|
|
|
72
80
|
*gdfs: GeoDataFrame | dict[str, GeoDataFrame],
|
|
73
81
|
column: str | None = None,
|
|
74
82
|
center: Any | None = None,
|
|
75
|
-
center_4326: Any | None = None,
|
|
76
|
-
labels: tuple[str] | None = None,
|
|
77
83
|
max_zoom: int = 40,
|
|
78
84
|
browser: bool = False,
|
|
79
85
|
smooth_factor: int | float = 1.5,
|
|
80
86
|
size: int | None = None,
|
|
87
|
+
max_images: int = 15,
|
|
81
88
|
**kwargs,
|
|
82
|
-
) ->
|
|
89
|
+
) -> Explore:
|
|
83
90
|
"""Interactive map of GeoDataFrames with layers that can be toggled on/off.
|
|
84
91
|
|
|
85
92
|
It takes all the given GeoDataFrames and displays them together in an
|
|
@@ -94,13 +101,9 @@ def explore(
|
|
|
94
101
|
*gdfs: one or more GeoDataFrames.
|
|
95
102
|
column: The column to color the geometries by. Defaults to None, which means
|
|
96
103
|
each GeoDataFrame will get a unique color.
|
|
97
|
-
center:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
size parameter. If a polygon is given, it will not be buffered.
|
|
101
|
-
labels: By default, the GeoDataFrames will be labeled by their object names.
|
|
102
|
-
Alternatively, labels can be specified as a tuple of strings with the same
|
|
103
|
-
length as the number of gdfs.
|
|
104
|
+
center: Geometry-like object to center the map on. If a three-length tuple
|
|
105
|
+
is given, the first two should be x and y coordinates and the third
|
|
106
|
+
should be a number of meters to buffer the centerpoint by.
|
|
104
107
|
max_zoom: The maximum allowed level of zoom. Higher number means more zoom
|
|
105
108
|
allowed. Defaults to 30, which is higher than the geopandas default.
|
|
106
109
|
browser: If False (default), the maps will be shown in Jupyter.
|
|
@@ -109,17 +112,19 @@ def explore(
|
|
|
109
112
|
5 is quite a lot of simplification.
|
|
110
113
|
size: The buffer distance. Only used when center is given. It then defaults to
|
|
111
114
|
1000.
|
|
115
|
+
max_images: Maximum number of images (Image, ImageCollection, Band) to show per
|
|
116
|
+
map. Defaults to 15.
|
|
112
117
|
**kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
|
|
113
118
|
instance 'cmap' to change the colors, 'scheme' to change how the data
|
|
114
119
|
is grouped. This defaults to 'fisherjenkssampled' for numeric data.
|
|
115
120
|
|
|
116
|
-
See
|
|
117
|
-
|
|
121
|
+
See Also:
|
|
122
|
+
---------
|
|
118
123
|
samplemap: same functionality, but shows only a random area of a given size.
|
|
119
124
|
clipmap: same functionality, but shows only the areas clipped by a given mask.
|
|
120
125
|
|
|
121
|
-
Examples
|
|
122
|
-
|
|
126
|
+
Examples:
|
|
127
|
+
---------
|
|
123
128
|
>>> import sgis as sg
|
|
124
129
|
>>> roads = sg.read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
|
|
125
130
|
>>> points = sg.read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/points_oslo.parquet")
|
|
@@ -138,7 +143,6 @@ def explore(
|
|
|
138
143
|
>>> points["meters"] = points.length
|
|
139
144
|
>>> sg.explore(roads, points, column="meters", cmap="plasma", max_zoom=60, center_4326=(10.7463, 59.92, 500))
|
|
140
145
|
"""
|
|
141
|
-
|
|
142
146
|
gdfs, column, kwargs = Map._separate_args(gdfs, column, kwargs)
|
|
143
147
|
|
|
144
148
|
loc_mask, kwargs = _get_location_mask(kwargs | {"size": size}, gdfs)
|
|
@@ -152,7 +156,6 @@ def explore(
|
|
|
152
156
|
*gdfs,
|
|
153
157
|
column=column,
|
|
154
158
|
mask=mask,
|
|
155
|
-
labels=labels,
|
|
156
159
|
browser=browser,
|
|
157
160
|
max_zoom=max_zoom,
|
|
158
161
|
**kwargs,
|
|
@@ -160,16 +163,13 @@ def explore(
|
|
|
160
163
|
|
|
161
164
|
try:
|
|
162
165
|
to_crs = gdfs[0].crs
|
|
163
|
-
except IndexError:
|
|
166
|
+
except (IndexError, AttributeError):
|
|
164
167
|
try:
|
|
165
|
-
to_crs =
|
|
166
|
-
except IndexError:
|
|
168
|
+
to_crs = next(x for x in kwargs.values() if hasattr(x, "crs")).crs
|
|
169
|
+
except (IndexError, StopIteration):
|
|
167
170
|
to_crs = None
|
|
168
171
|
|
|
169
|
-
if
|
|
170
|
-
from_crs = 4326
|
|
171
|
-
center = center_4326
|
|
172
|
-
elif "crs" in kwargs:
|
|
172
|
+
if "crs" in kwargs:
|
|
173
173
|
from_crs = kwargs.pop("crs")
|
|
174
174
|
else:
|
|
175
175
|
from_crs = to_crs
|
|
@@ -183,7 +183,11 @@ def explore(
|
|
|
183
183
|
else:
|
|
184
184
|
if isinstance(center, (tuple, list)) and len(center) == 3:
|
|
185
185
|
*center, size = center
|
|
186
|
-
mask =
|
|
186
|
+
mask = to_gdf(center, crs=from_crs)
|
|
187
|
+
|
|
188
|
+
bounds: Polygon = box(*get_total_bounds(*gdfs, *list(kwargs.values())))
|
|
189
|
+
if not mask.intersects(bounds).any():
|
|
190
|
+
mask = mask.set_crs(4326, allow_override=True)
|
|
187
191
|
|
|
188
192
|
try:
|
|
189
193
|
mask = mask.to_crs(to_crs)
|
|
@@ -197,7 +201,6 @@ def explore(
|
|
|
197
201
|
*gdfs,
|
|
198
202
|
column=column,
|
|
199
203
|
mask=mask,
|
|
200
|
-
labels=labels,
|
|
201
204
|
browser=browser,
|
|
202
205
|
max_zoom=max_zoom,
|
|
203
206
|
**kwargs,
|
|
@@ -206,34 +209,36 @@ def explore(
|
|
|
206
209
|
m = Explore(
|
|
207
210
|
*gdfs,
|
|
208
211
|
column=column,
|
|
209
|
-
labels=labels,
|
|
210
212
|
browser=browser,
|
|
211
213
|
max_zoom=max_zoom,
|
|
212
214
|
smooth_factor=smooth_factor,
|
|
215
|
+
max_images=max_images,
|
|
213
216
|
**kwargs,
|
|
214
217
|
)
|
|
215
218
|
|
|
216
|
-
if m.gdfs is None and not len(m.
|
|
217
|
-
return
|
|
219
|
+
if m.gdfs is None and not len(m.rasters):
|
|
220
|
+
return m
|
|
218
221
|
|
|
219
222
|
if not kwargs.pop("explore", True):
|
|
220
223
|
return qtm(m._gdf, column=m.column, cmap=m._cmap, k=m.k)
|
|
221
224
|
|
|
222
225
|
m.explore()
|
|
223
226
|
|
|
227
|
+
return m
|
|
228
|
+
|
|
224
229
|
|
|
225
230
|
def samplemap(
|
|
226
231
|
*gdfs: GeoDataFrame,
|
|
227
232
|
column: str | None = None,
|
|
228
233
|
size: int = 1000,
|
|
229
234
|
sample_from_first: bool = True,
|
|
230
|
-
labels: tuple[str] | None = None,
|
|
231
235
|
max_zoom: int = 40,
|
|
232
236
|
smooth_factor: int = 1.5,
|
|
233
237
|
explore: bool = True,
|
|
234
238
|
browser: bool = False,
|
|
239
|
+
max_images: int = 15,
|
|
235
240
|
**kwargs,
|
|
236
|
-
) ->
|
|
241
|
+
) -> Explore:
|
|
237
242
|
"""Shows an interactive map of a random area of GeoDataFrames.
|
|
238
243
|
|
|
239
244
|
It takes all the GeoDataFrames specified, takes a random sample point from the
|
|
@@ -255,9 +260,6 @@ def samplemap(
|
|
|
255
260
|
Defaults to 1000 (meters).
|
|
256
261
|
sample_from_first: If True (default), the sample point is taken form the
|
|
257
262
|
first specified GeoDataFrame. If False, all GeoDataFrames are considered.
|
|
258
|
-
labels: By default, the GeoDataFrames will be labeled by their object names.
|
|
259
|
-
Alternatively, labels can be specified as a tuple of strings the same
|
|
260
|
-
length as the number of gdfs.
|
|
261
263
|
max_zoom: The maximum allowed level of zoom. Higher number means more zoom
|
|
262
264
|
allowed. Defaults to 30, which is higher than the geopandas default.
|
|
263
265
|
smooth_factor: How much to simplify the geometries. 1 is the minimum,
|
|
@@ -266,17 +268,19 @@ def samplemap(
|
|
|
266
268
|
or not in Jupyter, a static plot will be shown.
|
|
267
269
|
browser: If False (default), the maps will be shown in Jupyter.
|
|
268
270
|
If True the maps will be opened in a browser folder.
|
|
271
|
+
max_images: Maximum number of images (Image, ImageCollection, Band) to show per
|
|
272
|
+
map. Defaults to 15.
|
|
269
273
|
**kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
|
|
270
274
|
instance 'cmap' to change the colors, 'scheme' to change how the data
|
|
271
275
|
is grouped. This defaults to 'fisherjenkssampled' for numeric data.
|
|
272
276
|
|
|
273
|
-
See
|
|
274
|
-
|
|
277
|
+
See Also:
|
|
278
|
+
---------
|
|
275
279
|
explore: Same functionality, but shows the entire area of the geometries.
|
|
276
280
|
clipmap: Same functionality, but shows only the areas clipped by a given mask.
|
|
277
281
|
|
|
278
|
-
Examples
|
|
279
|
-
|
|
282
|
+
Examples:
|
|
283
|
+
---------
|
|
280
284
|
>>> from sgis import read_parquet_url, samplemap
|
|
281
285
|
>>> roads = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_eidskog_2022.parquet")
|
|
282
286
|
>>> points = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/points_eidskog.parquet")
|
|
@@ -290,78 +294,72 @@ def samplemap(
|
|
|
290
294
|
>>> samplemap(roads, points, size=5_000, column="meters")
|
|
291
295
|
|
|
292
296
|
"""
|
|
293
|
-
|
|
294
|
-
if gdfs and isinstance(gdfs[-1], (float, int)):
|
|
297
|
+
if gdfs and len(gdfs) > 1 and isinstance(gdfs[-1], (float, int)):
|
|
295
298
|
*gdfs, size = gdfs
|
|
296
299
|
|
|
297
300
|
gdfs, column, kwargs = Map._separate_args(gdfs, column, kwargs)
|
|
298
301
|
|
|
299
|
-
|
|
302
|
+
loc_mask, kwargs = _get_location_mask(kwargs | {"size": size}, gdfs)
|
|
300
303
|
kwargs.pop("size")
|
|
304
|
+
mask = kwargs.pop("mask", loc_mask)
|
|
301
305
|
|
|
302
|
-
if
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
browser=browser,
|
|
308
|
-
max_zoom=max_zoom,
|
|
309
|
-
smooth_factor=smooth_factor,
|
|
310
|
-
**kwargs,
|
|
311
|
-
)
|
|
312
|
-
if m.gdfs is None and not len(m.raster_datasets):
|
|
313
|
-
return
|
|
314
|
-
if mask is not None:
|
|
315
|
-
m._gdfs = [gdf.clip(mask) for gdf in m._gdfs]
|
|
316
|
-
m._gdf = m._gdf.clip(mask)
|
|
317
|
-
m._nan_idx = m._gdf[m._column].isna()
|
|
318
|
-
m._get_unique_values()
|
|
319
|
-
|
|
320
|
-
m.samplemap(size, sample_from_first=sample_from_first)
|
|
306
|
+
i = 0 if sample_from_first else random.choice(list(range(len(gdfs))))
|
|
307
|
+
try:
|
|
308
|
+
sample = gdfs[i]
|
|
309
|
+
except IndexError:
|
|
310
|
+
sample = list(kwargs.values())[i]
|
|
321
311
|
|
|
312
|
+
if mask is None:
|
|
313
|
+
try:
|
|
314
|
+
sample = sample.geometry.dropna().sample(1)
|
|
315
|
+
except Exception:
|
|
316
|
+
try:
|
|
317
|
+
sample = sample.sample(1)
|
|
318
|
+
except Exception:
|
|
319
|
+
pass
|
|
320
|
+
try:
|
|
321
|
+
sample = to_gdf(to_shapely(sample)).explode(ignore_index=True)
|
|
322
|
+
except Exception:
|
|
323
|
+
sample = to_gdf(to_shapely(to_bbox(sample))).explode(ignore_index=True)
|
|
322
324
|
else:
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
**kwargs,
|
|
328
|
-
)
|
|
329
|
-
|
|
330
|
-
if sample_from_first:
|
|
331
|
-
sample = m._gdfs[0].sample(1)
|
|
332
|
-
else:
|
|
333
|
-
sample = m._gdf.sample(1)
|
|
325
|
+
try:
|
|
326
|
+
sample = to_gdf(to_shapely(sample)).explode(ignore_index=True)
|
|
327
|
+
except Exception:
|
|
328
|
+
sample = to_gdf(to_shapely(to_bbox(sample))).explode(ignore_index=True)
|
|
334
329
|
|
|
335
|
-
|
|
336
|
-
if get_geom_type(sample) == "line":
|
|
337
|
-
sample["geometry"] = sample.buffer(1)
|
|
330
|
+
sample = sample.clip(mask).sample(1)
|
|
338
331
|
|
|
339
|
-
|
|
340
|
-
random_point = sample.sample_points(size=1)
|
|
332
|
+
random_point = sample.sample_points(size=1)
|
|
341
333
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
random_point = sample.centroid
|
|
334
|
+
center = (random_point.geometry.iloc[0].x, random_point.geometry.iloc[0].y)
|
|
335
|
+
print(f"center={center}, size={size}")
|
|
345
336
|
|
|
346
|
-
|
|
347
|
-
print(f"center={center}, size={size}")
|
|
337
|
+
mask = random_point.buffer(size)
|
|
348
338
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
339
|
+
return clipmap(
|
|
340
|
+
*gdfs,
|
|
341
|
+
column=column,
|
|
342
|
+
mask=mask,
|
|
343
|
+
browser=browser,
|
|
344
|
+
max_zoom=max_zoom,
|
|
345
|
+
explore=explore,
|
|
346
|
+
smooth_factor=smooth_factor,
|
|
347
|
+
max_images=max_images,
|
|
348
|
+
**kwargs,
|
|
349
|
+
)
|
|
352
350
|
|
|
353
351
|
|
|
354
352
|
def clipmap(
|
|
355
353
|
*gdfs: GeoDataFrame,
|
|
356
354
|
column: str | None = None,
|
|
357
355
|
mask: GeoDataFrame | GeoSeries | Geometry = None,
|
|
358
|
-
labels: tuple[str] | None = None,
|
|
359
356
|
explore: bool = True,
|
|
360
357
|
max_zoom: int = 40,
|
|
361
358
|
smooth_factor: int | float = 1.5,
|
|
362
359
|
browser: bool = False,
|
|
360
|
+
max_images: int = 15,
|
|
363
361
|
**kwargs,
|
|
364
|
-
) ->
|
|
362
|
+
) -> Explore | Map:
|
|
365
363
|
"""Shows an interactive map of a of GeoDataFrames clipped to the mask extent.
|
|
366
364
|
|
|
367
365
|
It takes all the GeoDataFrames specified, clips them to the extent of the mask,
|
|
@@ -378,9 +376,6 @@ def clipmap(
|
|
|
378
376
|
mask: the geometry to clip the data by.
|
|
379
377
|
column: The column to color the geometries by. Defaults to None, which means
|
|
380
378
|
each GeoDataFrame will get a unique color.
|
|
381
|
-
labels: By default, the GeoDataFrames will be labeled by their object names.
|
|
382
|
-
Alternatively, labels can be specified as a tuple of strings the same
|
|
383
|
-
length as the number of gdfs.
|
|
384
379
|
max_zoom: The maximum allowed level of zoom. Higher number means more zoom
|
|
385
380
|
allowed. Defaults to 30, which is higher than the geopandas default.
|
|
386
381
|
smooth_factor: How much to simplify the geometries. 1 is the minimum,
|
|
@@ -389,22 +384,29 @@ def clipmap(
|
|
|
389
384
|
or not in Jupyter, a static plot will be shown.
|
|
390
385
|
browser: If False (default), the maps will be shown in Jupyter.
|
|
391
386
|
If True the maps will be opened in a browser folder.
|
|
387
|
+
max_images: Maximum number of images (Image, ImageCollection, Band) to show per
|
|
388
|
+
map. Defaults to 15.
|
|
392
389
|
**kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
|
|
393
390
|
instance 'cmap' to change the colors, 'scheme' to change how the data
|
|
394
391
|
is grouped. This defaults to 'fisherjenkssampled' for numeric data.
|
|
395
392
|
|
|
396
|
-
See
|
|
397
|
-
|
|
393
|
+
See Also:
|
|
394
|
+
---------
|
|
398
395
|
explore: same functionality, but shows the entire area of the geometries.
|
|
399
396
|
samplemap: same functionality, but shows only a random area of a given size.
|
|
400
397
|
"""
|
|
401
|
-
|
|
402
398
|
gdfs, column, kwargs = Map._separate_args(gdfs, column, kwargs)
|
|
403
399
|
|
|
404
400
|
if mask is None and len(gdfs) > 1:
|
|
405
401
|
mask = gdfs[-1]
|
|
406
402
|
gdfs = gdfs[:-1]
|
|
407
403
|
|
|
404
|
+
if not isinstance(mask, (GeoDataFrame | GeoSeries | Geometry | tuple)):
|
|
405
|
+
try:
|
|
406
|
+
mask = to_gdf(mask)
|
|
407
|
+
except Exception:
|
|
408
|
+
mask = to_shapely(to_bbox(mask))
|
|
409
|
+
|
|
408
410
|
center = kwargs.pop("center", None)
|
|
409
411
|
size = kwargs.pop("size", None)
|
|
410
412
|
|
|
@@ -412,29 +414,31 @@ def clipmap(
|
|
|
412
414
|
m = Explore(
|
|
413
415
|
*gdfs,
|
|
414
416
|
column=column,
|
|
415
|
-
labels=labels,
|
|
416
417
|
browser=browser,
|
|
417
418
|
max_zoom=max_zoom,
|
|
418
419
|
smooth_factor=smooth_factor,
|
|
420
|
+
max_images=max_images,
|
|
419
421
|
**kwargs,
|
|
420
422
|
)
|
|
421
|
-
|
|
422
|
-
|
|
423
|
+
m.mask = mask
|
|
424
|
+
|
|
425
|
+
if m.gdfs is None and not len(m.rasters):
|
|
426
|
+
return m
|
|
423
427
|
|
|
424
428
|
m._gdfs = [gdf.clip(mask) for gdf in m._gdfs]
|
|
425
429
|
m._gdf = m._gdf.clip(mask)
|
|
426
430
|
m._nan_idx = m._gdf[m._column].isna()
|
|
427
431
|
m._get_unique_values()
|
|
428
432
|
m.explore(center=center, size=size)
|
|
433
|
+
return m
|
|
429
434
|
else:
|
|
430
435
|
m = Map(
|
|
431
436
|
*gdfs,
|
|
432
437
|
column=column,
|
|
433
|
-
labels=labels,
|
|
434
438
|
**kwargs,
|
|
435
439
|
)
|
|
436
440
|
if m.gdfs is None:
|
|
437
|
-
return
|
|
441
|
+
return m
|
|
438
442
|
|
|
439
443
|
m._gdfs = [gdf.clip(mask) for gdf in m._gdfs]
|
|
440
444
|
m._gdf = m._gdf.clip(mask)
|
|
@@ -443,8 +447,10 @@ def clipmap(
|
|
|
443
447
|
|
|
444
448
|
qtm(m._gdf, column=m.column, cmap=m._cmap, k=m.k)
|
|
445
449
|
|
|
450
|
+
return m
|
|
451
|
+
|
|
446
452
|
|
|
447
|
-
def explore_locals(*gdfs, convert: bool = True, **kwargs):
|
|
453
|
+
def explore_locals(*gdfs: GeoDataFrame, convert: bool = True, **kwargs) -> None:
|
|
448
454
|
"""Displays all local variables with geometries (GeoDataFrame etc.).
|
|
449
455
|
|
|
450
456
|
Local means inside a function or file/notebook.
|
|
@@ -478,17 +484,17 @@ def explore_locals(*gdfs, convert: bool = True, **kwargs):
|
|
|
478
484
|
|
|
479
485
|
if isinstance(value, dict) or hasattr(value, "__dict__"):
|
|
480
486
|
# add dicts or classes with GeoDataFrames to kwargs
|
|
481
|
-
for key,
|
|
482
|
-
if isinstance(
|
|
483
|
-
gdf = clean_geoms(
|
|
487
|
+
for key, val in as_dict(value).items():
|
|
488
|
+
if isinstance(val, allowed_types):
|
|
489
|
+
gdf = clean_geoms(to_gdf(val))
|
|
484
490
|
if len(gdf):
|
|
485
491
|
local_gdfs[key] = gdf
|
|
486
492
|
|
|
487
|
-
elif isinstance(
|
|
493
|
+
elif isinstance(val, dict) or hasattr(val, "__dict__"):
|
|
488
494
|
try:
|
|
489
|
-
for k, v in
|
|
495
|
+
for k, v in val.items():
|
|
490
496
|
if isinstance(v, allowed_types):
|
|
491
|
-
gdf = clean_geoms(
|
|
497
|
+
gdf = clean_geoms(to_gdf(v))
|
|
492
498
|
if len(gdf):
|
|
493
499
|
local_gdfs[k] = gdf
|
|
494
500
|
except Exception:
|
|
@@ -497,7 +503,7 @@ def explore_locals(*gdfs, convert: bool = True, **kwargs):
|
|
|
497
503
|
|
|
498
504
|
continue
|
|
499
505
|
try:
|
|
500
|
-
gdf = clean_geoms(
|
|
506
|
+
gdf = clean_geoms(to_gdf(value))
|
|
501
507
|
if len(gdf):
|
|
502
508
|
local_gdfs[name] = gdf
|
|
503
509
|
continue
|
|
@@ -512,7 +518,7 @@ def explore_locals(*gdfs, convert: bool = True, **kwargs):
|
|
|
512
518
|
if not frame:
|
|
513
519
|
break
|
|
514
520
|
|
|
515
|
-
explore(*gdfs, **local_gdfs, **kwargs)
|
|
521
|
+
return explore(*gdfs, **local_gdfs, **kwargs)
|
|
516
522
|
|
|
517
523
|
|
|
518
524
|
def qtm(
|
|
@@ -543,12 +549,13 @@ def qtm(
|
|
|
543
549
|
'viridis' when black, and 'RdPu' when white.
|
|
544
550
|
size: Size of the plot. Defaults to 10.
|
|
545
551
|
title_fontsize: Size of the title.
|
|
552
|
+
legend: Whether to add legend. Defaults to True.
|
|
546
553
|
cmap: Color palette of the map. See:
|
|
547
554
|
https://matplotlib.org/stable/tutorials/colors/colormaps.html
|
|
548
555
|
k: Number of color groups.
|
|
549
556
|
**kwargs: Additional keyword arguments taken by the geopandas plot method.
|
|
550
557
|
|
|
551
|
-
See
|
|
558
|
+
See Also:
|
|
552
559
|
ThematicMap: Class with more options for customising the plot.
|
|
553
560
|
"""
|
|
554
561
|
gdfs, column, kwargs = Map._separate_args(gdfs, column, kwargs)
|
|
@@ -561,9 +568,6 @@ def qtm(
|
|
|
561
568
|
else:
|
|
562
569
|
new_kwargs[key] = value
|
|
563
570
|
|
|
564
|
-
# self.labels.append(key)
|
|
565
|
-
# self.show.append(last_show)
|
|
566
|
-
|
|
567
571
|
m = ThematicMap(*gdfs, column=column, size=size, black=black)
|
|
568
572
|
|
|
569
573
|
if m._gdfs is None:
|