Spaces:
Sleeping
Sleeping
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import argparse | |
import gc | |
import glob | |
import logging | |
import multiprocessing | |
import os | |
import traceback | |
import netCDF4 | |
import numpy as np | |
import PIL | |
from mpl_toolkits.basemap import Basemap | |
from libs.utils import setup_logging | |
from libs.utils import verbose as vprint | |
setup_logging() | |
log = logging.getLogger(__name__) | |
CONFIG = {} | |
V = 1 | |
V_IGNORE = [] # Debug, Warning, Error | |
# print(os.getcwd()) | |
def vis(files, layers=["SM1", "SM2", "SM3", "SM4", "SM5", "DD"], days="all"): | |
"""Save the visualisation of the soil moisture content for given layers, | |
year files, and days. | |
Parameters | |
---------- | |
files : list | |
Iterable of the absolute or relative paths to the netcdf data ending with .nc. | |
layers : list | |
Soil layers to visualise. Default is ["SM1","SM2","SM3","SM4","SM5","DD"]. | |
days : list / str | |
Iterable days of year range to visualise. Default is 'all'. | |
Returns | |
------- | |
None | |
""" | |
inputs = [(file, layer, days) for file in files for layer in layers] | |
num_processes = multiprocessing.cpu_count() | |
with multiprocessing.Pool(processes=max(1, int(num_processes / 2))) as pool: | |
# pool.starmap(vis_process, [(f, l, days) for f in files for l in layers]) | |
# pool.apply_async(vis_process, args=inputs) | |
for result in pool.imap_unordered(vis_process, inputs): | |
print(f"Result file: {result}", flush=True) | |
# pool.close() | |
# pool.join() | |
def vis_process(input_nc_layer_days): | |
"""Save the visualisation of the soil moisture content for a given layer, | |
year file, and days. | |
Parameters | |
---------- | |
input_nc : str | |
Absolute or relative path to the netcdf data ending with .nc. | |
layer : str | |
Soil layer to visualise. | |
days : list / str | |
Iterable days of year range to visualise. | |
Returns | |
------- | |
None | |
""" | |
import matplotlib | |
import matplotlib.pyplot as plt | |
input_nc, layer, days = input_nc_layer_days | |
nc = netCDF4.Dataset(input_nc) | |
# ref = nc.variables["spatial_ref"] | |
# vprint(1, V, V_IGNORE, Debug=ref) | |
lons = nc.variables["x"][:] | |
lats = nc.variables["y"][:] | |
mp = Basemap( | |
projection="merc", | |
llcrnrlon=lons.min() - 0.02, # lower longitude | |
llcrnrlat=lats.min() - 0.02, # lower latitude | |
urcrnrlon=lons.max() + 0.02, # uppper longitude | |
urcrnrlat=lats.max() + 0.02, # uppper latitude | |
resolution="i", | |
) | |
lon, lat = np.meshgrid(lons, lats) # this converts coordinates into 2D arrray | |
x, y = mp(lon, lat) # mapping them together | |
layer_data = nc.variables[layer][:] | |
if days == "all": | |
days = np.arange(0, layer_data.shape[0]) | |
# Generate daily images | |
for i in days: | |
day = i + 1 | |
matplotlib.use("Agg") | |
plt.figure(figsize=(6, 8)) # figure size | |
c_scheme = mp.pcolor(x, y, np.squeeze(layer_data[i, :, :]), cmap="jet") | |
# mp.etopo() | |
mp.shadedrelief() | |
mp.drawcoastlines() | |
mp.drawstates() | |
mp.drawcountries() | |
mp.colorbar(c_scheme, location="right", pad="10%") | |
plt.title("Soil moisture content for day " + str(day) + " of the year") | |
plt.clim(layer_data.min(), layer_data.max()) | |
plt.savefig(f".tmp/{layer}_{str(day)}.jpg") | |
plt.clf() | |
plt.close("all") | |
# Generate gif animation | |
image_frames = [] # creating a empty list to be appended later on | |
for day in days: | |
new_fram = PIL.Image.open(f".tmp/{layer}_{str(day + 1)}.jpg") | |
image_frames.append(new_fram) | |
o_name = input_nc.replace(".nc", f"_{layer}.gif") | |
image_frames[0].save( | |
o_name, | |
format="GIF", | |
append_images=image_frames[1:], | |
save_all=True, | |
duration=150, | |
loop=0, | |
) | |
# Delete temporary files | |
del ( | |
nc, | |
layer_data, | |
mp, | |
image_frames, | |
c_scheme, | |
plt, | |
new_fram, | |
lon, | |
lat, | |
x, | |
y, | |
lons, | |
lats, | |
day, | |
input_nc, | |
layer, | |
days, | |
i, | |
) | |
gc.collect() | |
return o_name | |
if __name__ == "__main__": | |
# Load Configs | |
parser = argparse.ArgumentParser( | |
description="Download rainfall data from Google Earth Engine for a range of dates.", | |
formatter_class=argparse.ArgumentDefaultsHelpFormatter, | |
) | |
parser.add_argument( | |
"-i", | |
"--input", | |
help="Absolute or relative path to the netcdf data ending with .nc. By dfault it is set to data.nc", | |
default="data.nc", | |
) | |
parser.add_argument( | |
"-l", | |
"--layer", | |
help="Soil layer to visualise. Default is all. Select between SM1 to SM5 or DD.", | |
default="all", | |
) | |
parser.add_argument( | |
"-d", | |
"--days", | |
help="Iterable days of year range to visualise. Default is all.", | |
default="all", | |
) | |
args = parser.parse_args() | |
try: | |
# Get the files | |
if os.path.isdir(args.input): | |
files = glob.glob(os.path.join(args.input, "*.nc")) | |
else: | |
files = [args.input] | |
# Get the layers | |
if args.layer == "all": | |
layers = ["SM1", "SM2", "SM3", "SM4", "SM5", "DD"] | |
else: | |
layers = str(args.layer).split(",") | |
# Get the days | |
if args.days == "all": | |
days = "all" | |
else: | |
days = str(args.days).split(",") | |
vis(files, layers, days) | |
except Exception as e: | |
vprint( | |
0, | |
V, | |
V_IGNORE, | |
Error="Failed to execute the main function:", | |
ErrorMessage=e, | |
) | |
traceback.print_exc() | |
raise e | |