mapreader 1.3.11__tar.gz → 1.4.0__tar.gz

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 (52) hide show
  1. {mapreader-1.3.11 → mapreader-1.4.0}/PKG-INFO +1 -1
  2. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/_version.py +3 -3
  3. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/annotate/annotator.py +40 -39
  4. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/classify/datasets.py +74 -64
  5. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/classify/load_annotations.py +91 -79
  6. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/downloader.py +3 -3
  7. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/sheet_downloader.py +268 -493
  8. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/tile_merging.py +3 -5
  9. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/load/images.py +290 -286
  10. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/process/context_post_process.py +29 -10
  11. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/process/occlusion_analysis.py +20 -19
  12. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/spot_text/deepsolo_runner.py +10 -122
  13. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/spot_text/dptext_detr_runner.py +23 -9
  14. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/spot_text/maptext_runner.py +11 -122
  15. mapreader-1.4.0/mapreader/spot_text/rec_runner_base.py +315 -0
  16. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/spot_text/runner_base.py +54 -93
  17. mapreader-1.4.0/mapreader/utils/load_frames.py +125 -0
  18. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/PKG-INFO +1 -1
  19. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/SOURCES.txt +4 -1
  20. mapreader-1.4.0/tests/test_utils_load_frames.py +206 -0
  21. {mapreader-1.3.11 → mapreader-1.4.0}/LICENSE +0 -0
  22. {mapreader-1.3.11 → mapreader-1.4.0}/README.md +0 -0
  23. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/__init__.py +0 -0
  24. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/__main__.py +0 -0
  25. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/annotate/__init__.py +0 -0
  26. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/annotate/utils.py +0 -0
  27. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/classify/__init__.py +0 -0
  28. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/classify/classifier.py +0 -0
  29. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/classify/custom_models.py +0 -0
  30. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/__init__.py +0 -0
  31. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/data_structures.py +0 -0
  32. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/downloader_utils.py +0 -0
  33. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/download/tile_loading.py +0 -0
  34. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/load/__init__.py +0 -0
  35. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/load/geo_utils.py +0 -0
  36. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/load/loader.py +0 -0
  37. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/process/__init__.py +0 -0
  38. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/process/process.py +0 -0
  39. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/spot_text/__init__.py +0 -0
  40. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/utils/__init__.py +0 -0
  41. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/utils/compute_and_save_stats.py +0 -0
  42. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader/utils/slice_parallel.py +0 -0
  43. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/dependency_links.txt +0 -0
  44. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/entry_points.txt +0 -0
  45. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/not-zip-safe +0 -0
  46. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/requires.txt +0 -0
  47. {mapreader-1.3.11 → mapreader-1.4.0}/mapreader.egg-info/top_level.txt +0 -0
  48. {mapreader-1.3.11 → mapreader-1.4.0}/setup.cfg +0 -0
  49. {mapreader-1.3.11 → mapreader-1.4.0}/setup.py +0 -0
  50. {mapreader-1.3.11 → mapreader-1.4.0}/tests/test_geo_pipeline.py +0 -0
  51. {mapreader-1.3.11 → mapreader-1.4.0}/tests/test_import.py +0 -0
  52. {mapreader-1.3.11 → mapreader-1.4.0}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mapreader
3
- Version: 1.3.11
3
+ Version: 1.4.0
4
4
  Summary: A computer vision pipeline for the semantic exploration of maps/images at scale
5
5
  Home-page: https://github.com/Living-with-machines/MapReader
6
6
  Download-URL: https://github.com/Living-with-machines/MapReader/archive/refs/heads/main.zip
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2024-09-12T08:29:12+0100",
11
+ "date": "2024-09-12T19:16:25+0100",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "3db8e6fbaef97b79e4cd663f664585041b539c99",
15
- "version": "1.3.11"
14
+ "full-revisionid": "2651e3de148e0069aa93151268b18534108dbe91",
15
+ "version": "1.4.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -4,13 +4,15 @@ import functools
4
4
  import hashlib
5
5
  import json
6
6
  import os
7
+ import pathlib
7
8
  import random
9
+ import re
8
10
  import string
9
11
  import warnings
10
- from ast import literal_eval
11
12
  from itertools import product
12
13
  from pathlib import Path
13
14
 
15
+ import geopandas as gpd
14
16
  import ipywidgets as widgets
15
17
  import numpy as np
16
18
  import pandas as pd
@@ -18,6 +20,8 @@ from IPython.display import clear_output, display
18
20
  from numpy import array_split
19
21
  from PIL import Image, ImageOps
20
22
 
23
+ from mapreader.utils.load_frames import load_from_csv, load_from_geojson
24
+
21
25
  from ..load.loader import load_patches
22
26
 
23
27
  warnings.filterwarnings("ignore", category=UserWarning)
@@ -33,10 +37,10 @@ class Annotator:
33
37
 
34
38
  Parameters
35
39
  ----------
36
- patch_df : str or pd.DataFrame or None, optional
37
- Path to a CSV file or a pandas DataFrame containing patch data, by default None
38
- parent_df : str or pd.DataFrame or None, optional
39
- Path to a CSV file or a pandas DataFrame containing parent data, by default None
40
+ patch_df : str, pathlib.Path, pd.DataFrame or gpd.GeoDataFrame or None, optional
41
+ Path to a CSV/geojson file or a pandas DataFrame/ geopandas GeoDataFrame containing patch data, by default None
42
+ parent_df : str, pathlib.Path, pd.DataFrame or gpd.GeoDataFrame or None, optional
43
+ Path to a CSV/geojson file or a pandas DataFrame/ geopandas GeoDataFrame containing parent data, by default None
40
44
  labels : list, optional
41
45
  List of labels for annotation, by default None
42
46
  patch_paths : str or None, optional
@@ -89,7 +93,7 @@ class Annotator:
89
93
  FileNotFoundError
90
94
  If the provided patch_df or parent_df file path does not exist
91
95
  ValueError
92
- If patch_df or parent_df is not a valid path to a CSV file or a pandas DataFrame
96
+ If patch_df or parent_df is not a valid path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame
93
97
  If patch_df or patch_paths is not provided
94
98
  If the DataFrame does not have the required columns
95
99
  If sortby is not a string or None
@@ -100,8 +104,8 @@ class Annotator:
100
104
 
101
105
  def __init__(
102
106
  self,
103
- patch_df: str | pd.DataFrame | None = None,
104
- parent_df: str | pd.DataFrame | None = None,
107
+ patch_df: str | pathlib.Path | pd.DataFrame | gpd.GeoDataFrame | None = None,
108
+ parent_df: str | pathlib.Path | pd.DataFrame | gpd.GeoDataFrame | None = None,
105
109
  labels: list = None,
106
110
  patch_paths: str | None = None,
107
111
  parent_paths: str | None = None,
@@ -127,36 +131,40 @@ class Annotator:
127
131
  if labels is None:
128
132
  labels = []
129
133
  if patch_df is not None:
130
- if isinstance(patch_df, str):
131
- if os.path.exists(patch_df):
132
- patch_df = pd.read_csv(
134
+ if isinstance(patch_df, (str, pathlib.Path)):
135
+ if re.search(r"\..?sv$", str(patch_df)):
136
+ patch_df = load_from_csv(
133
137
  patch_df,
134
- index_col=0,
135
- sep=delimiter,
138
+ delimiter=delimiter,
136
139
  )
140
+ elif re.search(r"\..*?json$", str(patch_df)):
141
+ patch_df = load_from_geojson(patch_df)
137
142
  else:
138
- raise FileNotFoundError(f"[ERROR] Could not find {patch_df}.")
139
- if not isinstance(patch_df, pd.DataFrame):
143
+ raise ValueError(
144
+ "[ERROR] ``patch_df`` must be a path to a CSV/TSV/etc or geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
145
+ )
146
+ elif not isinstance(patch_df, pd.DataFrame):
140
147
  raise ValueError(
141
- "[ERROR] ``patch_df`` must be a path to a csv or a pandas DataFrame."
148
+ "[ERROR] ``patch_df`` must be a path to a CSV/TSV/etc or geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
142
149
  )
143
- patch_df = self._eval_df(patch_df) # eval tuples/lists in df
144
150
 
145
151
  if parent_df is not None:
146
- if isinstance(parent_df, str):
147
- if os.path.exists(parent_df):
148
- parent_df = pd.read_csv(
152
+ if isinstance(parent_df, (str, pathlib.Path)):
153
+ if re.search(r"\..?sv$", str(parent_df)):
154
+ parent_df = load_from_csv(
149
155
  parent_df,
150
- index_col=0,
151
- sep=delimiter,
156
+ delimiter=delimiter,
152
157
  )
158
+ elif re.search(r"\..*?json$", str(parent_df)):
159
+ parent_df = load_from_geojson(parent_df)
153
160
  else:
154
- raise FileNotFoundError(f"[ERROR] Could not find {parent_df}.")
161
+ raise ValueError(
162
+ "[ERROR] ``parent_df`` must be a path to a CSV/TSV/etc or geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
163
+ )
155
164
  if not isinstance(parent_df, pd.DataFrame):
156
165
  raise ValueError(
157
- "[ERROR] ``parent_df`` must be a path to a csv or a pandas DataFrame."
166
+ "[ERROR] ``parent_df`` must be a path to a CSV/TSV/etc or geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
158
167
  )
159
- parent_df = self._eval_df(parent_df) # eval tuples/lists in df
160
168
 
161
169
  if patch_df is None:
162
170
  # If we don't get patch data provided, we'll use the patches and parents to create the dataframes
@@ -354,18 +362,9 @@ class Annotator:
354
362
 
355
363
  return parent_df, patch_df
356
364
 
357
- @staticmethod
358
- def _eval_df(df):
359
- for col in df.columns:
360
- try:
361
- df[col] = df[col].apply(literal_eval)
362
- except (ValueError, TypeError, SyntaxError):
363
- pass
364
- return df
365
-
366
365
  @staticmethod
367
366
  def _load_annotations(
368
- patch_df: pd.DataFrame,
367
+ patch_df: pd.DataFrame | gpd.GeoDataFrame,
369
368
  annotations_file: str,
370
369
  labels: list,
371
370
  label_col: str,
@@ -375,7 +374,7 @@ class Annotator:
375
374
 
376
375
  Parameters
377
376
  ----------
378
- patch_df : pd.DataFrame
377
+ patch_df : pd.DataFrame or gpd.GeoDataFrame
379
378
  Current patch dataframe.
380
379
  annotations_file : str
381
380
  Name of the annotations file
@@ -387,7 +386,9 @@ class Annotator:
387
386
  Delimiter used in CSV files
388
387
 
389
388
  """
390
- existing_annotations = pd.read_csv(annotations_file, index_col=0, sep=delimiter)
389
+ existing_annotations = load_from_csv(
390
+ annotations_file, index_col=0, sep=delimiter
391
+ )
391
392
 
392
393
  if label_col not in existing_annotations.columns:
393
394
  raise ValueError(
@@ -995,8 +996,8 @@ class Annotator:
995
996
 
996
997
  Returns
997
998
  -------
998
- pandas.DataFrame
999
- A dataframe containing the labelled images and their associated
999
+ pandas.DataFrame or geopandas.GeoDataFrame
1000
+ A DataFrame/GeoDataFrame containing the labelled images and their associated
1000
1001
  label index.
1001
1002
  """
1002
1003
  filtered_df = self.patch_df[self.patch_df[self.label_col].notna()].copy(
@@ -2,10 +2,12 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import os
5
- from ast import literal_eval
5
+ import pathlib
6
+ import re
6
7
  from itertools import product
7
8
  from typing import Callable
8
9
 
10
+ import geopandas as gpd
9
11
  import matplotlib.pyplot as plt
10
12
  import pandas as pd
11
13
  import torch
@@ -24,14 +26,16 @@ except ImportError:
24
26
  )
25
27
  parhugin_installed = False
26
28
 
29
+ from mapreader.utils.load_frames import eval_dataframe, load_from_csv, load_from_geojson
30
+
27
31
 
28
32
  class PatchDataset(Dataset):
29
33
  """A PyTorch Dataset class for loading image patches from a DataFrame.
30
34
 
31
35
  Parameters
32
36
  ----------
33
- patch_df : pandas.DataFrame or str
34
- DataFrame or path to csv file containing the paths to image patches and their labels.
37
+ patch_df : str or pathlib.Path or pandas.DataFrame or gpd.GeoDataFrame
38
+ DataFrame or path to CSV/TSV/geojson file containing the paths to image patches and their labels.
35
39
  transform : Union[str, transforms.Compose, Callable]
36
40
  The transform to use on the image.
37
41
  A string can be used to call default transforms - options are "train", "test" or "val".
@@ -39,7 +43,7 @@ class PatchDataset(Dataset):
39
43
  and performs image transformations can be used.
40
44
  At minimum, transform should be ``torchvision.transforms.ToTensor()``.
41
45
  delimiter : str, optional
42
- The delimiter to use when reading the dataframe. By default ``","``.
46
+ The delimiter to use when reading the CSV/TSV file. By default ``","``.
43
47
  patch_paths_col : str, optional
44
48
  The name of the column in the DataFrame containing the image paths. Default is "image_path".
45
49
  label_col : str, optional
@@ -51,7 +55,7 @@ class PatchDataset(Dataset):
51
55
 
52
56
  Attributes
53
57
  ----------
54
- patch_df : pandas.DataFrame
58
+ patch_df : pandas.DataFrame or gpd.GeoDataFrame
55
59
  DataFrame containing the paths to image patches and their labels.
56
60
  label_col : str
57
61
  The name of the column containing the image labels.
@@ -91,7 +95,7 @@ class PatchDataset(Dataset):
91
95
 
92
96
  def __init__(
93
97
  self,
94
- patch_df: pd.DataFrame | str,
98
+ patch_df: str | pathlib.Path | pd.DataFrame | gpd.GeoDataFrame,
95
99
  transform: str | (transforms.Compose | Callable),
96
100
  delimiter: str = ",",
97
101
  patch_paths_col: str | None = "image_path",
@@ -102,19 +106,22 @@ class PatchDataset(Dataset):
102
106
  if isinstance(patch_df, pd.DataFrame):
103
107
  self.patch_df = patch_df
104
108
 
105
- elif isinstance(patch_df, str):
106
- if os.path.isfile(patch_df):
107
- print(f'[INFO] Reading "{patch_df}".')
108
- patch_df = pd.read_csv(patch_df, sep=delimiter)
109
- # ensure tuple/list columns are read as such
110
- patch_df = self._eval_df(patch_df)
111
- self.patch_df = patch_df
109
+ elif isinstance(patch_df, (str, pathlib.Path)):
110
+ print(f'[INFO] Reading "{patch_df}".')
111
+ if re.search(r"\..?sv$", str(patch_df)):
112
+ self.patch_df = load_from_csv(
113
+ patch_df,
114
+ delimiter=delimiter,
115
+ )
116
+ elif re.search(r"\..*?json$", str(patch_df)):
117
+ self.patch_df = load_from_geojson(patch_df)
112
118
  else:
113
- raise ValueError(f'[ERROR] "{patch_df}" cannot be found.')
114
-
119
+ raise ValueError(
120
+ "[ERROR] ``patch_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
121
+ )
115
122
  else:
116
123
  raise ValueError(
117
- "[ERROR] Please pass ``patch_df`` as a string (path to csv file) or pd.DataFrame."
124
+ "[ERROR] ``patch_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
118
125
  )
119
126
 
120
127
  # force index to be image_id
@@ -133,7 +140,7 @@ class PatchDataset(Dataset):
133
140
  if self.label_col:
134
141
  if self.label_col not in self.patch_df.columns:
135
142
  raise ValueError(
136
- f"[ERROR] Label column ({label_col}) not in dataframe."
143
+ f"[ERROR] Label column ({label_col}) not in DataFrame."
137
144
  )
138
145
  else:
139
146
  self.unique_labels = self.patch_df[self.label_col].unique().tolist()
@@ -142,14 +149,14 @@ class PatchDataset(Dataset):
142
149
  if self.label_index_col not in self.patch_df.columns:
143
150
  if self.label_col:
144
151
  print(
145
- f"[INFO] Label index column ({label_index_col}) not in dataframe. Creating column."
152
+ f"[INFO] Label index column ({label_index_col}) not in DataFrame. Creating column."
146
153
  )
147
154
  self.patch_df[self.label_index_col] = self.patch_df[
148
155
  self.label_col
149
156
  ].apply(self._get_label_index)
150
157
  else:
151
158
  raise ValueError(
152
- f"[ERROR] Label index column ({label_index_col}) not in dataframe."
159
+ f"[ERROR] Label index column ({label_index_col}) not in DataFrame."
153
160
  )
154
161
 
155
162
  if isinstance(transform, str):
@@ -162,15 +169,6 @@ class PatchDataset(Dataset):
162
169
  else:
163
170
  self.transform = transform
164
171
 
165
- @staticmethod
166
- def _eval_df(df):
167
- for col in df.columns:
168
- try:
169
- df[col] = df[col].apply(literal_eval)
170
- except (ValueError, TypeError, SyntaxError):
171
- pass
172
- return df
173
-
174
172
  def __len__(self) -> int:
175
173
  """
176
174
  Return the length of the dataset.
@@ -393,15 +391,15 @@ class PatchContextDataset(PatchDataset):
393
391
 
394
392
  Parameters
395
393
  ----------
396
- patch_df : pandas.DataFrame or str
397
- DataFrame or path to csv file containing the paths to image patches and their labels.
398
- total_df : pandas.DataFrame or str
399
- DataFrame or path to csv file containing the paths to all images and their labels.
394
+ patch_df : str or pathlib.Path or pandas.DataFrame or gpd.GeoDataFrame
395
+ DataFrame or path to CSV/TSV/geojson file containing the paths to image patches and their labels.
396
+ total_df : str or pathlib.Path or pandas.DataFrame or gpd.GeoDataFrame
397
+ DataFrame or path to CSV/TSV/geojson file containing the paths to all images and their labels.
400
398
  transform : str
401
399
  Torchvision transform to be applied to context images.
402
400
  Either "train" or "val".
403
401
  delimiter : str
404
- The delimiter to use when reading the csv file. By default ``","``.
402
+ The delimiter to use when reading the CSV/TSV file. By default ``","``.
405
403
  patch_paths_col : str, optional
406
404
  The name of the column in the DataFrame containing the image paths. Default is "image_path".
407
405
  label_col : str, optional
@@ -421,8 +419,8 @@ class PatchContextDataset(PatchDataset):
421
419
 
422
420
  Attributes
423
421
  ----------
424
- patch_df : pandas.DataFrame
425
- A pandas DataFrame with columns representing image paths, labels,
422
+ patch_df : pandas.DataFrame or gpd.GeoDataFrame
423
+ DataFrame with columns representing image paths, labels,
426
424
  and object bounding boxes.
427
425
  label_col : str
428
426
  The name of the column containing the image labels.
@@ -445,8 +443,8 @@ class PatchContextDataset(PatchDataset):
445
443
 
446
444
  def __init__(
447
445
  self,
448
- patch_df: pd.DataFrame | str,
449
- total_df: pd.DataFrame | str,
446
+ patch_df: str | pathlib.Path | pd.DataFrame | gpd.GeoDataFrame,
447
+ total_df: str | pathlib.Path | pd.DataFrame | gpd.GeoDataFrame,
450
448
  transform: str,
451
449
  delimiter: str = ",",
452
450
  patch_paths_col: str | None = "image_path",
@@ -459,35 +457,42 @@ class PatchContextDataset(PatchDataset):
459
457
  ):
460
458
  if isinstance(patch_df, pd.DataFrame):
461
459
  self.patch_df = patch_df
462
-
463
- elif isinstance(patch_df, str):
464
- if os.path.isfile(patch_df):
465
- print(f'[INFO] Reading "{patch_df}".')
466
- patch_df = pd.read_csv(patch_df, sep=delimiter)
467
- patch_df = self._eval_df(patch_df)
468
- self.patch_df = patch_df
460
+ elif isinstance(patch_df, (str, pathlib.Path)):
461
+ print(f'[INFO] Reading "{patch_df}".')
462
+ if re.search(r"\..?sv$", str(patch_df)):
463
+ self.patch_df = load_from_csv(
464
+ patch_df,
465
+ delimiter=delimiter,
466
+ )
467
+ elif re.search(r"\..*?json$", str(patch_df)):
468
+ self.patch_df = load_from_geojson(patch_df)
469
469
  else:
470
- raise ValueError(f'[ERROR] "{patch_df}" cannot be found.')
471
-
470
+ raise ValueError(
471
+ "[ERROR] ``patch_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
472
+ )
472
473
  else:
473
474
  raise ValueError(
474
- "[ERROR] Please pass ``patch_df`` as a string (path to csv file) or pd.DataFrame."
475
+ "[ERROR] ``patch_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
475
476
  )
476
477
 
477
478
  if isinstance(total_df, pd.DataFrame):
478
479
  self.total_df = total_df
479
-
480
- elif isinstance(total_df, str):
481
- if os.path.isfile(total_df):
482
- total_df = pd.read_csv(total_df, sep=delimiter)
483
- total_df = self._eval_df(total_df)
484
- self.total_df = total_df
480
+ elif isinstance(total_df, (str, pathlib.Path)):
481
+ print(f'[INFO] Reading "{total_df}".')
482
+ if re.search(r"\..?sv$", str(total_df)):
483
+ self.total_df = load_from_csv(
484
+ total_df,
485
+ delimiter=delimiter,
486
+ )
487
+ elif re.search(r"\..*?json$", str(total_df)):
488
+ self.total_df = load_from_geojson(total_df)
485
489
  else:
486
- raise ValueError(f'[ERROR] "{total_df}" cannot be found.')
487
-
490
+ raise ValueError(
491
+ "[ERROR] ``total_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
492
+ )
488
493
  else:
489
494
  raise ValueError(
490
- "[ERROR] Please pass ``total_df`` as a string (path to csv file) or pd.DataFrame."
495
+ "[ERROR] ``total_df`` must be a path to a CSV/geojson file or a pandas DataFrame or a geopandas GeoDataFrame."
491
496
  )
492
497
 
493
498
  # force index to be image_id
@@ -506,18 +511,23 @@ class PatchContextDataset(PatchDataset):
506
511
  if self.label_col:
507
512
  if self.label_col not in self.patch_df.columns:
508
513
  raise ValueError(
509
- f"[ERROR] Label column ({self.label_col}) not in dataframe."
514
+ f"[ERROR] Label column ({self.label_col}) not in DataFrame."
510
515
  )
511
516
  self.unique_labels = self.patch_df[self.label_col].unique().tolist()
512
517
 
513
518
  if self.label_index_col:
514
519
  if self.label_index_col not in self.patch_df.columns:
515
- print(
516
- f"[INFO] Label index column ({label_index_col}) not in dataframe. Creating column."
517
- )
518
- self.patch_df[self.label_index_col] = self.patch_df[
519
- self.label_col
520
- ].apply(self._get_label_index)
520
+ if self.label_col:
521
+ print(
522
+ f"[INFO] Label index column ({label_index_col}) not in DataFrame. Creating column."
523
+ )
524
+ self.patch_df[self.label_index_col] = self.patch_df[
525
+ self.label_col
526
+ ].apply(self._get_label_index)
527
+ else:
528
+ raise ValueError(
529
+ f"[ERROR] Label index column ({label_index_col}) not in DataFrame."
530
+ )
521
531
 
522
532
  if isinstance(transform, str):
523
533
  if transform in ["train", "val", "test"]:
@@ -646,7 +656,7 @@ class PatchContextDataset(PatchDataset):
646
656
  )
647
657
  if "parent_id" not in total_df.columns:
648
658
  total_df["parent_id"] = total_df.index.map(lambda x: x.split("#")[1])
649
- total_df = self._eval_df(total_df)
659
+ total_df = eval_dataframe(total_df)
650
660
 
651
661
  if not all(
652
662
  [col in total_df.columns for col in ["min_x", "min_y", "max_x", "max_y"]]