@@ -2009,7 +2009,15 @@ def hctsa(self, samples, hctsa_folder, workers=None, return_meta=False):
20092009 pass
20102010
20112011
2012- def compute_features (self , samples , n_jobs = None , chunksize = None , start_method = "spawn" ):
2012+ def compute_features (
2013+ self ,
2014+ samples ,
2015+ n_jobs = None ,
2016+ chunksize = None ,
2017+ start_method = "spawn" ,
2018+ progress_callback = None ,
2019+ log_callback = None ,
2020+ ):
20132021 """
20142022 Compute features from a collection of 1D samples in parallel.
20152023
@@ -2023,6 +2031,12 @@ def compute_features(self, samples, n_jobs=None, chunksize=None, start_method="s
20232031 Chunk size for multiprocessing scheduling.
20242032 start_method : {"spawn","fork","forkserver"}
20252033 Process start method. "spawn" is most robust across platforms.
2034+ progress_callback : callable | None
2035+ Optional callback receiving progress updates as
2036+ ``progress_callback(completed, total, percent)``.
2037+ If the callback only accepts one argument, ``percent`` is passed.
2038+ log_callback : callable | None
2039+ Optional callback receiving textual progress messages.
20262040
20272041 Returns
20282042 -------
@@ -2040,6 +2054,20 @@ def compute_features(self, samples, n_jobs=None, chunksize=None, start_method="s
20402054 if n == 0 :
20412055 return []
20422056
2057+ if log_callback :
2058+ try :
2059+ log_callback (f"Starting feature computation ({ self .method } ) on { n } sample(s)." )
2060+ except Exception :
2061+ pass
2062+
2063+ if progress_callback :
2064+ try :
2065+ progress_callback (0 , n , 0 )
2066+ except TypeError :
2067+ progress_callback (0 )
2068+ except Exception :
2069+ pass
2070+
20432071 if self .method == "hctsa" :
20442072 hctsa_folder = self .params .get ("hctsa_folder" , None )
20452073 if hctsa_folder is None :
@@ -2048,7 +2076,25 @@ def compute_features(self, samples, n_jobs=None, chunksize=None, start_method="s
20482076 "Make sure hctsa is installed and its setup instructions have been followed."
20492077 )
20502078 workers = n_jobs if n_jobs is not None else (os .cpu_count () or 1 )
2051- return self .hctsa (samples_list , hctsa_folder = hctsa_folder , workers = workers )
2079+ if log_callback :
2080+ try :
2081+ log_callback (f"Running hctsa with { workers } worker(s)." )
2082+ except Exception :
2083+ pass
2084+ result = self .hctsa (samples_list , hctsa_folder = hctsa_folder , workers = workers )
2085+ if progress_callback :
2086+ try :
2087+ progress_callback (n , n , 100 )
2088+ except TypeError :
2089+ progress_callback (100 )
2090+ except Exception :
2091+ pass
2092+ if log_callback :
2093+ try :
2094+ log_callback ("Feature computation finished." )
2095+ except Exception :
2096+ pass
2097+ return result
20522098
20532099 # Determine number of processes
20542100 if n_jobs is None :
@@ -2072,5 +2118,32 @@ def compute_features(self, samples, n_jobs=None, chunksize=None, start_method="s
20722118
20732119 if self .tqdm_inst :
20742120 it = self .tqdm (it , total = n , desc = f"Computing { self .method } features" )
2075-
2076- return list (it )
2121+ results = []
2122+ last_percent = - 1
2123+ next_log_percent = 5
2124+ for completed , feature_out in enumerate (it , start = 1 ):
2125+ results .append (feature_out )
2126+ percent = int ((completed * 100 ) / n )
2127+ if percent != last_percent and progress_callback :
2128+ try :
2129+ progress_callback (completed , n , percent )
2130+ except TypeError :
2131+ progress_callback (percent )
2132+ except Exception :
2133+ pass
2134+ last_percent = percent
2135+
2136+ if log_callback and (percent >= next_log_percent or completed == n ):
2137+ try :
2138+ log_callback (f"Feature progress: { completed } /{ n } ({ percent } %)." )
2139+ except Exception :
2140+ pass
2141+ while next_log_percent <= percent :
2142+ next_log_percent += 5
2143+
2144+ if log_callback :
2145+ try :
2146+ log_callback ("Feature computation finished." )
2147+ except Exception :
2148+ pass
2149+ return results
0 commit comments