wolfhece 2.1.46__py3-none-any.whl → 2.1.48__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.
- wolfhece/Coordinates_operations.py +189 -0
- wolfhece/apps/version.py +1 -1
- wolfhece/wolf_array.py +257 -33
- {wolfhece-2.1.46.dist-info → wolfhece-2.1.48.dist-info}/METADATA +8 -8
- {wolfhece-2.1.46.dist-info → wolfhece-2.1.48.dist-info}/RECORD +8 -7
- {wolfhece-2.1.46.dist-info → wolfhece-2.1.48.dist-info}/WHEEL +0 -0
- {wolfhece-2.1.46.dist-info → wolfhece-2.1.48.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.46.dist-info → wolfhece-2.1.48.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,189 @@
|
|
1
|
+
from pyproj import Transformer
|
2
|
+
from concurrent.futures import ProcessPoolExecutor
|
3
|
+
import numpy as np
|
4
|
+
from osgeo import gdal
|
5
|
+
import os
|
6
|
+
import logging
|
7
|
+
|
8
|
+
from .PyTranslate import _
|
9
|
+
|
10
|
+
def transform_chunk_coordinates(inputEPSG:str, outputEPSG:str, chunk:np.ndarray):
|
11
|
+
"""
|
12
|
+
Transforms a chunk of coordinates
|
13
|
+
|
14
|
+
:param inputEPSG: input EPSG code (e.g. "EPSG:3812")
|
15
|
+
:type inputEPSG: str
|
16
|
+
:param outputEPSG: output EPSG code (e.g. "EPSG:31370")
|
17
|
+
:type outputEPSG: str
|
18
|
+
:param chunk: list of points to be transformed
|
19
|
+
:type chunk: np.ndarray
|
20
|
+
"""
|
21
|
+
COO_TRANSFORMER = Transformer.from_crs(inputEPSG, outputEPSG, always_xy=True)
|
22
|
+
return COO_TRANSFORMER.transform(chunk[:, 0], chunk[:, 1])
|
23
|
+
|
24
|
+
def transform_coordinates(points:np.ndarray, inputEPSG:str="EPSG:3812", outputEPSG:str="EPSG:31370", chunk_size:int=1000):
|
25
|
+
"""
|
26
|
+
Transforms coordinates in batches using multiprocessing. If more than chunk_size points are provided, the
|
27
|
+
function will split the points into chunks and transform them in parallel => requiring in the main script
|
28
|
+
to use the statement if __name__ == '__main__':.
|
29
|
+
|
30
|
+
:param points: Array of coordinates to be transformed
|
31
|
+
:type points: numpy.ndarray
|
32
|
+
:param inputEPSG: (optional) Input EPSG code. Defaults to "EPSG:3812"
|
33
|
+
:type inputEPSG: str
|
34
|
+
:param outputEPSG: (optional) Output EPSG code. Defaults to "EPSG:31370"
|
35
|
+
:type outputEPSG: str
|
36
|
+
:param chunk_size: (optional) Size of each batch for transformation. Defaults to 100000
|
37
|
+
:type chunk_size: int
|
38
|
+
|
39
|
+
:return numpy.ndarray: Transformed coordinates
|
40
|
+
"""
|
41
|
+
|
42
|
+
# sanitize inputs
|
43
|
+
inputEPSG = str(inputEPSG)
|
44
|
+
outputEPSG = str(outputEPSG)
|
45
|
+
|
46
|
+
if not "EPSG" in inputEPSG or not "EPSG" in inputEPSG:
|
47
|
+
logging.error(_("EPSG code must be in the format 'EPSG:XXXX'"))
|
48
|
+
return
|
49
|
+
|
50
|
+
num_points = len(points)
|
51
|
+
results = []
|
52
|
+
|
53
|
+
total_steps = (num_points + chunk_size - 1) // chunk_size
|
54
|
+
|
55
|
+
if total_steps == 1:
|
56
|
+
result_x, result_y = transform_chunk_coordinates(inputEPSG, outputEPSG, points)
|
57
|
+
return np.vstack((result_x, result_y)).T
|
58
|
+
|
59
|
+
with ProcessPoolExecutor() as executor:
|
60
|
+
futures = []
|
61
|
+
for i in range(0, num_points, chunk_size):
|
62
|
+
chunk = points[i:i + chunk_size]
|
63
|
+
futures.append(executor.submit(transform_chunk_coordinates, inputEPSG, outputEPSG, chunk))
|
64
|
+
|
65
|
+
for step, future in enumerate(futures):
|
66
|
+
result_x, result_y = future.result()
|
67
|
+
results.append(np.vstack((result_x, result_y)).T)
|
68
|
+
|
69
|
+
return np.vstack(results)
|
70
|
+
|
71
|
+
def reproject_and_resample_raster(input_raster_path:str, output_raster_path:str,
|
72
|
+
input_srs:str='EPSG:3812', output_srs:str='EPSG:31370',
|
73
|
+
resampling_method:str|int=gdal.GRA_Bilinear,
|
74
|
+
xRes:float=0.5, yRes:float=0.5, debug:bool=False):
|
75
|
+
"""
|
76
|
+
Use gdal to open a tiff raster in a given input EPSG 'inputEPSG' and transforms the raster into another EPSG system 'outputEPSG'.
|
77
|
+
The resolution can be forced through xRes and yRes (the origin will be rounded to the nearest multiple of the resolution). The
|
78
|
+
resampling method can be chosen among the gdal GRA_* constants (gdal.GRA_Average; gdal.GRA_Bilinear; gdal.GRA_Cubic; gdal.GRA_CubicSpline;
|
79
|
+
gdal.GRA_Lanczos; gdal.GRA_Mode; gdal.GRA_NearestNeighbor).
|
80
|
+
|
81
|
+
:param input_raster_path: the path to the input raster file (.tif or .tiff)
|
82
|
+
:type input_raster_path: str
|
83
|
+
:param output_raster_path: the path to the output raster file (.tif or .tiff) that will be created
|
84
|
+
:type output_raster_path: str
|
85
|
+
:param input_srs: Input EPSG code. Defaults to Lambert 2008 "EPSG:3812"
|
86
|
+
:type input_srs: str
|
87
|
+
:param output_srs: Output EPSG code. Defaults to Lambert 72 "EPSG:31370"
|
88
|
+
:type output_srs: str
|
89
|
+
:param resampling_method: Resampling method. Defaults to gdal.GRA_Bilinear
|
90
|
+
:type resampling_method: int, str
|
91
|
+
:param xRes: Resolution along X. Defaults to 0.5
|
92
|
+
:type xRes: float
|
93
|
+
:param yRes: Resolution along Y. Defaults to 0.5
|
94
|
+
:type yRes: float
|
95
|
+
:param debug: If True, print debug information. Defaults to False
|
96
|
+
:type debug: bool
|
97
|
+
"""
|
98
|
+
from osgeo import osr
|
99
|
+
|
100
|
+
# santitize inputs
|
101
|
+
input_raster_path = str(input_raster_path)
|
102
|
+
output_raster_path = str(output_raster_path)
|
103
|
+
|
104
|
+
# ATTENTION: mask values should be negative in the tiff corresponding to input_raster_path!
|
105
|
+
if not(input_raster_path.endswith('.tif') or input_raster_path.endswith('.tiff')):
|
106
|
+
logging.error(_("Input raster must be a GeoTIFF file"))
|
107
|
+
return
|
108
|
+
if not(output_raster_path.endswith('.tif') or output_raster_path.endswith('.tiff')):
|
109
|
+
logging.error(_("Output raster must be a GeoTIFF file"))
|
110
|
+
return
|
111
|
+
|
112
|
+
# check the output file
|
113
|
+
if os.path.exists(output_raster_path):
|
114
|
+
try:
|
115
|
+
os.remove(output_raster_path)
|
116
|
+
except PermissionError as e:
|
117
|
+
logging.error(_(f"Permission denied while trying to delete {output_raster_path}. Ensure the file is not open in another program and you have sufficient privileges."))
|
118
|
+
return
|
119
|
+
except Exception as e:
|
120
|
+
logging.error(_(f"An unexpected error occurred while trying to delete {output_raster_path}: {str(e)}"))
|
121
|
+
return
|
122
|
+
|
123
|
+
# Open the input raster
|
124
|
+
input_raster = gdal.Open(input_raster_path)
|
125
|
+
if input_raster is None:
|
126
|
+
logging.error(_(f"Unable to open input raster: {input_raster_path}"))
|
127
|
+
return
|
128
|
+
|
129
|
+
# Get the source SRS from the input raster
|
130
|
+
source_srs = osr.SpatialReference()
|
131
|
+
if debug:
|
132
|
+
print('Initial projection: ',input_raster.GetProjection())
|
133
|
+
print('set projection init: ',int(input_srs.split(':')[1]))
|
134
|
+
source_srs.ImportFromEPSG(int(input_srs.split(':')[1]))
|
135
|
+
|
136
|
+
# Create the target SRS
|
137
|
+
target_srs = osr.SpatialReference()
|
138
|
+
if debug:
|
139
|
+
print('set projection out: ',int(output_srs.split(':')[1]))
|
140
|
+
target_srs.ImportFromEPSG(int(output_srs.split(':')[1]))
|
141
|
+
|
142
|
+
# Define the options for the reprojection
|
143
|
+
# Load the initial array to obtain the origin and the limits
|
144
|
+
ulx, xres, xskew, uly, yskew, yres = input_raster.GetGeoTransform()
|
145
|
+
Orig = np.array([[ulx,uly],
|
146
|
+
[ulx+input_raster.RasterXSize*xres, uly+input_raster.RasterYSize*yres]])
|
147
|
+
Orig.sort(0)
|
148
|
+
|
149
|
+
# Transform the origin and the limits into the new projection 'Lambert 72'
|
150
|
+
Orig_out = transform_coordinates(Orig, inputEPSG=input_srs, outputEPSG=output_srs)
|
151
|
+
|
152
|
+
# Round each coordinate to the nearest multiple of the wanted resolution
|
153
|
+
Orig_out[:,0] = np.round(Orig_out[:,0]/xRes)*xRes
|
154
|
+
Orig_out[:,1] = np.round(Orig_out[:,1]/yRes)*yRes
|
155
|
+
if debug:
|
156
|
+
print(Orig_out)
|
157
|
+
print(tuple(Orig_out.reshape(-1)))
|
158
|
+
|
159
|
+
# Define the reprojection options
|
160
|
+
# outputBounds=tuple(Orig_out.reshape(-1)),
|
161
|
+
# xRes=xRes, yRes=yRes,
|
162
|
+
reproject_options = gdal.WarpOptions(
|
163
|
+
outputBounds=tuple(Orig_out.reshape(-1)), # Output bounds: (minX, minY, maxX, maxY)
|
164
|
+
xRes=xRes, yRes=yRes,
|
165
|
+
srcSRS=source_srs.ExportToWkt(),
|
166
|
+
dstSRS=target_srs.ExportToWkt(),
|
167
|
+
resampleAlg=resampling_method
|
168
|
+
)
|
169
|
+
|
170
|
+
# Reproject and resample the input raster
|
171
|
+
output_raster = gdal.Warp(
|
172
|
+
destNameOrDestDS=output_raster_path,
|
173
|
+
srcDSOrSrcDSTab=input_raster,
|
174
|
+
options=reproject_options
|
175
|
+
)
|
176
|
+
|
177
|
+
if output_raster is None:
|
178
|
+
logging.error(_(f"Reprojection failed for input raster: {input_raster_path}"))
|
179
|
+
return
|
180
|
+
|
181
|
+
# Flush cache to ensure the output is written to disk
|
182
|
+
output_raster.FlushCache()
|
183
|
+
|
184
|
+
# Close the datasets IMPORTANT to set to None in order to close them
|
185
|
+
input_raster = None
|
186
|
+
output_raster = None
|
187
|
+
|
188
|
+
if debug:
|
189
|
+
print(f"Reprojection and resampling completed successfully. Output saved to: {output_raster_path}")
|
wolfhece/apps/version.py
CHANGED
wolfhece/wolf_array.py
CHANGED
@@ -20,6 +20,7 @@ import numpy.ma as ma
|
|
20
20
|
import math as m
|
21
21
|
import logging
|
22
22
|
import json
|
23
|
+
import tempfile
|
23
24
|
from pathlib import Path
|
24
25
|
|
25
26
|
try:
|
@@ -45,7 +46,11 @@ from os.path import dirname,basename,join
|
|
45
46
|
import logging
|
46
47
|
from typing import Literal
|
47
48
|
from copy import deepcopy
|
49
|
+
from osgeo import gdal
|
50
|
+
from enum import Enum
|
48
51
|
|
52
|
+
|
53
|
+
from .Coordinates_operations import reproject_and_resample_raster
|
49
54
|
from .PyTranslate import _
|
50
55
|
from .GraphNotebook import PlotPanel
|
51
56
|
from .CpGrid import CpGrid
|
@@ -90,6 +95,42 @@ WOLF_ARRAY_MB = [WOLF_ARRAY_MB_SINGLE, WOLF_ARRAY_MB_INTEGER, WOLF_ARRAY_MNAP_IN
|
|
90
95
|
|
91
96
|
VERSION_RGB = 2
|
92
97
|
|
98
|
+
class Rebin_Ops(Enum):
|
99
|
+
MIN = 0
|
100
|
+
MEAN = 1
|
101
|
+
MAX = 2
|
102
|
+
SUM = 3
|
103
|
+
MEDIAN = 4
|
104
|
+
|
105
|
+
@classmethod
|
106
|
+
def get_numpy_ops(cls):
|
107
|
+
""" Return a list of numpy functions corresponding to the enum values """
|
108
|
+
|
109
|
+
# CAUTION : Order is important and must match the enum values
|
110
|
+
return [np.ma.min, np.ma.mean, np.ma.max, np.ma.sum, np.ma.median]
|
111
|
+
|
112
|
+
@classmethod
|
113
|
+
def get_ops(cls, name:str):
|
114
|
+
""" Return the numpy function corresponding to a string """
|
115
|
+
|
116
|
+
if isinstance(name, Rebin_Ops):
|
117
|
+
return cls.get_numpy_ops()[name.value]
|
118
|
+
elif isinstance(name, str):
|
119
|
+
if name == 'min':
|
120
|
+
return np.ma.min
|
121
|
+
elif name == 'mean':
|
122
|
+
return np.ma.mean
|
123
|
+
elif name == 'max':
|
124
|
+
return np.ma.max
|
125
|
+
elif name == 'sum':
|
126
|
+
return np.ma.sum
|
127
|
+
elif name == 'median':
|
128
|
+
return np.ma.median
|
129
|
+
else:
|
130
|
+
return None
|
131
|
+
else:
|
132
|
+
return None
|
133
|
+
|
93
134
|
def getkeyblock(i, addone=True) -> str:
|
94
135
|
"""
|
95
136
|
Name/Key of a block in the dictionnary of a WolfArrayMB instance
|
@@ -111,6 +152,9 @@ def decodekeyblock(key, addone=True) -> int:
|
|
111
152
|
return int(key[5:])
|
112
153
|
else:
|
113
154
|
return int(key[5:]) - 1
|
155
|
+
|
156
|
+
|
157
|
+
|
114
158
|
class header_wolf():
|
115
159
|
"""
|
116
160
|
Header of WolfArray
|
@@ -284,9 +328,9 @@ class header_wolf():
|
|
284
328
|
"""
|
285
329
|
Set translation
|
286
330
|
|
287
|
-
:param tr_x
|
288
|
-
:param tr_y
|
289
|
-
:param tr_z
|
331
|
+
:param tr_x: translation along X
|
332
|
+
:param tr_y: translation along Y
|
333
|
+
:param tr_z: translation along Z
|
290
334
|
"""
|
291
335
|
self.translx = tr_x
|
292
336
|
self.transly = tr_y
|
@@ -4396,14 +4440,24 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
4396
4440
|
|
4397
4441
|
def __del__(self):
|
4398
4442
|
""" Destructeur de la classe """
|
4399
|
-
|
4400
|
-
|
4401
|
-
|
4402
|
-
|
4403
|
-
|
4404
|
-
|
4405
|
-
|
4406
|
-
|
4443
|
+
try:
|
4444
|
+
# Perform cleanup tasks safely
|
4445
|
+
self.delete_lists()
|
4446
|
+
if hasattr(self, 'array'):
|
4447
|
+
del self.array
|
4448
|
+
if VERSION_RGB == 1 and hasattr(self, 'rgb'):
|
4449
|
+
del self.rgb
|
4450
|
+
if hasattr(self, '_array3d'):
|
4451
|
+
del self._array3d
|
4452
|
+
if hasattr(self, 'mypal'):
|
4453
|
+
del self.mypal
|
4454
|
+
if hasattr(self, 'shaded'):
|
4455
|
+
del self.shaded
|
4456
|
+
# Perform garbage collection if gc is available
|
4457
|
+
import gc
|
4458
|
+
gc.collect()
|
4459
|
+
except Exception as e:
|
4460
|
+
print(f"Exception in WolfArray destructor: {e} -- Please report this issue")
|
4407
4461
|
|
4408
4462
|
def extract_selection(self):
|
4409
4463
|
""" Extract the current selection """
|
@@ -4802,7 +4856,7 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
4802
4856
|
if reset_plot:
|
4803
4857
|
self.reset_plot()
|
4804
4858
|
|
4805
|
-
def export_geotif(self, outdir='', extent = ''):
|
4859
|
+
def export_geotif(self, outdir='', extent = '', EPSG:int = 31370):
|
4806
4860
|
"""
|
4807
4861
|
Export de la matrice au format Geotiff (Lambert 72 - EPSG:31370)
|
4808
4862
|
|
@@ -4813,11 +4867,12 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
4813
4867
|
|
4814
4868
|
:param outdir: directory
|
4815
4869
|
:param extent: suffix to add to the filename before the extension '.tif'
|
4870
|
+
:param EPSG: EPSG code, by default 31370 (Lambert 72)
|
4816
4871
|
"""
|
4817
4872
|
from osgeo import gdal, osr, gdalconst
|
4818
4873
|
|
4819
4874
|
srs = osr.SpatialReference()
|
4820
|
-
srs.ImportFromEPSG(
|
4875
|
+
srs.ImportFromEPSG(EPSG)
|
4821
4876
|
|
4822
4877
|
if outdir=='' and extent=='':
|
4823
4878
|
filename = self.filename
|
@@ -4845,7 +4900,17 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
4845
4900
|
out_ds: gdal.Dataset
|
4846
4901
|
band: gdal.Band
|
4847
4902
|
driver = gdal.GetDriverByName("GTiff")
|
4848
|
-
|
4903
|
+
# bytes_per_pixel = arr.data.dtype.itemsize
|
4904
|
+
estimated_file_size = self.memory_usage #arr.shape[0] * arr.shape[1] * bytes_per_pixel
|
4905
|
+
|
4906
|
+
# Check if estimated file size exceeds 4GB
|
4907
|
+
if (estimated_file_size > 4 * 1024**3): # 4GB in bytes
|
4908
|
+
options = ['COMPRESS=LZW', 'BIGTIFF=YES']
|
4909
|
+
print('BigTIFF format will be used!')
|
4910
|
+
else:
|
4911
|
+
options = ['COMPRESS=LZW']
|
4912
|
+
|
4913
|
+
out_ds = driver.Create(filename, arr.shape[0], arr.shape[1], 1, arr_type, options=options)
|
4849
4914
|
out_ds.SetProjection(srs.ExportToWkt())
|
4850
4915
|
|
4851
4916
|
|
@@ -5109,6 +5174,10 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
5109
5174
|
except:
|
5110
5175
|
logging.warning(_('Error during importing tif file'))
|
5111
5176
|
|
5177
|
+
# Close the raster
|
5178
|
+
raster.FlushCache()
|
5179
|
+
raster = None
|
5180
|
+
|
5112
5181
|
def add_ops_sel(self):
|
5113
5182
|
"""
|
5114
5183
|
Adding selection manager and operations array
|
@@ -6682,11 +6751,12 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
6682
6751
|
if update_min_max:
|
6683
6752
|
self.mypal.distribute_values(self.array.min(), self.array.max())
|
6684
6753
|
|
6685
|
-
def write_all(self, newpath:str = None):
|
6754
|
+
def write_all(self, newpath:str = None, EPSG:int = 31370):
|
6686
6755
|
"""
|
6687
6756
|
Ecriture de tous les fichiers d'un Wolf array
|
6688
6757
|
|
6689
6758
|
:param newpath: new path and filename with extension -- if None, use the current filename
|
6759
|
+
:param EPSG: EPSG code for geotiff
|
6690
6760
|
"""
|
6691
6761
|
|
6692
6762
|
if isinstance(newpath, Path):
|
@@ -6696,7 +6766,7 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
6696
6766
|
self.filename = newpath
|
6697
6767
|
|
6698
6768
|
if self.filename.endswith('.tif'):
|
6699
|
-
self.export_geotif()
|
6769
|
+
self.export_geotif(EPSG=EPSG)
|
6700
6770
|
elif self.filename.endswith('.npy'):
|
6701
6771
|
|
6702
6772
|
writing_header = True
|
@@ -6730,18 +6800,26 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
6730
6800
|
self.write_txt_header()
|
6731
6801
|
self.write_array()
|
6732
6802
|
|
6733
|
-
def
|
6803
|
+
def get_rebin_shape_size(self, factor:float) -> tuple[tuple[int, int], tuple[float, float]]:
|
6734
6804
|
"""
|
6735
|
-
|
6805
|
+
Return the new shape after rebinning.
|
6736
6806
|
|
6737
|
-
|
6807
|
+
newdx = dx * factor
|
6808
|
+
newdy = dy * factor
|
6809
|
+
|
6810
|
+
The shape is adjusted to be a multiple of the factor.
|
6738
6811
|
|
6739
|
-
|
6812
|
+
:param factor: factor of resolution change -- > 1.0 : decrease resolution, < 1.0 : increase resolution
|
6813
|
+
:type factor: float
|
6814
|
+
:return: new shape
|
6815
|
+
:rtype: Tuple[int, int]
|
6740
6816
|
"""
|
6741
|
-
operation = operation.lower()
|
6742
|
-
if not operation in ['sum', 'mean', 'min']:
|
6743
|
-
raise ValueError("Operator not supported.")
|
6744
6817
|
|
6818
|
+
newdx = self.dx * float(factor)
|
6819
|
+
newdy = self.dy * float(factor)
|
6820
|
+
|
6821
|
+
newnbx = self.nbx
|
6822
|
+
newnby = self.nby
|
6745
6823
|
if np.mod(self.nbx,factor) != 0 or np.mod(self.nby,factor) != 0 :
|
6746
6824
|
newnbx = self.nbx
|
6747
6825
|
newnby = self.nby
|
@@ -6750,8 +6828,85 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
6750
6828
|
if np.mod(self.nby,factor) !=0:
|
6751
6829
|
newnby = self.nby + factor - np.mod(self.nby,factor)
|
6752
6830
|
|
6753
|
-
|
6831
|
+
newnbx = int(newnbx / factor)
|
6832
|
+
newnby = int(newnby / factor)
|
6833
|
+
|
6834
|
+
return (newnbx, newnby), (newdx, newdy)
|
6835
|
+
|
6836
|
+
def get_rebin_header(self, factor:float) -> header_wolf:
|
6837
|
+
"""
|
6838
|
+
Return a new header after rebinning.
|
6839
|
+
|
6840
|
+
:param factor: factor of resolution change -- > 1.0 : decrease resolution, < 1.0 : increase resolution
|
6841
|
+
:type factor: float
|
6842
|
+
|
6843
|
+
:return: new header
|
6844
|
+
:rtype: header_wolf
|
6845
|
+
"""
|
6846
|
+
|
6847
|
+
newshape, newdx_dy = self.get_rebin_shape_size(factor)
|
6848
|
+
|
6849
|
+
newheader = self.get_header()
|
6850
|
+
|
6851
|
+
newheader.nbx = newshape[0]
|
6852
|
+
newheader.nby = newshape[1]
|
6853
|
+
newheader.dx = newdx_dy[0]
|
6854
|
+
newheader.dy = newdx_dy[1]
|
6855
|
+
|
6856
|
+
return newheader
|
6857
|
+
|
6858
|
+
def rebin(self,
|
6859
|
+
factor:float,
|
6860
|
+
operation:Literal['mean', 'sum', 'min', 'max', 'median'] ='mean',
|
6861
|
+
operation_matrix:"WolfArray"=None) -> None:
|
6862
|
+
"""
|
6863
|
+
Change resolution - **in place**.
|
6864
|
+
|
6865
|
+
If you want to keep current data, copy the WolfArray into a new variable -> newWA = Wolfarray(mold=curWA).
|
6866
|
+
|
6867
|
+
:param factor: factor of resolution change -- > 1.0 : decrease resolution, < 1.0 : increase resolution
|
6868
|
+
:type factor: float
|
6869
|
+
:param operation: operation to apply on the blocks ('mean', 'sum', 'min', 'max', 'median')
|
6870
|
+
:type operation: str, Rebin_Ops
|
6871
|
+
:param operation_matrix: operation matrix to apply on the blocks -- see the Enum "Rebin_Ops" for more infos. The matrix must have the same shape as the new array
|
6872
|
+
:type operation_matrix: WolfArray
|
6873
|
+
|
6874
|
+
"""
|
6875
|
+
|
6876
|
+
if operation_matrix is not None:
|
6877
|
+
tmp_header = self.get_rebin_header(factor)
|
6878
|
+
if not operation_matrix.is_like(tmp_header):
|
6879
|
+
logging.error(_("The operation matrix must have the same shape as the new array"))
|
6880
|
+
logging.info(_("You can use the get_rebin_header method to get the new header if you don't know it"))
|
6881
|
+
return
|
6882
|
+
|
6883
|
+
logging.info(_("Operation matrix detected"))
|
6884
|
+
logging.info(_("The operation matrix will be used to apply the operation on the blocks"))
|
6885
|
+
else:
|
6886
|
+
|
6887
|
+
operation = Rebin_Ops.get_ops(operation)
|
6888
|
+
|
6889
|
+
if operation is None:
|
6890
|
+
logging.error(_("Operator not supported -- Must be a string in ['sum', 'mean', 'min', 'max', 'median'] or a Rebin_Ops Enum"))
|
6891
|
+
return
|
6892
|
+
|
6893
|
+
if not callable(operation):
|
6894
|
+
logging.error(_("Operator not supported -- Must be a string in ['sum', 'mean', 'min', 'max', 'median'] or a Rebin_Ops Enum"))
|
6895
|
+
|
6896
|
+
|
6897
|
+
if np.mod(self.nbx,factor) != 0 or np.mod(self.nby,factor) != 0 :
|
6898
|
+
# The shape is adjusted to be a multiple of the factor.
|
6899
|
+
# Fill the array with nullvalue
|
6900
|
+
newnbx = self.nbx
|
6901
|
+
newnby = self.nby
|
6902
|
+
if np.mod(self.nbx,factor) !=0:
|
6903
|
+
newnbx = int(self.nbx + factor - np.mod(self.nbx,factor))
|
6904
|
+
if np.mod(self.nby,factor) !=0:
|
6905
|
+
newnby = int(self.nby + factor - np.mod(self.nby,factor))
|
6906
|
+
|
6907
|
+
newarray = np.ma.ones((newnbx,newnby), dtype = self.dtype) * self.nullvalue
|
6754
6908
|
newarray[:self.nbx,:self.nby] = self.array
|
6909
|
+
newarray.mask[:self.nbx,:self.nby] = self.array.mask
|
6755
6910
|
self.array = newarray
|
6756
6911
|
|
6757
6912
|
self.nbx = newnbx
|
@@ -6765,20 +6920,41 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
6765
6920
|
new_shape = (self.nbx, self.nby)
|
6766
6921
|
|
6767
6922
|
if factor>1.:
|
6768
|
-
|
6769
|
-
|
6770
|
-
|
6771
|
-
|
6772
|
-
|
6773
|
-
|
6774
|
-
|
6923
|
+
if operation_matrix is not None:
|
6924
|
+
# Reshape the input array to split it into blocks of size f x f
|
6925
|
+
reshaped_a = self.array.reshape(new_shape[0], int(factor), new_shape[1], int(factor))
|
6926
|
+
|
6927
|
+
# Swap axes to make blocks as separate dimensions
|
6928
|
+
reshaped_a = reshaped_a.swapaxes(1, 2)
|
6929
|
+
|
6930
|
+
# Initialize the output matrix
|
6931
|
+
self.array = ma.masked_array(np.ones((new_shape[0], new_shape[1]), dtype= self.dtype) * self.nullvalue, dtype= self.dtype)
|
6932
|
+
|
6933
|
+
# Check the dtype of the newly initialized array
|
6934
|
+
assert self.array.dtype == self.dtype, _('Bad dtype')
|
6935
|
+
|
6936
|
+
# Vectorized operations
|
6937
|
+
for op_idx, operation in enumerate(Rebin_Ops.get_numpy_ops()):
|
6938
|
+
mask = (operation_matrix.array == op_idx)
|
6939
|
+
if np.any(mask):
|
6940
|
+
block_results = operation(reshaped_a, axis=(2, 3))
|
6941
|
+
self.array[mask] = block_results[mask]
|
6942
|
+
|
6943
|
+
else:
|
6944
|
+
compression_pairs = [(d, c // d) for d, c in zip(new_shape,
|
6945
|
+
self.array.shape)]
|
6946
|
+
flattened = [l for p in compression_pairs for l in p]
|
6947
|
+
self.array = operation(self.array.reshape(flattened), axis=(1, 3)).astype(self.dtype)
|
6948
|
+
|
6949
|
+
self.set_nullvalue_in_mask()
|
6775
6950
|
else:
|
6776
6951
|
self.array = np.kron(self.array, np.ones((int(1/factor), int(1/factor)), dtype=self.array.dtype))
|
6777
6952
|
|
6778
|
-
self.mask_reset()
|
6779
|
-
|
6780
6953
|
self.count()
|
6781
6954
|
|
6955
|
+
# rebin must not change the type of the array
|
6956
|
+
assert self.array.dtype == self.dtype, _('Bad dtype')
|
6957
|
+
|
6782
6958
|
def read_txt_header(self):
|
6783
6959
|
"""
|
6784
6960
|
Read header from txt file
|
@@ -8001,6 +8177,54 @@ class WolfArray(Element_To_Draw, header_wolf):
|
|
8001
8177
|
|
8002
8178
|
self.reset_plot()
|
8003
8179
|
|
8180
|
+
@classmethod
|
8181
|
+
def from_other_epsg_coo(cls,
|
8182
|
+
input_raster_path:str,
|
8183
|
+
input_srs='EPSG:3812',
|
8184
|
+
output_srs='EPSG:31370',
|
8185
|
+
resampling_method=gdal.GRA_Bilinear,
|
8186
|
+
xRes:float=0.5, yRes:float=0.5):
|
8187
|
+
"""
|
8188
|
+
Reprojects and resamples a raster file from an other EPSG coordinates and return it as a WolfArray.
|
8189
|
+
|
8190
|
+
:param input_raster_path: The path to the input raster file.
|
8191
|
+
:type input_raster_path: str
|
8192
|
+
:param input_srs: The input spatial reference system (SRS) in the format 'EPSG:XXXX'. Defaults to Lambert 2008 'EPSG:3812'.
|
8193
|
+
:type input_srs: str
|
8194
|
+
:param output_srs: The output spatial reference system (SRS) in the format 'EPSG:XXXX'. Defaults to Belgian Lambert 72 'EPSG:31370'.
|
8195
|
+
:type output_srs: str
|
8196
|
+
:param resampling_method: The resampling method to use. Defaults to gdal.GRA_Bilinear. Resampling method can be chosen among the gdal GRA_*
|
8197
|
+
constants (gdal.GRA_Average; gdal.GRA_Bilinear; gdal.GRA_Cubic; gdal.GRA_CubicSpline;
|
8198
|
+
gdal.GRA_Lanczos; gdal.GRA_Mode; gdal.GRA_NearestNeighbour)
|
8199
|
+
:type resampling_method: int
|
8200
|
+
:param xRes: The desired output resolution in the x direction. Defaults to 0.5.
|
8201
|
+
:type xRes (float): float
|
8202
|
+
:param yRes: The desired output resolution in the y direction. Defaults to 0.5.
|
8203
|
+
:type yRes (float): float
|
8204
|
+
|
8205
|
+
:raises AssertionError: If the input or output raster file is not a GeoTIFF file.
|
8206
|
+
:raises RuntimeError: If the input raster file cannot be opened.
|
8207
|
+
:raises PermissionError: If there is a permission error while trying to delete the output raster file.
|
8208
|
+
:raises Exception: If an unexpected error occurs while trying to delete the output raster file.
|
8209
|
+
:raises RuntimeError: If the reprojection fails for the input raster file.
|
8210
|
+
|
8211
|
+
:return: WolfArray
|
8212
|
+
"""
|
8213
|
+
|
8214
|
+
#sanitize input
|
8215
|
+
input_raster_path = str(input_raster_path)
|
8216
|
+
input_srs = str(input_srs)
|
8217
|
+
output_srs = str(output_srs)
|
8218
|
+
|
8219
|
+
assert resampling_method in [gdal.GRA_Average, gdal.GRA_Bilinear, gdal.GRA_Cubic, gdal.GRA_CubicSpline, gdal.GRA_Lanczos, gdal.GRA_Mode, gdal.GRA_NearestNeighbour], "Invalid resampling method"
|
8220
|
+
|
8221
|
+
# Define temporary files
|
8222
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
8223
|
+
output_raster_path = os.path.join(temp_dir, "Array_72.tif")
|
8224
|
+
reproject_and_resample_raster(input_raster_path, output_raster_path, input_srs, output_srs, resampling_method, xRes, yRes)
|
8225
|
+
Array3 = WolfArray(output_raster_path, nullvalue=-9999)
|
8226
|
+
return Array3
|
8227
|
+
|
8004
8228
|
class WolfArrayMB(WolfArray):
|
8005
8229
|
"""
|
8006
8230
|
Matrice multiblocks
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: wolfhece
|
3
|
-
Version: 2.1.
|
3
|
+
Version: 2.1.48
|
4
4
|
Author-email: Pierre Archambeau <pierre.archambeau@uliege.be>
|
5
5
|
License: Copyright (c) 2024 University of Liege. All rights reserved.
|
6
6
|
Project-URL: Homepage, https://uee.uliege.be/hece
|
@@ -13,14 +13,14 @@ Classifier: Topic :: Scientific/Engineering :: Physics
|
|
13
13
|
Requires-Python: <3.11,>=3.10
|
14
14
|
Description-Content-Type: text/markdown
|
15
15
|
Requires-Dist: wxpython
|
16
|
-
Requires-Dist: colorlog
|
16
|
+
Requires-Dist: colorlog ==6.7.*
|
17
17
|
Requires-Dist: intel-fortran-rt
|
18
18
|
Requires-Dist: scikit-learn
|
19
19
|
Requires-Dist: cryptography
|
20
|
-
Requires-Dist: jax
|
20
|
+
Requires-Dist: jax ==0.4.30
|
21
21
|
Requires-Dist: triangle
|
22
|
-
Requires-Dist: numpy
|
23
|
-
Requires-Dist: pyopengl
|
22
|
+
Requires-Dist: numpy ==1.23.*
|
23
|
+
Requires-Dist: pyopengl ==3.1.*
|
24
24
|
Requires-Dist: pandas
|
25
25
|
Requires-Dist: geopandas
|
26
26
|
Requires-Dist: scipy
|
@@ -33,7 +33,7 @@ Requires-Dist: graphviz
|
|
33
33
|
Requires-Dist: beautifulsoup4
|
34
34
|
Requires-Dist: requests
|
35
35
|
Requires-Dist: notebook
|
36
|
-
Requires-Dist: matplotlib
|
36
|
+
Requires-Dist: matplotlib ==3.6.*
|
37
37
|
Requires-Dist: mkl
|
38
38
|
Requires-Dist: python-gettext
|
39
39
|
Requires-Dist: shapely
|
@@ -49,10 +49,10 @@ Requires-Dist: python-docx
|
|
49
49
|
Requires-Dist: pygltflib
|
50
50
|
Requires-Dist: ezdxf
|
51
51
|
Requires-Dist: pyvista
|
52
|
-
Requires-Dist: tqdm
|
52
|
+
Requires-Dist: tqdm ==4.64.*
|
53
53
|
Requires-Dist: osmnx
|
54
54
|
Requires-Dist: tifffile
|
55
|
-
Requires-Dist: numba
|
55
|
+
Requires-Dist: numba ==0.58.*
|
56
56
|
Requires-Dist: xmltodict
|
57
57
|
Requires-Dist: opencv-python
|
58
58
|
Requires-Dist: xarray
|
@@ -1,3 +1,4 @@
|
|
1
|
+
wolfhece/Coordinates_operations.py,sha256=YyWlAwKManb-ReQrmP37rEXxehunUCihmkeDYX6qTAQ,8037
|
1
2
|
wolfhece/CpGrid.py,sha256=ke4n1khTUoed2asJl1GR25PsEkI4TpiBDCo4u0aSo9M,10658
|
2
3
|
wolfhece/GraphNotebook.py,sha256=V1_Ak4F_hoIpKm2GAakuyKOALhujjIXB5FwzFHtM5-8,28021
|
3
4
|
wolfhece/GraphProfile.py,sha256=OCgJo0YFFBI6H1z-5egJsOOoWF_iziiza0-bbPejNMc,69656
|
@@ -47,7 +48,7 @@ wolfhece/pywalous.py,sha256=yRaWJjKckXef1d9D5devP0yFHC9uc6kRV4G5x9PNq9k,18972
|
|
47
48
|
wolfhece/rain_SPWMI.py,sha256=qCfcmF7LajloOaCwnTrrSMzyME03YyilmRUOqrPrv3U,13846
|
48
49
|
wolfhece/textpillow.py,sha256=map7HsGYML_o5NHRdFg2s_TVQed_lDnpYNDv27MM0Vw,14130
|
49
50
|
wolfhece/tools_mpl.py,sha256=gQ3Jg1iuZiecmMqa5Eli2ZLSkttu68VXL8YmMDBaEYU,564
|
50
|
-
wolfhece/wolf_array.py,sha256=
|
51
|
+
wolfhece/wolf_array.py,sha256=cWkTaA4nY9I8-FLNlXBwn0xkvaN1EXw6M9NYUYnTqf8,368492
|
51
52
|
wolfhece/wolf_hist.py,sha256=7jeVrgSkM3ErJO6SRMH_PGzfLjIdw8vTy87kesldggk,3582
|
52
53
|
wolfhece/wolf_texture.py,sha256=DS5eobLxrq9ljyebYfpMSQPn8shkUAZZVfqrOKN_QUU,16951
|
53
54
|
wolfhece/wolf_tiles.py,sha256=2Ho2I20rHRY81KXxjgLOYISdF4OkJ2d6omeY4shDoGI,10386
|
@@ -71,7 +72,7 @@ wolfhece/apps/check_install.py,sha256=SG024u18G7VRLKynbp7DKD1jImtHwuWwN4bJWHm-YH
|
|
71
72
|
wolfhece/apps/curvedigitizer.py,sha256=_hRR2PWow7PU7rTHIbc6ykZ08tCXcK9uy7RFrb4EKkE,5196
|
72
73
|
wolfhece/apps/isocurrent.py,sha256=MuwTodHxdc6PrqNpphR2ntYf1NLL2n9klTPndGrOHDQ,4109
|
73
74
|
wolfhece/apps/splashscreen.py,sha256=SrustmIQeXnsiD-92OzjdGhBi-S7c_j-cSvuX4T6rtg,2929
|
74
|
-
wolfhece/apps/version.py,sha256=
|
75
|
+
wolfhece/apps/version.py,sha256=1j6FkD-S6lKIU8cwsITdvdCE6HZVOxDK9aVtSrdT5Vw,388
|
75
76
|
wolfhece/apps/wolf.py,sha256=mM6Tyi4DlKQILmO49cDUCip9fYVy-hLXkY3YhZgIeUQ,591
|
76
77
|
wolfhece/apps/wolf2D.py,sha256=yPQGee7fsegoQ8GfWKrWEjX1Az_ApL-UWlBiqPvaIyY,565
|
77
78
|
wolfhece/apps/wolf_logo.bmp,sha256=ruJ4MA51CpGO_AYUp_dB4SWKHelvhOvd7Q8NrVOjDJk,3126
|
@@ -277,8 +278,8 @@ wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=8PlMYrb_8jI8h9F0_EagpM
|
|
277
278
|
wolfhece/ui/wolf_times_selection_comparison_models.py,sha256=ORy7fz4dcp691qKzaOZHrRLZ0uXNhL-LIHxmpDGL6BI,5007
|
278
279
|
wolfhece/wintab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
279
280
|
wolfhece/wintab/wintab.py,sha256=8A-JNONV6ujgsgG3lM5Uw-pVgglPATwKs86oBzzljoc,7179
|
280
|
-
wolfhece-2.1.
|
281
|
-
wolfhece-2.1.
|
282
|
-
wolfhece-2.1.
|
283
|
-
wolfhece-2.1.
|
284
|
-
wolfhece-2.1.
|
281
|
+
wolfhece-2.1.48.dist-info/METADATA,sha256=2S8MGX7bCP41sSY7a9scSmcsfKj2w8uiaMzIY5bIY9k,2548
|
282
|
+
wolfhece-2.1.48.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
283
|
+
wolfhece-2.1.48.dist-info/entry_points.txt,sha256=Q5JuIWV4odeIJI3qc6fV9MwRoz0ezqPVlFC1Ppm_vdQ,395
|
284
|
+
wolfhece-2.1.48.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
|
285
|
+
wolfhece-2.1.48.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|