@@ -175,9 +175,6 @@ def add_raster_series(self, baseseries, fill_gaps=False):
175
175
self .baseseries = baseseries
176
176
self ._fill_gaps = fill_gaps
177
177
self ._baseseries_added = True
178
-
179
- self ._base_calls = []
180
- self ._legend = None
181
178
# create list of layers to render and date/times
182
179
self ._layers , self ._labels = collect_layers (
183
180
self .baseseries , self ._element_type , self ._fill_gaps
@@ -202,9 +199,6 @@ def add_vector_series(self, baseseries, fill_gaps=False):
202
199
self .baseseries = baseseries
203
200
self ._fill_gaps = fill_gaps
204
201
self ._baseseries_added = True
205
- # NEW CODE: Reset overlays and legend when adding a new series
206
- self ._base_calls = []
207
- self ._legend = None
208
202
# create list of layers to render and date/times
209
203
self ._layers , self ._labels = collect_layers (
210
204
self .baseseries , self ._element_type , self ._fill_gaps
@@ -217,108 +211,74 @@ def add_vector_series(self, baseseries, fill_gaps=False):
217
211
self ._indices = self ._labels
218
212
219
213
def d_legend (self , ** kwargs ):
220
- """Display legend.
221
-
222
- Wraps d.legend and uses same keyword arguments.
214
+ """Display legend for all timesteps .
215
+
216
+ Wraps ` d.legend` and uses the same keyword arguments.
223
217
"""
224
- if "raster" in kwargs and not self ._baseseries_added :
225
- self ._base_layer_calls .append (("d.legend" , kwargs ))
226
- if "raster" in kwargs and self ._baseseries_added :
227
- self ._base_calls .append (("d.legend" , kwargs ))
228
- else :
229
- self ._legend = kwargs
230
- # If d_legend has been called, we need to re-render layers
231
- self ._layers_rendered = False
232
-
233
- def _render_legend (self , img ):
234
- """Add legend to Map instance"""
235
- info = gs .parse_command (
236
- "t.info" , input = self .baseseries , flags = "g" , env = self ._env
237
- )
238
- min_min = info ["min_min" ]
239
- max_max = info ["max_max" ]
240
- img .d_legend (
241
- raster = self ._layers [0 ],
242
- range = f"{ min_min } , { max_max } " ,
243
- ** self ._legend ,
244
- )
218
+ self ._legend = kwargs
219
+ self ._layers_rendered = False
245
220
246
- def _render_overlays (self , img ):
247
- """Add collected overlays to Map instance"""
248
- for grass_module , kwargs in self ._base_calls :
249
- img .run (grass_module , ** kwargs )
250
-
251
- def _render_blank_layer (self , filename ):
252
- """Write blank image for gaps in time series.
253
-
254
- Adds overlays and legend to base map.
255
- """
256
- img = Map (
257
- width = self ._width ,
258
- height = self ._height ,
259
- filename = filename ,
260
- use_region = True ,
261
- env = self ._env ,
262
- read_file = True ,
263
- )
264
- # Add overlays
265
- self ._render_overlays (img )
266
- # Add legend if needed
221
+ def _apply_legend (self , img ):
222
+ """Override BaseSeriesMap to set dynamic legend range for time series."""
267
223
if self ._legend :
268
- self ._render_legend (img )
269
-
270
- def _render_layer (self , layer , filename ):
271
- """Render layer to file with overlays and legend"""
272
- img = Map (
273
- width = self ._width ,
274
- height = self ._height ,
275
- filename = filename ,
276
- use_region = True ,
277
- env = self ._env ,
278
- read_file = True ,
279
- )
280
-
281
-
282
- img .run ("d.erase" , flags = "f" )
224
+ info = gs .parse_command (
225
+ "t.info" , input = self .baseseries , flags = "g" , env = self ._env
226
+ )
227
+ min_min = info ["min_min" ]
228
+ max_max = info ["max_max" ]
229
+ img .d_legend (
230
+ raster = self ._layers [0 ], # Use first layer for range
231
+ range = f"{ min_min } , { max_max } " ,
232
+ ** self ._legend ,
233
+ )
283
234
235
+ def _render_worker (self , date , layer , filename ):
236
+ """Render a timestep with overlays/legends"""
237
+ img = Map (
238
+ width = self ._width ,
239
+ height = self ._height ,
240
+ filename = filename ,
241
+ use_region = True ,
242
+ env = self ._env ,
243
+ read_file = False ,
244
+ )
245
+ img .d_erase ()
246
+
247
+ # Render base layer only if not "None"
248
+ if layer != "None" :
284
249
if self ._element_type == "strds" :
285
250
img .d_rast (map = layer )
286
251
elif self ._element_type == "stvds" :
287
252
img .d_vect (map = layer )
288
- # Add overlays
289
- self ._render_overlays (img )
290
- # Add legend if needed
291
- if self ._legend :
292
- self ._render_legend (img )
293
253
294
- def _render_worker (self , date , layer , filename ):
295
- """Function to render a single layer."""
296
- shutil .copyfile (self .base_file , filename )
297
- if layer == "None" :
298
- self ._render_blank_layer (filename )
299
- else :
300
- self ._render_layer (layer , filename )
301
- return date , filename
254
+ #Apply overlays/legend to ALL layers (including "None")
255
+ self ._apply_overlays (img ) # Fixed indentation
256
+ self ._apply_legend (img ) # Fixed indentation
257
+
258
+ img .save (filename )
259
+ return (date , filename )
302
260
303
261
def render (self ):
304
- """Renders image for each time-step in space-time dataset."""
305
- if not self ._baseseries_added :
306
- msg = (
307
- "Cannot render space time dataset since none has been added."
308
- " Use TimeSeriesMap.add_raster_series() or "
309
- "TimeSeriesMap.add_vector_series() to add dataset"
262
+ """Renders image for each time-step in space-time dataset."""
263
+ if not self ._baseseries_added :
264
+ msg = (
265
+ "Cannot render space time dataset since none has been added."
266
+ " Use TimeSeriesMap.add_raster_series() or "
267
+ "TimeSeriesMap.add_vector_series() to add dataset"
268
+ )
269
+ raise RuntimeError (msg )
270
+
271
+ # Prepare tasks with tuples
272
+ tasks = []
273
+ for date , layer in self ._date_layer_dict .items ():
274
+ if layer == "None" :
275
+ # Generate unique filename for each "None" layer
276
+ filename = os .path .join (
277
+ self ._tmpdir .name ,
278
+ f"none_{ gs .append_random ('' , 8 )} .png" # Unique random name
310
279
)
311
- raise RuntimeError (msg )
312
-
313
- # Create name for empty layers
314
- random_name_none = gs .append_random ("none" , 8 ) + ".png"
315
-
316
- # Prepare tasks with tuples
317
- tasks = []
318
- for date , layer in self ._date_layer_dict .items ():
319
- if layer == "None" :
320
- filename = os .path .join (self ._tmpdir .name , random_name_none )
321
- else :
322
- filename = os .path .join (self ._tmpdir .name , f"{ layer } .png" )
323
- tasks .append ((date , layer , filename ))
324
- self ._render (tasks )
280
+ else :
281
+ filename = os .path .join (self ._tmpdir .name , f"{ layer } .png" )
282
+
283
+ tasks .append ((date , layer , filename ))
284
+ self ._render (tasks )
0 commit comments