ssb-sgis 0.2.7__py3-none-any.whl → 0.2.8__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 CHANGED
@@ -3,7 +3,9 @@ from .geopandas_tools.buffer_dissolve_explode import (
3
3
  buff,
4
4
  buffdiss,
5
5
  buffdissexp,
6
+ buffdissexp_by_cluster,
6
7
  dissexp,
8
+ dissexp_by_cluster,
7
9
  )
8
10
  from .geopandas_tools.general import (
9
11
  bounds_to_points,
@@ -23,6 +25,7 @@ from .geopandas_tools.general import (
23
25
  from .geopandas_tools.geometry_types import (
24
26
  get_geom_type,
25
27
  is_single_geom_type,
28
+ make_all_singlepart,
26
29
  to_single_geom_type,
27
30
  )
28
31
  from .geopandas_tools.neighbors import (
@@ -17,6 +17,7 @@ for the following:
17
17
  from geopandas import GeoDataFrame, GeoSeries
18
18
 
19
19
  from .geometry_types import make_all_singlepart
20
+ from .polygon_operations import get_polygon_clusters
20
21
 
21
22
 
22
23
  def _decide_ignore_index(kwargs: dict) -> tuple[dict, bool]:
@@ -190,6 +191,31 @@ def dissexp(
190
191
  )
191
192
 
192
193
 
194
+ def dissexp_by_cluster(gdf: GeoDataFrame) -> GeoDataFrame:
195
+ return (
196
+ gdf.explode(ignore_index=True)
197
+ .pipe(get_polygon_clusters, cluster_col="cluster")
198
+ .pipe(dissexp, by="cluster")
199
+ .reset_index(drop=True)
200
+ )
201
+
202
+
203
+ def buffdissexp_by_cluster(
204
+ gdf: GeoDataFrame,
205
+ distance: int | float,
206
+ *,
207
+ resolution: int = 50,
208
+ copy: bool = True,
209
+ ) -> GeoDataFrame:
210
+ return (
211
+ buff(gdf, distance, resolution=resolution, copy=copy)
212
+ .explode(ignore_index=True)
213
+ .pipe(get_polygon_clusters, cluster_col="cluster")
214
+ .pipe(dissexp, by="cluster")
215
+ .reset_index(drop=True)
216
+ )
217
+
218
+
193
219
  def buff(
194
220
  gdf: GeoDataFrame | GeoSeries,
195
221
  distance: int | float,
@@ -2,6 +2,7 @@ import warnings
2
2
 
3
3
  import geopandas as gpd
4
4
  import numpy as np
5
+ import pandas as pd
5
6
  from geopandas import GeoDataFrame, GeoSeries
6
7
  from geopandas.array import GeometryDtype
7
8
  from shapely import (
@@ -519,11 +520,17 @@ def to_lines(*gdfs: GeoDataFrame, copy: bool = True) -> GeoDataFrame:
519
520
  if len(lines) == 1:
520
521
  return lines[0]
521
522
 
522
- unioned = lines[0].overlay(lines[1], how="union", keep_geom_type=True)
523
+ if len(lines[0]) and len(lines[1]):
524
+ unioned = lines[0].overlay(lines[1], how="union", keep_geom_type=True)
525
+ else:
526
+ unioned = pd.concat([lines[0], lines[1]], ignore_index=True)
523
527
 
524
528
  if len(lines) > 2:
525
529
  for line_gdf in lines[2:]:
526
- unioned = unioned.overlay(line_gdf, how="union", keep_geom_type=True)
530
+ if len(line_gdf):
531
+ unioned = unioned.overlay(line_gdf, how="union", keep_geom_type=True)
532
+ else:
533
+ unioned = pd.concat([unioned, line_gdf], ignore_index=True)
527
534
 
528
535
  return make_all_singlepart(unioned, ignore_index=True)
529
536
 
@@ -23,6 +23,147 @@ from .neighbors import get_neighbor_indices
23
23
  from .overlay import clean_overlay
24
24
 
25
25
 
26
+ def get_polygon_clusters(
27
+ *gdfs: GeoDataFrame | GeoSeries,
28
+ cluster_col: str = "cluster",
29
+ allow_multipart: bool = False,
30
+ ) -> GeoDataFrame | tuple[GeoDataFrame]:
31
+ """Find which polygons overlap without dissolving.
32
+
33
+ Devides polygons into clusters in a fast and precice manner by using spatial join
34
+ and networkx to find the connected components, i.e. overlapping geometries.
35
+ If multiple GeoDataFrames are given, the clusters will be based on all
36
+ combined.
37
+
38
+ This can be used instead of dissolve+explode, or before dissolving by the cluster
39
+ column. This has been tested to be a lot faster if there are many
40
+ non-overlapping polygons, but somewhat slower than dissolve+explode if most
41
+ polygons overlap.
42
+
43
+ Args:
44
+ gdfs: One or more GeoDataFrames of polygons.
45
+ cluster_col: Name of the resulting cluster column.
46
+ allow_multipart: Whether to allow mutipart geometries in the gdfs.
47
+ Defaults to False to avoid confusing results.
48
+
49
+ Returns:
50
+ One or more GeoDataFrames (same amount as was given) with a new cluster column.
51
+
52
+ Examples
53
+ --------
54
+
55
+ Create geometries with three clusters of overlapping polygons.
56
+
57
+ >>> import sgis as sg
58
+ >>> gdf = sg.to_gdf([(0, 0), (1, 1), (0, 1), (4, 4), (4, 3), (7, 7)])
59
+ >>> buffered = sg.buff(gdf, 1)
60
+ >>> gdf
61
+ geometry
62
+ 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
63
+ 1 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
64
+ 2 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
65
+ 3 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
66
+ 4 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
67
+ 5 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
68
+
69
+ Add a cluster column to the GeoDataFrame:
70
+
71
+ >>> gdf = sg.get_polygon_clusters(gdf, cluster_col="cluster")
72
+ >>> gdf
73
+ cluster geometry
74
+ 0 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
75
+ 1 0 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
76
+ 2 0 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
77
+ 3 1 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
78
+ 4 1 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
79
+ 5 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
80
+
81
+ If multiple GeoDataFrames are given, all are returned with common
82
+ cluster values.
83
+
84
+ >>> gdf2 = sg.to_gdf([(0, 0), (7, 7)])
85
+ >>> gdf, gdf2 = sg.get_polygon_clusters(gdf, gdf2, cluster_col="cluster")
86
+ >>> gdf2
87
+ cluster geometry
88
+ 0 0 POINT (0.00000 0.00000)
89
+ 1 2 POINT (7.00000 7.00000)
90
+ >>> gdf
91
+ cluster geometry
92
+ 0 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
93
+ 1 0 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
94
+ 2 0 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
95
+ 3 1 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
96
+ 4 1 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
97
+ 5 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
98
+
99
+ Dissolving 'by' the cluster column will make the dissolve much
100
+ faster if there are a lot of non-overlapping polygons.
101
+
102
+ >>> dissolved = gdf.dissolve(by="cluster", as_index=False)
103
+ >>> dissolved
104
+ cluster geometry
105
+ 0 0 POLYGON ((0.99951 -0.03141, 0.99803 -0.06279, ...
106
+ 1 1 POLYGON ((4.99951 2.96859, 4.99803 2.93721, 4....
107
+ 2 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
108
+ """
109
+ if isinstance(gdfs[-1], str):
110
+ *gdfs, cluster_col = gdfs
111
+
112
+ concated = pd.DataFrame()
113
+ orig_indices = ()
114
+ for i, gdf in enumerate(gdfs):
115
+ if isinstance(gdf, GeoSeries):
116
+ gdf = gdf.to_frame()
117
+
118
+ if not isinstance(gdf, GeoDataFrame):
119
+ raise TypeError("'gdfs' should be GeoDataFrames or GeoSeries.")
120
+
121
+ if not allow_multipart and len(gdf) != len(gdf.explode(index_parts=False)):
122
+ raise ValueError(
123
+ "All geometries should be exploded to singlepart "
124
+ "in order to get correct polygon clusters. "
125
+ "To allow multipart geometries, set allow_multipart=True"
126
+ )
127
+
128
+ orig_indices = orig_indices + (gdf.index,)
129
+
130
+ gdf["i__"] = i
131
+
132
+ concated = pd.concat([concated, gdf], ignore_index=True)
133
+
134
+ neighbors = get_neighbor_indices(concated, concated)
135
+
136
+ edges = [(source, target) for source, target in neighbors.items()]
137
+
138
+ graph = nx.Graph()
139
+ graph.add_edges_from(edges)
140
+
141
+ component_mapper = {
142
+ j: i
143
+ for i, component in enumerate(nx.connected_components(graph))
144
+ for j in component
145
+ }
146
+
147
+ concated[cluster_col] = component_mapper
148
+
149
+ concated = _push_geom_col(concated)
150
+
151
+ n_gdfs = concated["i__"].unique()
152
+
153
+ if len(n_gdfs) == 1:
154
+ concated.index = orig_indices[0]
155
+ return concated.drop(["i__"], axis=1)
156
+
157
+ unconcated = ()
158
+ for i in n_gdfs:
159
+ gdf = concated[concated["i__"] == i]
160
+ gdf.index = orig_indices[i]
161
+ gdf = gdf.drop(["i__"], axis=1)
162
+ unconcated = unconcated + (gdf,)
163
+
164
+ return unconcated
165
+
166
+
26
167
  def eliminate_by_longest(
27
168
  gdf: GeoDataFrame,
28
169
  to_eliminate: GeoDataFrame,
@@ -215,146 +356,6 @@ def _eliminate_by_area(
215
356
  return eliminated
216
357
 
217
358
 
218
- def get_polygon_clusters(
219
- *gdfs: GeoDataFrame | GeoSeries,
220
- cluster_col: str = "cluster",
221
- allow_multipart: bool = False,
222
- ) -> GeoDataFrame | tuple[GeoDataFrame]:
223
- """Find which polygons overlap without dissolving.
224
-
225
- Devides polygons into clusters in a fast and precice manner by using spatial join
226
- and networkx to find the connected components, i.e. overlapping geometries.
227
- If multiple GeoDataFrames are given, the clusters will be based on all
228
- combined.
229
-
230
- This can be used instead of dissolve+explode, or before dissolving by the cluster
231
- column. This has been tested to be a lot faster if there are many
232
- non-overlapping polygons, but somewhat slower than dissolve+explode if most
233
- polygons overlap.
234
-
235
- Args:
236
- gdfs: One or more GeoDataFrames of polygons.
237
- cluster_col: Name of the resulting cluster column.
238
- allow_multipart: Whether to allow mutipart geometries in the gdfs.
239
- Defaults to False to avoid confusing results.
240
-
241
- Returns:
242
- One or more GeoDataFrames (same amount as was given) with a new cluster column.
243
-
244
- Examples
245
- --------
246
-
247
- Create geometries with three clusters of overlapping polygons.
248
-
249
- >>> import sgis as sg
250
- >>> gdf = sg.to_gdf([(0, 0), (1, 1), (0, 1), (4, 4), (4, 3), (7, 7)])
251
- >>> buffered = sg.buff(gdf, 1)
252
- >>> gdf
253
- geometry
254
- 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
255
- 1 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
256
- 2 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
257
- 3 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
258
- 4 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
259
- 5 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
260
-
261
- Add a cluster column to the GeoDataFrame:
262
-
263
- >>> gdf = sg.get_polygon_clusters(gdf, cluster_col="cluster")
264
- >>> gdf
265
- cluster geometry
266
- 0 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
267
- 1 0 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
268
- 2 0 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
269
- 3 1 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
270
- 4 1 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
271
- 5 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
272
-
273
- If multiple GeoDataFrames are given, all are returned with common
274
- cluster values.
275
-
276
- >>> gdf2 = sg.to_gdf([(0, 0), (7, 7)])
277
- >>> gdf, gdf2 = sg.get_polygon_clusters(gdf, gdf2, cluster_col="cluster")
278
- >>> gdf2
279
- cluster geometry
280
- 0 0 POINT (0.00000 0.00000)
281
- 1 2 POINT (7.00000 7.00000)
282
- >>> gdf
283
- cluster geometry
284
- 0 0 POLYGON ((1.00000 0.00000, 0.99951 -0.03141, 0...
285
- 1 0 POLYGON ((2.00000 1.00000, 1.99951 0.96859, 1....
286
- 2 0 POLYGON ((1.00000 1.00000, 0.99951 0.96859, 0....
287
- 3 1 POLYGON ((5.00000 4.00000, 4.99951 3.96859, 4....
288
- 4 1 POLYGON ((5.00000 3.00000, 4.99951 2.96859, 4....
289
- 5 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
290
-
291
- Dissolving 'by' the cluster column will make the dissolve much
292
- faster if there are a lot of non-overlapping polygons.
293
-
294
- >>> dissolved = gdf.dissolve(by="cluster", as_index=False)
295
- >>> dissolved
296
- cluster geometry
297
- 0 0 POLYGON ((0.99951 -0.03141, 0.99803 -0.06279, ...
298
- 1 1 POLYGON ((4.99951 2.96859, 4.99803 2.93721, 4....
299
- 2 2 POLYGON ((8.00000 7.00000, 7.99951 6.96859, 7....
300
- """
301
- if isinstance(gdfs[-1], str):
302
- *gdfs, cluster_col = gdfs
303
-
304
- concated = pd.DataFrame()
305
- orig_indices = ()
306
- for i, gdf in enumerate(gdfs):
307
- if isinstance(gdf, GeoSeries):
308
- gdf = gdf.to_frame()
309
-
310
- if not isinstance(gdf, GeoDataFrame):
311
- raise TypeError("'gdfs' should be one or more GeoDataFrames or GeoSeries.")
312
-
313
- if not allow_multipart and len(gdf) != len(gdf.explode(index_parts=False)):
314
- raise ValueError(
315
- "All geometries should be exploded to singlepart "
316
- "in order to get correct polygon clusters. "
317
- "To allow multipart geometries, set allow_multipart=True"
318
- )
319
-
320
- orig_indices = orig_indices + (gdf.index,)
321
- gdf["i__"] = i
322
-
323
- concated = pd.concat([concated, gdf], ignore_index=True)
324
-
325
- neighbors = get_neighbor_indices(concated, concated)
326
-
327
- edges = [(source, target) for source, target in neighbors.items()]
328
-
329
- graph = nx.Graph()
330
- graph.add_edges_from(edges)
331
-
332
- component_mapper = {
333
- j: i
334
- for i, component in enumerate(nx.connected_components(graph))
335
- for j in component
336
- }
337
-
338
- concated[cluster_col] = component_mapper
339
-
340
- concated = _push_geom_col(concated)
341
-
342
- n_gdfs = concated["i__"].unique()
343
-
344
- if len(n_gdfs) == 1:
345
- concated.index = orig_indices[0]
346
- return concated.drop(["i__"], axis=1)
347
-
348
- unconcated = ()
349
- for i in n_gdfs:
350
- gdf = concated[concated["i__"] == i]
351
- gdf.index = orig_indices[i]
352
- gdf = gdf.drop(["i__"], axis=1)
353
- unconcated = unconcated + (gdf,)
354
-
355
- return unconcated
356
-
357
-
358
359
  def get_overlapping_polygons(
359
360
  gdf: GeoDataFrame | GeoSeries, ignore_index: bool = False
360
361
  ) -> GeoDataFrame | GeoSeries:
@@ -3,6 +3,7 @@ from collections.abc import Iterator, Sized
3
3
 
4
4
  import geopandas as gpd
5
5
  import pandas as pd
6
+ import shapely
6
7
  from geopandas import GeoDataFrame, GeoSeries
7
8
  from pandas.api.types import is_array_like, is_dict_like, is_list_like
8
9
  from shapely import Geometry, box, wkb, wkt
@@ -128,7 +129,7 @@ def to_gdf(
128
129
  raise TypeError("'to_gdf' doesn't accept GeoDataFrames as input type.")
129
130
 
130
131
  if isinstance(geom, GeoSeries):
131
- geom_col = "geometry" if not geometry else geometry
132
+ geom_col = geometry if geometry else "geometry"
132
133
  return _geoseries_to_gdf(geom, geom_col, crs, **kwargs)
133
134
 
134
135
  geom_col = _find_geometry_column(geom, geometry)
@@ -144,8 +145,26 @@ def to_gdf(
144
145
  return GeoDataFrame({geom_col: geom}, geometry=geom_col, crs=crs, **kwargs)
145
146
 
146
147
  if not is_dict_like(geom):
147
- geom = GeoSeries(_make_shapely_geoms(geom), index=index)
148
- return GeoDataFrame({geom_col: geom}, geometry=geom_col, crs=crs, **kwargs)
148
+ if not hasattr(geom, "__iter__") and hasattr(geom, "__dict__"):
149
+ if all(attr in geom.__dict__ for attr in ["minx", "miny", "maxx", "maxy"]):
150
+ geom = GeoSeries(
151
+ shapely.box(*(geom.minx, geom.miny, geom.maxx, geom.maxy)),
152
+ index=index,
153
+ )
154
+ return GeoDataFrame(
155
+ {geom_col: geom}, geometry=geom_col, crs=crs, **kwargs
156
+ )
157
+ if hasattr(geom, "__iter__") and all(isinstance(g, dict) for g in geom):
158
+ crs = crs if crs else _get_crs(geom)
159
+ geom = pd.concat(GeoSeries(_from_json(g)) for g in geom)
160
+ if index is not None:
161
+ geom.index = index
162
+ else:
163
+ geom = geom.reset_index(drop=True)
164
+ return GeoDataFrame({geom_col: geom}, geometry=geom_col, crs=crs, **kwargs)
165
+ else:
166
+ geom = GeoSeries(_make_shapely_geoms(geom), index=index)
167
+ return GeoDataFrame({geom_col: geom}, geometry=geom_col, crs=crs, **kwargs)
149
168
 
150
169
  # now we have dict, Series or DataFrame
151
170
 
@@ -177,10 +196,61 @@ def to_gdf(
177
196
  if geometry and geom_col not in geom or isinstance(geom, pd.DataFrame):
178
197
  raise ValueError("Cannot find geometry column(s)", geometry)
179
198
 
199
+ # geojson, __geo_interface__
200
+ if (
201
+ isinstance(geom, dict)
202
+ and sum(key in geom for key in ["type", "coordinates", "features"]) >= 2
203
+ ):
204
+ if "geometry" in geom:
205
+ geometry = "geometry"
206
+
207
+ crs = crs if crs else _get_crs(geom)
208
+ print(crs)
209
+ geom = GeoSeries(_from_json(geom), index=index)
210
+ return GeoDataFrame({geom_col: geom}, geometry=geom_col, crs=crs, **kwargs)
211
+
180
212
  geoseries = _series_like_to_geoseries(geom, index=index)
181
213
  return GeoDataFrame(geometry=geoseries, crs=crs, **kwargs)
182
214
 
183
215
 
216
+ def _get_crs(geom):
217
+ if not is_dict_like(geom) and is_dict_like(geom[0]):
218
+ crss = list({_get_crs(g) for g in geom})
219
+ if len(crss) == 1:
220
+ return crss[0]
221
+ return None
222
+ if "properties" in geom:
223
+ return _get_crs(geom["properties"])
224
+ if "crs" in geom:
225
+ geom = geom["crs"]
226
+ while is_dict_like(geom):
227
+ if "properties" in geom:
228
+ geom = geom["properties"]
229
+ elif "name" in geom:
230
+ geom = geom["name"]
231
+ else:
232
+ return None
233
+ return geom
234
+ return None
235
+
236
+
237
+ def _from_json(geom: dict):
238
+ if not isinstance(geom, dict) and isinstance(geom[0], dict):
239
+ return [_from_json(g) for g in geom]
240
+ if "geometry" in geom:
241
+ return _from_json(geom["geometry"])
242
+ if "features" in geom:
243
+ return _from_json(geom["features"])
244
+ coords = geom["coordinates"]
245
+ constructor = eval("shapely.geometry." + geom.get("type", Point))
246
+ try:
247
+ return constructor(coords)
248
+ except TypeError:
249
+ while len(coords) == 1:
250
+ coords = coords[0]
251
+ return constructor(coords)
252
+
253
+
184
254
  def _series_like_to_geoseries(geom, index):
185
255
  if index is None:
186
256
  index = geom.keys()
@@ -252,6 +322,8 @@ def _is_one_geometry(geom) -> bool:
252
322
  def _make_shapely_geoms(geom):
253
323
  if _is_one_geometry(geom):
254
324
  return _make_one_shapely_geom(geom)
325
+ if isinstance(geom, dict) and "coordinates" in geom:
326
+ return _from_json(geom)
255
327
  return (_make_one_shapely_geom(g) for g in geom)
256
328
 
257
329
 
sgis/helpers.py CHANGED
@@ -58,9 +58,9 @@ def get_name(var: object, n: int = 5) -> str | None:
58
58
  frame = inspect.currentframe().f_back.f_back
59
59
 
60
60
  for _ in range(n):
61
- locals_ = frame.f_locals
62
-
63
- names = [var_name for var_name, var_val in locals_.items() if var_val is var]
61
+ names = [
62
+ var_name for var_name, var_val in frame.f_locals.items() if var_val is var
63
+ ]
64
64
  if names and len(names) == 1:
65
65
  return names[0]
66
66
 
sgis/maps/explore.py CHANGED
@@ -4,6 +4,7 @@ This module holds the Explore class, which is the basis for the explore, samplem
4
4
  clipmap functions from the 'maps' module.
5
5
  """
6
6
  import warnings
7
+ from numbers import Number
7
8
  from statistics import mean
8
9
 
9
10
  import branca as bc
@@ -15,10 +16,11 @@ from folium import plugins
15
16
  from geopandas import GeoDataFrame
16
17
  from IPython.display import display
17
18
  from jinja2 import Template
19
+ from shapely import Geometry
18
20
  from shapely.geometry import LineString
19
21
 
20
22
  from ..geopandas_tools.general import clean_geoms, make_all_singlepart
21
- from ..geopandas_tools.geometry_types import get_geom_type
23
+ from ..geopandas_tools.geometry_types import get_geom_type, to_single_geom_type
22
24
  from ..geopandas_tools.to_geodataframe import to_gdf
23
25
  from ..helpers import unit_is_degrees
24
26
  from .httpserver import run_html_server
@@ -110,6 +112,17 @@ class Explore(Map):
110
112
 
111
113
  super().__init__(*gdfs, column=column, **kwargs)
112
114
 
115
+ # remove columns not renerable by leaflet (list columns etc.)
116
+ new_gdfs = []
117
+ for gdf in self.gdfs:
118
+ cols_to_keep = [
119
+ col
120
+ for col in gdf.columns
121
+ if isinstance(gdf[col].iloc[0], (Number, str, Geometry))
122
+ ]
123
+ new_gdfs.append(gdf[cols_to_keep])
124
+ self._gdfs = new_gdfs
125
+
113
126
  self.popup = popup
114
127
  self.max_zoom = max_zoom
115
128
  self.smooth_factor = smooth_factor
@@ -266,6 +279,7 @@ class Explore(Map):
266
279
 
267
280
  new_gdfs = []
268
281
  for gdf in self._gdfs:
282
+ print(gdf)
269
283
  if get_geom_type(gdf) == "mixed" and not unit_is_degrees(gdf):
270
284
  gdf[gdf._geometry_column_name] = gdf.buffer(0.01)
271
285
  gdf = make_all_singlepart(gdf)
@@ -615,7 +629,26 @@ class Explore(Map):
615
629
  "supported as marker values"
616
630
  )
617
631
 
618
- gdf = clean_geoms(gdf)
632
+ gdf = clean_geoms(gdf).pipe(make_all_singlepart)
633
+ if get_geom_type(gdf) == "mixed":
634
+ if gdf.geom_type.str.lower().str.contains("polygon").any():
635
+ warnings.warn(
636
+ "GeoJsonTooltip is not configured to render for GeoJson "
637
+ "GeometryCollection geometries. Keeping only polygons."
638
+ )
639
+ gdf = to_single_geom_type(gdf, geom_type="polygon")
640
+ elif gdf.geom_type.str.lower().str.contains("line").any():
641
+ warnings.warn(
642
+ "GeoJsonTooltip is not configured to render for GeoJson "
643
+ "GeometryCollection geometries. Keeping only lines."
644
+ )
645
+ gdf = to_single_geom_type(gdf, geom_type="line")
646
+ else:
647
+ warnings.warn(
648
+ "GeoJsonTooltip is not configured to render for GeoJson "
649
+ "GeometryCollection geometries. Keeping only points."
650
+ )
651
+ gdf = to_single_geom_type(gdf, geom_type="point")
619
652
 
620
653
  # prepare tooltip and popup
621
654
  if isinstance(gdf, GeoDataFrame):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-sgis
3
- Version: 0.2.7
3
+ Version: 0.2.8
4
4
  Summary: GIS functions used at Statistics Norway.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-sgis
6
6
  License: MIT
@@ -1,19 +1,19 @@
1
- sgis/__init__.py,sha256=BWIQpUVt_X9jFJ6VkJO1XVcGQiOKv60PskNG5XO26G0,2368
1
+ sgis/__init__.py,sha256=84lCHfBsH9nHwopwoPTMNHs1FvTWemuRPLALAhUEFIA,2445
2
2
  sgis/dapla.py,sha256=BlJ62kLwpTTQtmbj0Yutbh-bwokVPXHVb3QsRlMugF8,3542
3
3
  sgis/exceptions.py,sha256=ztMp4sB9xxPvwj2IEsO5kOaB4FmHuU_7-M2pZ7qaxTs,576
4
4
  sgis/geopandas_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- sgis/geopandas_tools/buffer_dissolve_explode.py,sha256=46uBomQJMDFtGWVNZWyZLl-NLMwYyhr4wWkwj6BTxoo,8080
6
- sgis/geopandas_tools/general.py,sha256=BGBXobFRFl9fmFF-vRkkrcA2xHKGy4hylOEC4y4Ooto,17659
5
+ sgis/geopandas_tools/buffer_dissolve_explode.py,sha256=JHFdhFVURHKAW9NraQZ7YEtvp_lBveGdL0PkBZn1fuE,8780
6
+ sgis/geopandas_tools/general.py,sha256=Hbk1A_aFH_xgD_TkvaJQDW1U2lJYh-LHI9CmsPTkHaI,17930
7
7
  sgis/geopandas_tools/geometry_types.py,sha256=o3MbBP-aI7hVWWKVr_5p91TDhjiqZ_2IGxJq7SxlCT4,5870
8
8
  sgis/geopandas_tools/neighbors.py,sha256=tv8bmYgq4VNFbXmT2wcmJsFH8946NwbIBMQXAi3n8L4,14520
9
9
  sgis/geopandas_tools/overlay.py,sha256=RSxrDF0sXs6ZMxbeBJC9HFBVM4yaz10-cdbq3SCosFQ,11862
10
10
  sgis/geopandas_tools/point_operations.py,sha256=3JynroucouAbpON4DWG32S3MQQGmfIJuY7D6gkqtk70,6888
11
- sgis/geopandas_tools/polygon_operations.py,sha256=ZzRx57w4LodN8_P_Tqc-zBAxGCvgvObIi9kJQKa-LLc,22646
12
- sgis/geopandas_tools/to_geodataframe.py,sha256=g1NqPVVH6hAdMupWxHVd10EvipLY9wPiahh2u_vLOnk,9887
13
- sgis/helpers.py,sha256=OqTojkSl-JVKlJzqqB-d_0CH6mk7_LS1DkiIjp1gD8E,2674
11
+ sgis/geopandas_tools/polygon_operations.py,sha256=84AGRHKZR-3zKKVDNbKYCziC9YNUVm2qUEpfRvmIdn4,22635
12
+ sgis/geopandas_tools/to_geodataframe.py,sha256=qtbeiQ9rPcM9afopNPzlN2fiMH5o6SoIYDotX6e_E0Q,12458
13
+ sgis/helpers.py,sha256=6tElQx9Rr3nbQPp_vAgugw-pNHNuYQO-Ta2311_EcWs,2669
14
14
  sgis/maps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  sgis/maps/examine.py,sha256=Wf48WwyNyPC1vYdw-n7GpvJYhwd-YMd_VZLOUI5vWZ4,6479
16
- sgis/maps/explore.py,sha256=mab8LE8c_dsGwS1gVCCA2A3r5_Vh7hnzEfEs5MBadvE,23631
16
+ sgis/maps/explore.py,sha256=d16h8hHyUeSfsrAWdeFUPK6XT6S7-xr1w4_cHu2XA_I,25138
17
17
  sgis/maps/httpserver.py,sha256=7ksCSs-WlchcREgjdCZd6II-riJpox34HpVXsCzN_AU,1923
18
18
  sgis/maps/legend.py,sha256=GXAqGOb_zAWcDavd5aHzRyRB7nTRhPCQfSupYA693lk,20499
19
19
  sgis/maps/map.py,sha256=niK6N0eFJjAalxjHTNA7kh-2KuazLVsnWlu8i9Ava7o,18611
@@ -34,7 +34,7 @@ sgis/networkanalysis/networkanalysisrules.py,sha256=BhhaSXIyBRNzxSOUP2kVBIR--TRq
34
34
  sgis/networkanalysis/nodes.py,sha256=Ys3FjB39Pir3U0jOoLKIPxCC4psC9mdlqdC7G6dSJg0,6767
35
35
  sgis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  sgis/read_parquet.py,sha256=GSW2NDy4-XosbamPEzB1xhWxFAPHuGEJZglfQ-V6DzY,3774
37
- ssb_sgis-0.2.7.dist-info/LICENSE,sha256=lL2h0dNKGTKAE0CjTy62SDbRennVD1xPgM5LzGqhKeo,1074
38
- ssb_sgis-0.2.7.dist-info/METADATA,sha256=hpcq2ydyXosFFnw-35qJtrdL3a7bhdblNERuDUiQea8,8831
39
- ssb_sgis-0.2.7.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
40
- ssb_sgis-0.2.7.dist-info/RECORD,,
37
+ ssb_sgis-0.2.8.dist-info/LICENSE,sha256=lL2h0dNKGTKAE0CjTy62SDbRennVD1xPgM5LzGqhKeo,1074
38
+ ssb_sgis-0.2.8.dist-info/METADATA,sha256=hR3yvnhqhsaE8jEvutRwNHAFJq78Hhua5JodgYX99mE,8831
39
+ ssb_sgis-0.2.8.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
40
+ ssb_sgis-0.2.8.dist-info/RECORD,,