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/thematicmap.py
CHANGED
|
@@ -1,86 +1,153 @@
|
|
|
1
1
|
"""Make static maps with geopandas and matplotlib."""
|
|
2
|
+
|
|
2
3
|
import warnings
|
|
4
|
+
from typing import Any
|
|
3
5
|
|
|
4
6
|
import matplotlib
|
|
7
|
+
import matplotlib.figure
|
|
5
8
|
import matplotlib.pyplot as plt
|
|
6
9
|
import numpy as np
|
|
7
10
|
import pandas as pd
|
|
8
11
|
from geopandas import GeoDataFrame
|
|
9
12
|
|
|
10
|
-
from .legend import
|
|
13
|
+
from .legend import LEGEND_KWARGS
|
|
14
|
+
from .legend import ContinousLegend
|
|
15
|
+
from .legend import Legend
|
|
16
|
+
from .legend import prettify_bins
|
|
11
17
|
from .map import Map
|
|
12
18
|
|
|
13
|
-
|
|
14
19
|
# the geopandas._explore raises a deprication warning. Ignoring for now.
|
|
15
20
|
warnings.filterwarnings(
|
|
16
21
|
action="ignore", category=matplotlib.MatplotlibDeprecationWarning
|
|
17
22
|
)
|
|
18
23
|
pd.options.mode.chained_assignment = None
|
|
19
24
|
|
|
25
|
+
MAP_KWARGS = {
|
|
26
|
+
"bins",
|
|
27
|
+
"title",
|
|
28
|
+
"title_fontsize",
|
|
29
|
+
"size",
|
|
30
|
+
"cmap",
|
|
31
|
+
"cmap_start",
|
|
32
|
+
"cmap_stop",
|
|
33
|
+
"scheme",
|
|
34
|
+
"k",
|
|
35
|
+
"column",
|
|
36
|
+
"title_color",
|
|
37
|
+
"facecolor",
|
|
38
|
+
"labelcolor",
|
|
39
|
+
"nan_color",
|
|
40
|
+
"title_kwargs",
|
|
41
|
+
"bg_gdf_color",
|
|
42
|
+
"title_position",
|
|
43
|
+
}
|
|
20
44
|
|
|
21
|
-
class ThematicMap(Map):
|
|
22
|
-
"""Class for creating static maps with geopandas and matplotlib.
|
|
23
45
|
|
|
24
|
-
|
|
25
|
-
|
|
46
|
+
class ThematicMap(Map):
|
|
47
|
+
"""Class for making static maps.
|
|
26
48
|
|
|
27
49
|
Args:
|
|
28
50
|
*gdfs: One or more GeoDataFrames.
|
|
29
51
|
column: The name of the column to plot.
|
|
52
|
+
title: Title of the plot.
|
|
53
|
+
title_position: Title position. Either "center" (default), "left" or "right".
|
|
30
54
|
size: Width and height of the plot in inches. Fontsize of title and legend is
|
|
31
55
|
adjusted accordingly. Defaults to 25.
|
|
32
|
-
|
|
56
|
+
dark: If False (default), the background will be white and the text black. If
|
|
33
57
|
True, the background will be black and the text white. When True, the
|
|
34
58
|
default cmap is "viridis", and when False, the default is red to purple
|
|
35
59
|
(RdPu).
|
|
36
|
-
|
|
37
|
-
Attributes:
|
|
38
|
-
size (int): Width and height of the plot in inches.
|
|
39
|
-
k (int): Number of color groups.
|
|
40
|
-
legend (Legend): The legend object of the map. The legend holds its own set of
|
|
41
|
-
attributes. See the Legend class for details.
|
|
42
|
-
title (str): Title of the plot.
|
|
43
|
-
title_color (str): Color of the title font.
|
|
44
|
-
title_fontsize (int): Color of the title font.
|
|
45
|
-
bins (list[int | float]): For numeric columns. List of numbers that define the
|
|
46
|
-
maximum value for the color groups.
|
|
47
|
-
cmap (str): Colormap of the plot. See:
|
|
60
|
+
cmap: Colormap of the plot. See:
|
|
48
61
|
https://matplotlib.org/stable/tutorials/colors/colormaps.html
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
scheme: How to devide numeric values into categories. Defaults to
|
|
63
|
+
"naturalbreaks".
|
|
64
|
+
k: Number of color groups.
|
|
65
|
+
bins: For numeric columns. List of numbers that define the
|
|
66
|
+
maximum value for the color groups.
|
|
67
|
+
nan_label: Label for missing data.
|
|
68
|
+
legend_kwargs: dictionary with attributes for the legend. E.g.:
|
|
69
|
+
title: Legend title. Defaults to the column name.
|
|
70
|
+
rounding: If positive number, it will round floats to n decimals.
|
|
71
|
+
If negative, eg. -2, the number 3429 is rounded to 3400.
|
|
72
|
+
By default, the rounding depends on the column's maximum value
|
|
73
|
+
and standard deviation.
|
|
74
|
+
position: The legend's x and y position in the plot. By default, it's
|
|
75
|
+
decided dynamically by finding the space with most distance to
|
|
76
|
+
the geometries. To be specified as a tuple of
|
|
77
|
+
x and y position between 0 and 1. E.g. position=(0.8, 0.2) for a position
|
|
78
|
+
in the bottom right corner, (0.2, 0.8) for the upper left corner.
|
|
79
|
+
pretty_labels: Whether to capitalize words in text categories.
|
|
80
|
+
label_suffix: For numeric columns. The text to put after each number
|
|
81
|
+
in the legend labels. Defaults to None.
|
|
82
|
+
label_sep: For numeric columns. Text to put in between the two numbers
|
|
83
|
+
in each color group in the legend. Defaults to '-'.
|
|
84
|
+
thousand_sep: For numeric columns. Separator between each thousand for
|
|
85
|
+
large numbers. Defaults to None, meaning no separator.
|
|
86
|
+
decimal_mark: For numeric columns. Text to use as decimal point.
|
|
87
|
+
Defaults to None, meaning '.' (dot) unless 'thousand_sep' is
|
|
88
|
+
'.'. In this case, ',' (comma) will be used as decimal mark.
|
|
89
|
+
**kwargs: Additional attributes for the map. E.g.:
|
|
90
|
+
title_color (str): Color of the title font.
|
|
91
|
+
title_fontsize (int): Color of the title font.
|
|
92
|
+
cmap_start (int): Start position for the color palette.
|
|
93
|
+
cmap_stop (int): End position for the color palette.
|
|
94
|
+
facecolor (str): Background color.
|
|
95
|
+
labelcolor (str): Color for the labels.
|
|
96
|
+
nan_color: Color for missing data.
|
|
97
|
+
|
|
98
|
+
Examples:
|
|
54
99
|
--------
|
|
55
100
|
>>> import sgis as sg
|
|
56
|
-
>>> points = sg.random_points(100).pipe(sg.buff, np.random.rand(100))
|
|
57
|
-
>>> points2 = sg.random_points(100).pipe(sg.buff, np.random.rand(100))
|
|
101
|
+
>>> points = sg.random_points(100, loc=1000).pipe(sg.buff, np.random.rand(100) * 100)
|
|
102
|
+
>>> points2 = sg.random_points(100, loc=1000).pipe(sg.buff, np.random.rand(100) * 100)
|
|
103
|
+
|
|
58
104
|
|
|
59
105
|
Simple plot with legend and title.
|
|
60
106
|
|
|
61
|
-
>>> m = sg.ThematicMap(points, points2, "area")
|
|
62
|
-
>>> m.title = "Area of random circles"
|
|
107
|
+
>>> m = sg.ThematicMap(points, points2, column="area", title="Area of random circles")
|
|
63
108
|
>>> m.plot()
|
|
64
109
|
|
|
65
|
-
Plot with custom legend units (label_suffix) and separator
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
>>> m
|
|
70
|
-
|
|
110
|
+
Plot with custom legend units (label_suffix) and thousand separator.
|
|
111
|
+
And with rounding set to -2, meaning e.g. 3429 is rounded to 3400.
|
|
112
|
+
If rounding was set to positive 2, 3429 would be rounded to 3429.00.
|
|
113
|
+
|
|
114
|
+
>>> m = sg.ThematicMap(
|
|
115
|
+
... points,
|
|
116
|
+
... points2,
|
|
117
|
+
... column="area",
|
|
118
|
+
... title = "Area of random circles",
|
|
119
|
+
... legend_kwargs=dict(
|
|
120
|
+
... rounding=-2,
|
|
121
|
+
... thousand_sep=" ",
|
|
122
|
+
... label_sep="to",
|
|
123
|
+
... ),
|
|
124
|
+
... )
|
|
71
125
|
>>> m.plot()
|
|
72
126
|
|
|
73
|
-
With custom bins and
|
|
74
|
-
|
|
75
|
-
>>> m = sg.ThematicMap(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
...
|
|
80
|
-
...
|
|
81
|
-
...
|
|
82
|
-
...
|
|
83
|
-
...
|
|
127
|
+
With custom bins for the categories, and other customizations.
|
|
128
|
+
|
|
129
|
+
>>> m = sg.ThematicMap(
|
|
130
|
+
... points,
|
|
131
|
+
... points2,
|
|
132
|
+
... column="area",
|
|
133
|
+
... cmap="Greens",
|
|
134
|
+
... cmap_start=50,
|
|
135
|
+
... cmap_stop=255,
|
|
136
|
+
... nan_label="Missing",
|
|
137
|
+
... title = "Area of random circles",
|
|
138
|
+
... bins = [5000, 10000, 15000, 20000],
|
|
139
|
+
... title_kwargs=dict(
|
|
140
|
+
... loc="left",
|
|
141
|
+
... y=0.93,
|
|
142
|
+
... x=0.025,
|
|
143
|
+
... ),
|
|
144
|
+
... legend_kwargs=dict(
|
|
145
|
+
... thousand_sep=" ",
|
|
146
|
+
... label_sep="to",
|
|
147
|
+
... decimal_mark=".",
|
|
148
|
+
... label_suffix="m2",
|
|
149
|
+
... ),
|
|
150
|
+
... )
|
|
84
151
|
>>> m.plot()
|
|
85
152
|
"""
|
|
86
153
|
|
|
@@ -88,25 +155,101 @@ class ThematicMap(Map):
|
|
|
88
155
|
self,
|
|
89
156
|
*gdfs: GeoDataFrame,
|
|
90
157
|
column: str | None = None,
|
|
158
|
+
title: str | None = None,
|
|
159
|
+
title_position: tuple[float, float] | None = None,
|
|
91
160
|
size: int = 25,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
161
|
+
dark: bool = False,
|
|
162
|
+
cmap: str | None = None,
|
|
163
|
+
scheme: str = "naturalbreaks",
|
|
164
|
+
k: int = 5,
|
|
165
|
+
bins: tuple[float] | None = None,
|
|
166
|
+
nan_label: str = "Missing",
|
|
167
|
+
legend_kwargs: dict | None = None,
|
|
168
|
+
title_kwargs: dict | None = None,
|
|
169
|
+
**kwargs,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Initialiser."""
|
|
172
|
+
super().__init__(
|
|
173
|
+
*gdfs,
|
|
174
|
+
column=column,
|
|
175
|
+
scheme=scheme,
|
|
176
|
+
k=k,
|
|
177
|
+
bins=bins,
|
|
178
|
+
nan_label=nan_label,
|
|
179
|
+
)
|
|
95
180
|
|
|
181
|
+
self.title = title
|
|
96
182
|
self._size = size
|
|
97
|
-
self.
|
|
183
|
+
self._dark = dark
|
|
184
|
+
self.title_kwargs = title_kwargs or {}
|
|
185
|
+
if title_position and "position" in self.title_kwargs:
|
|
186
|
+
raise TypeError(
|
|
187
|
+
"Specify either 'title_position' or title_kwargs position, not both."
|
|
188
|
+
)
|
|
189
|
+
if title_position or "position" in self.title_kwargs:
|
|
190
|
+
position = self.title_kwargs.pop("position", title_position)
|
|
191
|
+
error_mess = (
|
|
192
|
+
"legend_kwargs position should be a two length tuple/list with two numbers between "
|
|
193
|
+
"0 and 1 (x, y position)"
|
|
194
|
+
)
|
|
195
|
+
if not hasattr(position, "__len__"):
|
|
196
|
+
raise TypeError(error_mess)
|
|
197
|
+
if len(position) != 2:
|
|
198
|
+
raise ValueError(error_mess)
|
|
199
|
+
x, y = position
|
|
200
|
+
if "loc" not in self.title_kwargs:
|
|
201
|
+
if x < 0.4:
|
|
202
|
+
self.title_kwargs["loc"] = "left"
|
|
203
|
+
elif x > 0.6:
|
|
204
|
+
self.title_kwargs["loc"] = "right"
|
|
205
|
+
else:
|
|
206
|
+
self.title_kwargs["loc"] = "center"
|
|
207
|
+
|
|
208
|
+
self.title_kwargs["x"], self.title_kwargs["y"] = x, y
|
|
98
209
|
self.background_gdfs = []
|
|
99
210
|
|
|
100
|
-
|
|
211
|
+
legend_kwargs = legend_kwargs or {}
|
|
101
212
|
|
|
102
|
-
self.
|
|
213
|
+
self._title_fontsize = self._size * 1.9
|
|
103
214
|
|
|
104
|
-
|
|
215
|
+
black = kwargs.pop("black", None)
|
|
216
|
+
self._dark = self._dark or black
|
|
217
|
+
|
|
218
|
+
if not self.cmap and not self._is_categorical:
|
|
105
219
|
self._choose_cmap()
|
|
106
220
|
|
|
221
|
+
self._dark_or_light()
|
|
107
222
|
self._create_legend()
|
|
108
223
|
|
|
109
|
-
|
|
224
|
+
if cmap:
|
|
225
|
+
self._cmap = cmap
|
|
226
|
+
|
|
227
|
+
for key, value in kwargs.items():
|
|
228
|
+
if key not in MAP_KWARGS:
|
|
229
|
+
raise TypeError(
|
|
230
|
+
f"{self.__class__.__name__} got an unexpected keyword argument {key}"
|
|
231
|
+
)
|
|
232
|
+
try:
|
|
233
|
+
setattr(self, key, value)
|
|
234
|
+
except Exception:
|
|
235
|
+
setattr(self, f"_{key}", value)
|
|
236
|
+
|
|
237
|
+
for key, value in legend_kwargs.items():
|
|
238
|
+
if key not in LEGEND_KWARGS:
|
|
239
|
+
raise TypeError(
|
|
240
|
+
f"{self.__class__.__name__} legend_kwargs got an unexpected key {key}"
|
|
241
|
+
)
|
|
242
|
+
try:
|
|
243
|
+
setattr(self.legend, key, value)
|
|
244
|
+
except Exception:
|
|
245
|
+
setattr(self.legend, f"_{key}", value)
|
|
246
|
+
|
|
247
|
+
@property
|
|
248
|
+
def valid_keywords(self) -> set[str]:
|
|
249
|
+
"""List all valid keywords for the class initialiser."""
|
|
250
|
+
return MAP_KWARGS
|
|
251
|
+
|
|
252
|
+
def change_cmap(self, cmap: str, start: int = 0, stop: int = 256) -> "ThematicMap":
|
|
110
253
|
"""Change the color palette of the plot.
|
|
111
254
|
|
|
112
255
|
Args:
|
|
@@ -119,7 +262,9 @@ class ThematicMap(Map):
|
|
|
119
262
|
super().change_cmap(cmap, start, stop)
|
|
120
263
|
return self
|
|
121
264
|
|
|
122
|
-
def add_background(
|
|
265
|
+
def add_background(
|
|
266
|
+
self, gdf: GeoDataFrame, color: str | None = None
|
|
267
|
+
) -> "ThematicMap":
|
|
123
268
|
"""Add a GeoDataFrame as a background layer.
|
|
124
269
|
|
|
125
270
|
Args:
|
|
@@ -145,7 +290,6 @@ class ThematicMap(Map):
|
|
|
145
290
|
|
|
146
291
|
This method should be run after customising the map, but before saving.
|
|
147
292
|
"""
|
|
148
|
-
|
|
149
293
|
__test = kwargs.pop("__test", False)
|
|
150
294
|
include_legend = bool(kwargs.pop("legend", self.legend))
|
|
151
295
|
|
|
@@ -170,7 +314,7 @@ class ThematicMap(Map):
|
|
|
170
314
|
else:
|
|
171
315
|
kwargs = self._prepare_continous_plot(kwargs)
|
|
172
316
|
if self.legend:
|
|
173
|
-
if not self.legend.
|
|
317
|
+
if not self.legend.rounding:
|
|
174
318
|
self.legend._rounding = self.legend._get_rounding(
|
|
175
319
|
array=self._gdf.loc[~self._nan_idx, self._column]
|
|
176
320
|
)
|
|
@@ -187,15 +331,15 @@ class ThematicMap(Map):
|
|
|
187
331
|
self._gdf, k=self._k + bool(len(self._nan_idx))
|
|
188
332
|
)
|
|
189
333
|
|
|
190
|
-
if __test:
|
|
191
|
-
return
|
|
192
|
-
|
|
193
334
|
self._prepare_plot(**kwargs)
|
|
194
335
|
|
|
195
336
|
if self.legend:
|
|
196
337
|
self.ax = self.legend._actually_add_legend(ax=self.ax)
|
|
197
338
|
|
|
198
|
-
self._gdf.plot(legend=include_legend, ax=self.ax, **kwargs)
|
|
339
|
+
self.ax = self._gdf.plot(legend=include_legend, ax=self.ax, **kwargs)
|
|
340
|
+
|
|
341
|
+
if __test:
|
|
342
|
+
return self
|
|
199
343
|
|
|
200
344
|
def save(self, path: str) -> None:
|
|
201
345
|
"""Save figure as image file.
|
|
@@ -214,7 +358,7 @@ class ThematicMap(Map):
|
|
|
214
358
|
with fs.open(path, "wb") as file:
|
|
215
359
|
plt.savefig(file)
|
|
216
360
|
|
|
217
|
-
def _prepare_plot(self, **kwargs):
|
|
361
|
+
def _prepare_plot(self, **kwargs) -> None:
|
|
218
362
|
"""Add figure and axis, title and background gdf."""
|
|
219
363
|
for attr in self.__dict__.keys():
|
|
220
364
|
if attr in self.kwargs:
|
|
@@ -231,12 +375,16 @@ class ThematicMap(Map):
|
|
|
231
375
|
if hasattr(self, "_background_gdfs"):
|
|
232
376
|
self._actually_add_background()
|
|
233
377
|
|
|
234
|
-
if
|
|
378
|
+
if self.title:
|
|
235
379
|
self.ax.set_title(
|
|
236
|
-
self.title,
|
|
380
|
+
self.title,
|
|
381
|
+
**(
|
|
382
|
+
dict(fontsize=self.title_fontsize, color=self.title_color)
|
|
383
|
+
| self.title_kwargs
|
|
384
|
+
),
|
|
237
385
|
)
|
|
238
386
|
|
|
239
|
-
def _prepare_continous_plot(self, kwargs) -> dict:
|
|
387
|
+
def _prepare_continous_plot(self, kwargs: dict) -> dict:
|
|
240
388
|
"""Create bins and colors."""
|
|
241
389
|
self._prepare_continous_map()
|
|
242
390
|
|
|
@@ -250,6 +398,13 @@ class ThematicMap(Map):
|
|
|
250
398
|
return kwargs
|
|
251
399
|
|
|
252
400
|
else:
|
|
401
|
+
if self.legend.rounding and self.legend.rounding < 0:
|
|
402
|
+
self.bins = prettify_bins(self.bins, self.legend.rounding)
|
|
403
|
+
self.bins = list({round(bin_, 5) for bin_ in self.bins})
|
|
404
|
+
self.bins.sort()
|
|
405
|
+
# self.legend._rounding_was = self.legend.rounding
|
|
406
|
+
# self.legend.rounding = None
|
|
407
|
+
|
|
253
408
|
classified = self._classify_from_bins(self._gdf, bins=self.bins)
|
|
254
409
|
classified_sequential = self._push_classification(classified)
|
|
255
410
|
n_colors = len(np.unique(classified_sequential)) - any(self._nan_idx)
|
|
@@ -257,10 +412,13 @@ class ThematicMap(Map):
|
|
|
257
412
|
self._bins_unique_values = self._make_bin_value_dict(
|
|
258
413
|
self._gdf, classified_sequential
|
|
259
414
|
)
|
|
415
|
+
|
|
260
416
|
colorarray = self._unique_colors[classified_sequential]
|
|
261
417
|
kwargs["color"] = colorarray
|
|
262
418
|
|
|
263
|
-
if
|
|
419
|
+
if (
|
|
420
|
+
self.legend and self.legend.rounding
|
|
421
|
+
): # not self.legend._rounding_has_been_set:
|
|
264
422
|
self.bins = self.legend._set_rounding(
|
|
265
423
|
bins=self.bins, rounding=self.legend._rounding
|
|
266
424
|
)
|
|
@@ -270,12 +428,15 @@ class ThematicMap(Map):
|
|
|
270
428
|
|
|
271
429
|
return kwargs
|
|
272
430
|
|
|
273
|
-
def _prepare_categorical_plot(self, kwargs) -> dict:
|
|
431
|
+
def _prepare_categorical_plot(self, kwargs: dict) -> dict:
|
|
274
432
|
"""Map values to colors."""
|
|
275
|
-
self.
|
|
276
|
-
|
|
433
|
+
self._make_categories_colors_dict()
|
|
434
|
+
if self._gdf is not None and len(self._gdf):
|
|
435
|
+
self._fix_nans()
|
|
277
436
|
|
|
278
|
-
|
|
437
|
+
if self._gdf is not None:
|
|
438
|
+
colorarray = self._gdf["color"]
|
|
439
|
+
kwargs["color"] = colorarray
|
|
279
440
|
return kwargs
|
|
280
441
|
|
|
281
442
|
def _actually_add_legend(self) -> None:
|
|
@@ -300,10 +461,10 @@ class ThematicMap(Map):
|
|
|
300
461
|
bin_values=self._bins_unique_values,
|
|
301
462
|
)
|
|
302
463
|
|
|
303
|
-
def _create_legend(self):
|
|
464
|
+
def _create_legend(self) -> None:
|
|
304
465
|
"""Instantiate the Legend class."""
|
|
305
466
|
kwargs = {}
|
|
306
|
-
if self.
|
|
467
|
+
if self._dark:
|
|
307
468
|
kwargs["facecolor"] = "#0f0f0f"
|
|
308
469
|
kwargs["labelcolor"] = "#fefefe"
|
|
309
470
|
kwargs["title_color"] = "#fefefe"
|
|
@@ -313,9 +474,9 @@ class ThematicMap(Map):
|
|
|
313
474
|
else:
|
|
314
475
|
self.legend = ContinousLegend(title=self._column, size=self._size, **kwargs)
|
|
315
476
|
|
|
316
|
-
def _choose_cmap(self):
|
|
317
|
-
"""
|
|
318
|
-
if self.
|
|
477
|
+
def _choose_cmap(self) -> None:
|
|
478
|
+
"""Kwargs is to catch start and stop points for the cmap in __init__."""
|
|
479
|
+
if self._dark:
|
|
319
480
|
self._cmap = "viridis"
|
|
320
481
|
self.cmap_start = 0
|
|
321
482
|
self.cmap_stop = 256
|
|
@@ -324,7 +485,7 @@ class ThematicMap(Map):
|
|
|
324
485
|
self.cmap_start = 23
|
|
325
486
|
self.cmap_stop = 256
|
|
326
487
|
|
|
327
|
-
def _make_bin_value_dict(self, gdf, classified) -> dict:
|
|
488
|
+
def _make_bin_value_dict(self, gdf: GeoDataFrame, classified: np.ndarray) -> dict:
|
|
328
489
|
"""Dict with unique values of all bins. Used in labels in ContinousLegend."""
|
|
329
490
|
bins_unique_values = {
|
|
330
491
|
i: list(set(gdf.loc[classified == i, self._column]))
|
|
@@ -332,19 +493,21 @@ class ThematicMap(Map):
|
|
|
332
493
|
}
|
|
333
494
|
return bins_unique_values
|
|
334
495
|
|
|
335
|
-
def _actually_add_background(self):
|
|
496
|
+
def _actually_add_background(self) -> None:
|
|
336
497
|
self.ax.set_xlim([self.minx - self.diffx * 0.03, self.maxx + self.diffx * 0.03])
|
|
337
498
|
self.ax.set_ylim([self.miny - self.diffy * 0.03, self.maxy + self.diffy * 0.03])
|
|
338
499
|
self._background_gdfs.plot(ax=self.ax, color=self.bg_gdf_color)
|
|
339
500
|
|
|
340
501
|
@staticmethod
|
|
341
|
-
def _get_matplotlib_figure_and_axix(
|
|
502
|
+
def _get_matplotlib_figure_and_axix(
|
|
503
|
+
figsize: tuple[int, int]
|
|
504
|
+
) -> tuple[matplotlib.figure.Figure, matplotlib.axes.Axes]:
|
|
342
505
|
fig = plt.figure(figsize=figsize)
|
|
343
506
|
ax = fig.add_subplot(1, 1, 1)
|
|
344
507
|
return fig, ax
|
|
345
508
|
|
|
346
|
-
def
|
|
347
|
-
if self.
|
|
509
|
+
def _dark_or_light(self) -> None:
|
|
510
|
+
if self._dark:
|
|
348
511
|
self.facecolor, self.title_color, self.bg_gdf_color = (
|
|
349
512
|
"#0f0f0f",
|
|
350
513
|
"#fefefe",
|
|
@@ -358,38 +521,40 @@ class ThematicMap(Map):
|
|
|
358
521
|
self.facecolor, self.title_color, self.bg_gdf_color = (
|
|
359
522
|
"#fefefe",
|
|
360
523
|
"#0f0f0f",
|
|
361
|
-
"#
|
|
524
|
+
"#dbdbdb",
|
|
362
525
|
)
|
|
363
526
|
self.nan_color = "#c2c2c2"
|
|
364
527
|
if not self._is_categorical:
|
|
365
528
|
self.change_cmap("RdPu", start=23)
|
|
366
529
|
|
|
367
|
-
self._create_legend()
|
|
368
|
-
|
|
369
530
|
@property
|
|
370
|
-
def
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
self.
|
|
531
|
+
def dark(self) -> bool:
|
|
532
|
+
"""Whether to use dark background and light text colors."""
|
|
533
|
+
return self._dark
|
|
534
|
+
|
|
535
|
+
@dark.setter
|
|
536
|
+
def dark(self, new_value: bool):
|
|
537
|
+
self._dark = new_value
|
|
538
|
+
self._dark_or_light()
|
|
539
|
+
self._create_legend()
|
|
377
540
|
|
|
378
541
|
@property
|
|
379
|
-
def title_fontsize(self):
|
|
542
|
+
def title_fontsize(self) -> int:
|
|
543
|
+
"""Title fontsize, not to be confused with legend.title_fontsize."""
|
|
380
544
|
return self._title_fontsize
|
|
381
545
|
|
|
382
546
|
@title_fontsize.setter
|
|
383
|
-
def title_fontsize(self, new_value:
|
|
547
|
+
def title_fontsize(self, new_value: int) -> None:
|
|
384
548
|
self._title_fontsize = new_value
|
|
385
549
|
self._title_fontsize_has_been_set = True
|
|
386
550
|
|
|
387
551
|
@property
|
|
388
|
-
def size(self):
|
|
552
|
+
def size(self) -> int:
|
|
553
|
+
"""Size of the image."""
|
|
389
554
|
return self._size
|
|
390
555
|
|
|
391
556
|
@size.setter
|
|
392
|
-
def size(self, new_value: bool):
|
|
557
|
+
def size(self, new_value: bool) -> None:
|
|
393
558
|
"""Adjust font and marker size if not actively set."""
|
|
394
559
|
self._size = new_value
|
|
395
560
|
if not hasattr(self, "_title_fontsize_has_been_set"):
|
|
@@ -403,7 +568,8 @@ class ThematicMap(Map):
|
|
|
403
568
|
if not hasattr(self.legend, "_markersize_has_been_set"):
|
|
404
569
|
self.legend._markersize = self._size
|
|
405
570
|
|
|
406
|
-
def __setattr__(self, __name: str, __value) -> None:
|
|
571
|
+
def __setattr__(self, __name: str, __value: Any) -> None:
|
|
572
|
+
"""Set an attribute with square brackets."""
|
|
407
573
|
if "legend_" in __name:
|
|
408
574
|
last_part = __name.split("legend_")[-1]
|
|
409
575
|
raise AttributeError(
|
sgis/maps/tilesources.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from xyzservices import
|
|
1
|
+
from xyzservices import Bunch
|
|
2
|
+
from xyzservices import TileProvider
|
|
3
|
+
from xyzservices import providers
|
|
2
4
|
|
|
3
5
|
kartverket = Bunch(
|
|
4
6
|
norgeskart=TileProvider(
|
|
@@ -7,49 +9,42 @@ kartverket = Bunch(
|
|
|
7
9
|
attribution="© Kartverket",
|
|
8
10
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
9
11
|
),
|
|
10
|
-
|
|
11
12
|
bakgrunnskart_forenklet=TileProvider(
|
|
12
13
|
name="Norgeskart forenklet",
|
|
13
14
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=bakgrunnskart_forenklet&zoom={z}&x={x}&y={y}",
|
|
14
15
|
attribution="© Kartverket",
|
|
15
16
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
16
17
|
),
|
|
17
|
-
|
|
18
18
|
norges_grunnkart=TileProvider(
|
|
19
19
|
name="Norges grunnkart",
|
|
20
20
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=norges_grunnkart&zoom={z}&x={x}&y={y}",
|
|
21
21
|
attribution="© Kartverket",
|
|
22
22
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
23
23
|
),
|
|
24
|
-
|
|
25
24
|
norges_grunnkart_gråtone=TileProvider(
|
|
26
25
|
name="Norges grunnkart gråtone",
|
|
27
26
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=norges_grunnkart_graatone&zoom={z}&x={x}&y={y}",
|
|
28
27
|
attribution="© Kartverket",
|
|
29
28
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
30
29
|
),
|
|
31
|
-
|
|
32
30
|
n50=TileProvider(
|
|
33
31
|
name="N5 til N50 kartdata",
|
|
34
32
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=kartdata3&zoom={z}&x={x}&y={y}",
|
|
35
33
|
attribution="© Kartverket",
|
|
36
34
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
37
35
|
),
|
|
38
|
-
|
|
39
36
|
topogråtone=TileProvider(
|
|
40
37
|
name="Topografisk norgeskart gråtone",
|
|
41
38
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo4graatone&zoom={z}&x={x}&y={y}",
|
|
42
39
|
attribution="© Kartverket",
|
|
43
40
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
44
41
|
),
|
|
45
|
-
|
|
46
42
|
toporaster=TileProvider(
|
|
47
43
|
name="Topografisk raster",
|
|
48
44
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=toporaster4&zoom={z}&x={x}&y={y}",
|
|
49
45
|
attribution="© Kartverket",
|
|
50
46
|
html_attribution='© <a href="https://kartverket.no">Kartverket</a>',
|
|
51
47
|
),
|
|
52
|
-
|
|
53
48
|
norge_i_bilder=TileProvider(
|
|
54
49
|
name="Norge i bilder",
|
|
55
50
|
url="https://opencache.statkart.no/gatekeeper/gk/gk.open_nib_web_mercator_wmts_v2?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=Nibcache_web_mercator_v2&STYLE=default&FORMAT=image/jpgpng&tileMatrixSet=default028mm&tileMatrix={z}&tileRow={y}&tileCol={x}",
|
|
@@ -7,7 +7,7 @@ from pandas import DataFrame
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def _get_route_frequencies(
|
|
10
|
-
graph,
|
|
10
|
+
graph: Graph,
|
|
11
11
|
roads: GeoDataFrame,
|
|
12
12
|
weight_df: DataFrame,
|
|
13
13
|
) -> GeoDataFrame:
|
|
@@ -60,7 +60,6 @@ def _get_route(
|
|
|
60
60
|
od_pairs: pd.MultiIndex,
|
|
61
61
|
) -> GeoDataFrame:
|
|
62
62
|
"""Function used in the get_route method of NetworkAnalysis."""
|
|
63
|
-
|
|
64
63
|
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
|
65
64
|
|
|
66
65
|
resultlist: list[DataFrame] = []
|
|
@@ -86,7 +85,8 @@ def _get_route(
|
|
|
86
85
|
if not resultlist:
|
|
87
86
|
warnings.warn(
|
|
88
87
|
"No paths were found. Try larger search_tolerance or search_factor. "
|
|
89
|
-
"Or close_network_holes() or remove_isolated()."
|
|
88
|
+
"Or close_network_holes() or remove_isolated().",
|
|
89
|
+
stacklevel=1,
|
|
90
90
|
)
|
|
91
91
|
return pd.DataFrame(columns=["origin", "destination", weight, "geometry"])
|
|
92
92
|
|
|
@@ -121,7 +121,8 @@ def _get_k_routes(
|
|
|
121
121
|
if not resultlist:
|
|
122
122
|
warnings.warn(
|
|
123
123
|
"No paths were found. Try larger search_tolerance or search_factor. "
|
|
124
|
-
"Or close_network_holes() or remove_isolated()."
|
|
124
|
+
"Or close_network_holes() or remove_isolated().",
|
|
125
|
+
stacklevel=1,
|
|
125
126
|
)
|
|
126
127
|
return pd.DataFrame(columns=["origin", "destination", weight, "geometry"])
|
|
127
128
|
|