From aabdce599d077f07e25ce830ca17ec46456a6501 Mon Sep 17 00:00:00 2001 From: Alex Morling Date: Tue, 28 May 2024 15:48:50 +0200 Subject: [PATCH] lazy load of expensive / niche imports --- ecoscope/analysis/ecograph.py | 14 ++++++-------- ecoscope/analysis/seasons.py | 3 +-- ecoscope/analysis/speed.py | 19 ++++++++++--------- ecoscope/base/base.py | 5 ++++- ecoscope/mapping/map.py | 5 ++++- ecoscope/plotting/plot.py | 3 +-- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/ecoscope/analysis/ecograph.py b/ecoscope/analysis/ecograph.py index 36bf3ba2..9496468f 100644 --- a/ecoscope/analysis/ecograph.py +++ b/ecoscope/analysis/ecograph.py @@ -2,6 +2,7 @@ import geopandas as gpd import igraph +import sklearn import networkx as nx import numpy as np import pandas as pd @@ -10,7 +11,7 @@ from shapely.geometry import shape from skimage.draw import line -import ecoscope +from ecoscope.io.raster import RasterExtent, RasterProfile, RasterPy class Ecograph: @@ -118,7 +119,6 @@ def to_geotiff(self, feature, output_path, individual="all", interpolation=None, transform : sklearn.base.TransformerMixin or None A feature transform method (Default : None) """ - from sklearn.base import TransformerMixin if feature in self.features: if individual == "all": @@ -130,22 +130,20 @@ def to_geotiff(self, feature, output_path, individual="all", interpolation=None, else: raise ValueError("This feature was not computed by EcoGraph") - if isinstance(transform, TransformerMixin): + if isinstance(transform, sklearn.base.TransformerMixin): nan_mask = ~np.isnan(feature_ndarray) feature_ndarray[nan_mask] = transform.fit_transform(feature_ndarray[nan_mask].reshape(-1, 1)).reshape( feature_ndarray[nan_mask].shape ) - raster_profile = ecoscope.io.raster.RasterProfile( + raster_profile = RasterProfile( pixel_size=self.resolution, crs=self.utm_crs, nodata_value=np.nan, band_count=1, ) - raster_profile.raster_extent = ecoscope.io.raster.RasterExtent( - x_min=self.xmin, x_max=self.xmax, y_min=self.ymin, y_max=self.ymax - ) - ecoscope.io.raster.RasterPy.write( + raster_profile.raster_extent = RasterExtent(x_min=self.xmin, x_max=self.xmax, y_min=self.ymin, y_max=self.ymax) + RasterPy.write( ndarray=feature_ndarray, fp=output_path, **raster_profile, diff --git a/ecoscope/analysis/seasons.py b/ecoscope/analysis/seasons.py index fb1e8cc0..f9a27cb9 100644 --- a/ecoscope/analysis/seasons.py +++ b/ecoscope/analysis/seasons.py @@ -6,6 +6,7 @@ import shapely from scipy.stats import norm from sklearn.preprocessing import LabelEncoder +from sklearn.mixture import GaussianMixture logger = logging.getLogger(__name__) @@ -49,8 +50,6 @@ def std_ndvi_vals(aoi=None, img_coll=None, nir_band=None, red_band=None, img_sca def val_cuts(vals, num_seasons=2): - from sklearn.mixture import GaussianMixture - distr = GaussianMixture(n_components=num_seasons, max_iter=500) vals = vals["NDVI"].to_numpy().reshape(-1, 1) distr.fit(vals) diff --git a/ecoscope/analysis/speed.py b/ecoscope/analysis/speed.py index 06f6efc0..1a339436 100644 --- a/ecoscope/analysis/speed.py +++ b/ecoscope/analysis/speed.py @@ -5,6 +5,9 @@ import shapely import ecoscope.base +import lazy_loader as lazy + +mapclassify = lazy.load("mapclassify") class SpeedDataFrame(ecoscope.base.EcoDataFrame): @@ -64,15 +67,13 @@ def apply_classification(x, k, cls_method="natural_breaks", multiples=[-2, -1, 1 The multiples of the standard deviation to add/subtract from the sample mean to define the bins. defaults= """ - from mapclassify import classifiers - classification_methods = { - "equal_interval": classifiers.EqualInterval, - "natural_breaks": classifiers.NaturalBreaks, - "quantile": classifiers.Quantiles, - "std_mean": classifiers.StdMean, - "max_breaks": classifiers.MaximumBreaks, - "fisher_jenks": classifiers.FisherJenks, + "equal_interval": mapclassify.EqualInterval, + "natural_breaks": mapclassify.NaturalBreaks, + "quantile": mapclassify.Quantiles, + "std_mean": mapclassify.StdMean, + "max_breaks": mapclassify.MaximumBreaks, + "fisher_jenks": mapclassify.FisherJenks, } classifier = classification_methods.get(cls_method) @@ -80,7 +81,7 @@ def apply_classification(x, k, cls_method="natural_breaks", multiples=[-2, -1, 1 return map_classifier = classifier(x, multiples) if cls_method == "std_mean" else classifier(x, k) - edges, _, _ = classifiers._format_intervals(map_classifier, fmt="{:.2f}") + edges, _, _ = mapclassify.classifiers._format_intervals(map_classifier, fmt="{:.2f}") return [float(i) for i in edges] diff --git a/ecoscope/base/base.py b/ecoscope/base/base.py index 74db6f41..dde112bd 100644 --- a/ecoscope/base/base.py +++ b/ecoscope/base/base.py @@ -17,6 +17,10 @@ ) from ecoscope.base.utils import cachedproperty +import lazy_loader as lazy + +astroplan = lazy.load("astroplan") + class EcoDataFrame(gpd.GeoDataFrame): """ @@ -393,7 +397,6 @@ def get_daynight_ratio(self, n_grid_points=150) -> pd.Series: pd.Series: Daynight ratio for each unique individual subject in the grouby_col column. """ - import astroplan locations = to_EarthLocation(self.geometry.to_crs(crs=self.estimate_utm_crs()).centroid) diff --git a/ecoscope/mapping/map.py b/ecoscope/mapping/map.py index 07502583..cefc8dd0 100644 --- a/ecoscope/mapping/map.py +++ b/ecoscope/mapping/map.py @@ -21,6 +21,10 @@ import ecoscope from ecoscope.contrib.foliumap import Map +import lazy_loader as lazy + +ds = lazy.load("datashader") + warnings.filterwarnings("ignore", "GeoSeries.isna", UserWarning) @@ -508,7 +512,6 @@ def add_datashader_gdf( kwargs Additional kwargs passed to datashader.transfer_functions.shade """ - import datashader as ds gdf = gdf.to_crs(epsg=4326) bounds = gdf.geometry.total_bounds diff --git a/ecoscope/plotting/plot.py b/ecoscope/plotting/plot.py index 930c91dd..60a58418 100644 --- a/ecoscope/plotting/plot.py +++ b/ecoscope/plotting/plot.py @@ -3,6 +3,7 @@ import plotly.graph_objs as go import shapely from plotly.subplots import make_subplots +from sklearn.neighbors import KernelDensity class EcoPlotData: @@ -242,8 +243,6 @@ def speed(trajectory): def plot_seasonal_dist(ndvi_vals, cuts, bandwidth=0.05, output_file=None): - from sklearn.neighbors import KernelDensity - x = ndvi_vals.sort_values().to_numpy().reshape(-1, 1) kde = KernelDensity(kernel="gaussian", bandwidth=bandwidth).fit(x) dens = np.exp(kde.score_samples(x))