geo-explorer 0.9.11__tar.gz → 0.9.12__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: geo-explorer
3
- Version: 0.9.11
3
+ Version: 0.9.12
4
4
  Summary: Explore geodata interactively.
5
5
  License: MIT
6
6
  Author: Morten Letnes
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "geo-explorer"
3
- version = "0.9.11"
3
+ version = "0.9.12"
4
4
  description = "Explore geodata interactively."
5
5
  authors = ["Morten Letnes <morten.letnes@ssb.no>"]
6
6
  license = "MIT"
@@ -25,6 +25,7 @@ from typing import Any
25
25
  from typing import ClassVar
26
26
 
27
27
  import dash
28
+ import pyproj
28
29
  import dash_bootstrap_components as dbc
29
30
  import dash_leaflet as dl
30
31
  import folium
@@ -686,12 +687,15 @@ def _read_files(explorer, paths: list[str], mask=None, **kwargs) -> None:
686
687
  paths = [
687
688
  path
688
689
  for path in paths
689
- if mask is None
690
- or (
691
- path in bbox_set
692
- and (
693
- pd.isna(explorer._bbox_series[path])
694
- or shapely.intersects(mask, explorer._bbox_series[path])
690
+ if explorer._loaded_data_sizes[path] > 0
691
+ and (
692
+ mask is None
693
+ or (
694
+ path in bbox_set
695
+ and (
696
+ pd.isna(explorer._bbox_series[path])
697
+ or shapely.intersects(mask, explorer._bbox_series[path])
698
+ )
695
699
  )
696
700
  )
697
701
  ]
@@ -768,30 +772,55 @@ def _try_to_get_bbox_else_none(
768
772
 
769
773
 
770
774
  def _get_bbox_series_as_4326(paths, file_system):
771
- # bbox_series = sg.get_bbox_series(paths, file_system=file_system)
772
- # return bbox_series.to_crs(4326)
773
-
774
775
  func = partial(_try_to_get_bbox_else_none, file_system=file_system)
775
776
  with ThreadPoolExecutor() as executor:
776
777
  bbox_and_crs = list(executor.map(func, paths))
777
778
 
778
- crss = {json.dumps(x[1]) for x in bbox_and_crs}
779
- crss = {
780
- crs
781
- for crs in crss
782
- if not any(str(crs).lower() == txt for txt in ["none", "null"])
783
- }
779
+ bbox_and_crs = [(bbox, json.dumps(crs)) for bbox, crs in bbox_and_crs]
780
+ bbox_and_crs = [
781
+ (
782
+ bbox,
783
+ (
784
+ pyproj.CRS(crs).to_string()
785
+ if not any(crs.lower() == txt for txt in ["none", "null"])
786
+ else None
787
+ ),
788
+ )
789
+ for bbox, crs in bbox_and_crs
790
+ ]
791
+ crss = {crs for (_, crs) in bbox_and_crs}
784
792
  if not crss:
785
793
  return GeoSeries([None for _ in range(len(paths))], index=paths)
786
- crs = get_common_crs(crss)
787
- return GeoSeries(
788
- [
789
- shapely.box(*bbox[0]) if bbox[0] is not None else None
790
- for bbox in bbox_and_crs
791
- ],
792
- index=paths,
793
- crs=crs,
794
- ).to_crs(4326)
794
+ missing = GeoSeries(
795
+ {
796
+ path: Polygon()
797
+ for path, (bbox, _) in zip(paths, bbox_and_crs, strict=True)
798
+ if bbox is None
799
+ }
800
+ )
801
+ paths_bbox_and_crs = {
802
+ path: (bbox, crs)
803
+ for path, (bbox, crs) in zip(paths, bbox_and_crs, strict=True)
804
+ if bbox is not None
805
+ }
806
+ crs_with_paths = {}
807
+ geoms = shapely.box(
808
+ [bbox[0] for (bbox, _) in paths_bbox_and_crs.values()],
809
+ [bbox[1] for (bbox, _) in paths_bbox_and_crs.values()],
810
+ [bbox[2] for (bbox, _) in paths_bbox_and_crs.values()],
811
+ [bbox[3] for (bbox, _) in paths_bbox_and_crs.values()],
812
+ )
813
+ for crs in crss:
814
+ crs_with_paths[crs] = {
815
+ path: geoms[i]
816
+ for i, (path, (bbox, this_crs)) in enumerate(paths_bbox_and_crs.items())
817
+ if this_crs == crs and bbox is not None
818
+ }
819
+ no_crs = GeoSeries(crs_with_paths.pop(None, {}), crs=4326)
820
+ return pd.concat(
821
+ [GeoSeries(data, crs=crs).to_crs(4326) for crs, data in crs_with_paths.items()]
822
+ + [missing, no_crs]
823
+ )
795
824
 
796
825
 
797
826
  def get_index(values: list[Any], ids: list[Any], index: Any):
@@ -2844,7 +2873,7 @@ class GeoExplorer:
2844
2873
  self.color_dict = {}
2845
2874
  elif not column and triggered is None:
2846
2875
  column = self.column
2847
- elif self._concatted_data is None:
2876
+ if self._concatted_data is None:
2848
2877
  return (
2849
2878
  [],
2850
2879
  None,
@@ -3151,6 +3180,7 @@ class GeoExplorer:
3151
3180
 
3152
3181
  if images:
3153
3182
  # make sure all single-band images are normalized by same extremities
3183
+ debug_print(images)
3154
3184
  vmin = np.min([np.min(x[0]) for x in images.values()])
3155
3185
  vmax = np.min([np.max(x[0]) for x in images.values()])
3156
3186
 
@@ -59,11 +59,9 @@ class AbstractImageConfig(abc.ABC):
59
59
  clipped_bbox = bbox_correct_crs.intersection(shapely.box(*ds_bounds))
60
60
  minx, miny, maxx, maxy = clipped_bbox.bounds
61
61
 
62
- ds = ds.sel(
63
- x=slice(minx, maxx),
64
- y=slice(maxy, miny),
65
- )
66
-
62
+ x = "x" if "x" in list(ds.coords) else "X"
63
+ y = "y" if "y" in list(ds.coords) else "Y"
64
+ ds = ds.sel(**{x: slice(minx, maxx), y: slice(maxy, miny)})
67
65
  return self._run_code_block(ds)
68
66
 
69
67
  @time_method_call(_PROFILE_DICT)
@@ -173,7 +171,7 @@ class NetCDFConfig(AbstractImageConfig):
173
171
  for x in set(ds.attrs).union(
174
172
  set(ds.data_vars if isinstance(ds, Dataset) else set())
175
173
  )
176
- if "projection" in x.lower() or "crs" in x.lower()
174
+ if "projection" in x.lower() or "crs" in x.lower() or "utm" in x.lower()
177
175
  ]
178
176
  if not attrs:
179
177
  raise ValueError(f"Could not find CRS attribute/data_var in dataset: {ds}")
@@ -181,7 +179,10 @@ class NetCDFConfig(AbstractImageConfig):
181
179
  def getattr_xarray(ds, attr):
182
180
  x = ds.attrs.get(attr, ds.get(attr))
183
181
  if isinstance(x, DataArray):
184
- return pyproj.CRS(str(x.values))
182
+ try:
183
+ return pyproj.CRS(str(x.attrs["proj4"]))
184
+ except Exception:
185
+ return pyproj.CRS(str(x.values))
185
186
  elif x is not None:
186
187
  return pyproj.CRS(x)
187
188
  raise ValueError(f"Could not find CRS attribute/data_var in dataset: {ds}")
@@ -91,9 +91,11 @@ def get_xarray_resolution(ds) -> int:
91
91
  minx, miny, maxx, maxy = _get_raw_xarray_bounds(ds)
92
92
  diffx = maxx - minx
93
93
  diffy = maxy - miny
94
+ x = "x" if "x" in list(ds.coords) else "X"
95
+ y = "y" if "y" in list(ds.coords) else "Y"
94
96
  try:
95
- resx = diffx / (ds.sizes["x"] - 1)
96
- resy = diffy / (ds.sizes["y"] - 1)
97
+ resx = diffx / (ds.sizes[x] - 1)
98
+ resy = diffy / (ds.sizes[y] - 1)
97
99
  except ZeroDivisionError:
98
100
  raise ValueError(
99
101
  f"Cannot calculate resolution for Dataset with {diffx=}, {diffy=}, {ds.sizes['x']=}, {ds.sizes['y']=}"
@@ -117,11 +119,13 @@ def get_xarray_bounds(ds) -> tuple[float, float, float, float]:
117
119
 
118
120
 
119
121
  def _get_raw_xarray_bounds(ds) -> tuple[float, float, float, float]:
122
+ x = "x" if "x" in list(ds.coords) else "X"
123
+ y = "y" if "y" in list(ds.coords) else "Y"
120
124
  return (
121
- float(ds["x"].min().values),
122
- float(ds["y"].min().values),
123
- float(ds["x"].max().values),
124
- float(ds["y"].max().values),
125
+ float(ds[x].min().values),
126
+ float(ds[y].min().values),
127
+ float(ds[x].max().values),
128
+ float(ds[y].max().values),
125
129
  )
126
130
 
127
131
 
File without changes
File without changes
File without changes