From 981f5656edb2927e2fa01d0147e012345c5fdbdf Mon Sep 17 00:00:00 2001 From: Krixna-Kant Date: Mon, 5 May 2025 16:52:09 +0530 Subject: [PATCH] Added inline comments and docstrings to geoplot.py for clarity (#65) --- geoplot.py | 57 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/geoplot.py b/geoplot.py index 6f264d1..77c55dc 100644 --- a/geoplot.py +++ b/geoplot.py @@ -40,6 +40,8 @@ from string import Template from agent_torch.core.helpers import get_by_path +# HTML template for the Cesium-powered visualization +# This template includes JavaScript for handling time-series data visualization using Cesium geoplot_template = """ @@ -214,39 +216,51 @@ def read_var(state, var): + """Access nested state variables using slash-separated path (e.g. 'agents/position')""" return get_by_path(state, re.split("/", var)) class GeoPlot: + """Cesium-based geospatial visualizer for agent simulation data. + + Converts agent state trajectories into time-series GeoJSON format and generates + interactive 3D maps showing property evolution using color/size encoding. + """ def __init__(self, config, options): + # Cesium Ion API access token + self.cesium_token = options["cesium_token"] + # Time between simulation steps (seconds) + self.step_time = options["step_time"] + # Path to agent coordinates in state (e.g. "agents/location") + self.entity_position = options["coordinates"] + # Path to visualized property in state (e.g. "agents/energy") + self.entity_property = options["feature"] + # Visualization encoding type: 'color' or 'size' + self.visualization_type = options["visualization_type"] self.config = config - ( - self.cesium_token, - self.step_time, - self.entity_position, - self.entity_property, - self.visualization_type, - ) = ( - options["cesium_token"], - options["step_time"], - options["coordinates"], - options["feature"], - options["visualization_type"], - ) def render(self, state_trajectory): + """Process simulation states and generate visualization files: + - GeoJSON file with time-series agent data + - HTML file with Cesium visualization setup + """ coords, values = [], [] name = self.config["simulation_metadata"]["name"] geodata_path, geoplot_path = f"{name}.geojson", f"{name}.html" + # Extract coordinates and property values from each episode's final state for i in range(0, len(state_trajectory) - 1): - final_state = state_trajectory[i][-1] + final_state = state_trajectory[i][-1] # Final state of episode + # Get agent coordinates as [[lat1, lon1], [lat2, lon2], ...] coords = np.array(read_var(final_state, self.entity_position)).tolist() + + # Extract and flatten property values for heatmap generation values.append( np.array(read_var(final_state, self.entity_property)).flatten().tolist() ) + # Generate simulation timestamps for Cesium timeline start_time = pd.Timestamp.utcnow() timestamps = [ start_time + pd.Timedelta(seconds=i * self.step_time) @@ -256,15 +270,18 @@ def render(self, state_trajectory): ) ] + # Build GeoJSON structure for Cesium visualization geojsons = [] for i, coord in enumerate(coords): features = [] + # Create time-encoded features for each agent's property values for time, value_list in zip(timestamps, values): features.append( { "type": "Feature", "geometry": { "type": "Point", + # Convert to GeoJSON [longitude, latitude] order "coordinates": [coord[1], coord[0]], }, "properties": { @@ -275,19 +292,21 @@ def render(self, state_trajectory): ) geojsons.append({"type": "FeatureCollection", "features": features}) + # Write GeoJSON data file with open(geodata_path, "w", encoding="utf-8") as f: json.dump(geojsons, f, ensure_ascii=False, indent=2) + # Generate HTML visualization with template substitution tmpl = Template(geoplot_template) with open(geoplot_path, "w", encoding="utf-8") as f: f.write( tmpl.substitute( { - "accessToken": self.cesium_token, - "startTime": timestamps[0].isoformat(), - "stopTime": timestamps[-1].isoformat(), - "data": json.dumps(geojsons), - "visualType": self.visualization_type, + "accessToken": self.cesium_token, # Cesium API token + "startTime": timestamps[0].isoformat(), # Simulation start + "stopTime": timestamps[-1].isoformat(), # Simulation end + "data": json.dumps(geojsons), # Embedded GeoJSON + "visualType": self.visualization_type, # Color/size encoding } ) )