ssb-sgis 1.0.2__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.
Files changed (42) hide show
  1. sgis/__init__.py +10 -6
  2. sgis/exceptions.py +2 -2
  3. sgis/geopandas_tools/bounds.py +17 -15
  4. sgis/geopandas_tools/buffer_dissolve_explode.py +24 -5
  5. sgis/geopandas_tools/conversion.py +15 -6
  6. sgis/geopandas_tools/duplicates.py +2 -2
  7. sgis/geopandas_tools/general.py +9 -5
  8. sgis/geopandas_tools/geometry_types.py +3 -3
  9. sgis/geopandas_tools/neighbors.py +3 -3
  10. sgis/geopandas_tools/point_operations.py +2 -2
  11. sgis/geopandas_tools/polygon_operations.py +5 -5
  12. sgis/geopandas_tools/sfilter.py +3 -3
  13. sgis/helpers.py +3 -3
  14. sgis/io/read_parquet.py +1 -1
  15. sgis/maps/examine.py +16 -2
  16. sgis/maps/explore.py +370 -57
  17. sgis/maps/legend.py +164 -72
  18. sgis/maps/map.py +184 -90
  19. sgis/maps/maps.py +92 -90
  20. sgis/maps/thematicmap.py +236 -83
  21. sgis/networkanalysis/closing_network_holes.py +2 -2
  22. sgis/networkanalysis/cutting_lines.py +3 -3
  23. sgis/networkanalysis/directednetwork.py +1 -1
  24. sgis/networkanalysis/finding_isolated_networks.py +2 -2
  25. sgis/networkanalysis/networkanalysis.py +7 -7
  26. sgis/networkanalysis/networkanalysisrules.py +1 -1
  27. sgis/networkanalysis/traveling_salesman.py +1 -1
  28. sgis/parallel/parallel.py +39 -19
  29. sgis/raster/__init__.py +0 -6
  30. sgis/raster/cube.py +51 -5
  31. sgis/raster/image_collection.py +2560 -0
  32. sgis/raster/indices.py +14 -5
  33. sgis/raster/raster.py +131 -236
  34. sgis/raster/sentinel_config.py +104 -0
  35. sgis/raster/zonal.py +0 -1
  36. {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/METADATA +1 -1
  37. ssb_sgis-1.0.3.dist-info/RECORD +61 -0
  38. sgis/raster/methods_as_functions.py +0 -0
  39. sgis/raster/torchgeo.py +0 -171
  40. ssb_sgis-1.0.2.dist-info/RECORD +0 -61
  41. {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/LICENSE +0 -0
  42. {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/WHEEL +0 -0
sgis/maps/thematicmap.py CHANGED
@@ -10,8 +10,10 @@ import numpy as np
10
10
  import pandas as pd
11
11
  from geopandas import GeoDataFrame
12
12
 
13
+ from .legend import LEGEND_KWARGS
13
14
  from .legend import ContinousLegend
14
15
  from .legend import Legend
16
+ from .legend import prettify_bins
15
17
  from .map import Map
16
18
 
17
19
  # the geopandas._explore raises a deprication warning. Ignoring for now.
@@ -20,60 +22,132 @@ warnings.filterwarnings(
20
22
  )
21
23
  pd.options.mode.chained_assignment = None
22
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
+ }
44
+
23
45
 
24
46
  class ThematicMap(Map):
25
- """Class for creating static maps with geopandas and matplotlib.
26
-
27
- The class takes one or more GeoDataFrames and a column name. The class attributes
28
- can then be set to customise the map before plotting.
29
-
30
- Attributes:
31
- size (int): Width and height of the plot in inches.
32
- k (int): Number of color groups.
33
- legend (Legend): The legend object of the map. The legend holds its own set of
34
- attributes. See the Legend class for details.
35
- title (str): Title of the plot.
36
- title_color (str): Color of the title font.
37
- title_fontsize (int): Color of the title font.
38
- bins (list[int | float]): For numeric columns. List of numbers that define the
39
- maximum value for the color groups.
40
- cmap (str): Colormap of the plot. See:
47
+ """Class for making static maps.
48
+
49
+ Args:
50
+ *gdfs: One or more GeoDataFrames.
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".
54
+ size: Width and height of the plot in inches. Fontsize of title and legend is
55
+ adjusted accordingly. Defaults to 25.
56
+ dark: If False (default), the background will be white and the text black. If
57
+ True, the background will be black and the text white. When True, the
58
+ default cmap is "viridis", and when False, the default is red to purple
59
+ (RdPu).
60
+ cmap: Colormap of the plot. See:
41
61
  https://matplotlib.org/stable/tutorials/colors/colormaps.html
42
- cmap_start (int): Start position for the color palette.
43
- cmap_stop (int): End position for the color palette.
44
- facecolor (str): Background color.
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.
45
97
 
46
98
  Examples:
47
99
  --------
48
100
  >>> import sgis as sg
49
- >>> points = sg.random_points(100).pipe(sg.buff, np.random.rand(100))
50
- >>> 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
+
51
104
 
52
105
  Simple plot with legend and title.
53
106
 
54
- >>> m = sg.ThematicMap(points, points2, "area")
55
- >>> m.title = "Area of random circles"
107
+ >>> m = sg.ThematicMap(points, points2, column="area", title="Area of random circles")
56
108
  >>> m.plot()
57
109
 
58
- Plot with custom legend units (label_suffix) and separator (label_sep).
59
-
60
- >>> m = sg.ThematicMap(points, points2, "area")
61
- >>> m.title = "Area of random circles"
62
- >>> m.legend.label_suffix = "m2"
63
- >>> m.legend.label_sep = "to"
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
+ ... )
64
125
  >>> m.plot()
65
126
 
66
- With custom bins and legend labels.
67
-
68
- >>> m = sg.ThematicMap(points, points2, "area")
69
- >>> m.title = "Area of random circles"
70
- >>> m.bins = [1, 2, 3]
71
- >>> m.legend.labels = [
72
- ... f"{int(round(min(points.length),0))} to 1",
73
- ... "1 to 2",
74
- ... "2 to 3",
75
- ... f"3 to {int(round(max(points.length),0))}",
76
- ... ]
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
+ ... )
77
151
  >>> m.plot()
78
152
  """
79
153
 
@@ -81,37 +155,100 @@ class ThematicMap(Map):
81
155
  self,
82
156
  *gdfs: GeoDataFrame,
83
157
  column: str | None = None,
158
+ title: str | None = None,
159
+ title_position: tuple[float, float] | None = None,
84
160
  size: int = 25,
85
- black: bool = False,
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,
86
170
  ) -> None:
87
- """Initialiser.
88
-
89
- Args:
90
- *gdfs: One or more GeoDataFrames.
91
- column: The name of the column to plot.
92
- size: Width and height of the plot in inches. Fontsize of title and legend is
93
- adjusted accordingly. Defaults to 25.
94
- black: If False (default), the background will be white and the text black. If
95
- True, the background will be black and the text white. When True, the
96
- default cmap is "viridis", and when False, the default is red to purple
97
- (RdPu).
98
-
99
- """
100
- super().__init__(*gdfs, column=column)
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
+ )
101
180
 
181
+ self.title = title
102
182
  self._size = size
103
- self._black = black
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
104
209
  self.background_gdfs = []
105
210
 
106
- self._title_fontsize = self._size * 2
211
+ legend_kwargs = legend_kwargs or {}
107
212
 
108
- self.black = black
213
+ self._title_fontsize = self._size * 1.9
109
214
 
110
- if not self._is_categorical:
215
+ black = kwargs.pop("black", None)
216
+ self._dark = self._dark or black
217
+
218
+ if not self.cmap and not self._is_categorical:
111
219
  self._choose_cmap()
112
220
 
221
+ self._dark_or_light()
113
222
  self._create_legend()
114
223
 
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
+
115
252
  def change_cmap(self, cmap: str, start: int = 0, stop: int = 256) -> "ThematicMap":
116
253
  """Change the color palette of the plot.
117
254
 
@@ -177,7 +314,7 @@ class ThematicMap(Map):
177
314
  else:
178
315
  kwargs = self._prepare_continous_plot(kwargs)
179
316
  if self.legend:
180
- if not self.legend._rounding_has_been_set:
317
+ if not self.legend.rounding:
181
318
  self.legend._rounding = self.legend._get_rounding(
182
319
  array=self._gdf.loc[~self._nan_idx, self._column]
183
320
  )
@@ -194,15 +331,15 @@ class ThematicMap(Map):
194
331
  self._gdf, k=self._k + bool(len(self._nan_idx))
195
332
  )
196
333
 
197
- if __test:
198
- return
199
-
200
334
  self._prepare_plot(**kwargs)
201
335
 
202
336
  if self.legend:
203
337
  self.ax = self.legend._actually_add_legend(ax=self.ax)
204
338
 
205
- 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
206
343
 
207
344
  def save(self, path: str) -> None:
208
345
  """Save figure as image file.
@@ -238,9 +375,13 @@ class ThematicMap(Map):
238
375
  if hasattr(self, "_background_gdfs"):
239
376
  self._actually_add_background()
240
377
 
241
- if hasattr(self, "title") and self.title:
378
+ if self.title:
242
379
  self.ax.set_title(
243
- self.title, fontsize=self.title_fontsize, color=self.title_color
380
+ self.title,
381
+ **(
382
+ dict(fontsize=self.title_fontsize, color=self.title_color)
383
+ | self.title_kwargs
384
+ ),
244
385
  )
245
386
 
246
387
  def _prepare_continous_plot(self, kwargs: dict) -> dict:
@@ -257,6 +398,13 @@ class ThematicMap(Map):
257
398
  return kwargs
258
399
 
259
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
+
260
408
  classified = self._classify_from_bins(self._gdf, bins=self.bins)
261
409
  classified_sequential = self._push_classification(classified)
262
410
  n_colors = len(np.unique(classified_sequential)) - any(self._nan_idx)
@@ -264,10 +412,13 @@ class ThematicMap(Map):
264
412
  self._bins_unique_values = self._make_bin_value_dict(
265
413
  self._gdf, classified_sequential
266
414
  )
415
+
267
416
  colorarray = self._unique_colors[classified_sequential]
268
417
  kwargs["color"] = colorarray
269
418
 
270
- if self.legend and not self.legend._rounding_has_been_set:
419
+ if (
420
+ self.legend and self.legend.rounding
421
+ ): # not self.legend._rounding_has_been_set:
271
422
  self.bins = self.legend._set_rounding(
272
423
  bins=self.bins, rounding=self.legend._rounding
273
424
  )
@@ -279,10 +430,13 @@ class ThematicMap(Map):
279
430
 
280
431
  def _prepare_categorical_plot(self, kwargs: dict) -> dict:
281
432
  """Map values to colors."""
282
- self._get_categorical_colors()
283
- colorarray = self._gdf["color"]
433
+ self._make_categories_colors_dict()
434
+ if self._gdf is not None and len(self._gdf):
435
+ self._fix_nans()
284
436
 
285
- kwargs["color"] = colorarray
437
+ if self._gdf is not None:
438
+ colorarray = self._gdf["color"]
439
+ kwargs["color"] = colorarray
286
440
  return kwargs
287
441
 
288
442
  def _actually_add_legend(self) -> None:
@@ -310,7 +464,7 @@ class ThematicMap(Map):
310
464
  def _create_legend(self) -> None:
311
465
  """Instantiate the Legend class."""
312
466
  kwargs = {}
313
- if self._black:
467
+ if self._dark:
314
468
  kwargs["facecolor"] = "#0f0f0f"
315
469
  kwargs["labelcolor"] = "#fefefe"
316
470
  kwargs["title_color"] = "#fefefe"
@@ -322,7 +476,7 @@ class ThematicMap(Map):
322
476
 
323
477
  def _choose_cmap(self) -> None:
324
478
  """Kwargs is to catch start and stop points for the cmap in __init__."""
325
- if self._black:
479
+ if self._dark:
326
480
  self._cmap = "viridis"
327
481
  self.cmap_start = 0
328
482
  self.cmap_stop = 256
@@ -352,8 +506,8 @@ class ThematicMap(Map):
352
506
  ax = fig.add_subplot(1, 1, 1)
353
507
  return fig, ax
354
508
 
355
- def _black_or_white(self) -> None:
356
- if self._black:
509
+ def _dark_or_light(self) -> None:
510
+ if self._dark:
357
511
  self.facecolor, self.title_color, self.bg_gdf_color = (
358
512
  "#0f0f0f",
359
513
  "#fefefe",
@@ -367,23 +521,22 @@ class ThematicMap(Map):
367
521
  self.facecolor, self.title_color, self.bg_gdf_color = (
368
522
  "#fefefe",
369
523
  "#0f0f0f",
370
- "#ebebeb",
524
+ "#dbdbdb",
371
525
  )
372
526
  self.nan_color = "#c2c2c2"
373
527
  if not self._is_categorical:
374
528
  self.change_cmap("RdPu", start=23)
375
529
 
376
- self._create_legend()
377
-
378
530
  @property
379
- def black(self) -> bool:
531
+ def dark(self) -> bool:
380
532
  """Whether to use dark background and light text colors."""
381
- return self._black
533
+ return self._dark
382
534
 
383
- @black.setter
384
- def black(self, new_value: bool):
385
- self._black = new_value
386
- self._black_or_white()
535
+ @dark.setter
536
+ def dark(self, new_value: bool):
537
+ self._dark = new_value
538
+ self._dark_or_light()
539
+ self._create_legend()
387
540
 
388
541
  @property
389
542
  def title_fontsize(self) -> int:
@@ -44,7 +44,7 @@ def close_network_holes(
44
44
  NetworkAnalysis. These values must be filled before analysis.
45
45
 
46
46
  Examples:
47
- --------
47
+ ---------
48
48
  Read road data with small gaps.
49
49
 
50
50
  >>> import sgis as sg
@@ -157,7 +157,7 @@ def close_network_holes_to_deadends(
157
157
  The input GeoDataFrame with new lines added.
158
158
 
159
159
  Examples:
160
- --------
160
+ ---------
161
161
  Read road data with small gaps.
162
162
 
163
163
  >>> import sgis as sg
@@ -52,7 +52,7 @@ def split_lines_by_nearest_point(
52
52
  ValueError: If the crs of the input data differs.
53
53
 
54
54
  Examples:
55
- --------
55
+ ---------
56
56
  >>> from sgis import read_parquet_url, split_lines_by_nearest_point
57
57
  >>> roads = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
58
58
  >>> points = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/points_oslo.parquet")
@@ -255,7 +255,7 @@ def cut_lines(
255
255
  This method is time consuming for large networks and low 'max_length'.
256
256
 
257
257
  Examples:
258
- --------
258
+ ---------
259
259
  >>> from sgis import read_parquet_url, cut_lines
260
260
  >>> roads = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
261
261
  >>> roads.length.describe().round(1)
@@ -327,7 +327,7 @@ def cut_lines_once(
327
327
  Defaults to False.
328
328
 
329
329
  Examples:
330
- --------
330
+ ---------
331
331
  >>> from sgis import cut_lines_once, to_gdf
332
332
  >>> import pandas as pd
333
333
  >>> from shapely.geometry import LineString
@@ -29,7 +29,7 @@ def make_directed_network_norway(gdf: GeoDataFrame, dropnegative: bool) -> GeoDa
29
29
  to keep them.
30
30
 
31
31
  Examples:
32
- --------
32
+ ---------
33
33
  2022 data for the municipalities of Oslo and Eidskog can be read directly like this:
34
34
 
35
35
  >>> import sgis as sg
@@ -23,7 +23,7 @@ def get_connected_components(gdf: GeoDataFrame) -> GeoDataFrame:
23
23
  The GeoDataFrame with a new column "connected".
24
24
 
25
25
  Examples:
26
- --------
26
+ ---------
27
27
  >>> from sgis import read_parquet_url, get_connected_components
28
28
  >>> roads = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
29
29
 
@@ -76,7 +76,7 @@ def get_component_size(gdf: GeoDataFrame) -> GeoDataFrame:
76
76
  A GeoDataFrame with a new column "component_size".
77
77
 
78
78
  Examples:
79
- --------
79
+ ---------
80
80
  >>> from sgis import read_parquet_url, get_component_size
81
81
  >>> roads = read_parquet_url("https://media.githubusercontent.com/media/statisticsnorway/ssb-sgis/main/tests/testdata/roads_oslo_2022.parquet")
82
82
 
@@ -57,7 +57,7 @@ class NetworkAnalysis:
57
57
  log: A DataFrame with information about each analysis run.
58
58
 
59
59
  Examples:
60
- --------
60
+ ---------
61
61
  Read example data.
62
62
 
63
63
  >>> import sgis as sg
@@ -191,7 +191,7 @@ class NetworkAnalysis:
191
191
  straight lines between origin and destination.
192
192
 
193
193
  Examples:
194
- --------
194
+ ---------
195
195
  Create the NetworkAnalysis instance.
196
196
 
197
197
  >>> import sgis as sg
@@ -479,7 +479,7 @@ class NetworkAnalysis:
479
479
  that contain weights and all indices of 'origins' and 'destinations'.
480
480
 
481
481
  Examples:
482
- --------
482
+ ---------
483
483
  Create the NetworkAnalysis instance.
484
484
 
485
485
  >>> import sgis as sg
@@ -692,7 +692,7 @@ class NetworkAnalysis:
692
692
  containing the indices of the origins and destinations GeoDataFrames.
693
693
 
694
694
  Examples:
695
- --------
695
+ ---------
696
696
  Create the NetworkAnalysis instance.
697
697
 
698
698
  >>> import sgis as sg
@@ -820,7 +820,7 @@ class NetworkAnalysis:
820
820
  ValueError: if drop_middle_percent is not between 0 and 100.
821
821
 
822
822
  Examples:
823
- --------
823
+ ---------
824
824
  Create the NetworkAnalysis instance.
825
825
 
826
826
  >>> import sgis as sg
@@ -966,7 +966,7 @@ class NetworkAnalysis:
966
966
  precice results.
967
967
 
968
968
  Examples:
969
- --------
969
+ ---------
970
970
  Create the NetworkAnalysis instance.
971
971
 
972
972
  >>> import sgis as sg
@@ -1093,7 +1093,7 @@ class NetworkAnalysis:
1093
1093
  service_area: Faster method where lines are not cut to get precice results.
1094
1094
 
1095
1095
  Examples:
1096
- --------
1096
+ ---------
1097
1097
  Create the NetworkAnalysis instance.
1098
1098
 
1099
1099
  >>> import sgis as sg
@@ -50,7 +50,7 @@ class NetworkAnalysisRules:
50
50
  to 1, the weight will be equal to the straigt line distance.
51
51
 
52
52
  Examples:
53
- --------
53
+ ---------
54
54
  Read testdata.
55
55
 
56
56
  >>> import sgis as sg
@@ -32,7 +32,7 @@ def traveling_salesman_problem(
32
32
  List of Points making up the traveling salesman's path.
33
33
 
34
34
  Examples:
35
- --------
35
+ ---------
36
36
  >>> import sgis as sg
37
37
  >>> from shapely.geometry import LineString
38
38
  >>> points = sg.to_gdf(